diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index 60b641fbe5d..df173be3bae 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 dbdb00e122c..ed4d0f8f993 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);