[PATCH v4 06/11] msscript.ocx: Implement IScriptModuleCollection::Add.
Gabriel Ivăncescu
gabrielopcode at gmail.com
Mon Jun 15 08:00:09 CDT 2020
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
dlls/msscript.ocx/msscript.c | 68 ++++++++++++--
dlls/msscript.ocx/tests/msscript.c | 145 ++++++++++++++++++++++++++---
2 files changed, 194 insertions(+), 19 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c
index 2b19785..b2e6cf2 100644
--- a/dlls/msscript.ocx/msscript.c
+++ b/dlls/msscript.ocx/msscript.c
@@ -70,6 +70,7 @@ typedef struct {
IScriptModule IScriptModule_iface;
LONG ref;
+ BSTR name;
ScriptHost *host;
} ScriptModule;
@@ -196,6 +197,11 @@ static void release_typelib(void)
ITypeLib_Release(typelib);
}
+static inline BOOL is_power_of_2(unsigned x)
+{
+ return !(x & (x - 1));
+}
+
static void clear_named_items(ScriptHost *host)
{
struct named_item *item, *item1;
@@ -648,6 +654,7 @@ static ULONG WINAPI ScriptModule_Release(IScriptModule *iface)
{
if (This->host)
IActiveScriptSite_Release(&This->host->IActiveScriptSite_iface);
+ SysFreeString(This->name);
heap_free(This);
}
@@ -795,7 +802,7 @@ static const IScriptModuleVtbl ScriptModuleVtbl = {
ScriptModule_Run
};
-static ScriptModule *create_module(void)
+static ScriptModule *create_module(BSTR name)
{
ScriptModule *module;
@@ -803,7 +810,13 @@ static ScriptModule *create_module(void)
module->IScriptModule_iface.lpVtbl = &ScriptModuleVtbl;
module->ref = 1;
+ module->name = NULL;
module->host = NULL;
+ if (name && !(module->name = SysAllocString(name)))
+ {
+ heap_free(module);
+ return NULL;
+ }
return module;
}
@@ -820,12 +833,18 @@ static void release_modules(ScriptControl *control)
static ScriptModule *find_module(ScriptControl *control, BSTR name)
{
- unsigned int len = SysStringLen(name);
+ unsigned int i, len = SysStringLen(name);
if (len == sizeof("Global") - 1 && !wcsicmp(name, L"Global"))
return control->modules[0];
- /* FIXME: Look for other modules when they can be added */
+ for (i = 1; i < control->module_count; i++)
+ {
+ BSTR module_name = control->modules[i]->name;
+ if (SysStringLen(module_name) == len && !wcsicmp(name, module_name))
+ return control->modules[i];
+ }
+
return NULL;
}
@@ -980,10 +999,47 @@ static HRESULT WINAPI ScriptModuleCollection_Add(IScriptModuleCollection *iface,
VARIANT *object, IScriptModule **ppmod)
{
ScriptControl *This = impl_from_IScriptModuleCollection(iface);
+ ScriptModule *module, **modules;
+ HRESULT hr;
- FIXME("(%p)->(%s %s %p)\n", This, wine_dbgstr_w(name), wine_dbgstr_variant(object), ppmod);
+ TRACE("(%p)->(%s %s %p)\n", This, wine_dbgstr_w(name), wine_dbgstr_variant(object), ppmod);
- return E_NOTIMPL;
+ if (!ppmod) return E_POINTER;
+ if (!name || V_VT(object) != VT_DISPATCH || find_module(This, name))
+ return E_INVALIDARG;
+ if (!This->host) return E_FAIL;
+
+ /* See if we need to grow the array */
+ if (is_power_of_2(This->module_count))
+ {
+ modules = heap_realloc(This->modules, This->module_count * 2 * sizeof(*This->modules));
+ if (!modules) return E_OUTOFMEMORY;
+ This->modules = modules;
+ }
+
+ if (!(module = create_module(name)))
+ return E_OUTOFMEMORY;
+
+ /* If no object, Windows only calls AddNamedItem without adding a NULL object */
+ if (V_DISPATCH(object))
+ hr = add_script_object(This->host, name, V_DISPATCH(object), 0);
+ else
+ hr = IActiveScript_AddNamedItem(This->host->script, name, SCRIPTITEM_CODEONLY);
+
+ if (FAILED(hr))
+ {
+ IScriptModule_Release(&module->IScriptModule_iface);
+ return hr;
+ }
+
+ module->host = This->host;
+ IActiveScriptSite_AddRef(&module->host->IActiveScriptSite_iface);
+
+ This->modules[This->module_count++] = module;
+
+ *ppmod = &module->IScriptModule_iface;
+ IScriptModule_AddRef(*ppmod);
+ return S_OK;
}
static const IScriptModuleCollectionVtbl ScriptModuleCollectionVtbl = {
@@ -1248,7 +1304,7 @@ static HRESULT WINAPI ScriptControl_put_Language(IScriptControl *iface, BSTR lan
modules = heap_alloc_zero(sizeof(*modules));
if (!modules) return E_OUTOFMEMORY;
- modules[0] = create_module();
+ modules[0] = create_module(NULL);
if (!modules[0]) {
heap_free(modules);
return E_OUTOFMEMORY;
diff --git a/dlls/msscript.ocx/tests/msscript.c b/dlls/msscript.ocx/tests/msscript.c
index 7297b8e..64a4520 100644
--- a/dlls/msscript.ocx/tests/msscript.c
+++ b/dlls/msscript.ocx/tests/msscript.c
@@ -2310,6 +2310,7 @@ static void test_IScriptControl_get_Modules(void)
IScriptModuleCollection *mods;
IScriptModule *mod;
IScriptControl *sc;
+ IUnknown *unknown;
VARIANT var;
LONG count;
HRESULT hr;
@@ -2347,33 +2348,33 @@ static void test_IScriptControl_get_Modules(void)
V_VT(&var) = VT_EMPTY;
str = SysAllocString(L"foobar");
hr = IScriptModuleCollection_Add(mods, str, &var, &mod);
- todo_wine ok(hr == E_INVALIDARG, "IScriptModuleCollection_Add returned: 0x%08x.\n", hr);
+ ok(hr == E_INVALIDARG, "IScriptModuleCollection_Add returned: 0x%08x.\n", hr);
hr = IScriptModuleCollection_Add(mods, str, &var, NULL);
- todo_wine ok(hr == E_POINTER, "IScriptModuleCollection_Add returned: 0x%08x.\n", hr);
+ ok(hr == E_POINTER, "IScriptModuleCollection_Add returned: 0x%08x.\n", hr);
V_VT(&var) = VT_DISPATCH;
V_DISPATCH(&var) = NULL;
hr = IScriptModuleCollection_Add(mods, NULL, &var, &mod);
- todo_wine ok(hr == E_INVALIDARG, "IScriptModuleCollection_Add returned: 0x%08x.\n", hr);
+ ok(hr == E_INVALIDARG, "IScriptModuleCollection_Add returned: 0x%08x.\n", hr);
hr = IScriptModuleCollection_Add(mods, str, &var, &mod);
- todo_wine ok(hr == S_OK, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr);
- if (hr == S_OK) IScriptModule_Release(mod);
+ ok(hr == S_OK, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr);
+ IScriptModule_Release(mod);
SysFreeString(str);
str = SysAllocString(L"some other Module");
hr = IScriptModuleCollection_Add(mods, str, &var, &mod);
- todo_wine ok(hr == S_OK, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr);
- if (hr == S_OK) IScriptModule_Release(mod);
+ ok(hr == S_OK, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr);
+ IScriptModule_Release(mod);
SysFreeString(str);
/* Adding a module with the same name is invalid (case insensitive) */
str = SysAllocString(L"FooBar");
hr = IScriptModuleCollection_Add(mods, str, &var, &mod);
- todo_wine ok(hr == E_INVALIDARG, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr);
+ ok(hr == E_INVALIDARG, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr);
SysFreeString(str);
hr = IScriptModuleCollection_get_Count(mods, &count);
ok(hr == S_OK, "IScriptModuleCollection_get_Count failed: 0x%08x.\n", hr);
- todo_wine ok(count == 3, "count is not 3, got %d.\n", count);
+ ok(count == 3, "count is not 3, got %d.\n", count);
V_VT(&var) = VT_I4;
V_I4(&var) = count + 1;
hr = IScriptModuleCollection_get_Item(mods, var, &mod);
@@ -2403,16 +2404,26 @@ static void test_IScriptControl_get_Modules(void)
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"some other module");
hr = IScriptModuleCollection_get_Item(mods, var, &mod);
- todo_wine ok(hr == S_OK, "IScriptModuleCollection_get_Item failed: 0x%08x.\n", hr);
+ ok(hr == S_OK, "IScriptModuleCollection_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) IScriptModule_Release(mod);
+ hr = IScriptModule_get_Name(mod, &str);
+ todo_wine ok(hr == S_OK, "IScriptModule_get_Name failed: 0x%08x.\n", hr);
+ IScriptModule_Release(mod);
+ if (hr == S_OK) SysFreeString(str);
V_VT(&var) = VT_R8;
V_R8(&var) = 2.0;
hr = IScriptModuleCollection_get_Item(mods, var, &mod);
- todo_wine ok(hr == S_OK, "IScriptModuleCollection_get_Item failed: 0x%08x.\n", hr);
- if (hr == S_OK) IScriptModule_Release(mod);
+ ok(hr == S_OK, "IScriptModuleCollection_get_Item failed: 0x%08x.\n", hr);
+ hr = IScriptModule_get_Name(mod, &str);
+ todo_wine ok(hr == S_OK, "IScriptModule_get_Name failed: 0x%08x.\n", hr);
+ if (hr == S_OK) SysFreeString(str);
+ str = SysAllocString(L"function sub(a, b) { return a - b; }\n");
+ hr = IScriptModule_AddCode(mod, str);
+ todo_wine ok(hr == S_OK, "IScriptModule_AddCode failed: 0x%08x.\n", hr);
+ IScriptModule_Release(mod);
+ SysFreeString(str);
/* The 'Global' module is the same as the script control */
str = SysAllocString(L"add(10, 5)");
@@ -2425,14 +2436,31 @@ static void test_IScriptControl_get_Modules(void)
ok(FAILED(hr), "IScriptControl_Eval succeeded: 0x%08x.\n", hr);
SysFreeString(str);
+ /* Grab a module ref and change the language to something valid */
+ V_VT(&var) = VT_I2;
+ V_I2(&var) = 3;
+ hr = IScriptModuleCollection_get_Item(mods, var, &mod);
+ ok(hr == S_OK, "IScriptModuleCollection_get_Item failed: 0x%08x.\n", hr);
str = SysAllocString(L"vbscript");
hr = IScriptControl_put_Language(sc, str);
ok(hr == S_OK, "IScriptControl_put_Language failed: 0x%08x.\n", hr);
SysFreeString(str);
+ /* The module collection changes and module ref is invalid */
hr = IScriptModuleCollection_get_Count(mods, &count);
ok(hr == S_OK, "IScriptModuleCollection_get_Count failed: 0x%08x.\n", hr);
ok(count == 1, "count is not 1, got %d.\n", count);
+ hr = IScriptModule_get_Name(mod, &str);
+ todo_wine ok(hr == E_FAIL, "IScriptModule_get_Name returned: 0x%08x.\n", hr);
+ str = SysAllocString(L"function closed() { }\n");
+ hr = IScriptModule_AddCode(mod, str);
+ todo_wine ok(hr == E_FAIL, "IScriptModule_AddCode failed: 0x%08x.\n", hr);
+ SysFreeString(str);
+ str = SysAllocString(L"sub closed\nend sub");
+ hr = IScriptModule_AddCode(mod, str);
+ todo_wine ok(hr == E_FAIL, "IScriptModule_AddCode failed: 0x%08x.\n", hr);
+ IScriptModule_Release(mod);
+ SysFreeString(str);
IScriptModuleCollection_Release(mods);
IScriptControl_Release(sc);
@@ -2440,6 +2468,8 @@ static void test_IScriptControl_get_Modules(void)
/* custom script engine */
if (have_custom_engine)
{
+ BSTR code_str;
+
/* A module collection ref keeps the control alive */
hr = CoCreateInstance(&CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
&IID_IScriptControl, (void**)&sc);
@@ -2470,6 +2500,7 @@ static void test_IScriptControl_get_Modules(void)
IScriptModuleCollection_Release(mods);
CHECK_CALLED(Close);
+ /* Add a module with a non-null object and add some code to it */
hr = CoCreateInstance(&CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
&IID_IScriptControl, (void**)&sc);
ok(hr == S_OK, "Failed to create IScriptControl interface: 0x%08x.\n", hr);
@@ -2492,6 +2523,36 @@ static void test_IScriptControl_get_Modules(void)
hr = IScriptControl_get_Modules(sc, &mods);
ok(hr == S_OK, "IScriptControl_get_Modules failed: 0x%08x.\n", hr);
+ SET_EXPECT(AddNamedItem);
+ str = SysAllocString(L"modname");
+ AddNamedItem_expected_name = str;
+ AddNamedItem_expected_flags = 0;
+ V_VT(&var) = VT_DISPATCH;
+ V_DISPATCH(&var) = &testdisp;
+ hr = IScriptModuleCollection_Add(mods, str, &var, &mod);
+ ok(hr == S_OK, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr);
+ VariantClear(&var);
+ CHECK_CALLED(AddNamedItem);
+
+ unknown = (IUnknown*)0xdeadbeef;
+ hr = IActiveScriptSite_GetItemInfo(site, str, SCRIPTINFO_IUNKNOWN, &unknown, NULL);
+ ok(hr == S_OK, "IActiveScriptSite_GetItemInfo failed: 0x%08x.\n", hr);
+ ok(unknown == (IUnknown*)&testdisp, "Unexpected IUnknown for the item: %p.\n", unknown);
+ IUnknown_Release(unknown);
+
+ SET_EXPECT(SetScriptState_STARTED);
+ SET_EXPECT(ParseScriptText);
+ parse_item_name = str;
+ parse_flags = SCRIPTTEXT_ISVISIBLE;
+ code_str = SysAllocString(L"some code");
+ hr = IScriptModule_AddCode(mod, code_str);
+ todo_wine ok(hr == S_OK, "IScriptControl_AddCode failed: 0x%08x.\n", hr);
+ todo_wine CHECK_CALLED(SetScriptState_STARTED);
+ todo_wine CHECK_CALLED(ParseScriptText);
+ SysFreeString(code_str);
+ SysFreeString(str);
+
+ /* Keep the module ref before changing the language */
SET_EXPECT(Close);
hr = IScriptControl_put_Language(sc, NULL);
ok(hr == S_OK, "IScriptControl_put_Language failed: 0x%08x.\n", hr);
@@ -2499,6 +2560,64 @@ static void test_IScriptControl_get_Modules(void)
IScriptModuleCollection_Release(mods);
IActiveScriptSite_Release(site);
IScriptControl_Release(sc);
+ IScriptModule_Release(mod);
+
+ /* Now try holding a module ref while closing the script */
+ hr = CoCreateInstance(&CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
+ &IID_IScriptControl, (void**)&sc);
+ ok(hr == S_OK, "Failed to create IScriptControl interface: 0x%08x.\n", hr);
+
+ SET_EXPECT(CreateInstance);
+ SET_EXPECT(SetInterfaceSafetyOptions);
+ SET_EXPECT(SetScriptSite);
+ SET_EXPECT(QI_IActiveScriptParse);
+ SET_EXPECT(InitNew);
+ str = SysAllocString(L"testscript");
+ hr = IScriptControl_put_Language(sc, str);
+ ok(hr == S_OK, "IScriptControl_put_Language failed: 0x%08x.\n", hr);
+ SysFreeString(str);
+ CHECK_CALLED(CreateInstance);
+ CHECK_CALLED(SetInterfaceSafetyOptions);
+ CHECK_CALLED(SetScriptSite);
+ CHECK_CALLED(QI_IActiveScriptParse);
+ CHECK_CALLED(InitNew);
+
+ hr = IScriptControl_get_Modules(sc, &mods);
+ ok(hr == S_OK, "IScriptControl_get_Modules failed: 0x%08x.\n", hr);
+
+ SET_EXPECT(AddNamedItem);
+ str = SysAllocString(L"foo");
+ AddNamedItem_expected_name = str;
+ AddNamedItem_expected_flags = SCRIPTITEM_CODEONLY;
+ V_VT(&var) = VT_DISPATCH;
+ V_DISPATCH(&var) = NULL;
+ hr = IScriptModuleCollection_Add(mods, str, &var, &mod);
+ ok(hr == S_OK, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr);
+ VariantClear(&var);
+ CHECK_CALLED(AddNamedItem);
+
+ unknown = (IUnknown*)0xdeadbeef;
+ hr = IActiveScriptSite_GetItemInfo(site, str, SCRIPTINFO_IUNKNOWN, &unknown, NULL);
+ ok(hr == TYPE_E_ELEMENTNOTFOUND, "IActiveScriptSite_GetItemInfo returned: 0x%08x.\n", hr);
+ IScriptModuleCollection_Release(mods);
+ IActiveScriptSite_Release(site);
+ IScriptControl_Release(sc);
+
+ SET_EXPECT(SetScriptState_STARTED);
+ SET_EXPECT(ParseScriptText);
+ parse_item_name = str;
+ parse_flags = SCRIPTTEXT_ISVISIBLE;
+ code_str = SysAllocString(L"code after close");
+ hr = IScriptModule_AddCode(mod, code_str);
+ todo_wine ok(hr == S_OK, "IScriptControl_AddCode failed: 0x%08x.\n", hr);
+ todo_wine CHECK_CALLED(SetScriptState_STARTED);
+ todo_wine CHECK_CALLED(ParseScriptText);
+ SysFreeString(code_str);
+ SysFreeString(str);
+
+ SET_EXPECT(Close);
+ IScriptModule_Release(mod);
+ CHECK_CALLED(Close);
}
}
--
2.21.0
More information about the wine-devel
mailing list