[PATCH 5/9] msscript.ocx: Implement ScriptProcedureCollection::get_Item.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Aug 10 09:58:00 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