wine-wine/dlls/scrobj/scrobj.c

2563 lines
74 KiB
C

/*
* Copyright 2017 Nikolay Sivov
* Copyright 2019 Jacek Caban for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define COBJMACROS
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "ole2.h"
#include "olectl.h"
#include "rpcproxy.h"
#include "activscp.h"
#include "dispex.h"
#include "mshtmhst.h"
#include "initguid.h"
#include "scrobj.h"
#include "xmllite.h"
#include "wine/debug.h"
#include "wine/heap.h"
#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(scrobj);
#ifdef _WIN64
#define IActiveScriptParse_Release IActiveScriptParse64_Release
#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
#else
#define IActiveScriptParse_Release IActiveScriptParse32_Release
#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
#endif
static HINSTANCE scrobj_instance;
enum member_type
{
MEMBER_METHOD,
MEMBER_PROPERTY
};
#define PROP_GETTER 0x01
#define PROP_SETTER 0x02
struct scriptlet_member
{
struct list entry;
enum member_type type;
WCHAR *name;
union
{
struct list parameters;
unsigned int flags;
} u;
};
struct method_parameter
{
struct list entry;
WCHAR *name;
};
struct scriptlet_script
{
struct list entry;
WCHAR *language;
WCHAR *body;
};
struct scriptlet_global
{
IDispatchEx IDispatchEx_iface;
LONG ref;
};
struct scriptlet_factory
{
IClassFactory IClassFactory_iface;
LONG ref;
IXmlReader *xml_reader;
IMoniker *moniker;
BOOL have_registration;
BOOL have_public;
WCHAR *description;
WCHAR *progid;
WCHAR *versioned_progid;
WCHAR *version;
WCHAR *classid_str;
CLSID classid;
struct list hosts;
struct list members;
struct list scripts;
};
struct script_reference
{
struct script_host *host;
DISPID id;
};
struct object_member
{
enum member_type type;
BSTR name;
union
{
struct script_reference method;
struct
{
struct script_reference get;
struct script_reference put;
} property;
} u;
};
struct scriptlet_instance
{
IDispatchEx IDispatchEx_iface;
LONG ref;
struct list hosts;
struct scriptlet_global *global;
unsigned member_cnt;
struct object_member *members;
};
struct script_host
{
IActiveScriptSite IActiveScriptSite_iface;
IActiveScriptSiteWindow IActiveScriptSiteWindow_iface;
IServiceProvider IServiceProvider_iface;
LONG ref;
struct list entry;
WCHAR *language;
IActiveScript *active_script;
IActiveScriptParse *parser;
IDispatchEx *script_dispatch;
struct scriptlet_instance *object;
SCRIPTSTATE state;
BOOL cloned;
};
typedef enum tid_t
{
NULL_tid,
IGenScriptletTLib_tid,
LAST_tid
} tid_t;
static ITypeLib *typelib;
static ITypeInfo *typeinfos[LAST_tid];
static REFIID tid_ids[] = {
&IID_NULL,
&IID_IGenScriptletTLib,
};
static HRESULT load_typelib(void)
{
HRESULT hres;
ITypeLib *tl;
if (typelib)
return S_OK;
hres = LoadRegTypeLib(&LIBID_Scriptlet, 1, 0, LOCALE_SYSTEM_DEFAULT, &tl);
if (FAILED(hres))
{
ERR("LoadRegTypeLib failed: %08x\n", hres);
return hres;
}
if (InterlockedCompareExchangePointer((void **)&typelib, tl, NULL))
ITypeLib_Release(tl);
return hres;
}
static HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo)
{
HRESULT hres;
if (FAILED(hres = load_typelib()))
return hres;
if (!typeinfos[tid])
{
ITypeInfo *ti;
hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti);
if (FAILED(hres)) {
ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids[tid]), hres);
return hres;
}
if (InterlockedCompareExchangePointer((void **)(typeinfos+tid), ti, NULL))
ITypeInfo_Release(ti);
}
*typeinfo = typeinfos[tid];
ITypeInfo_AddRef(typeinfos[tid]);
return S_OK;
}
static void release_typelib(void)
{
unsigned i;
if (!typelib)
return;
for (i = 0; i < ARRAY_SIZE(typeinfos); i++)
if (typeinfos[i])
ITypeInfo_Release(typeinfos[i]);
ITypeLib_Release(typelib);
}
static WCHAR *heap_strdupW(const WCHAR *str)
{
WCHAR *ret;
size_t size = (wcslen(str) + 1) * sizeof(WCHAR);
if (!(ret = heap_alloc(size))) return NULL;
memcpy(ret, str, size);
return ret;
}
static inline struct scriptlet_global *global_from_IDispatchEx(IDispatchEx *iface)
{
return CONTAINING_RECORD(iface, struct scriptlet_global, IDispatchEx_iface);
}
static HRESULT WINAPI global_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
if (IsEqualGUID(&IID_IUnknown, riid))
{
TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
*ppv = &This->IDispatchEx_iface;
}
else if (IsEqualGUID(&IID_IDispatch, riid))
{
TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
*ppv = &This->IDispatchEx_iface;
}
else if (IsEqualGUID(&IID_IDispatchEx, riid))
{
TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
*ppv = &This->IDispatchEx_iface;
}
else
{
WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
*ppv = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef((IUnknown*)*ppv);
return S_OK;
}
static ULONG WINAPI global_AddRef(IDispatchEx *iface)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
return ref;
}
static ULONG WINAPI global_Release(IDispatchEx *iface)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
if (!ref) heap_free(This);
return ref;
}
static HRESULT WINAPI global_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
FIXME("(%p)->(%p)\n", This, pctinfo);
return E_NOTIMPL;
}
static HRESULT WINAPI global_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
return E_NOTIMPL;
}
static HRESULT WINAPI global_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
UINT i;
HRESULT hres;
TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
for(i=0; i < cNames; i++)
{
hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId + i);
if(FAILED(hres))
return hres;
}
return S_OK;
}
static HRESULT WINAPI global_Invoke(IDispatchEx *iface, DISPID dispIdMember,
REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
pDispParams, pVarResult, pExcepInfo, NULL);
}
static HRESULT WINAPI global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
FIXME("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
return E_NOTIMPL;
}
static HRESULT WINAPI global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
FIXME("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
return E_NOTIMPL;
}
static HRESULT WINAPI global_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
return E_NOTIMPL;
}
static HRESULT WINAPI global_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
FIXME("(%p)->(%x)\n", This, id);
return E_NOTIMPL;
}
static HRESULT WINAPI global_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
return E_NOTIMPL;
}
static HRESULT WINAPI global_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
return E_NOTIMPL;
}
static HRESULT WINAPI global_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
return E_NOTIMPL;
}
static HRESULT WINAPI global_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
{
struct scriptlet_global *This = global_from_IDispatchEx(iface);
FIXME("(%p)->(%p)\n", This, ppunk);
return E_NOTIMPL;
}
static IDispatchExVtbl global_vtbl = {
global_QueryInterface,
global_AddRef,
global_Release,
global_GetTypeInfoCount,
global_GetTypeInfo,
global_GetIDsOfNames,
global_Invoke,
global_GetDispID,
global_InvokeEx,
global_DeleteMemberByName,
global_DeleteMemberByDispID,
global_GetMemberProperties,
global_GetMemberName,
global_GetNextDispID,
global_GetNameSpaceParent
};
static HRESULT set_script_state(struct script_host *host, SCRIPTSTATE state)
{
HRESULT hres;
if (state == host->state) return S_OK;
hres = IActiveScript_SetScriptState(host->active_script, state);
if (FAILED(hres)) return hres;
host->state = state;
return S_OK;
}
static inline struct script_host *impl_from_IActiveScriptSite(IActiveScriptSite *iface)
{
return CONTAINING_RECORD(iface, struct script_host, IActiveScriptSite_iface);
}
static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
if (IsEqualGUID(&IID_IUnknown, riid))
{
TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
*ppv = &This->IActiveScriptSite_iface;
}
else if (IsEqualGUID(&IID_IActiveScriptSite, riid))
{
TRACE("(%p)->(IID_IActiveScriptSite %p)\n", This, ppv);
*ppv = &This->IActiveScriptSite_iface;
}
else if (IsEqualGUID(&IID_IActiveScriptSiteWindow, riid))
{
TRACE("(%p)->(IID_IActiveScriptSiteWindow %p)\n", This, ppv);
*ppv = &This->IActiveScriptSiteWindow_iface;
}
else if(IsEqualGUID(&IID_IServiceProvider, riid))
{
TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
*ppv = &This->IServiceProvider_iface;
}
else
{
WARN("(%p)->(%s %p) interface not supported\n", This, debugstr_guid(riid), ppv);
*ppv = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef((IUnknown*)*ppv);
return S_OK;
}
static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
LONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
return ref;
}
static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
LONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
if(!ref) {
heap_free(This->language);
heap_free(This);
}
return ref;
}
static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *lcid)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
TRACE("(%p, %p)\n", This, lcid);
*lcid = GetUserDefaultLCID();
return S_OK;
}
static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR name, DWORD mask,
IUnknown **unk, ITypeInfo **ti)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
TRACE("(%p, %s, %#x, %p, %p)\n", This, debugstr_w(name), mask, unk, ti);
if (mask != SCRIPTINFO_IUNKNOWN)
{
FIXME("mask %x not supported\n", mask);
return E_NOTIMPL;
}
if (wcscmp(name, L"scriptlet") && wcscmp(name, L"globals"))
{
FIXME("%s not supported\n", debugstr_w(name));
return E_FAIL;
}
if (!This->object) return E_UNEXPECTED;
*unk = (IUnknown *)&This->object->global->IDispatchEx_iface;
IUnknown_AddRef(*unk);
return S_OK;
}
static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *version)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
FIXME("(%p, %p)\n", This, version);
return E_NOTIMPL;
}
static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface, const VARIANT *result,
const EXCEPINFO *ei)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
FIXME("(%p, %s, %p)\n", This, debugstr_variant(result), ei);
return E_NOTIMPL;
}
static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE state)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
TRACE("(%p, %d)\n", This, state);
return E_NOTIMPL;
}
static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *script_error)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
FIXME("(%p, %p)\n", This, script_error);
return E_NOTIMPL;
}
static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
TRACE("(%p)\n", This);
return S_OK;
}
static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
{
struct script_host *This = impl_from_IActiveScriptSite(iface);
TRACE("(%p)\n", This);
return S_OK;
}
static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
ActiveScriptSite_QueryInterface,
ActiveScriptSite_AddRef,
ActiveScriptSite_Release,
ActiveScriptSite_GetLCID,
ActiveScriptSite_GetItemInfo,
ActiveScriptSite_GetDocVersionString,
ActiveScriptSite_OnScriptTerminate,
ActiveScriptSite_OnStateChange,
ActiveScriptSite_OnScriptError,
ActiveScriptSite_OnEnterScript,
ActiveScriptSite_OnLeaveScript
};
static inline struct script_host *impl_from_IActiveScriptSiteWindow(IActiveScriptSiteWindow *iface)
{
return CONTAINING_RECORD(iface, struct script_host, IActiveScriptSiteWindow_iface);
}
static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface, REFIID riid, void **obj)
{
struct script_host *This = impl_from_IActiveScriptSiteWindow(iface);
return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, obj);
}
static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
{
struct script_host *This = impl_from_IActiveScriptSiteWindow(iface);
return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
}
static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
{
struct script_host *This = impl_from_IActiveScriptSiteWindow(iface);
return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
}
static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *hwnd)
{
struct script_host *This = impl_from_IActiveScriptSiteWindow(iface);
FIXME("(%p, %p)\n", This, hwnd);
return E_NOTIMPL;
}
static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL enable)
{
struct script_host *This = impl_from_IActiveScriptSiteWindow(iface);
FIXME("(%p, %d)\n", This, enable);
return E_NOTIMPL;
}
static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
ActiveScriptSiteWindow_QueryInterface,
ActiveScriptSiteWindow_AddRef,
ActiveScriptSiteWindow_Release,
ActiveScriptSiteWindow_GetWindow,
ActiveScriptSiteWindow_EnableModeless
};
static inline struct script_host *impl_from_IServiceProvider(IServiceProvider *iface)
{
return CONTAINING_RECORD(iface, struct script_host, IServiceProvider_iface);
}
static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **obj)
{
struct script_host *This = impl_from_IServiceProvider(iface);
return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, obj);
}
static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
{
struct script_host *This = impl_from_IServiceProvider(iface);
return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
}
static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
{
struct script_host *This = impl_from_IServiceProvider(iface);
return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
}
static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, REFGUID service,
REFIID riid, void **obj)
{
struct script_host *This = impl_from_IServiceProvider(iface);
FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(service), debugstr_guid(riid), obj);
return E_NOTIMPL;
}
static const IServiceProviderVtbl ServiceProviderVtbl = {
ServiceProvider_QueryInterface,
ServiceProvider_AddRef,
ServiceProvider_Release,
ServiceProvider_QueryService
};
static struct script_host *find_script_host(struct list *hosts, const WCHAR *language)
{
struct script_host *host;
LIST_FOR_EACH_ENTRY(host, hosts, struct script_host, entry)
{
if (!wcscmp(host->language, language)) return host;
}
return NULL;
}
static HRESULT parse_scripts(struct scriptlet_factory *factory, struct list *hosts, BOOL start)
{
DWORD parse_flags = SCRIPTTEXT_ISVISIBLE;
struct scriptlet_script *script;
struct script_host *host;
HRESULT hres;
if (!start) parse_flags |= SCRIPTITEM_ISPERSISTENT;
LIST_FOR_EACH_ENTRY(script, &factory->scripts, struct scriptlet_script, entry)
{
host = find_script_host(hosts, script->language);
if (start && host->state != SCRIPTSTATE_STARTED)
{
hres = set_script_state(host, SCRIPTSTATE_STARTED);
if (FAILED(hres)) return hres;
}
if (host->cloned) continue;
hres = IActiveScriptParse_ParseScriptText(host->parser, script->body, NULL, NULL, NULL, 0, 0 /* FIXME */,
parse_flags, NULL, NULL);
if (FAILED(hres))
{
WARN("ParseScriptText failed: %08x\n", hres);
return hres;
}
}
if (!start)
{
LIST_FOR_EACH_ENTRY(host, hosts, struct script_host, entry)
{
if (host->state != SCRIPTSTATE_UNINITIALIZED)
set_script_state(host, SCRIPTSTATE_UNINITIALIZED);
}
}
return S_OK;
}
static HRESULT lookup_script_properties(struct scriptlet_instance *object, BSTR name, struct script_reference *ret)
{
struct script_host *host;
HRESULT hres;
LIST_FOR_EACH_ENTRY(host, &object->hosts, struct script_host, entry)
{
hres = IDispatchEx_GetDispID(host->script_dispatch, name, 0, &ret->id);
if (FAILED(hres)) continue;
ret->host = host;
return S_OK;
}
FIXME("Could not find %s in scripts\n", debugstr_w(name));
return E_FAIL;
}
static HRESULT lookup_object_properties(struct scriptlet_instance *object, struct scriptlet_factory *factory)
{
struct scriptlet_member *member;
unsigned i = 0, member_cnt = 0;
size_t len;
BSTR name;
HRESULT hres;
LIST_FOR_EACH_ENTRY(member, &factory->members, struct scriptlet_member, entry)
member_cnt++;
if (!member_cnt) return S_OK;
if (!(object->members = heap_alloc_zero(member_cnt * sizeof(*object->members)))) return E_OUTOFMEMORY;
object->member_cnt = member_cnt;
LIST_FOR_EACH_ENTRY(member, &factory->members, struct scriptlet_member, entry)
{
object->members[i].type = member->type;
if (!(object->members[i].name = SysAllocString(member->name))) return E_OUTOFMEMORY;
switch (member->type)
{
case MEMBER_METHOD:
hres = lookup_script_properties(object, object->members[i].name, &object->members[i].u.method);
if (FAILED(hres)) return hres;
break;
case MEMBER_PROPERTY:
len = wcslen(member->name);
if (!(name = SysAllocStringLen(NULL, len + 4))) return E_OUTOFMEMORY;
wcscpy(name, L"get_");
wcscat(name, member->name);
hres = lookup_script_properties(object, name, &object->members[i].u.property.get);
if (SUCCEEDED(hres))
{
memcpy(name, L"put", 3 * sizeof(WCHAR));
hres = lookup_script_properties(object, name, &object->members[i].u.property.put);
}
SysFreeString(name);
if (FAILED(hres)) return hres;
break;
}
i++;
}
return S_OK;
}
static HRESULT init_script_host(struct script_host *host, IActiveScript *clone)
{
HRESULT hres;
if (!clone)
{
IClassFactoryEx *factory_ex;
IClassFactory *factory;
IUnknown *unk;
CLSID clsid;
if (FAILED(hres = CLSIDFromProgID(host->language, &clsid)))
{
WARN("Could not find script engine for %s\n", debugstr_w(host->language));
return hres;
}
hres = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, NULL,
&IID_IClassFactory, (void**)&factory);
if (FAILED(hres)) return hres;
hres = IClassFactory_QueryInterface(factory, &IID_IClassFactoryEx, (void**)&factory_ex);
if (SUCCEEDED(hres))
{
FIXME("Use IClassFactoryEx\n");
IClassFactoryEx_Release(factory_ex);
}
hres = IClassFactory_CreateInstance(factory, NULL, &IID_IUnknown, (void**)&unk);
IClassFactory_Release(factory);
if (FAILED(hres)) return hres;
hres = IUnknown_QueryInterface(unk, &IID_IActiveScript, (void**)&host->active_script);
IUnknown_Release(unk);
if (FAILED(hres)) return hres;
}
else
{
IActiveScript_AddRef(clone);
host->active_script = clone;
host->cloned = TRUE;
}
hres = IActiveScript_QueryInterface(host->active_script, &IID_IActiveScriptParse, (void**)&host->parser);
if (FAILED(hres)) return hres;
if (!clone)
{
hres = IActiveScriptParse_InitNew(host->parser);
if (FAILED(hres))
{
IActiveScriptParse_Release(host->parser);
host->parser = NULL;
return hres;
}
}
return IActiveScript_SetScriptSite(host->active_script, &host->IActiveScriptSite_iface);
}
static HRESULT create_script_host(const WCHAR *language, IActiveScript *origin_script, struct list *hosts, struct script_host **ret)
{
IActiveScript *clone = NULL;
struct script_host *host;
HRESULT hres;
if (!(host = heap_alloc_zero(sizeof(*host)))) return E_OUTOFMEMORY;
host->IActiveScriptSite_iface.lpVtbl = &ActiveScriptSiteVtbl;
host->IActiveScriptSiteWindow_iface.lpVtbl = &ActiveScriptSiteWindowVtbl;
host->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
host->ref = 1;
host->state = SCRIPTSTATE_CLOSED;
if (!(host->language = heap_strdupW(language)))
{
IActiveScriptSite_Release(&host->IActiveScriptSite_iface);
return E_OUTOFMEMORY;
}
if (origin_script)
{
hres = IActiveScript_Clone(origin_script, &clone);
if (FAILED(hres)) clone = NULL;
}
list_add_tail(hosts, &host->entry);
hres = init_script_host(host, clone);
if (clone) IActiveScript_Release(clone);
if (FAILED(hres)) return hres;
if (ret) *ret = host;
return S_OK;
}
static void detach_script_hosts(struct list *hosts)
{
while (!list_empty(hosts))
{
struct script_host *host = LIST_ENTRY(list_head(hosts), struct script_host, entry);
if (host->state != SCRIPTSTATE_UNINITIALIZED) set_script_state(host, SCRIPTSTATE_UNINITIALIZED);
list_remove(&host->entry);
host->object = NULL;
if (host->script_dispatch)
{
IDispatchEx_Release(host->script_dispatch);
host->script_dispatch = NULL;
}
if (host->parser)
{
IActiveScript_Close(host->active_script);
IActiveScriptParse_Release(host->parser);
host->parser = NULL;
}
if (host->active_script)
{
IActiveScript_Release(host->active_script);
host->active_script = NULL;
}
IActiveScriptSite_Release(&host->IActiveScriptSite_iface);
}
}
static HRESULT create_scriptlet_hosts(struct scriptlet_factory *factory, struct list *hosts)
{
struct scriptlet_script *script;
HRESULT hres;
LIST_FOR_EACH_ENTRY(script, &factory->scripts, struct scriptlet_script, entry)
{
if (find_script_host(hosts, script->language)) continue;
hres = create_script_host(script->language, NULL, hosts, NULL);
if (FAILED(hres))
{
detach_script_hosts(hosts);
return hres;
}
}
return S_OK;
}
static inline struct scriptlet_instance *impl_from_IDispatchEx(IDispatchEx *iface)
{
return CONTAINING_RECORD(iface, struct scriptlet_instance, IDispatchEx_iface);
}
static HRESULT WINAPI scriptlet_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
if (IsEqualGUID(&IID_IUnknown, riid))
{
TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
*ppv = &This->IDispatchEx_iface;
}
else if (IsEqualGUID(&IID_IDispatch, riid))
{
TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
*ppv = &This->IDispatchEx_iface;
}
else if (IsEqualGUID(&IID_IDispatchEx, riid))
{
TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
*ppv = &This->IDispatchEx_iface;
}
else
{
WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
*ppv = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef((IUnknown*)*ppv);
return S_OK;
}
static ULONG WINAPI scriptlet_AddRef(IDispatchEx *iface)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
return ref;
}
static ULONG WINAPI scriptlet_Release(IDispatchEx *iface)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
if (!ref)
{
unsigned i;
for (i = 0; i < This->member_cnt; i++)
SysFreeString(This->members[i].name);
heap_free(This->members);
detach_script_hosts(&This->hosts);
if (This->global) IDispatchEx_Release(&This->global->IDispatchEx_iface);
heap_free(This);
}
return ref;
}
static HRESULT WINAPI scriptlet_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
FIXME("(%p)->(%p)\n", This, pctinfo);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
UINT i;
HRESULT hres;
TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
lcid, rgDispId);
for(i=0; i < cNames; i++)
{
hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId + i);
if(FAILED(hres))
return hres;
}
return S_OK;
}
static HRESULT WINAPI scriptlet_Invoke(IDispatchEx *iface, DISPID dispIdMember,
REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
pDispParams, pVarResult, pExcepInfo, NULL);
}
static HRESULT WINAPI scriptlet_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
unsigned i;
TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
if (grfdex & ~(fdexNameCaseInsensitive|fdexNameCaseSensitive))
FIXME("Unsupported grfdex %x\n", grfdex);
for (i = 0; i < This->member_cnt; i++)
{
if (grfdex & fdexNameCaseInsensitive)
{
if (wcsicmp(This->members[i].name, bstrName)) continue;
}
else if (wcscmp(This->members[i].name, bstrName)) continue;
*pid = i + 1;
return S_OK;
}
WARN("Unknown property %s\n", debugstr_w(bstrName));
return DISP_E_UNKNOWNNAME;
}
static HRESULT WINAPI scriptlet_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *pdp,
VARIANT *res, EXCEPINFO *pei, IServiceProvider *caller)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
struct object_member *member;
TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, pdp, res, pei, caller);
if (id < 1 || id > This->member_cnt)
{
WARN("Unknown id %xu\n", id);
return DISP_E_MEMBERNOTFOUND;
}
member = &This->members[id - 1];
switch (member->type)
{
case MEMBER_METHOD:
if ((flags & ~DISPATCH_PROPERTYGET) != DISPATCH_METHOD)
{
FIXME("unsupported method flags %x\n", flags);
return DISP_E_MEMBERNOTFOUND;
}
return IDispatchEx_InvokeEx(member->u.method.host->script_dispatch, member->u.method.id, lcid,
DISPATCH_METHOD, pdp, res, pei, caller);
case MEMBER_PROPERTY:
if (flags & DISPATCH_PROPERTYGET)
{
if (!member->u.property.get.host)
{
FIXME("No %s getter\n", debugstr_w(member->name));
return DISP_E_MEMBERNOTFOUND;
}
return IDispatchEx_InvokeEx(member->u.property.get.host->script_dispatch, member->u.property.get.id, lcid,
DISPATCH_METHOD, pdp, res, pei, caller);
}
if (flags & DISPATCH_PROPERTYPUT)
{
DISPPARAMS dp;
if (!member->u.property.put.host)
{
FIXME("No %s setter\n", debugstr_w(member->name));
return DISP_E_MEMBERNOTFOUND;
}
if (pdp->cNamedArgs != 1 || pdp->rgdispidNamedArgs[0] != DISPID_PROPERTYPUT)
{
FIXME("no propput argument\n");
return E_FAIL;
}
dp = *pdp;
dp.cNamedArgs = 0;
return IDispatchEx_InvokeEx(member->u.property.put.host->script_dispatch, member->u.property.put.id, lcid,
DISPATCH_METHOD, &dp, res, pei, caller);
}
FIXME("unsupported flags %x\n", flags);
}
return DISP_E_MEMBERNOTFOUND;
}
static HRESULT WINAPI scriptlet_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
FIXME("(%p)->(%x)\n", This, id);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
{
struct scriptlet_instance *This = impl_from_IDispatchEx(iface);
FIXME("(%p)->(%p)\n", This, ppunk);
return E_NOTIMPL;
}
static IDispatchExVtbl DispatchExVtbl = {
scriptlet_QueryInterface,
scriptlet_AddRef,
scriptlet_Release,
scriptlet_GetTypeInfoCount,
scriptlet_GetTypeInfo,
scriptlet_GetIDsOfNames,
scriptlet_Invoke,
scriptlet_GetDispID,
scriptlet_InvokeEx,
scriptlet_DeleteMemberByName,
scriptlet_DeleteMemberByDispID,
scriptlet_GetMemberProperties,
scriptlet_GetMemberName,
scriptlet_GetNextDispID,
scriptlet_GetNameSpaceParent
};
static HRESULT create_scriptlet_instance(struct scriptlet_factory *factory, IDispatchEx **disp)
{
struct script_host *factory_host, *host;
struct scriptlet_instance *obj;
IDispatch *script_dispatch;
HRESULT hres;
if (!(obj = heap_alloc_zero(sizeof(*obj)))) return E_OUTOFMEMORY;
obj->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
obj->ref = 1;
list_init(&obj->hosts);
if (!(obj->global = heap_alloc(sizeof(*obj->global))))
{
IDispatchEx_Release(&obj->IDispatchEx_iface);
return E_OUTOFMEMORY;
}
obj->global->IDispatchEx_iface.lpVtbl = &global_vtbl;
obj->global->ref = 1;
LIST_FOR_EACH_ENTRY(factory_host, &factory->hosts, struct script_host, entry)
{
hres = create_script_host(factory_host->language, factory_host->active_script, &obj->hosts, &host);
if (FAILED(hres)) break;
host->object = obj;
hres = IActiveScript_AddNamedItem(host->active_script, L"scriptlet",
SCRIPTITEM_ISVISIBLE | SCRIPTITEM_GLOBALMEMBERS);
if (FAILED(hres)) break;
hres = IActiveScript_AddNamedItem(host->active_script, L"globals", SCRIPTITEM_ISVISIBLE);
if (FAILED(hres)) break;
hres = IActiveScript_GetScriptDispatch(host->active_script, NULL, &script_dispatch);
if (FAILED(hres)) return hres;
hres = IDispatch_QueryInterface(script_dispatch, &IID_IDispatchEx, (void**)&host->script_dispatch);
IDispatch_Release(script_dispatch);
if (FAILED(hres))
{
FIXME("IDispatchEx not supported by script engine\n");
return hres;
}
}
if (SUCCEEDED(hres)) hres = parse_scripts(factory, &obj->hosts, TRUE);
if (SUCCEEDED(hres)) hres = lookup_object_properties(obj, factory);
if (FAILED(hres))
{
IDispatchEx_Release(&obj->IDispatchEx_iface);
return hres;
}
*disp = &obj->IDispatchEx_iface;
return S_OK;
}
static const char *debugstr_xml_name(struct scriptlet_factory *factory)
{
const WCHAR *str;
UINT len;
HRESULT hres;
hres = IXmlReader_GetLocalName(factory->xml_reader, &str, &len);
if (FAILED(hres)) return "#err";
return debugstr_wn(str, len);
}
static HRESULT next_xml_node(struct scriptlet_factory *factory, XmlNodeType *node_type)
{
HRESULT hres;
for (;;)
{
hres = IXmlReader_Read(factory->xml_reader, node_type);
if (FAILED(hres)) break;
if (*node_type == XmlNodeType_Whitespace) continue;
if (*node_type == XmlNodeType_ProcessingInstruction)
{
FIXME("Ignoring processing instruction\n");
continue;
}
break;
}
return hres;
}
static BOOL is_xml_name(struct scriptlet_factory *factory, const WCHAR *name)
{
const WCHAR *qname;
UINT len;
HRESULT hres;
hres = IXmlReader_GetQualifiedName(factory->xml_reader, &qname, &len);
return hres == S_OK && len == wcslen(name) && !memcmp(qname, name, len * sizeof(WCHAR));
}
static HRESULT expect_end_element(struct scriptlet_factory *factory)
{
XmlNodeType node_type;
HRESULT hres;
hres = next_xml_node(factory, &node_type);
if (hres != S_OK || node_type != XmlNodeType_EndElement)
{
FIXME("Unexpected node %u %s\n", node_type, debugstr_xml_name(factory));
return E_FAIL;
}
return S_OK;
}
static HRESULT expect_no_attributes(struct scriptlet_factory *factory)
{
UINT count;
HRESULT hres;
hres = IXmlReader_GetAttributeCount(factory->xml_reader, &count);
if (FAILED(hres)) return hres;
if (!count) return S_OK;
FIXME("Unexpected attributes\n");
return E_FAIL;
}
static BOOL is_case_xml_name(struct scriptlet_factory *factory, const WCHAR *name)
{
const WCHAR *qname;
UINT len;
HRESULT hres;
hres = IXmlReader_GetQualifiedName(factory->xml_reader, &qname, &len);
return hres == S_OK && len == wcslen(name) && !memicmp(qname, name, len * sizeof(WCHAR));
}
static HRESULT read_xml_value(struct scriptlet_factory *factory, WCHAR **ret)
{
const WCHAR *str;
UINT len;
HRESULT hres;
hres = IXmlReader_GetValue(factory->xml_reader, &str, &len);
if (FAILED(hres)) return hres;
if (!(*ret = heap_alloc((len + 1) * sizeof(WCHAR)))) return E_OUTOFMEMORY;
memcpy(*ret, str, len * sizeof(WCHAR));
(*ret)[len] = 0;
return S_OK;
}
static HRESULT parse_scriptlet_registration(struct scriptlet_factory *factory)
{
HRESULT hres;
TRACE("\n");
if (factory->have_registration)
{
FIXME("duplicated registration element\n");
return E_FAIL;
}
factory->have_registration = TRUE;
for (;;)
{
hres = IXmlReader_MoveToNextAttribute(factory->xml_reader);
if (hres != S_OK) break;
if (is_xml_name(factory, L"description"))
{
if (factory->description)
{
FIXME("Duplicated description\n");
return E_FAIL;
}
hres = read_xml_value(factory, &factory->description);
if (FAILED(hres)) return hres;
}
else if (is_case_xml_name(factory, L"progid"))
{
if (factory->progid)
{
FIXME("Duplicated progid\n");
return E_FAIL;
}
hres = read_xml_value(factory, &factory->progid);
if (FAILED(hres)) return hres;
}
else if (is_xml_name(factory, L"version"))
{
if (factory->version)
{
FIXME("Duplicated version\n");
return E_FAIL;
}
hres = read_xml_value(factory, &factory->version);
if (FAILED(hres)) return hres;
}
else if (is_xml_name(factory, L"classid"))
{
if (factory->classid_str)
{
FIXME("Duplicated classid attribute\n");
return E_FAIL;
}
hres = read_xml_value(factory, &factory->classid_str);
if (FAILED(hres)) return hres;
hres = IIDFromString(factory->classid_str, &factory->classid);
if (FAILED(hres))
{
FIXME("Invalid classid %s\n", debugstr_w(factory->classid_str));
return E_FAIL;
}
}
else
{
FIXME("Unexpected attribute\n");
return E_NOTIMPL;
}
}
if (!factory->progid && !factory->classid_str)
{
FIXME("Incomplet registration element\n");
return E_FAIL;
}
if (factory->progid)
{
size_t progid_len = wcslen(factory->progid);
size_t version_len = wcslen(factory->version);
if (!(factory->versioned_progid = heap_alloc((progid_len + version_len + 2) * sizeof(WCHAR))))
return E_OUTOFMEMORY;
memcpy(factory->versioned_progid, factory->progid, (progid_len + 1) * sizeof(WCHAR));
if (version_len)
{
factory->versioned_progid[progid_len++] = '.';
wcscpy(factory->versioned_progid + progid_len, factory->version);
}
else factory->versioned_progid[progid_len] = 0;
}
return expect_end_element(factory);
}
static HRESULT parse_scriptlet_public(struct scriptlet_factory *factory)
{
struct scriptlet_member *member, *member_iter;
enum member_type member_type;
XmlNodeType node_type;
BOOL empty;
HRESULT hres;
TRACE("\n");
if (factory->have_public)
{
FIXME("duplicated public element\n");
return E_FAIL;
}
factory->have_public = TRUE;
for (;;)
{
hres = next_xml_node(factory, &node_type);
if (FAILED(hres)) return hres;
if (node_type == XmlNodeType_EndElement) break;
if (node_type != XmlNodeType_Element)
{
FIXME("Unexpected node type %u\n", node_type);
return E_FAIL;
}
if (is_xml_name(factory, L"method"))
member_type = MEMBER_METHOD;
else if (is_xml_name(factory, L"property"))
member_type = MEMBER_PROPERTY;
else
{
FIXME("Unexpected element %s\n", debugstr_xml_name(factory));
return E_NOTIMPL;
}
empty = IXmlReader_IsEmptyElement(factory->xml_reader);
hres = IXmlReader_MoveToAttributeByName(factory->xml_reader, L"name", NULL);
if (hres != S_OK)
{
FIXME("Missing method name\n");
return E_FAIL;
}
if (!(member = heap_alloc(sizeof(*member)))) return E_OUTOFMEMORY;
member->type = member_type;
hres = read_xml_value(factory, &member->name);
if (FAILED(hres))
{
heap_free(member);
return hres;
}
LIST_FOR_EACH_ENTRY(member_iter, &factory->members, struct scriptlet_member, entry)
{
if (!wcsicmp(member_iter->name, member->name))
{
FIXME("Duplicated member %s\n", debugstr_w(member->name));
heap_free(member);
return E_FAIL;
}
}
list_add_tail(&factory->members, &member->entry);
switch (member_type)
{
case MEMBER_METHOD:
list_init(&member->u.parameters);
if (empty) break;
for (;;)
{
struct method_parameter *parameter;
hres = next_xml_node(factory, &node_type);
if (FAILED(hres)) return hres;
if (node_type == XmlNodeType_EndElement) break;
if (node_type != XmlNodeType_Element)
{
FIXME("Unexpected node type %u\n", node_type);
return E_FAIL;
}
if (!is_case_xml_name(factory, L"parameter"))
{
FIXME("Unexpected method element\n");
return E_FAIL;
}
empty = IXmlReader_IsEmptyElement(factory->xml_reader);
hres = IXmlReader_MoveToAttributeByName(factory->xml_reader, L"name", NULL);
if (hres != S_OK)
{
FIXME("Missing parameter name\n");
return E_FAIL;
}
if (!(parameter = heap_alloc_zero(sizeof(*parameter)))) return E_OUTOFMEMORY;
list_add_tail(&member->u.parameters, &parameter->entry);
hres = read_xml_value(factory, &parameter->name);
if (FAILED(hres)) return hres;
if (!empty && FAILED(hres = expect_end_element(factory))) return hres;
}
break;
case MEMBER_PROPERTY:
member->u.flags = 0;
if (empty) break;
for (;;)
{
hres = next_xml_node(factory, &node_type);
if (FAILED(hres)) return hres;
if (node_type == XmlNodeType_EndElement) break;
if (node_type != XmlNodeType_Element)
{
FIXME("Unexpected node type %u\n", node_type);
return E_FAIL;
}
if (is_case_xml_name(factory, L"get"))
{
if (member->u.flags & PROP_GETTER)
{
FIXME("Duplicated getter\n");
return E_FAIL;
}
member->u.flags |= PROP_GETTER;
}
else if (is_case_xml_name(factory, L"put"))
{
if (member->u.flags & PROP_SETTER)
{
FIXME("Duplicated setter\n");
return E_FAIL;
}
member->u.flags |= PROP_SETTER;
}
else
{
FIXME("Unexpected property element %s\n", debugstr_xml_name(factory));
return E_FAIL;
}
empty = IXmlReader_IsEmptyElement(factory->xml_reader);
if (!empty && FAILED(hres = expect_end_element(factory))) return hres;
}
if (!member->u.flags)
{
FIXME("No getter or setter\n");
return E_NOTIMPL;
}
break;
}
if (FAILED(hres)) return hres;
}
return S_OK;
}
static HRESULT parse_scriptlet_script(struct scriptlet_factory *factory, struct scriptlet_script *script)
{
XmlNodeType node_type;
size_t buf_size, size;
WCHAR *new_body;
DWORD read;
HRESULT hres;
TRACE("\n");
for (;;)
{
hres = IXmlReader_MoveToNextAttribute(factory->xml_reader);
if (hres != S_OK) break;
if (is_xml_name(factory, L"language"))
{
if (script->language)
{
FIXME("Duplicated language\n");
return E_FAIL;
}
hres = read_xml_value(factory, &script->language);
if (FAILED(hres)) return hres;
}
else
{
FIXME("Unexpected attribute\n");
return E_NOTIMPL;
}
}
if (!script->language)
{
FIXME("Language not specified\n");
return E_FAIL;
}
if (FAILED(hres = next_xml_node(factory, &node_type))) return hres;
if (node_type != XmlNodeType_Text && node_type != XmlNodeType_CDATA)
{
FIXME("Unexpected node type %u\n", node_type);
return E_FAIL;
}
if (!(script->body = heap_alloc((buf_size = 1024) * sizeof(WCHAR)))) return E_OUTOFMEMORY;
size = 0;
for (;;)
{
read = 0;
hres = IXmlReader_ReadValueChunk(factory->xml_reader, script->body + size, buf_size - size - 1, &read);
if (FAILED(hres)) return hres;
size += read;
if (hres == S_FALSE) break;
if (size + 1 == buf_size)
{
if (!(new_body = heap_realloc(script->body, (buf_size *= 2) * sizeof(WCHAR)))) return E_OUTOFMEMORY;
script->body = new_body;
}
}
script->body[size++] = 0;
if (size != buf_size) script->body = heap_realloc(script->body, size * sizeof(WCHAR));
TRACE("body %s\n", debugstr_w(script->body));
return expect_end_element(factory);
}
static HRESULT parse_scriptlet_file(struct scriptlet_factory *factory, const WCHAR *url)
{
XmlNodeType node_type;
IBindCtx *bind_ctx;
IStream *stream;
HRESULT hres;
hres = CreateURLMoniker(NULL, url, &factory->moniker);
if (FAILED(hres))
{
WARN("CreateURLMoniker failed: %08x\n", hres);
return hres;
}
hres = CreateBindCtx(0, &bind_ctx);
if(FAILED(hres))
return hres;
hres = IMoniker_BindToStorage(factory->moniker, bind_ctx, NULL, &IID_IStream, (void**)&stream);
IBindCtx_Release(bind_ctx);
if (FAILED(hres))
return hres;
hres = CreateXmlReader(&IID_IXmlReader, (void**)&factory->xml_reader, NULL);
if(SUCCEEDED(hres))
hres = IXmlReader_SetInput(factory->xml_reader, (IUnknown*)stream);
IStream_Release(stream);
if (FAILED(hres))
return hres;
hres = next_xml_node(factory, &node_type);
if (hres == S_OK && node_type == XmlNodeType_XmlDeclaration)
hres = next_xml_node(factory, &node_type);
if (FAILED(hres))
return hres;
if (node_type != XmlNodeType_Element || !is_xml_name(factory, L"component"))
{
FIXME("Unexpected %s element\n", debugstr_xml_name(factory));
return E_FAIL;
}
hres = expect_no_attributes(factory);
if (FAILED(hres)) return hres;
for (;;)
{
hres = next_xml_node(factory, &node_type);
if (FAILED(hres)) return hres;
if (node_type == XmlNodeType_EndElement) break;
if (node_type != XmlNodeType_Element)
{
FIXME("Unexpected node type %u\n", node_type);
return E_FAIL;
}
if (is_xml_name(factory, L"registration"))
hres = parse_scriptlet_registration(factory);
else if (is_xml_name(factory, L"public"))
hres = parse_scriptlet_public(factory);
else if (is_xml_name(factory, L"script"))
{
struct scriptlet_script *script;
if (!(script = heap_alloc_zero(sizeof(*script)))) return E_OUTOFMEMORY;
list_add_tail(&factory->scripts, &script->entry);
hres = parse_scriptlet_script(factory, script);
if (FAILED(hres)) return hres;
}
else
{
FIXME("Unexpected element %s\n", debugstr_xml_name(factory));
return E_NOTIMPL;
}
if (FAILED(hres)) return hres;
}
hres = next_xml_node(factory, &node_type);
if (hres != S_FALSE)
{
FIXME("Unexpected node type %u\n", node_type);
return E_FAIL;
}
return S_OK;
}
static inline struct scriptlet_factory *impl_from_IClassFactory(IClassFactory *iface)
{
return CONTAINING_RECORD(iface, struct scriptlet_factory, IClassFactory_iface);
}
static HRESULT WINAPI scriptlet_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
{
struct scriptlet_factory *This = impl_from_IClassFactory(iface);
if (IsEqualGUID(&IID_IUnknown, riid))
{
TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
*ppv = &This->IClassFactory_iface;
}
else if (IsEqualGUID(&IID_IClassFactory, riid))
{
TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
*ppv = &This->IClassFactory_iface;
}
else
{
WARN("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv);
*ppv = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef((IUnknown *)*ppv);
return S_OK;
}
static ULONG WINAPI scriptlet_factory_AddRef(IClassFactory *iface)
{
struct scriptlet_factory *This = impl_from_IClassFactory(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
return ref;
}
static ULONG WINAPI scriptlet_factory_Release(IClassFactory *iface)
{
struct scriptlet_factory *This = impl_from_IClassFactory(iface);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
if (!ref)
{
if (This->moniker) IMoniker_Release(This->moniker);
if (This->xml_reader) IXmlReader_Release(This->xml_reader);
detach_script_hosts(&This->hosts);
while (!list_empty(&This->members))
{
struct scriptlet_member *member = LIST_ENTRY(list_head(&This->members), struct scriptlet_member, entry);
list_remove(&member->entry);
heap_free(member->name);
if (member->type == MEMBER_METHOD)
{
while (!list_empty(&member->u.parameters))
{
struct method_parameter *parameter = LIST_ENTRY(list_head(&member->u.parameters), struct method_parameter, entry);
list_remove(&parameter->entry);
heap_free(parameter->name);
heap_free(parameter);
}
}
heap_free(member);
}
while (!list_empty(&This->scripts))
{
struct scriptlet_script *script = LIST_ENTRY(list_head(&This->scripts), struct scriptlet_script, entry);
list_remove(&script->entry);
heap_free(script->language);
heap_free(script->body);
heap_free(script);
}
heap_free(This->classid_str);
heap_free(This->description);
heap_free(This->versioned_progid);
heap_free(This->progid);
heap_free(This->version);
heap_free(This);
}
return ref;
}
static HRESULT WINAPI scriptlet_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
{
struct scriptlet_factory *This = impl_from_IClassFactory(iface);
IDispatchEx *disp;
HRESULT hres;
TRACE("(%p)->(%p %s %p)\n", This, outer, debugstr_guid(riid), ppv);
if (outer) FIXME("outer not supported\n");
if (list_empty(&This->hosts))
{
hres = create_scriptlet_hosts(This, &This->hosts);
if (FAILED(hres)) return hres;
hres = parse_scripts(This, &This->hosts, FALSE);
if (FAILED(hres))
{
detach_script_hosts(&This->hosts);
return hres;
}
}
hres = create_scriptlet_instance(This, &disp);
if (FAILED(hres)) return hres;
hres = IDispatchEx_QueryInterface(disp, riid, ppv);
IDispatchEx_Release(disp);
return hres;
}
static HRESULT WINAPI scriptlet_factory_LockServer(IClassFactory *iface, BOOL fLock)
{
struct scriptlet_factory *This = impl_from_IClassFactory(iface);
TRACE("(%p)->(%x)\n", This, fLock);
return S_OK;
}
static const struct IClassFactoryVtbl scriptlet_factory_vtbl =
{
scriptlet_factory_QueryInterface,
scriptlet_factory_AddRef,
scriptlet_factory_Release,
scriptlet_factory_CreateInstance,
scriptlet_factory_LockServer
};
static HRESULT create_scriptlet_factory(const WCHAR *url, struct scriptlet_factory **ret)
{
struct scriptlet_factory *factory;
HRESULT hres;
TRACE("%s\n", debugstr_w(url));
if (!(factory = heap_alloc_zero(sizeof(*factory))))
{
IClassFactory_Release(&factory->IClassFactory_iface);
return E_OUTOFMEMORY;
}
factory->IClassFactory_iface.lpVtbl = &scriptlet_factory_vtbl;
factory->ref = 1;
list_init(&factory->hosts);
list_init(&factory->members);
list_init(&factory->scripts);
hres = parse_scriptlet_file(factory, url);
if (FAILED(hres))
{
IClassFactory_Release(&factory->IClassFactory_iface);
return hres;
}
*ret = factory;
return S_OK;
}
static HRESULT register_scriptlet(struct scriptlet_factory *factory)
{
HKEY key, clsid_key, obj_key;
LSTATUS status;
HRESULT hres;
if (factory->classid_str)
{
WCHAR *url;
status = RegCreateKeyW(HKEY_CLASSES_ROOT, L"CLSID", &clsid_key);
if (status) return E_ACCESSDENIED;
status = RegCreateKeyW(clsid_key, factory->classid_str, &obj_key);
RegCloseKey(clsid_key);
if (status) return E_ACCESSDENIED;
hres = IMoniker_GetDisplayName(factory->moniker, NULL, NULL, &url);
if (FAILED(hres))
{
RegCloseKey(obj_key);
return hres;
}
status = RegCreateKeyW(obj_key, L"ScriptletURL", &key);
if (!status)
{
status = RegSetValueExW(key, NULL, 0, REG_SZ, (BYTE*)url,
(wcslen(url) + 1) * sizeof(WCHAR));
RegCloseKey(key);
}
CoTaskMemFree(url);
if (factory->description)
status = RegSetValueExW(obj_key, NULL, 0, REG_SZ, (BYTE*)factory->description,
(wcslen(factory->description) + 1) * sizeof(WCHAR));
if (!status)
{
status = RegCreateKeyW(obj_key, L"InprocServer32", &key);
if (!status)
{
WCHAR str[MAX_PATH];
GetModuleFileNameW(scrobj_instance, str, MAX_PATH);
status = RegSetValueExW(key, NULL, 0, REG_SZ, (BYTE*)str, (wcslen(str) + 1) * sizeof(WCHAR));
RegCloseKey(key);
}
}
if (!status && factory->versioned_progid)
{
status = RegCreateKeyW(obj_key, L"ProgID", &key);
if (!status)
{
status = RegSetValueExW(key, NULL, 0, REG_SZ, (BYTE*)factory->versioned_progid,
(wcslen(factory->versioned_progid) + 1) * sizeof(WCHAR));
RegCloseKey(key);
}
}
if (!status && factory->progid)
{
status = RegCreateKeyW(obj_key, L"VersionIndependentProgID", &key);
if (!status)
{
status = RegSetValueExW(key, NULL, 0, REG_SZ, (BYTE*)factory->progid,
(wcslen(factory->progid) + 1) * sizeof(WCHAR));
RegCloseKey(key);
}
}
RegCloseKey(obj_key);
if (status) return E_ACCESSDENIED;
}
if (factory->progid)
{
status = RegCreateKeyW(HKEY_CLASSES_ROOT, factory->progid, &key);
if (status) return E_ACCESSDENIED;
if (factory->description)
status = RegSetValueExW(key, NULL, 0, REG_SZ, (BYTE*)factory->description,
(wcslen(factory->description) + 1) * sizeof(WCHAR));
if (!status && factory->classid_str)
{
status = RegCreateKeyW(key, L"CLSID", &clsid_key);
if (!status)
{
status = RegSetValueExW(clsid_key, NULL, 0, REG_SZ, (BYTE*)factory->classid_str,
(wcslen(factory->classid_str) + 1) * sizeof(WCHAR));
RegCloseKey(clsid_key);
}
}
RegCloseKey(key);
if (status) return E_ACCESSDENIED;
}
if (factory->versioned_progid)
{
status = RegCreateKeyW(HKEY_CLASSES_ROOT, factory->versioned_progid, &key);
if (status) return E_ACCESSDENIED;
if (factory->description)
status = RegSetValueExW(key, NULL, 0, REG_SZ, (BYTE*)factory->description,
(wcslen(factory->description) + 1) * sizeof(WCHAR));
if (!status && factory->classid_str)
{
status = RegCreateKeyW(key, L"CLSID", &clsid_key);
if (!status)
{
status = RegSetValueExW(clsid_key, NULL, 0, REG_SZ, (BYTE*)factory->classid_str,
(wcslen(factory->classid_str) + 1) * sizeof(WCHAR));
RegCloseKey(clsid_key);
}
}
RegCloseKey(key);
if (status) return E_ACCESSDENIED;
}
return S_OK;
}
static HRESULT unregister_scriptlet(struct scriptlet_factory *factory)
{
LSTATUS status;
if (factory->classid_str)
{
HKEY clsid_key;
status = RegCreateKeyW(HKEY_CLASSES_ROOT, L"CLSID", &clsid_key);
if (!status)
{
RegDeleteTreeW(clsid_key, factory->classid_str);
RegCloseKey(clsid_key);
}
}
if (factory->progid) RegDeleteTreeW(HKEY_CLASSES_ROOT, factory->progid);
if (factory->versioned_progid) RegDeleteTreeW(HKEY_CLASSES_ROOT, factory->versioned_progid);
return S_OK;
}
struct scriptlet_typelib
{
IGenScriptletTLib IGenScriptletTLib_iface;
LONG ref;
BSTR guid;
};
static inline struct scriptlet_typelib *impl_from_IGenScriptletTLib(IGenScriptletTLib *iface)
{
return CONTAINING_RECORD(iface, struct scriptlet_typelib, IGenScriptletTLib_iface);
}
static HRESULT WINAPI scriptlet_typelib_QueryInterface(IGenScriptletTLib *iface, REFIID riid, void **obj)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IGenScriptletTLib) ||
IsEqualIID(riid, &IID_IDispatch) ||
IsEqualIID(riid, &IID_IUnknown))
{
*obj = iface;
IGenScriptletTLib_AddRef(iface);
return S_OK;
}
*obj = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI scriptlet_typelib_AddRef(IGenScriptletTLib *iface)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p)->(%u)\n", This, ref);
return ref;
}
static ULONG WINAPI scriptlet_typelib_Release(IGenScriptletTLib *iface)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
LONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p)->(%u)\n", This, ref);
if (!ref)
{
SysFreeString(This->guid);
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
}
static HRESULT WINAPI scriptlet_typelib_GetTypeInfoCount(IGenScriptletTLib *iface, UINT *count)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
TRACE("(%p, %p)\n", This, count);
*count = 1;
return S_OK;
}
static HRESULT WINAPI scriptlet_typelib_GetTypeInfo(IGenScriptletTLib *iface, UINT index, LCID lcid,
ITypeInfo **tinfo)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
TRACE("(%p, %u, %x, %p)\n", This, index, lcid, tinfo);
return get_typeinfo(IGenScriptletTLib_tid, tinfo);
}
static HRESULT WINAPI scriptlet_typelib_GetIDsOfNames(IGenScriptletTLib *iface, REFIID riid, LPOLESTR *names,
UINT cNames, LCID lcid, DISPID *dispid)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p, %s, %p, %u, %x, %p)\n", This, debugstr_guid(riid), names, cNames, lcid, dispid);
hr = get_typeinfo(IGenScriptletTLib_tid, &typeinfo);
if (SUCCEEDED(hr))
{
hr = ITypeInfo_GetIDsOfNames(typeinfo, names, cNames, dispid);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI scriptlet_typelib_Invoke(IGenScriptletTLib *iface, DISPID dispid, REFIID riid,
LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *ei, UINT *argerr)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p, %d, %s, %x, %x, %p, %p, %p, %p)\n", This, dispid, debugstr_guid(riid), lcid, flags,
params, result, ei, argerr);
hr = get_typeinfo(IGenScriptletTLib_tid, &typeinfo);
if (SUCCEEDED(hr))
{
hr = ITypeInfo_Invoke(typeinfo, &This->IGenScriptletTLib_iface, dispid, flags,
params, result, ei, argerr);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI scriptlet_typelib_AddURL(IGenScriptletTLib *iface, BSTR url)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %s): stub\n", This, debugstr_w(url));
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_put_Path(IGenScriptletTLib *iface, BSTR path)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %s): stub\n", This, debugstr_w(path));
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_get_Path(IGenScriptletTLib *iface, BSTR *path)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %p): stub\n", This, path);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_put_Doc(IGenScriptletTLib *iface, BSTR doc)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %s): stub\n", This, debugstr_w(doc));
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_get_Doc(IGenScriptletTLib *iface, BSTR *doc)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %p): stub\n", This, doc);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_put_Name(IGenScriptletTLib *iface, BSTR name)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %s): stub\n", This, debugstr_w(name));
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_get_Name(IGenScriptletTLib *iface, BSTR *name)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %p): stub\n", This, name);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_put_MajorVersion(IGenScriptletTLib *iface, WORD version)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %x): stub\n", This, version);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_get_MajorVersion(IGenScriptletTLib *iface, WORD *version)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %p): stub\n", This, version);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_put_MinorVersion(IGenScriptletTLib *iface, WORD version)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %x): stub\n", This, version);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_get_MinorVersion(IGenScriptletTLib *iface, WORD *version)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %p): stub\n", This, version);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_Write(IGenScriptletTLib *iface)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p): stub\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_Reset(IGenScriptletTLib *iface)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p): stub\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_put_GUID(IGenScriptletTLib *iface, BSTR guid)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
FIXME("(%p, %s): stub\n", This, debugstr_w(guid));
return E_NOTIMPL;
}
static HRESULT WINAPI scriptlet_typelib_get_GUID(IGenScriptletTLib *iface, BSTR *ret)
{
struct scriptlet_typelib *This = impl_from_IGenScriptletTLib(iface);
TRACE("(%p, %p)\n", This, ret);
*ret = NULL;
if (!This->guid)
{
WCHAR guidW[39];
GUID guid;
HRESULT hr;
hr = CoCreateGuid(&guid);
if (FAILED(hr))
return hr;
hr = StringFromGUID2(&guid, guidW, ARRAY_SIZE(guidW));
if (FAILED(hr))
return hr;
if (!(This->guid = SysAllocString(guidW)))
return E_OUTOFMEMORY;
}
*ret = SysAllocString(This->guid);
return *ret ? S_OK : E_OUTOFMEMORY;
}
static const IGenScriptletTLibVtbl scriptlet_typelib_vtbl =
{
scriptlet_typelib_QueryInterface,
scriptlet_typelib_AddRef,
scriptlet_typelib_Release,
scriptlet_typelib_GetTypeInfoCount,
scriptlet_typelib_GetTypeInfo,
scriptlet_typelib_GetIDsOfNames,
scriptlet_typelib_Invoke,
scriptlet_typelib_AddURL,
scriptlet_typelib_put_Path,
scriptlet_typelib_get_Path,
scriptlet_typelib_put_Doc,
scriptlet_typelib_get_Doc,
scriptlet_typelib_put_Name,
scriptlet_typelib_get_Name,
scriptlet_typelib_put_MajorVersion,
scriptlet_typelib_get_MajorVersion,
scriptlet_typelib_put_MinorVersion,
scriptlet_typelib_get_MinorVersion,
scriptlet_typelib_Write,
scriptlet_typelib_Reset,
scriptlet_typelib_put_GUID,
scriptlet_typelib_get_GUID
};
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved)
{
TRACE("%p, %u, %p\n", hinst, reason, reserved);
switch (reason)
{
case DLL_WINE_PREATTACH:
return FALSE; /* prefer native version */
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinst);
scrobj_instance = hinst;
break;
case DLL_PROCESS_DETACH:
if (reserved) break;
release_typelib();
break;
}
return TRUE;
}
/***********************************************************************
* DllRegisterServer (scrobj.@)
*/
HRESULT WINAPI DllRegisterServer(void)
{
TRACE("()\n");
return __wine_register_resources(scrobj_instance);
}
/***********************************************************************
* DllUnregisterServer (scrobj.@)
*/
HRESULT WINAPI DllUnregisterServer(void)
{
TRACE("()\n");
return __wine_unregister_resources(scrobj_instance);
}
/***********************************************************************
* DllInstall (scrobj.@)
*/
HRESULT WINAPI DllInstall(BOOL install, const WCHAR *arg)
{
struct scriptlet_factory *factory;
HRESULT hres;
if (install)
{
hres = DllRegisterServer();
if (!arg || FAILED(hres)) return hres;
}
else if (!arg)
return DllUnregisterServer();
hres = create_scriptlet_factory(arg, &factory);
if (SUCCEEDED(hres))
{
if (factory->have_registration)
{
/* validate scripts */
hres = create_scriptlet_hosts(factory, &factory->hosts);
if (SUCCEEDED(hres)) hres = parse_scripts(factory, &factory->hosts, FALSE);
}
else
{
FIXME("No registration info\n");
hres = E_FAIL;
}
if (SUCCEEDED(hres))
{
if (install)
hres = register_scriptlet(factory);
else
hres = unregister_scriptlet(factory);
}
IClassFactory_Release(&factory->IClassFactory_iface);
}
return hres;
}
static HRESULT WINAPI scriptlet_typelib_CreateInstance(IClassFactory *factory, IUnknown *outer, REFIID riid, void **obj)
{
struct scriptlet_typelib *This;
HRESULT hr;
TRACE("(%p, %p, %s, %p)\n", factory, outer, debugstr_guid(riid), obj);
*obj = NULL;
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
if (!This)
return E_OUTOFMEMORY;
This->IGenScriptletTLib_iface.lpVtbl = &scriptlet_typelib_vtbl;
This->ref = 1;
This->guid = NULL;
hr = IGenScriptletTLib_QueryInterface(&This->IGenScriptletTLib_iface, riid, obj);
IGenScriptletTLib_Release(&This->IGenScriptletTLib_iface);
return hr;
}
static HRESULT WINAPI scrruncf_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
{
*ppv = NULL;
if (IsEqualGUID(&IID_IUnknown, riid))
{
TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
*ppv = iface;
}
else if (IsEqualGUID(&IID_IClassFactory, riid))
{
TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
*ppv = iface;
}
if (*ppv)
{
IUnknown_AddRef((IUnknown *)*ppv);
return S_OK;
}
WARN("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv);
return E_NOINTERFACE;
}
static ULONG WINAPI scrruncf_AddRef(IClassFactory *iface)
{
TRACE("(%p)\n", iface);
return 2;
}
static ULONG WINAPI scrruncf_Release(IClassFactory *iface)
{
TRACE("(%p)\n", iface);
return 1;
}
static HRESULT WINAPI scrruncf_LockServer(IClassFactory *iface, BOOL fLock)
{
TRACE("(%p)->(%x)\n", iface, fLock);
return S_OK;
}
static const struct IClassFactoryVtbl scriptlet_typelib_factory_vtbl =
{
scrruncf_QueryInterface,
scrruncf_AddRef,
scrruncf_Release,
scriptlet_typelib_CreateInstance,
scrruncf_LockServer
};
static IClassFactory scriptlet_typelib_factory = { &scriptlet_typelib_factory_vtbl };
/***********************************************************************
* DllGetClassObject (scrobj.@)
*/
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
{
WCHAR key_name[128], *p;
LONG size = 0;
LSTATUS status;
if (IsEqualGUID(&CLSID_TypeLib, rclsid))
{
TRACE("(Scriptlet.TypeLib %s %p)\n", debugstr_guid(riid), ppv);
return IClassFactory_QueryInterface(&scriptlet_typelib_factory, riid, ppv);
}
wcscpy(key_name, L"CLSID\\");
p = key_name + wcslen(key_name);
p += StringFromGUID2(rclsid, p, ARRAY_SIZE(key_name) - (p - key_name)) - 1;
wcscpy(p, L"\\ScriptletURL");
status = RegQueryValueW(HKEY_CLASSES_ROOT, key_name, NULL, &size);
if (!status)
{
struct scriptlet_factory *factory;
WCHAR *url;
HRESULT hres;
if (!(url = heap_alloc(size * sizeof(WCHAR)))) return E_OUTOFMEMORY;
status = RegQueryValueW(HKEY_CLASSES_ROOT, key_name, url, &size);
hres = create_scriptlet_factory(url, &factory);
heap_free(url);
if (FAILED(hres)) return hres;
hres = IClassFactory_QueryInterface(&factory->IClassFactory_iface, riid, ppv);
IClassFactory_Release(&factory->IClassFactory_iface);
return hres;
}
FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
return CLASS_E_CLASSNOTAVAILABLE;
}
/***********************************************************************
* DllCanUnloadNow (scrobj.@)
*/
HRESULT WINAPI DllCanUnloadNow(void)
{
return S_FALSE;
}