[PATCH v2 4/8] msscript.ocx: Implement ScriptProcedureCollection::get_Item.
Gabriel Ivăncescu
gabrielopcode at gmail.com
Wed Aug 12 09:13:40 CDT 2020
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
dlls/msscript.ocx/msscript.c | 266 ++++++++++++++++++++++++++++-
dlls/msscript.ocx/tests/msscript.c | 64 +++----
2 files changed, 296 insertions(+), 34 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c
index 60b641f..df173be 100644
--- a/dlls/msscript.ocx/msscript.c
+++ b/dlls/msscript.ocx/msscript.c
@@ -84,10 +84,18 @@ typedef struct {
ScriptHost *host;
IDispatch *script_dispatch;
ITypeInfo *script_typeinfo;
+ ITypeComp *script_typecomp;
ScriptProcedureCollection *procedures;
} ScriptModule;
+typedef struct {
+ IScriptProcedure IScriptProcedure_iface;
+ LONG ref;
+
+ BSTR name;
+} ScriptProcedure;
+
struct ScriptProcedureCollection {
IScriptProcedureCollection IScriptProcedureCollection_iface;
LONG ref;
@@ -150,6 +158,7 @@ typedef enum tid_t {
IScriptModuleCollection_tid,
IScriptModule_tid,
IScriptProcedureCollection_tid,
+ IScriptProcedure_tid,
LAST_tid
} tid_t;
@@ -161,6 +170,7 @@ static REFIID tid_ids[] = {
&IID_IScriptModuleCollection,
&IID_IScriptModule,
&IID_IScriptProcedureCollection,
+ &IID_IScriptProcedure
};
static HRESULT load_typelib(void)
@@ -277,6 +287,19 @@ static HRESULT get_script_typeinfo(ScriptModule *module, ITypeInfo **typeinfo)
return S_OK;
}
+static HRESULT get_script_typecomp(ScriptModule *module, ITypeInfo *typeinfo, ITypeComp **typecomp)
+{
+ HRESULT hr;
+
+ if (!module->script_typecomp)
+ {
+ hr = ITypeInfo_QueryInterface(typeinfo, &IID_ITypeComp, (void**)&module->script_typecomp);
+ if (FAILED(hr)) return hr;
+ }
+ *typecomp = module->script_typecomp;
+ return S_OK;
+}
+
static void uncache_module_objects(ScriptModule *module)
{
if (module->script_dispatch)
@@ -289,6 +312,11 @@ static void uncache_module_objects(ScriptModule *module)
ITypeInfo_Release(module->script_typeinfo);
module->script_typeinfo = NULL;
}
+ if (module->script_typecomp)
+ {
+ ITypeComp_Release(module->script_typecomp);
+ module->script_typecomp = NULL;
+ }
if (module->procedures)
module->procedures->count = -1;
}
@@ -453,6 +481,11 @@ static inline ScriptControl *impl_from_IConnectionPointContainer(IConnectionPoin
return CONTAINING_RECORD(iface, ScriptControl, IConnectionPointContainer_iface);
}
+static inline ScriptProcedure *impl_from_IScriptProcedure(IScriptProcedure *iface)
+{
+ return CONTAINING_RECORD(iface, ScriptProcedure, IScriptProcedure_iface);
+}
+
static inline ScriptProcedureCollection *impl_from_IScriptProcedureCollection(IScriptProcedureCollection *iface)
{
return CONTAINING_RECORD(iface, ScriptProcedureCollection, IScriptProcedureCollection_iface);
@@ -728,6 +761,181 @@ static const IServiceProviderVtbl ServiceProviderVtbl = {
ServiceProvider_QueryService
};
+static HRESULT WINAPI ScriptProcedure_QueryInterface(IScriptProcedure *iface, REFIID riid, void **ppv)
+{
+ ScriptProcedure *This = impl_from_IScriptProcedure(iface);
+
+ if (IsEqualGUID(&IID_IDispatch, riid) || IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IScriptProcedure, riid))
+ {
+ *ppv = &This->IScriptProcedure_iface;
+ }
+ else
+ {
+ WARN("unsupported interface: (%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown*)*ppv);
+ return S_OK;
+}
+
+static ULONG WINAPI ScriptProcedure_AddRef(IScriptProcedure *iface)
+{
+ ScriptProcedure *This = impl_from_IScriptProcedure(iface);
+ LONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) ref=%d\n", This, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI ScriptProcedure_Release(IScriptProcedure *iface)
+{
+ ScriptProcedure *This = impl_from_IScriptProcedure(iface);
+ LONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) ref=%d\n", This, ref);
+
+ if (!ref)
+ {
+ SysFreeString(This->name);
+ heap_free(This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI ScriptProcedure_GetTypeInfoCount(IScriptProcedure *iface, UINT *pctinfo)
+{
+ ScriptProcedure *This = impl_from_IScriptProcedure(iface);
+
+ TRACE("(%p)->(%p)\n", This, pctinfo);
+
+ *pctinfo = 1;
+ return S_OK;
+}
+
+static HRESULT WINAPI ScriptProcedure_GetTypeInfo(IScriptProcedure *iface, UINT iTInfo,
+ LCID lcid, ITypeInfo **ppTInfo)
+{
+ ScriptProcedure *This = impl_from_IScriptProcedure(iface);
+
+ TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
+
+ return get_typeinfo(IScriptProcedure_tid, ppTInfo);
+}
+
+static HRESULT WINAPI ScriptProcedure_GetIDsOfNames(IScriptProcedure *iface, REFIID riid,
+ LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+ ScriptProcedure *This = impl_from_IScriptProcedure(iface);
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
+
+ hr = get_typeinfo(IScriptProcedure_tid, &typeinfo);
+ if (SUCCEEDED(hr))
+ {
+ hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
+ ITypeInfo_Release(typeinfo);
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI ScriptProcedure_Invoke(IScriptProcedure *iface, DISPID dispIdMember,
+ REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+ ScriptProcedure *This = impl_from_IScriptProcedure(iface);
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
+ lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+ hr = get_typeinfo(IScriptProcedure_tid, &typeinfo);
+ if(SUCCEEDED(hr))
+ {
+ hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
+ pDispParams, pVarResult, pExcepInfo, puArgErr);
+ ITypeInfo_Release(typeinfo);
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI ScriptProcedure_get_Name(IScriptProcedure *iface, BSTR *pbstrName)
+{
+ ScriptProcedure *This = impl_from_IScriptProcedure(iface);
+
+ FIXME("(%p)->(%p)\n", This, pbstrName);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ScriptProcedure_get_NumArgs(IScriptProcedure *iface, LONG *pcArgs)
+{
+ ScriptProcedure *This = impl_from_IScriptProcedure(iface);
+
+ FIXME("(%p)->(%p)\n", This, pcArgs);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ScriptProcedure_get_HasReturnValue(IScriptProcedure *iface, VARIANT_BOOL *pfHasReturnValue)
+{
+ ScriptProcedure *This = impl_from_IScriptProcedure(iface);
+
+ FIXME("(%p)->(%p)\n", This, pfHasReturnValue);
+
+ return E_NOTIMPL;
+}
+
+static const IScriptProcedureVtbl ScriptProcedureVtbl = {
+ ScriptProcedure_QueryInterface,
+ ScriptProcedure_AddRef,
+ ScriptProcedure_Release,
+ ScriptProcedure_GetTypeInfoCount,
+ ScriptProcedure_GetTypeInfo,
+ ScriptProcedure_GetIDsOfNames,
+ ScriptProcedure_Invoke,
+ ScriptProcedure_get_Name,
+ ScriptProcedure_get_NumArgs,
+ ScriptProcedure_get_HasReturnValue
+};
+
+/* This function always releases the FUNCDESC passed in */
+static HRESULT get_script_procedure(ITypeInfo *typeinfo, FUNCDESC *desc, IScriptProcedure **procedure)
+{
+ ScriptProcedure *proc;
+ HRESULT hr;
+ BSTR str;
+ UINT len;
+
+ hr = ITypeInfo_GetNames(typeinfo, desc->memid, &str, 1, &len);
+ if (FAILED(hr)) goto done;
+
+ if (!(proc = heap_alloc(sizeof(*proc))))
+ {
+ hr = E_OUTOFMEMORY;
+ SysFreeString(str);
+ goto done;
+ }
+
+ proc->IScriptProcedure_iface.lpVtbl = &ScriptProcedureVtbl;
+ proc->ref = 1;
+ proc->name = str;
+
+ *procedure = &proc->IScriptProcedure_iface;
+
+done:
+ ITypeInfo_ReleaseFuncDesc(typeinfo, desc);
+ return hr;
+}
+
static HRESULT WINAPI ScriptProcedureCollection_QueryInterface(IScriptProcedureCollection *iface, REFIID riid, void **ppv)
{
ScriptProcedureCollection *This = impl_from_IScriptProcedureCollection(iface);
@@ -848,10 +1056,64 @@ static HRESULT WINAPI ScriptProcedureCollection_get_Item(IScriptProcedureCollect
IScriptProcedure **ppdispProcedure)
{
ScriptProcedureCollection *This = impl_from_IScriptProcedureCollection(iface);
+ ITypeInfo *typeinfo;
+ FUNCDESC *desc;
+ HRESULT hr;
- FIXME("(%p)->(%s %p)\n", This, wine_dbgstr_variant(&index), ppdispProcedure);
+ TRACE("(%p)->(%s %p)\n", This, wine_dbgstr_variant(&index), ppdispProcedure);
- return E_NOTIMPL;
+ if (!ppdispProcedure) return E_POINTER;
+ if (!This->module->host) return E_FAIL;
+
+ hr = start_script(This->module->host);
+ if (FAILED(hr)) return hr;
+
+ hr = get_script_typeinfo(This->module, &typeinfo);
+ if (FAILED(hr)) return hr;
+
+ if (V_VT(&index) == VT_BSTR)
+ {
+ ITypeComp *comp;
+ BINDPTR bindptr;
+ DESCKIND kind;
+ ULONG hash;
+
+ hash = LHashValOfNameSys(sizeof(void*) == 8 ? SYS_WIN64 : SYS_WIN32, LOCALE_USER_DEFAULT, V_BSTR(&index));
+
+ hr = get_script_typecomp(This->module, typeinfo, &comp);
+ if (FAILED(hr)) return hr;
+
+ hr = ITypeComp_Bind(comp, V_BSTR(&index), hash, INVOKE_FUNC, &typeinfo, &kind, &bindptr);
+ if (FAILED(hr)) return hr;
+
+ switch (kind)
+ {
+ case DESCKIND_FUNCDESC:
+ hr = get_script_procedure(typeinfo, bindptr.lpfuncdesc, ppdispProcedure);
+ ITypeInfo_Release(typeinfo);
+ return hr;
+ case DESCKIND_IMPLICITAPPOBJ:
+ case DESCKIND_VARDESC:
+ ITypeInfo_ReleaseVarDesc(typeinfo, bindptr.lpvardesc);
+ ITypeInfo_Release(typeinfo);
+ break;
+ case DESCKIND_TYPECOMP:
+ ITypeComp_Release(bindptr.lptcomp);
+ break;
+ default:
+ break;
+ }
+ return CTL_E_ILLEGALFUNCTIONCALL;
+ }
+
+ hr = VariantChangeType(&index, &index, 0, VT_INT);
+ if (FAILED(hr)) return hr;
+ if (V_INT(&index) <= 0) return 0x800a0009;
+
+ hr = ITypeInfo_GetFuncDesc(typeinfo, V_INT(&index) - 1, &desc);
+ if (FAILED(hr)) return hr;
+
+ return get_script_procedure(typeinfo, desc, ppdispProcedure);
}
static HRESULT WINAPI ScriptProcedureCollection_get_Count(IScriptProcedureCollection *iface, LONG *plCount)
diff --git a/dlls/msscript.ocx/tests/msscript.c b/dlls/msscript.ocx/tests/msscript.c
index dbdb00e..ed4d0f8 100644
--- a/dlls/msscript.ocx/tests/msscript.c
+++ b/dlls/msscript.ocx/tests/msscript.c
@@ -3325,9 +3325,9 @@ static void test_IScriptControl_get_Procedures(void)
V_VT(&var) = VT_I4;
V_I4(&var) = -1;
hr = IScriptProcedureCollection_get_Item(procs, var, NULL);
- todo_wine ok(hr == E_POINTER, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
+ ok(hr == E_POINTER, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == 0x800a0009, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
+ ok(hr == 0x800a0009, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
str = SysAllocString(L""
"function add(a, b) { return a + b; }\n"
@@ -3348,25 +3348,25 @@ static void test_IScriptControl_get_Procedures(void)
IScriptProcedureCollection_AddRef(procs);
i = IScriptProcedureCollection_Release(procs);
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == S_OK, "IScriptProcedureCollection_get_Item failed: 0x%08x.\n", hr);
+ ok(hr == S_OK, "IScriptProcedureCollection_get_Item failed: 0x%08x.\n", hr);
IScriptProcedureCollection_AddRef(procs);
ok(i == IScriptProcedureCollection_Release(procs),
"IScriptProcedureCollection_get_Item should not have added a ref to the collection.\n");
- if (hr == S_OK) IScriptProcedure_Release(proc);
+ IScriptProcedure_Release(proc);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"Nop");
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == S_OK, "IScriptProcedureCollection_get_Item failed: 0x%08x.\n", hr);
+ ok(hr == S_OK, "IScriptProcedureCollection_get_Item failed: 0x%08x.\n", hr);
ok(V_VT(&var) == VT_BSTR, "var type not BSTR, got %d.\n", V_VT(&var));
VariantClear(&var);
- if (hr == S_OK) IScriptProcedure_Release(proc);
+ IScriptProcedure_Release(proc);
V_VT(&var) = VT_R8;
V_R8(&var) = 3.0;
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == S_OK, "IScriptProcedureCollection_get_Item failed: 0x%08x.\n", hr);
- if (hr == S_OK) IScriptProcedure_Release(proc);
+ ok(hr == S_OK, "IScriptProcedureCollection_get_Item failed: 0x%08x.\n", hr);
+ IScriptProcedure_Release(proc);
IScriptProcedureCollection_Release(procs);
IScriptControl_Release(sc);
@@ -3464,10 +3464,10 @@ static void test_IScriptControl_get_Procedures(void)
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"foobar");
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == E_NOINTERFACE, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
+ ok(hr == E_NOINTERFACE, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
ok(V_VT(&var) == VT_BSTR, "var type not BSTR, got %d.\n", V_VT(&var));
VariantClear(&var);
- todo_wine CHECK_CALLED(QI_ITypeComp);
+ CHECK_CALLED(QI_ITypeComp);
/* Make ITypeComp available */
TypeComp_available = TRUE;
@@ -3476,43 +3476,43 @@ static void test_IScriptControl_get_Procedures(void)
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"type_mismatch");
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == TYPE_E_TYPEMISMATCH, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
+ ok(hr == TYPE_E_TYPEMISMATCH, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
VariantClear(&var);
- todo_wine CHECK_CALLED(QI_ITypeComp);
- todo_wine CHECK_CALLED(Bind);
+ CHECK_CALLED(QI_ITypeComp);
+ CHECK_CALLED(Bind);
TypeComp_available = FALSE;
SET_EXPECT(Bind);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"not_found");
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == CTL_E_ILLEGALFUNCTIONCALL, "IScriptProcedureCollection_get_Item failed: 0x%08x.\n", hr);
+ ok(hr == CTL_E_ILLEGALFUNCTIONCALL, "IScriptProcedureCollection_get_Item failed: 0x%08x.\n", hr);
VariantClear(&var);
- todo_wine CHECK_CALLED(Bind);
+ CHECK_CALLED(Bind);
SET_EXPECT(Bind);
SET_EXPECT(ReleaseVarDesc);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"variable");
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == CTL_E_ILLEGALFUNCTIONCALL, "IScriptProcedureCollection_get_Item failed: 0x%08x.\n", hr);
+ ok(hr == CTL_E_ILLEGALFUNCTIONCALL, "IScriptProcedureCollection_get_Item failed: 0x%08x.\n", hr);
VariantClear(&var);
- todo_wine CHECK_CALLED(Bind);
- todo_wine CHECK_CALLED(ReleaseVarDesc);
+ CHECK_CALLED(Bind);
+ CHECK_CALLED(ReleaseVarDesc);
/* Index 0 and below are invalid (doesn't even call GetFuncDesc) */
V_VT(&var) = VT_I4;
V_I4(&var) = 0;
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == 0x800a0009, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
+ ok(hr == 0x800a0009, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
V_I4(&var) = -1;
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == 0x800a0009, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
+ ok(hr == 0x800a0009, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
SET_EXPECT(GetFuncDesc);
V_I4(&var) = 1337;
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == E_INVALIDARG, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
- todo_wine CHECK_CALLED(GetFuncDesc);
+ ok(hr == E_INVALIDARG, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
+ CHECK_CALLED(GetFuncDesc);
for (i = 0; i < ARRAY_SIZE(custom_engine_funcs); i++)
{
@@ -3523,11 +3523,11 @@ static void test_IScriptControl_get_Procedures(void)
V_VT(&var) = VT_R4;
V_R4(&var) = i + 1;
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == S_OK, "get_Item for index %u failed: 0x%08x.\n", i, hr);
- todo_wine CHECK_CALLED(GetFuncDesc);
- todo_wine CHECK_CALLED(GetNames);
- todo_wine CHECK_CALLED(ReleaseFuncDesc);
- if (hr == S_OK) IScriptProcedure_Release(proc);
+ ok(hr == S_OK, "get_Item for index %u failed: 0x%08x.\n", i, hr);
+ CHECK_CALLED(GetFuncDesc);
+ CHECK_CALLED(GetNames);
+ CHECK_CALLED(ReleaseFuncDesc);
+ IScriptProcedure_Release(proc);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(custom_engine_funcs[i].name);
@@ -3535,12 +3535,12 @@ static void test_IScriptControl_get_Procedures(void)
SET_EXPECT(GetNames);
SET_EXPECT(ReleaseFuncDesc);
hr = IScriptProcedureCollection_get_Item(procs, var, &proc);
- todo_wine ok(hr == S_OK, "get_Item for %s failed: 0x%08x.\n", wine_dbgstr_w(custom_engine_funcs[i].name), hr);
+ ok(hr == S_OK, "get_Item for %s failed: 0x%08x.\n", wine_dbgstr_w(custom_engine_funcs[i].name), hr);
VariantClear(&var);
- todo_wine CHECK_CALLED(Bind);
- todo_wine CHECK_CALLED(GetNames);
- todo_wine CHECK_CALLED(ReleaseFuncDesc);
- if (hr == S_OK) IScriptProcedure_Release(proc);
+ CHECK_CALLED(Bind);
+ CHECK_CALLED(GetNames);
+ CHECK_CALLED(ReleaseFuncDesc);
+ IScriptProcedure_Release(proc);
}
IScriptProcedureCollection_Release(procs);
--
2.21.0
More information about the wine-devel
mailing list