msscript.ocx: Implement ScriptProcedureCollection::get_Item.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Gabriel Ivăncescu 2020-08-12 17:13:40 +03:00 committed by Alexandre Julliard
parent d8e89f3119
commit e8348bdbcc
2 changed files with 296 additions and 34 deletions

View File

@ -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)

View File

@ -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);