Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
December 2019
- 73 participants
- 1394 messages
Re: [PATCH v4 5/9] jscript: Implement ScriptTypeInfo_GetIDsOfNames.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=62027
Your paranoid android.
=== debian10 (build log) ===
../../../wine/dlls/jscript/dispex.c:671:49: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
../../../wine/dlls/jscript/dispex.c:1121:38: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
Task: The win32 build failed
=== debian10 (build log) ===
../../../wine/dlls/jscript/dispex.c:671:49: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
../../../wine/dlls/jscript/dispex.c:1121:38: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
Task: The wow64 build failed
Dec. 12, 2019
Re: [PATCH v4 4/9] jscript: Implement ScriptTypeInfo_GetVarDesc.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=62026
Your paranoid android.
=== debian10 (build log) ===
../../../wine/dlls/jscript/dispex.c:671:49: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
../../../wine/dlls/jscript/dispex.c:1078:38: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
Task: The win32 build failed
=== debian10 (build log) ===
../../../wine/dlls/jscript/dispex.c:671:49: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
../../../wine/dlls/jscript/dispex.c:1078:38: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
Task: The wow64 build failed
Dec. 12, 2019
Re: [PATCH v4 3/9] jscript: Implement ScriptTypeInfo_GetFuncDesc.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=62025
Your paranoid android.
=== debian10 (build log) ===
../../../wine/dlls/jscript/dispex.c:671:49: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
../../../wine/dlls/jscript/dispex.c:1064:38: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
Task: The win32 build failed
=== debian10 (build log) ===
../../../wine/dlls/jscript/dispex.c:671:49: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
../../../wine/dlls/jscript/dispex.c:1064:38: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
Task: The wow64 build failed
Dec. 12, 2019
Re: [PATCH v4 2/9] jscript: Implement ScriptTypeInfo_GetTypeAttr.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=62024
Your paranoid android.
=== debian10 (build log) ===
../../../wine/dlls/jscript/dispex.c:671:49: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
../../../wine/dlls/jscript/dispex.c:1039:38: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
Task: The win32 build failed
=== debian10 (build log) ===
../../../wine/dlls/jscript/dispex.c:671:49: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
../../../wine/dlls/jscript/dispex.c:1039:38: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
Task: The wow64 build failed
Dec. 12, 2019
Re: [PATCH v4 1/9] jscript: Store the necessary function and variable info in the TypeInfo.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=62023
Your paranoid android.
=== debian10 (build log) ===
../../../wine/dlls/jscript/dispex.c:669:49: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
../../../wine/dlls/jscript/dispex.c:1013:38: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
Task: The win32 build failed
=== debian10 (build log) ===
../../../wine/dlls/jscript/dispex.c:669:49: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
../../../wine/dlls/jscript/dispex.c:1013:38: error: ‘function_code_t’ {aka ‘struct _function_code_t’} has no member named ‘bytecode’
Task: The wow64 build failed
Dec. 12, 2019
[PATCH v4 9/9] jscript/tests: Add initial tests for the script TypeInfo.
by Gabriel Ivăncescu
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/jscript/tests/jscript.c | 362 +++++++++++++++++++++++++++++++++++
1 file changed, 362 insertions(+)
diff --git a/dlls/jscript/tests/jscript.c b/dlls/jscript/tests/jscript.c
index 0904374..e608367 100644
--- a/dlls/jscript/tests/jscript.c
+++ b/dlls/jscript/tests/jscript.c
@@ -33,6 +33,8 @@
#define IActiveScriptParse_Release IActiveScriptParse64_Release
#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
+#define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_64_Release
+#define IActiveScriptParseProcedure2_ParseProcedureText IActiveScriptParseProcedure2_64_ParseProcedureText
#else
@@ -40,10 +42,13 @@
#define IActiveScriptParse_Release IActiveScriptParse32_Release
#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
+#define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_32_Release
+#define IActiveScriptParseProcedure2_ParseProcedureText IActiveScriptParseProcedure2_32_ParseProcedureText
#endif
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
+DEFINE_GUID(IID_IScriptTypeInfo, 0xc59c6b12, 0xf6c1, 0x11cf, 0x88,0x35, 0x00,0xa0,0xc9,0x11,0xe8,0xb2);
static const CLSID CLSID_JScript =
{0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
@@ -274,6 +279,20 @@ static IDispatchEx *get_script_dispatch(IActiveScript *script)
return dispex;
}
+static void parse_script(IActiveScriptParse *parser, const WCHAR *src)
+{
+ HRESULT hres;
+
+ SET_EXPECT(OnEnterScript);
+ SET_EXPECT(OnLeaveScript);
+
+ hres = IActiveScriptParse_ParseScriptText(parser, src, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+ ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+
+ CHECK_CALLED(OnEnterScript);
+ CHECK_CALLED(OnLeaveScript);
+}
+
#define get_disp_id(a,b,c,d) _get_disp_id(__LINE__,a,b,c,d)
static void _get_disp_id(unsigned line, IDispatchEx *dispex, const WCHAR *name, HRESULT exhr, DISPID *id)
{
@@ -907,6 +926,347 @@ static void test_code_persistence(void)
CHECK_CALLED(OnStateChange_CLOSED);
}
+static void test_typeinfo(const WCHAR *parse_func_name)
+{
+ static struct
+ {
+ const WCHAR *name;
+ UINT num_args;
+ } func[] =
+ {
+ { L"emptyfn", 0 },
+ { L"voidfn", 0 },
+ { L"math", 2 },
+ { L"foobar", 1 },
+ { L"C", 0 },
+ { L"funcvar", 2 },
+ { L"f1", 1 },
+ { L"f2", 1 }
+ };
+ static struct
+ {
+ const WCHAR *name;
+ } var[] =
+ {
+ { L"global_var" },
+ { L"uninit" },
+ { L"obj" }
+ };
+ const WCHAR *source = L""
+ "var global_var = 42;\n"
+
+ "function emptyfn() { }\n"
+ "function voidfn() { return void(0); }\n"
+ "function math(x, y) { return x - y; }\n"
+ "function foobar(x) { return \"foobar\"; }\n"
+
+ "function C() {\n"
+ " this.x;\n"
+ " this.strret = function() { return \"ret\"; }\n"
+ "}\n"
+
+ "var uninit;\n"
+ "var obj = new C();\n"
+
+ "var funcvar = function(x, y) { return x * y; };\n"
+ "var native_func = decodeURI;\n"
+
+ "(function() {\n"
+ " f1 = function infuncexpr(x) { return 1; }\n"
+ " f2 = function infuncexpr(x) { return 2; }\n"
+ "})();\n";
+ UINT expected_funcs_cnt = parse_func_name ? 0 : ARRAY_SIZE(func);
+ UINT expected_vars_cnt = parse_func_name ? 0 : ARRAY_SIZE(var);
+
+ ITypeInfo *typeinfo, *typeinfo2;
+ ITypeComp *typecomp, *typecomp2;
+ IActiveScriptParse *parser;
+ IActiveScript *script;
+ FUNCDESC *funcdesc;
+ VARDESC *vardesc;
+ IDispatchEx *disp;
+ DESCKIND desckind;
+ BINDPTR bindptr;
+ MEMBERID memid;
+ TYPEATTR *attr;
+ UINT index;
+ HRESULT hr;
+ WCHAR str[64], *names = str;
+ int i;
+
+ if (parse_func_name)
+ trace("Testing TypeInfo for function %s...\n", wine_dbgstr_w(parse_func_name));
+ else
+ trace("Testing TypeInfo for script dispatch...\n");
+
+ script = create_jscript();
+
+ hr = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parser);
+ ok(hr == S_OK, "Could not get IActiveScriptParse iface: %08x\n", hr);
+
+ SET_EXPECT(GetLCID);
+ hr = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
+ ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr);
+ CHECK_CALLED(GetLCID);
+
+ SET_EXPECT(OnStateChange_INITIALIZED);
+ hr = IActiveScriptParse_InitNew(parser);
+ ok(hr == S_OK, "InitNew failed: %08x\n", hr);
+ CHECK_CALLED(OnStateChange_INITIALIZED);
+
+ SET_EXPECT(OnStateChange_CONNECTED);
+ hr = IActiveScript_SetScriptState(script, SCRIPTSTATE_CONNECTED);
+ ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hr);
+ CHECK_CALLED(OnStateChange_CONNECTED);
+
+ if (parse_func_name)
+ {
+ IActiveScriptParseProcedure2 *parse_proc;
+ IDispatch *proc_disp;
+
+ hr = IActiveScript_QueryInterface(script, &IID_IActiveScriptParseProcedure2, (void**)&parse_proc);
+ ok(hr == S_OK, "Could not get IActiveScriptParse: %08x\n", hr);
+
+ hr = IActiveScriptParseProcedure2_ParseProcedureText(parse_proc, source, NULL, parse_func_name,
+ NULL, NULL, NULL, 0, 0, SCRIPTPROC_IMPLICIT_THIS | SCRIPTPROC_IMPLICIT_PARENTS, &proc_disp);
+ ok(hr == S_OK, "ParseProcedureText failed: %08x\n", hr);
+ IActiveScriptParseProcedure2_Release(parse_proc);
+
+ hr = IDispatch_QueryInterface(proc_disp, &IID_IDispatchEx, (void**)&disp);
+ ok(hr == S_OK, "Could not get IDispatchEx: %08x\n", hr);
+ IDispatch_Release(proc_disp);
+ }
+ else
+ {
+ parse_script(parser, source);
+ disp = get_script_dispatch(script);
+ }
+
+ hr = IDispatchEx_QueryInterface(disp, &IID_ITypeInfo, (void**)&typeinfo);
+ ok(hr == E_NOINTERFACE, "QueryInterface(IID_ITypeInfo) returned: %08x\n", hr);
+ hr = IDispatchEx_GetTypeInfo(disp, 1, LOCALE_USER_DEFAULT, &typeinfo);
+ ok(hr == DISP_E_BADINDEX, "GetTypeInfo returned: %08x\n", hr);
+ hr = IDispatchEx_GetTypeInfo(disp, 0, LOCALE_USER_DEFAULT, &typeinfo);
+ ok(hr == S_OK, "GetTypeInfo failed: %08x\n", hr);
+ hr = IDispatchEx_GetTypeInfo(disp, 0, LOCALE_USER_DEFAULT, &typeinfo2);
+ ok(hr == S_OK, "GetTypeInfo failed: %08x\n", hr);
+ ok(typeinfo != typeinfo2, "TypeInfo was not supposed to be shared.\n");
+ ITypeInfo_Release(typeinfo2);
+
+ hr = ITypeInfo_GetTypeAttr(typeinfo, &attr);
+ ok(hr == S_OK, "GetTypeAttr failed: %08x\n", hr);
+ ok(IsEqualGUID(&attr->guid, &IID_IScriptTypeInfo), "Unexpected GUID %s\n", wine_dbgstr_guid(&attr->guid));
+ ok(attr->lcid == LOCALE_USER_DEFAULT, "Unexpected LCID %u\n", attr->lcid);
+ ok(attr->memidConstructor == MEMBERID_NIL, "Unexpected constructor memid %u\n", attr->memidConstructor);
+ ok(attr->memidDestructor == MEMBERID_NIL, "Unexpected destructor memid %u\n", attr->memidDestructor);
+ ok(attr->cbSizeInstance == 4, "Unexpected cbSizeInstance %u\n", attr->cbSizeInstance);
+ ok(attr->typekind == TKIND_DISPATCH, "Unexpected typekind %u\n", attr->typekind);
+ ok(attr->cFuncs == expected_funcs_cnt, "Unexpected cFuncs %u\n", attr->cFuncs);
+ ok(attr->cVars == expected_vars_cnt, "Unexpected cVars %u\n", attr->cVars);
+ ok(attr->cImplTypes == 1, "Unexpected cImplTypes %u\n", attr->cImplTypes);
+ ok(attr->cbSizeVft == sizeof(IDispatchVtbl), "Unexpected cbSizeVft %u\n", attr->cbSizeVft);
+ ok(attr->cbAlignment == 4, "Unexpected cbAlignment %u\n", attr->cbAlignment);
+ ok(attr->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "Unexpected wTypeFlags 0x%x\n", attr->wTypeFlags);
+ ok(attr->tdescAlias.vt == VT_EMPTY, "Unexpected tdescAlias.vt %d\n", attr->tdescAlias.vt);
+ ok(attr->idldescType.wIDLFlags == IDLFLAG_NONE, "Unexpected idldescType.wIDLFlags 0x%x\n", attr->idldescType.wIDLFlags);
+ ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
+
+ /* GetIDsOfNames looks into the inherited types as well */
+ wcscpy(str, L"queryinterface");
+ hr = ITypeInfo_GetIDsOfNames(typeinfo, NULL, 1, &memid);
+ ok(hr == E_INVALIDARG, "GetIDsOfNames returned: %08x\n", hr);
+ hr = ITypeInfo_GetIDsOfNames(typeinfo, &names, 1, NULL);
+ ok(hr == E_INVALIDARG, "GetIDsOfNames returned: %08x\n", hr);
+ hr = ITypeInfo_GetIDsOfNames(typeinfo, &names, 0, &memid);
+ ok(hr == E_INVALIDARG, "GetIDsOfNames returned: %08x\n", hr);
+ hr = ITypeInfo_GetIDsOfNames(typeinfo, &names, 1, &memid);
+ ok(hr == S_OK, "GetIDsOfNames failed: %08x\n", hr);
+ ok(!lstrcmpW(str, L"queryinterface"), "Unexpected string %s\n", wine_dbgstr_w(str));
+ if (expected_funcs_cnt)
+ {
+ wcscpy(str, L"Math");
+ hr = ITypeInfo_GetIDsOfNames(typeinfo, &names, 1, &memid);
+ ok(hr == S_OK, "GetIDsOfNames failed: %08x\n", hr);
+ ok(!lstrcmpW(str, L"Math"), "Unexpected string %s\n", wine_dbgstr_w(str));
+ }
+
+ /* Check variable descriptions */
+ hr = ITypeInfo_GetVarDesc(typeinfo, 0, NULL);
+ ok(hr == E_INVALIDARG, "GetVarDesc returned: %08x\n", hr);
+ hr = ITypeInfo_GetVarDesc(typeinfo, 1337, &vardesc);
+ ok(hr == TYPE_E_ELEMENTNOTFOUND, "GetVarDesc returned: %08x\n", hr);
+ for (i = 0; i < expected_vars_cnt; i++)
+ {
+ hr = ITypeInfo_GetVarDesc(typeinfo, i, &vardesc);
+ ok(hr == S_OK, "GetVarDesc(%u) failed: %08x\n", i, hr);
+ ok(vardesc->memid <= 0xFFFF, "[%u] Unexpected memid 0x%x\n", i, vardesc->memid);
+ ok(vardesc->lpstrSchema == NULL, "[%u] Unexpected lpstrSchema %p\n", i, vardesc->lpstrSchema);
+ ok(vardesc->oInst == 0, "[%u] Unexpected oInst %u\n", i, vardesc->oInst);
+ ok(vardesc->varkind == VAR_DISPATCH, "[%u] Unexpected varkind %d\n", i, vardesc->varkind);
+ ok(vardesc->wVarFlags == 0, "[%u] Unexpected wVarFlags 0x%x\n", i, vardesc->wVarFlags);
+ ok(vardesc->elemdescVar.tdesc.vt == VT_VARIANT,
+ "[%u] Unexpected variable type vt %d (expected %d)\n", i, vardesc->elemdescVar.tdesc.vt, 0);
+ ok(vardesc->elemdescVar.paramdesc.pparamdescex == NULL,
+ "[%u] Unexpected variable type pparamdescex %p\n", i, vardesc->elemdescVar.paramdesc.pparamdescex);
+ ok(vardesc->elemdescVar.paramdesc.wParamFlags == PARAMFLAG_NONE,
+ "[%u] Unexpected variable type wParamFlags 0x%x\n", i, vardesc->elemdescVar.paramdesc.wParamFlags);
+ ITypeInfo_ReleaseVarDesc(typeinfo, vardesc);
+ }
+
+ /* Check function descriptions */
+ hr = ITypeInfo_GetFuncDesc(typeinfo, 0, NULL);
+ ok(hr == E_INVALIDARG, "GetFuncDesc returned: %08x\n", hr);
+ hr = ITypeInfo_GetFuncDesc(typeinfo, 1337, &funcdesc);
+ ok(hr == TYPE_E_ELEMENTNOTFOUND, "GetFuncDesc returned: %08x\n", hr);
+ for (i = 0; i < expected_funcs_cnt; i++)
+ {
+ hr = ITypeInfo_GetFuncDesc(typeinfo, i, &funcdesc);
+ ok(hr == S_OK, "GetFuncDesc(%u) failed: %08x\n", i, hr);
+ ok(funcdesc->memid <= 0xFFFF, "[%u] Unexpected memid 0x%x\n", i, funcdesc->memid);
+ ok(funcdesc->lprgscode == NULL, "[%u] Unexpected lprgscode %p\n", i, funcdesc->lprgscode);
+ ok(func[i].num_args ? (funcdesc->lprgelemdescParam != NULL) : (funcdesc->lprgelemdescParam == NULL),
+ "[%u] Unexpected lprgelemdescParam %p\n", i, funcdesc->lprgelemdescParam);
+ ok(funcdesc->funckind == FUNC_DISPATCH, "[%u] Unexpected funckind %u\n", i, funcdesc->funckind);
+ ok(funcdesc->invkind == INVOKE_FUNC, "[%u] Unexpected invkind %u\n", i, funcdesc->invkind);
+ ok(funcdesc->callconv == CC_STDCALL, "[%u] Unexpected callconv %u\n", i, funcdesc->callconv);
+ ok(funcdesc->cParams == func[i].num_args, "[%u] Unexpected cParams %d (expected %d)\n",
+ i, funcdesc->cParams, func[i].num_args);
+ ok(funcdesc->cParamsOpt == 0, "[%u] Unexpected cParamsOpt %d\n", i, funcdesc->cParamsOpt);
+ ok(funcdesc->cScodes == 0, "[%u] Unexpected cScodes %d\n", i, funcdesc->cScodes);
+ ok(funcdesc->wFuncFlags == 0, "[%u] Unexpected wFuncFlags 0x%x\n", i, funcdesc->wFuncFlags);
+ ok(funcdesc->elemdescFunc.tdesc.vt == VT_VARIANT,
+ "[%u] Unexpected return type vt %d\n", i, funcdesc->elemdescFunc.tdesc.vt);
+ ok(funcdesc->elemdescFunc.paramdesc.pparamdescex == NULL,
+ "[%u] Unexpected return type pparamdescex %p\n", i, funcdesc->elemdescFunc.paramdesc.pparamdescex);
+ ok(funcdesc->elemdescFunc.paramdesc.wParamFlags == PARAMFLAG_NONE,
+ "[%u] Unexpected return type wParamFlags 0x%x\n", i, funcdesc->elemdescFunc.paramdesc.wParamFlags);
+ if (funcdesc->lprgelemdescParam)
+ for (index = 0; index < funcdesc->cParams; index++)
+ {
+ ok(funcdesc->lprgelemdescParam[index].tdesc.vt == VT_VARIANT,
+ "[%u] Unexpected parameter %u vt %d\n", i, index, funcdesc->lprgelemdescParam[index].tdesc.vt);
+ ok(funcdesc->lprgelemdescParam[index].paramdesc.pparamdescex == NULL,
+ "[%u] Unexpected parameter %u pparamdescex %p\n", i, index, funcdesc->lprgelemdescParam[index].paramdesc.pparamdescex);
+ ok(funcdesc->lprgelemdescParam[index].paramdesc.wParamFlags == PARAMFLAG_NONE,
+ "[%u] Unexpected parameter %u wParamFlags 0x%x\n", i, index, funcdesc->lprgelemdescParam[index].paramdesc.wParamFlags);
+ }
+ ITypeInfo_ReleaseFuncDesc(typeinfo, funcdesc);
+ }
+
+ /* Test TypeComp Binds */
+ hr = ITypeInfo_QueryInterface(typeinfo, &IID_ITypeComp, (void**)&typecomp);
+ ok(hr == S_OK, "QueryInterface(IID_ITypeComp) failed: %08x\n", hr);
+ hr = ITypeInfo_GetTypeComp(typeinfo, NULL);
+ ok(hr == E_INVALIDARG, "GetTypeComp returned: %08x\n", hr);
+ hr = ITypeInfo_GetTypeComp(typeinfo, &typecomp2);
+ ok(hr == S_OK, "GetTypeComp failed: %08x\n", hr);
+ ok(typecomp == typecomp2, "QueryInterface(IID_ITypeComp) and GetTypeComp returned different TypeComps\n");
+ ITypeComp_Release(typecomp2);
+ wcscpy(str, L"not_found");
+ hr = ITypeComp_Bind(typecomp, NULL, 0, 0, &typeinfo2, &desckind, &bindptr);
+ ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr);
+ hr = ITypeComp_Bind(typecomp, str, 0, 0, NULL, &desckind, &bindptr);
+ ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr);
+ hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, NULL, &bindptr);
+ ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr);
+ hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, &desckind, NULL);
+ ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr);
+ hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, &desckind, &bindptr);
+ ok(hr == S_OK, "Bind failed: %08x\n", hr);
+ ok(desckind == DESCKIND_NONE, "Unexpected desckind %u\n", desckind);
+ wcscpy(str, L"addRef");
+ hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, &desckind, &bindptr);
+ ok(hr == S_OK, "Bind failed: %08x\n", hr);
+ ok(desckind == DESCKIND_FUNCDESC, "Unexpected desckind %u\n", desckind);
+ ok(!lstrcmpW(str, L"addRef"), "Unexpected string %s\n", wine_dbgstr_w(str));
+ ITypeInfo_ReleaseFuncDesc(typeinfo2, bindptr.lpfuncdesc);
+ ITypeInfo_Release(typeinfo2);
+ for (i = 0; i < expected_vars_cnt; i++)
+ {
+ wcscpy(str, var[i].name);
+ hr = ITypeComp_Bind(typecomp, str, 0, INVOKE_PROPERTYGET, &typeinfo2, &desckind, &bindptr);
+ ok(hr == S_OK, "Bind failed: %08x\n", hr);
+ ok(desckind == DESCKIND_VARDESC, "Unexpected desckind %u\n", desckind);
+ ITypeInfo_ReleaseVarDesc(typeinfo2, bindptr.lpvardesc);
+ ITypeInfo_Release(typeinfo2);
+ }
+ for (i = 0; i < expected_funcs_cnt; i++)
+ {
+ wcscpy(str, func[i].name);
+ hr = ITypeComp_Bind(typecomp, str, 0, INVOKE_FUNC, &typeinfo2, &desckind, &bindptr);
+ ok(hr == S_OK, "Bind failed: %08x\n", hr);
+ ok(desckind == DESCKIND_FUNCDESC, "Unexpected desckind %u\n", desckind);
+ ITypeInfo_ReleaseFuncDesc(typeinfo2, bindptr.lpfuncdesc);
+ ITypeInfo_Release(typeinfo2);
+ }
+ wcscpy(str, L"JScriptTypeInfo");
+ hr = ITypeComp_BindType(typecomp, NULL, 0, &typeinfo2, &typecomp2);
+ ok(hr == E_INVALIDARG, "BindType returned: %08x\n", hr);
+ hr = ITypeComp_BindType(typecomp, str, 0, NULL, &typecomp2);
+ ok(hr == E_INVALIDARG, "BindType returned: %08x\n", hr);
+ hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, NULL);
+ ok(hr == E_INVALIDARG, "BindType returned: %08x\n", hr);
+ hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, &typecomp2);
+ ok(hr == S_OK, "BindType failed: %08x\n", hr);
+ ok(!typeinfo2, "Unexpected TypeInfo %p (expected null)\n", typeinfo2);
+ ok(!typecomp2, "Unexpected TypeComp %p (expected null)\n", typecomp2);
+ wcscpy(str, L"C");
+ hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, &typecomp2);
+ ok(hr == S_OK, "BindType failed: %08x\n", hr);
+ ok(!typeinfo2, "Unexpected TypeInfo %p (expected null)\n", typeinfo2);
+ ok(!typecomp2, "Unexpected TypeComp %p (expected null)\n", typecomp2);
+ wcscpy(str, L"IDispatch");
+ hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, &typecomp2);
+ ok(hr == S_OK, "BindType failed: %08x\n", hr);
+ ok(!typeinfo2, "Unexpected TypeInfo %p (expected null)\n", typeinfo2);
+ ok(!typecomp2, "Unexpected TypeComp %p (expected null)\n", typecomp2);
+ ITypeComp_Release(typecomp);
+
+ /* Updating the script won't update the typeinfo obtained before,
+ but it will be reflected in any typeinfo obtained afterwards. */
+ if (!parse_func_name)
+ {
+ parse_script(parser, L""
+ "var new_var;\n"
+ "function new_func() { }\n");
+
+ hr = IDispatchEx_GetTypeInfo(disp, 0, LOCALE_USER_DEFAULT, &typeinfo2);
+ ok(hr == S_OK, "GetTypeInfo failed: %08x\n", hr);
+ hr = ITypeInfo_GetTypeAttr(typeinfo, &attr);
+ ok(hr == S_OK, "GetTypeAttr failed: %08x\n", hr);
+ ok(attr->cFuncs == expected_funcs_cnt, "Unexpected cFuncs %u\n", attr->cFuncs);
+ ok(attr->cVars == expected_vars_cnt, "Unexpected cVars %u\n", attr->cVars);
+ ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
+ hr = ITypeInfo_GetTypeAttr(typeinfo2, &attr);
+ ok(hr == S_OK, "GetTypeAttr failed: %08x\n", hr);
+ ok(attr->cFuncs == expected_funcs_cnt + 1, "Unexpected cFuncs %u\n", attr->cFuncs);
+ ok(attr->cVars == expected_vars_cnt + 1, "Unexpected cVars %u\n", attr->cVars);
+ ITypeInfo_ReleaseTypeAttr(typeinfo2, attr);
+ ITypeInfo_Release(typeinfo2);
+
+ /* Adding an identifier that differs only in case gives an error
+ when retrieving the TypeInfo, even though it is valid jscript. */
+ parse_script(parser, L"var NEW_FUNC;\n");
+ hr = IDispatchEx_GetTypeInfo(disp, 0, LOCALE_USER_DEFAULT, &typeinfo2);
+ ok(hr == TYPE_E_AMBIGUOUSNAME, "GetTypeInfo returned: %08x\n", hr);
+ }
+
+ ITypeInfo_Release(typeinfo);
+ IDispatchEx_Release(disp);
+ IActiveScriptParse_Release(parser);
+
+ SET_EXPECT(OnStateChange_DISCONNECTED);
+ SET_EXPECT(OnStateChange_INITIALIZED);
+ SET_EXPECT(OnStateChange_CLOSED);
+ hr = IActiveScript_Close(script);
+ ok(hr == S_OK, "Close failed: %08x\n", hr);
+ CHECK_CALLED(OnStateChange_DISCONNECTED);
+ CHECK_CALLED(OnStateChange_INITIALIZED);
+ CHECK_CALLED(OnStateChange_CLOSED);
+
+ IActiveScript_Release(script);
+}
+
static BOOL check_jscript(void)
{
IActiveScriptProperty *script_prop;
@@ -931,6 +1291,8 @@ START_TEST(jscript)
test_jscript_uninitializing();
test_aggregation();
test_code_persistence();
+ test_typeinfo(NULL);
+ test_typeinfo(L"some_func_name");
trace("Testing JScriptEncode object...\n");
engine_clsid = &CLSID_JScriptEncode;
--
2.21.0
Dec. 12, 2019
[PATCH v4 8/9] jscript: Implement ScriptTypeComp_BindType.
by Gabriel Ivăncescu
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/jscript/dispex.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index 6576605..6cc6df5 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -1069,10 +1069,25 @@ static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName,
ITypeInfo **ppTInfo, ITypeComp **ppTComp)
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
+ ITypeInfo *disp_typeinfo;
+ ITypeComp *disp_typecomp;
+ HRESULT hr;
- FIXME("(%p)->(%s %08x %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp);
+ TRACE("(%p)->(%s %08x %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp);
- return E_NOTIMPL;
+ if (!szName || !ppTInfo || !ppTComp)
+ return E_INVALIDARG;
+
+ /* Look into the inherited IDispatch */
+ hr = get_dispatch_typeinfo(&disp_typeinfo);
+ if (FAILED(hr)) return hr;
+
+ hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp);
+ if (FAILED(hr)) return hr;
+
+ hr = ITypeComp_BindType(disp_typecomp, szName, lHashVal, ppTInfo, ppTComp);
+ ITypeComp_Release(disp_typecomp);
+ return hr;
}
static const ITypeCompVtbl ScriptTypeCompVtbl = {
--
2.21.0
Dec. 12, 2019
[PATCH v4 7/9] jscript: Implement ScriptTypeComp_Bind.
by Gabriel Ivăncescu
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/jscript/dispex.c | 49 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 47 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index fb636b4..6576605 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -1013,11 +1013,56 @@ static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULO
ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr)
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
+ UINT flags = wFlags ? wFlags : ~0;
+ ITypeInfo *disp_typeinfo;
+ ITypeComp *disp_typecomp;
+ HRESULT hr;
+ UINT i;
- FIXME("(%p)->(%s %08x %d %p %p %p)\n", This, debugstr_w(szName), lHashVal,
+ TRACE("(%p)->(%s %08x %d %p %p %p)\n", This, debugstr_w(szName), lHashVal,
wFlags, ppTInfo, pDescKind, pBindPtr);
- return E_NOTIMPL;
+ if (!szName || !ppTInfo || !pDescKind || !pBindPtr)
+ return E_INVALIDARG;
+
+ for (i = 0; i < This->num_funcs; i++)
+ {
+ if (wcsicmp(szName, This->funcs[i].prop->name)) continue;
+ if (!(flags & INVOKE_FUNC)) return TYPE_E_TYPEMISMATCH;
+
+ hr = ITypeInfo_GetFuncDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpfuncdesc);
+ if (FAILED(hr)) return hr;
+
+ *pDescKind = DESCKIND_FUNCDESC;
+ *ppTInfo = &This->ITypeInfo_iface;
+ ITypeInfo_AddRef(*ppTInfo);
+ return S_OK;
+ }
+
+ for (i = 0; i < This->num_vars; i++)
+ {
+ if (wcsicmp(szName, This->vars[i]->name)) continue;
+ if (!(flags & INVOKE_PROPERTYGET)) return TYPE_E_TYPEMISMATCH;
+
+ hr = ITypeInfo_GetVarDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpvardesc);
+ if (FAILED(hr)) return hr;
+
+ *pDescKind = DESCKIND_VARDESC;
+ *ppTInfo = &This->ITypeInfo_iface;
+ ITypeInfo_AddRef(*ppTInfo);
+ return S_OK;
+ }
+
+ /* Look into the inherited IDispatch */
+ hr = get_dispatch_typeinfo(&disp_typeinfo);
+ if (FAILED(hr)) return hr;
+
+ hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp);
+ if (FAILED(hr)) return hr;
+
+ hr = ITypeComp_Bind(disp_typecomp, szName, lHashVal, wFlags, ppTInfo, pDescKind, pBindPtr);
+ ITypeComp_Release(disp_typecomp);
+ return hr;
}
static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal,
--
2.21.0
Dec. 12, 2019
[PATCH v4 6/9] jscript: Implement ScriptTypeInfo_GetTypeComp.
by Gabriel Ivăncescu
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/jscript/dispex.c | 64 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 62 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index 1ac747b..fb636b4 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -614,6 +614,7 @@ struct typeinfo_func {
typedef struct {
ITypeInfo ITypeInfo_iface;
+ ITypeComp ITypeComp_iface;
LONG ref;
UINT num_funcs;
@@ -629,12 +630,19 @@ static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface)
return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface);
}
+static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeComp(ITypeComp *iface)
+{
+ return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeComp_iface);
+}
+
static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv)
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid))
*ppv = &This->ITypeInfo_iface;
+ else if (IsEqualGUID(&IID_ITypeComp, riid))
+ *ppv = &This->ITypeComp_iface;
else
{
WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
@@ -712,9 +720,13 @@ static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **p
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, ppTComp);
+ TRACE("(%p)->(%p)\n", This, ppTComp);
- return E_NOTIMPL;
+ if (!ppTComp) return E_INVALIDARG;
+
+ *ppTComp = &This->ITypeComp_iface;
+ ITypeInfo_AddRef(iface);
+ return S_OK;
}
static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc)
@@ -979,6 +991,53 @@ static const ITypeInfoVtbl ScriptTypeInfoVtbl = {
ScriptTypeInfo_ReleaseVarDesc
};
+static HRESULT WINAPI ScriptTypeComp_QueryInterface(ITypeComp *iface, REFIID riid, void **ppv)
+{
+ ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
+ return ITypeInfo_QueryInterface(&This->ITypeInfo_iface, riid, ppv);
+}
+
+static ULONG WINAPI ScriptTypeComp_AddRef(ITypeComp *iface)
+{
+ ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
+ return ITypeInfo_AddRef(&This->ITypeInfo_iface);
+}
+
+static ULONG WINAPI ScriptTypeComp_Release(ITypeComp *iface)
+{
+ ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
+ return ITypeInfo_Release(&This->ITypeInfo_iface);
+}
+
+static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, WORD wFlags,
+ ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr)
+{
+ ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
+
+ FIXME("(%p)->(%s %08x %d %p %p %p)\n", This, debugstr_w(szName), lHashVal,
+ wFlags, ppTInfo, pDescKind, pBindPtr);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal,
+ ITypeInfo **ppTInfo, ITypeComp **ppTComp)
+{
+ ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
+
+ FIXME("(%p)->(%s %08x %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp);
+
+ return E_NOTIMPL;
+}
+
+static const ITypeCompVtbl ScriptTypeCompVtbl = {
+ ScriptTypeComp_QueryInterface,
+ ScriptTypeComp_AddRef,
+ ScriptTypeComp_Release,
+ ScriptTypeComp_Bind,
+ ScriptTypeComp_BindType
+};
+
static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
{
return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface);
@@ -1081,6 +1140,7 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LC
return E_OUTOFMEMORY;
typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl;
+ typeinfo->ITypeComp_iface.lpVtbl = &ScriptTypeCompVtbl;
typeinfo->ref = 1;
typeinfo->num_vars = num_vars;
typeinfo->num_funcs = num_funcs;
--
2.21.0
Dec. 12, 2019
[PATCH v4 5/9] jscript: Implement ScriptTypeInfo_GetIDsOfNames.
by Gabriel Ivăncescu
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/jscript/dispex.c | 47 +++++++++++++++++++++++++++++++++++--
dlls/jscript/jscript.h | 1 +
dlls/jscript/jscript_main.c | 25 ++++++++++++++++++++
3 files changed, 71 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index df87aed..1ac747b 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -802,10 +802,53 @@ static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *r
MEMBERID *pMemId)
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
+ ITypeInfo *disp_typeinfo;
+ const WCHAR *name;
+ HRESULT hr = S_OK;
+ int i, j, arg;
- FIXME("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId);
+ TRACE("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId);
- return E_NOTIMPL;
+ if (!rgszNames || !cNames || !pMemId) return E_INVALIDARG;
+
+ for (i = 0; i < cNames; i++) pMemId[i] = MEMBERID_NIL;
+ name = rgszNames[0];
+
+ for (i = 0; i < This->num_funcs; i++)
+ {
+ struct typeinfo_func *func = &This->funcs[i];
+
+ if (wcsicmp(name, func->prop->name)) continue;
+ pMemId[0] = prop_to_id(This->jsdisp, func->prop);
+
+ for (j = 1; j < cNames; j++)
+ {
+ name = rgszNames[j];
+ for (arg = func->code->param_cnt; --arg >= 0;)
+ if (!wcsicmp(name, func->code->params[arg]))
+ break;
+ if (arg >= 0)
+ pMemId[j] = arg;
+ else
+ hr = DISP_E_UNKNOWNNAME;
+ }
+ return hr;
+ }
+
+ for (i = 0; i < This->num_vars; i++)
+ {
+ dispex_prop_t *var = This->vars[i];
+
+ if (wcsicmp(name, var->name)) continue;
+ pMemId[0] = prop_to_id(This->jsdisp, var);
+ return S_OK;
+ }
+
+ /* Look into the inherited IDispatch */
+ hr = get_dispatch_typeinfo(&disp_typeinfo);
+ if (FAILED(hr)) return hr;
+
+ return ITypeInfo_GetIDsOfNames(disp_typeinfo, rgszNames, cNames, pMemId);
}
static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags,
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h
index 7174db8..4ec5004 100644
--- a/dlls/jscript/jscript.h
+++ b/dlls/jscript/jscript.h
@@ -87,6 +87,7 @@ static inline LPWSTR heap_strdupW(LPCWSTR str)
typedef struct jsdisp_t jsdisp_t;
extern HINSTANCE jscript_hinstance DECLSPEC_HIDDEN;
+HRESULT get_dispatch_typeinfo(ITypeInfo**) DECLSPEC_HIDDEN;
#define PROPF_ARGMASK 0x00ff
#define PROPF_METHOD 0x0100
diff --git a/dlls/jscript/jscript_main.c b/dlls/jscript/jscript_main.c
index 9f9f412..532cdf9 100644
--- a/dlls/jscript/jscript_main.c
+++ b/dlls/jscript/jscript_main.c
@@ -37,6 +37,30 @@ LONG module_ref = 0;
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
HINSTANCE jscript_hinstance;
+static ITypeInfo *dispatch_typeinfo;
+
+HRESULT get_dispatch_typeinfo(ITypeInfo **out)
+{
+ ITypeInfo *typeinfo;
+ ITypeLib *typelib;
+ HRESULT hr;
+
+ if (!dispatch_typeinfo)
+ {
+ hr = LoadRegTypeLib(&IID_StdOle, STDOLE_MAJORVERNUM, STDOLE_MINORVERNUM, STDOLE_LCID, &typelib);
+ if (FAILED(hr)) return hr;
+
+ hr = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IDispatch, &typeinfo);
+ ITypeLib_Release(typelib);
+ if (FAILED(hr)) return hr;
+
+ if (InterlockedCompareExchangePointer((void**)&dispatch_typeinfo, typeinfo, NULL))
+ ITypeInfo_Release(typeinfo);
+ }
+
+ *out = dispatch_typeinfo;
+ return S_OK;
+}
static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
{
@@ -145,6 +169,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
break;
case DLL_PROCESS_DETACH:
if (lpv) break;
+ if (dispatch_typeinfo) ITypeInfo_Release(dispatch_typeinfo);
free_strings();
}
--
2.21.0
Dec. 12, 2019
[PATCH v4 4/9] jscript: Implement ScriptTypeInfo_GetVarDesc.
by Gabriel Ivăncescu
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/jscript/dispex.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index 1f062fe..df87aed 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -752,10 +752,22 @@ static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, F
static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc)
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
+ VARDESC *desc;
- FIXME("(%p)->(%u %p)\n", This, index, ppVarDesc);
+ TRACE("(%p)->(%u %p)\n", This, index, ppVarDesc);
- return E_NOTIMPL;
+ if (!ppVarDesc) return E_INVALIDARG;
+ if (index >= This->num_vars) return TYPE_E_ELEMENTNOTFOUND;
+
+ desc = heap_alloc_zero(sizeof(*desc));
+ if (!desc) return E_OUTOFMEMORY;
+
+ desc->memid = prop_to_id(This->jsdisp, This->vars[index]);
+ desc->varkind = VAR_DISPATCH;
+ desc->elemdescVar.tdesc.vt = VT_VARIANT;
+
+ *ppVarDesc = desc;
+ return S_OK;
}
static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames,
@@ -894,7 +906,9 @@ static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVar
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, pVarDesc);
+ TRACE("(%p)->(%p)\n", This, pVarDesc);
+
+ heap_free(pVarDesc);
}
static const ITypeInfoVtbl ScriptTypeInfoVtbl = {
--
2.21.0
Dec. 12, 2019
[PATCH v4 3/9] jscript: Implement ScriptTypeInfo_GetFuncDesc.
by Gabriel Ivăncescu
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/jscript/dispex.c | 31 ++++++++++++++++++++++++++++---
1 file changed, 28 insertions(+), 3 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index ef002e4..1f062fe 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -720,10 +720,33 @@ static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **p
static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc)
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
+ struct typeinfo_func *func;
+ FUNCDESC *desc;
+ unsigned i;
- FIXME("(%p)->(%u %p)\n", This, index, ppFuncDesc);
+ TRACE("(%p)->(%u %p)\n", This, index, ppFuncDesc);
- return E_NOTIMPL;
+ if (!ppFuncDesc) return E_INVALIDARG;
+ if (index >= This->num_funcs) return TYPE_E_ELEMENTNOTFOUND;
+ func = &This->funcs[index];
+
+ /* Store the parameter array after the FUNCDESC structure */
+ desc = heap_alloc_zero(sizeof(*desc) + sizeof(ELEMDESC) * func->code->param_cnt);
+ if (!desc) return E_OUTOFMEMORY;
+
+ desc->memid = prop_to_id(This->jsdisp, func->prop);
+ desc->funckind = FUNC_DISPATCH;
+ desc->invkind = INVOKE_FUNC;
+ desc->callconv = CC_STDCALL;
+ desc->cParams = func->code->param_cnt;
+ desc->elemdescFunc.tdesc.vt = VT_VARIANT;
+
+ if (func->code->param_cnt) desc->lprgelemdescParam = (ELEMDESC*)(desc + 1);
+ for (i = 0; i < func->code->param_cnt; i++)
+ desc->lprgelemdescParam[i].tdesc.vt = VT_VARIANT;
+
+ *ppFuncDesc = desc;
+ return S_OK;
}
static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc)
@@ -862,7 +885,9 @@ static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pF
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, pFuncDesc);
+ TRACE("(%p)->(%p)\n", This, pFuncDesc);
+
+ heap_free(pFuncDesc);
}
static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc)
--
2.21.0
Dec. 12, 2019
[PATCH v4 2/9] jscript: Implement ScriptTypeInfo_GetTypeAttr.
by Gabriel Ivăncescu
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/jscript/dispex.c | 36 +++++++++++++++++++++++++++++++-----
1 file changed, 31 insertions(+), 5 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index 6c6d25a..ef002e4 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -25,6 +25,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(jscript);
+static const GUID GUID_JScriptTypeInfo = {0xc59c6b12,0xf6c1,0x11cf,{0x88,0x35,0x00,0xa0,0xc9,0x11,0xe8,0xb2}};
+
#define FDEX_VERSION_MASK 0xf0000000
#define GOLDEN_RATIO 0x9E3779B9U
@@ -678,10 +680,32 @@ static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface)
static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr)
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
-
- FIXME("(%p)->(%p)\n", This, ppTypeAttr);
-
- return E_NOTIMPL;
+ TYPEATTR *attr;
+
+ TRACE("(%p)->(%p)\n", This, ppTypeAttr);
+
+ if (!ppTypeAttr) return E_INVALIDARG;
+
+ attr = heap_alloc_zero(sizeof(*attr));
+ if (!attr) return E_OUTOFMEMORY;
+
+ attr->guid = GUID_JScriptTypeInfo;
+ attr->lcid = LOCALE_USER_DEFAULT;
+ attr->memidConstructor = MEMBERID_NIL;
+ attr->memidDestructor = MEMBERID_NIL;
+ attr->cbSizeInstance = 4;
+ attr->typekind = TKIND_DISPATCH;
+ attr->cFuncs = This->num_funcs;
+ attr->cVars = This->num_vars;
+ attr->cImplTypes = 1;
+ attr->cbSizeVft = sizeof(IDispatchVtbl);
+ attr->cbAlignment = 4;
+ attr->wTypeFlags = TYPEFLAG_FDISPATCHABLE;
+ attr->wMajorVerNum = JSCRIPT_MAJOR_VERSION;
+ attr->wMinorVerNum = JSCRIPT_MINOR_VERSION;
+
+ *ppTypeAttr = attr;
+ return S_OK;
}
static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp)
@@ -829,7 +853,9 @@ static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pT
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, pTypeAttr);
+ TRACE("(%p)->(%p)\n", This, pTypeAttr);
+
+ heap_free(pTypeAttr);
}
static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc)
--
2.21.0
Dec. 12, 2019
[PATCH v4 1/9] jscript: Store the necessary function and variable info in the TypeInfo.
by Gabriel Ivăncescu
The TypeInfo is built when it is retrieved and frozen at that moment, even
if the script changes after that and more identifiers are added to it,
or existing ones deleted.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/jscript/dispex.c | 110 ++++++++++++++++++++++++++++++++++++++++
dlls/jscript/function.c | 31 +++++++++++
dlls/jscript/jscript.h | 1 +
3 files changed, 142 insertions(+)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index 92e9b96..6c6d25a 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -19,6 +19,7 @@
#include <assert.h>
#include "jscript.h"
+#include "engine.h"
#include "wine/debug.h"
@@ -70,6 +71,20 @@ static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id)
return This->props+id;
}
+static inline BOOL is_function_prop(dispex_prop_t *prop)
+{
+ BOOL ret = FALSE;
+
+ if (is_object_instance(prop->u.val))
+ {
+ jsdisp_t *jsdisp = iface_to_jsdisp(get_object(prop->u.val));
+
+ if (jsdisp) ret = is_class(jsdisp, JSCLASS_FUNCTION);
+ jsdisp_release(jsdisp);
+ }
+ return ret;
+}
+
static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop)
{
if(prop->type == PROP_PROTREF) {
@@ -590,9 +605,21 @@ static HRESULT fill_protrefs(jsdisp_t *This)
return S_OK;
}
+struct typeinfo_func {
+ dispex_prop_t *prop;
+ function_code_t *code;
+};
+
typedef struct {
ITypeInfo ITypeInfo_iface;
LONG ref;
+
+ UINT num_funcs;
+ UINT num_vars;
+ struct typeinfo_func *funcs;
+ dispex_prop_t **vars;
+
+ jsdisp_t *jsdisp;
} ScriptTypeInfo;
static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface)
@@ -632,11 +659,17 @@ static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface)
{
ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
LONG ref = InterlockedDecrement(&This->ref);
+ UINT i;
TRACE("(%p) ref=%d\n", This, ref);
if (!ref)
{
+ for (i = This->num_funcs; i--;)
+ release_bytecode(This->funcs[i].code->bytecode);
+ IDispatchEx_Release(&This->jsdisp->IDispatchEx_iface);
+ heap_free(This->funcs);
+ heap_free(This->vars);
heap_free(This);
}
return ref;
@@ -897,17 +930,94 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LC
ITypeInfo **ppTInfo)
{
jsdisp_t *This = impl_from_IDispatchEx(iface);
+ dispex_prop_t *prop, *cur, *end, **typevar;
+ UINT num_funcs = 0, num_vars = 0;
+ struct typeinfo_func *typefunc;
+ function_code_t *func_code;
ScriptTypeInfo *typeinfo;
+ unsigned pos;
TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
if (iTInfo != 0) return DISP_E_BADINDEX;
+ for (prop = This->props, end = prop + This->prop_cnt; prop != end; prop++)
+ {
+ if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE))
+ continue;
+
+ /* If two identifiers differ only by case, the TypeInfo fails */
+ pos = This->props[get_props_idx(This, prop->hash)].bucket_head;
+ while (pos)
+ {
+ cur = This->props + pos;
+
+ if (prop->hash == cur->hash && prop != cur &&
+ cur->type == PROP_JSVAL && (cur->flags & PROPF_ENUMERABLE) &&
+ !wcsicmp(prop->name, cur->name))
+ {
+ return TYPE_E_AMBIGUOUSNAME;
+ }
+ pos = cur->bucket_next;
+ }
+
+ if (is_function_prop(prop))
+ {
+ if (Function_get_code(as_jsdisp(get_object(prop->u.val))))
+ num_funcs++;
+ }
+ else num_vars++;
+ }
+
if (!(typeinfo = heap_alloc(sizeof(*typeinfo))))
return E_OUTOFMEMORY;
typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl;
typeinfo->ref = 1;
+ typeinfo->num_vars = num_vars;
+ typeinfo->num_funcs = num_funcs;
+ typeinfo->jsdisp = This;
+
+ typeinfo->funcs = heap_alloc(sizeof(*typeinfo->funcs) * num_funcs);
+ if (!typeinfo->funcs)
+ {
+ heap_free(typeinfo);
+ return E_OUTOFMEMORY;
+ }
+
+ typeinfo->vars = heap_alloc(sizeof(*typeinfo->vars) * num_vars);
+ if (!typeinfo->vars)
+ {
+ heap_free(typeinfo->funcs);
+ heap_free(typeinfo);
+ return E_OUTOFMEMORY;
+ }
+
+ typefunc = typeinfo->funcs;
+ typevar = typeinfo->vars;
+ for (prop = This->props; prop != end; prop++)
+ {
+ if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE))
+ continue;
+
+ if (is_function_prop(prop))
+ {
+ func_code = Function_get_code(as_jsdisp(get_object(prop->u.val)));
+ if (!func_code) continue;
+
+ typefunc->prop = prop;
+ typefunc->code = func_code;
+ typefunc++;
+
+ /* The function may be deleted, so keep a ref */
+ bytecode_addref(func_code->bytecode);
+ }
+ else
+ *typevar++ = prop;
+ }
+
+ /* Keep a ref to the props and their names */
+ IDispatchEx_AddRef(&This->IDispatchEx_iface);
*ppTInfo = &typeinfo->ITypeInfo_iface;
return S_OK;
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c
index 7a44f50..52c1267 100644
--- a/dlls/jscript/function.c
+++ b/dlls/jscript/function.c
@@ -37,6 +37,7 @@ typedef struct {
struct _function_vtbl_t {
HRESULT (*call)(script_ctx_t*,FunctionInstance*,IDispatch*,unsigned,unsigned,jsval_t*,jsval_t*);
HRESULT (*toString)(FunctionInstance*,jsstr_t**);
+ function_code_t* (*get_code)(FunctionInstance*);
void (*destructor)(FunctionInstance*);
};
@@ -524,6 +525,16 @@ static HRESULT Function_get_arguments(script_ctx_t *ctx, jsdisp_t *jsthis, jsval
return S_OK;
}
+function_code_t *Function_get_code(jsdisp_t *jsthis)
+{
+ FunctionInstance *function;
+
+ assert(is_class(jsthis, JSCLASS_FUNCTION));
+ function = function_from_jsdisp(jsthis);
+
+ return function->vtbl->get_code(function);
+}
+
static void Function_destructor(jsdisp_t *dispex)
{
FunctionInstance *function = function_from_jsdisp(dispex);
@@ -638,6 +649,11 @@ static HRESULT NativeFunction_toString(FunctionInstance *func, jsstr_t **ret)
return S_OK;
}
+static function_code_t *NativeFunction_get_code(FunctionInstance *function)
+{
+ return NULL;
+}
+
static void NativeFunction_destructor(FunctionInstance *function)
{
}
@@ -645,6 +661,7 @@ static void NativeFunction_destructor(FunctionInstance *function)
static const function_vtbl_t NativeFunctionVtbl = {
NativeFunction_call,
NativeFunction_toString,
+ NativeFunction_get_code,
NativeFunction_destructor
};
@@ -749,6 +766,13 @@ static HRESULT InterpretedFunction_toString(FunctionInstance *func, jsstr_t **re
return *ret ? S_OK : E_OUTOFMEMORY;
}
+static function_code_t *InterpretedFunction_get_code(FunctionInstance *func)
+{
+ InterpretedFunction *function = (InterpretedFunction*)func;
+
+ return function->func_code;
+}
+
static void InterpretedFunction_destructor(FunctionInstance *func)
{
InterpretedFunction *function = (InterpretedFunction*)func;
@@ -761,6 +785,7 @@ static void InterpretedFunction_destructor(FunctionInstance *func)
static const function_vtbl_t InterpretedFunctionVtbl = {
InterpretedFunction_call,
InterpretedFunction_toString,
+ InterpretedFunction_get_code,
InterpretedFunction_destructor
};
@@ -842,6 +867,11 @@ static HRESULT BindFunction_toString(FunctionInstance *function, jsstr_t **ret)
return *ret ? S_OK : E_OUTOFMEMORY;
}
+static function_code_t *BindFunction_get_code(FunctionInstance *function)
+{
+ return NULL;
+}
+
static void BindFunction_destructor(FunctionInstance *func)
{
BindFunction *function = (BindFunction*)func;
@@ -858,6 +888,7 @@ static void BindFunction_destructor(FunctionInstance *func)
static const function_vtbl_t BindFunctionVtbl = {
BindFunction_call,
BindFunction_toString,
+ BindFunction_get_code,
BindFunction_destructor
};
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h
index 5d635b7..7174db8 100644
--- a/dlls/jscript/jscript.h
+++ b/dlls/jscript/jscript.h
@@ -307,6 +307,7 @@ HRESULT Function_invoke(jsdisp_t*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DE
HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
HRESULT Function_get_value(script_ctx_t*,jsdisp_t*,jsval_t*) DECLSPEC_HIDDEN;
+struct _function_code_t *Function_get_code(jsdisp_t*) DECLSPEC_HIDDEN;
#define DEFAULT_FUNCTION_VALUE {NULL, Function_value,0, Function_get_value}
HRESULT throw_eval_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
--
2.21.0
Dec. 12, 2019
[PATCH] testbot/Build: Update the Gecko download URL.
by Francois Gouget
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
testbot/lib/Build/Utils.pm | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/testbot/lib/Build/Utils.pm b/testbot/lib/Build/Utils.pm
index 15acf6783..a8e5a0e0e 100644
--- a/testbot/lib/Build/Utils.pm
+++ b/testbot/lib/Build/Utils.pm
@@ -314,8 +314,7 @@ sub _UpdateAddOn($$$)
return 0;
}
- $AddOn->{filename} = "wine". ($Name eq "gecko" ? "_" : "-") .
- "$Name-$AddOn->{version}".
+ $AddOn->{filename} = "wine-$Name-$AddOn->{version}".
($Arch eq "" ? "" : "-$Arch") .".msi";
return 1 if (!_VerifyAddOn($AddOn, $Arch));
--
2.20.1
Dec. 12, 2019
[PATCH vkd3d 2/2] vkd3d: Use multiple command queues if available.
by Conor McCarthy
Signed-off-by: Conor McCarthy <cmccarthy(a)codeweavers.com>
---
libs/vkd3d/command.c | 24 +++++++----
libs/vkd3d/device.c | 84 ++++++++++++++++++++++++--------------
libs/vkd3d/vkd3d_private.h | 16 ++++++--
3 files changed, 83 insertions(+), 41 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c
index 8a7ff66..6b0d9e0 100644
--- a/libs/vkd3d/command.c
+++ b/libs/vkd3d/command.c
@@ -22,7 +22,8 @@
static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkFence vk_fence);
HRESULT vkd3d_queue_create(struct d3d12_device *device,
- uint32_t family_index, const VkQueueFamilyProperties *properties, struct vkd3d_queue **queue)
+ uint32_t family_index, const VkQueueFamilyProperties *properties,
+ struct vkd3d_queue_array *queue_array, uint32_t queue_index)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
struct vkd3d_queue *object;
@@ -51,11 +52,11 @@ HRESULT vkd3d_queue_create(struct d3d12_device *device,
memset(object->old_vk_semaphores, 0, sizeof(object->old_vk_semaphores));
- VK_CALL(vkGetDeviceQueue(device->vk_device, family_index, 0, &object->vk_queue));
+ VK_CALL(vkGetDeviceQueue(device->vk_device, family_index, queue_index, &object->vk_queue));
TRACE("Created queue %p for queue family index %u.\n", object, family_index);
- *queue = object;
+ queue_array->queues[queue_index] = object;
return S_OK;
}
@@ -1683,17 +1684,26 @@ static struct d3d12_command_allocator *unsafe_impl_from_ID3D12CommandAllocator(I
return impl_from_ID3D12CommandAllocator(iface);
}
+static struct vkd3d_queue *d3d12_device_get_next_vkd3d_queue(struct vkd3d_queue_array *queue_array)
+{
+ LONG i = (InterlockedIncrement(queue_array->index_ptr) - 1) % VKD3D_MAX_QUEUE_CREATE_COUNT;
+ struct vkd3d_queue *queue = queue_array->queues[i];
+ if (queue)
+ return queue;
+ return queue_array->queues[0];
+}
+
struct vkd3d_queue *d3d12_device_get_vkd3d_queue(struct d3d12_device *device,
D3D12_COMMAND_LIST_TYPE type)
{
switch (type)
{
case D3D12_COMMAND_LIST_TYPE_DIRECT:
- return device->direct_queue;
+ return d3d12_device_get_next_vkd3d_queue(&device->direct_queues);
case D3D12_COMMAND_LIST_TYPE_COMPUTE:
- return device->compute_queue;
+ return d3d12_device_get_next_vkd3d_queue(&device->compute_queues);
case D3D12_COMMAND_LIST_TYPE_COPY:
- return device->copy_queue;
+ return d3d12_device_get_next_vkd3d_queue(&device->copy_queues);
default:
FIXME("Unhandled command list type %#x.\n", type);
return NULL;
@@ -1713,7 +1723,7 @@ static HRESULT d3d12_command_allocator_init(struct d3d12_command_allocator *allo
return hr;
if (!(queue = d3d12_device_get_vkd3d_queue(device, type)))
- queue = device->direct_queue;
+ queue = device->direct_queues.queues[0];
allocator->ID3D12CommandAllocator_iface.lpVtbl = &d3d12_command_allocator_vtbl;
allocator->refcount = 1;
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c
index ad32ff2..ff5dad1 100644
--- a/libs/vkd3d/device.c
+++ b/libs/vkd3d/device.c
@@ -1538,17 +1538,48 @@ struct vkd3d_device_queue_info
static void d3d12_device_destroy_vkd3d_queues(struct d3d12_device *device)
{
- if (device->direct_queue)
- vkd3d_queue_destroy(device->direct_queue, device);
- if (device->compute_queue && device->compute_queue != device->direct_queue)
- vkd3d_queue_destroy(device->compute_queue, device);
- if (device->copy_queue && device->copy_queue != device->direct_queue
- && device->copy_queue != device->compute_queue)
- vkd3d_queue_destroy(device->copy_queue, device);
+ struct vkd3d_queue_array *direct_queues = &device->direct_queues;
+ struct vkd3d_queue_array *compute_queues = &device->compute_queues;
+ struct vkd3d_queue_array *copy_queues = &device->copy_queues;
+ size_t i;
- device->direct_queue = NULL;
- device->compute_queue = NULL;
- device->copy_queue = NULL;
+ for (i = 0; i < ARRAY_SIZE(direct_queues->queues); ++i)
+ {
+ if (direct_queues->queues[i])
+ vkd3d_queue_destroy(direct_queues->queues[i], device);
+ if (compute_queues->queues[i] && compute_queues->queues[i] != direct_queues->queues[i])
+ vkd3d_queue_destroy(compute_queues->queues[i], device);
+ if (copy_queues->queues[i] && copy_queues->queues[i] != direct_queues->queues[i]
+ && copy_queues->queues[i] != compute_queues->queues[i])
+ vkd3d_queue_destroy(copy_queues->queues[i], device);
+ direct_queues->queues[i] = NULL;
+ compute_queues->queues[i] = NULL;
+ copy_queues->queues[i] = NULL;
+ }
+}
+
+static HRESULT d3d12_device_create_family_queues(struct d3d12_device *device,
+ const struct vkd3d_device_queue_info *queue_info, enum vkd3d_queue_family family,
+ struct vkd3d_queue_array *queue_array)
+{
+ uint32_t family_index = queue_info->family_index[family];
+ uint32_t i, count;
+ HRESULT hr;
+
+ queue_array->index_ptr = &queue_array->index;
+
+ count = min(queue_info->vk_properties[family].queueCount, VKD3D_MAX_QUEUE_CREATE_COUNT);
+
+ for (i = 0; i < count; ++i)
+ {
+ if (FAILED(hr = vkd3d_queue_create(device, family_index,
+ &queue_info->vk_properties[family], queue_array, i)))
+ return hr;
+ }
+
+ device->queue_family_indices[device->queue_family_count++] = family_index;
+
+ return S_OK;
}
static HRESULT d3d12_device_create_vkd3d_queues(struct d3d12_device *device,
@@ -1559,35 +1590,27 @@ static HRESULT d3d12_device_create_vkd3d_queues(struct d3d12_device *device,
uint32_t direct_family_index = queue_info->family_index[VKD3D_QUEUE_FAMILY_DIRECT];
HRESULT hr;
- device->direct_queue = NULL;
- device->compute_queue = NULL;
- device->copy_queue = NULL;
+ memset(&device->direct_queues, 0, sizeof(device->direct_queues));
+ memset(&device->compute_queues, 0, sizeof(device->compute_queues));
+ memset(&device->copy_queues, 0, sizeof(device->copy_queues));
device->queue_family_count = 0;
memset(device->queue_family_indices, 0, sizeof(device->queue_family_indices));
- if (SUCCEEDED((hr = vkd3d_queue_create(device, direct_family_index,
- &queue_info->vk_properties[VKD3D_QUEUE_FAMILY_DIRECT], &device->direct_queue))))
- device->queue_family_indices[device->queue_family_count++] = direct_family_index;
- else
+ if (FAILED(hr = d3d12_device_create_family_queues(device, queue_info, VKD3D_QUEUE_FAMILY_DIRECT, &device->direct_queues)))
goto out_destroy_queues;
+ /* A binary copy points index_ptr to the index in the source object, which is the desired behaviour. */
if (compute_family_index == direct_family_index)
- device->compute_queue = device->direct_queue;
- else if (SUCCEEDED(hr = vkd3d_queue_create(device, compute_family_index,
- &queue_info->vk_properties[VKD3D_QUEUE_FAMILY_COMPUTE], &device->compute_queue)))
- device->queue_family_indices[device->queue_family_count++] = compute_family_index;
- else
+ memcpy(&device->compute_queues, &device->direct_queues, sizeof(device->compute_queues));
+ else if (FAILED(hr = d3d12_device_create_family_queues(device, queue_info, VKD3D_QUEUE_FAMILY_COMPUTE, &device->compute_queues)))
goto out_destroy_queues;
if (transfer_family_index == direct_family_index)
- device->copy_queue = device->direct_queue;
+ memcpy(&device->copy_queues, &device->direct_queues, sizeof(device->copy_queues));
else if (transfer_family_index == compute_family_index)
- device->copy_queue = device->compute_queue;
- else if (SUCCEEDED(hr = vkd3d_queue_create(device, transfer_family_index,
- &queue_info->vk_properties[VKD3D_QUEUE_FAMILY_TRANSFER], &device->copy_queue)))
- device->queue_family_indices[device->queue_family_count++] = transfer_family_index;
- else
+ memcpy(&device->copy_queues, &device->compute_queues, sizeof(device->copy_queues));
+ else if (FAILED(hr = d3d12_device_create_family_queues(device, queue_info, VKD3D_QUEUE_FAMILY_TRANSFER, &device->copy_queues)))
goto out_destroy_queues;
return S_OK;
@@ -1597,7 +1620,8 @@ out_destroy_queues:
return hr;
}
-static float queue_priorities[] = {1.0f};
+static float queue_priorities[] = {1.0f, 1.0f, 1.0f, 1.0f};
+STATIC_ASSERT(ARRAY_SIZE(queue_priorities) == VKD3D_MAX_QUEUE_CREATE_COUNT);
static HRESULT vkd3d_select_queues(const struct vkd3d_instance *vkd3d_instance,
VkPhysicalDevice physical_device, struct vkd3d_device_queue_info *info)
@@ -1647,7 +1671,7 @@ static HRESULT vkd3d_select_queues(const struct vkd3d_instance *vkd3d_instance,
queue_info->pNext = NULL;
queue_info->flags = 0;
queue_info->queueFamilyIndex = i;
- queue_info->queueCount = 1; /* FIXME: Use multiple queues. */
+ queue_info->queueCount = min(queue_properties[i].queueCount, VKD3D_MAX_QUEUE_CREATE_COUNT);
queue_info->pQueuePriorities = queue_priorities;
}
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index 0c031d2..382b5ca 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -50,6 +50,7 @@
#define VKD3D_MAX_COMPATIBLE_FORMAT_COUNT 6u
#define VKD3D_MAX_QUEUE_FAMILY_COUNT 3u
+#define VKD3D_MAX_QUEUE_CREATE_COUNT 4u
#define VKD3D_MAX_SHADER_EXTENSIONS 1u
#define VKD3D_MAX_SHADER_STAGES 5u
#define VKD3D_MAX_VK_SYNC_OBJECTS 4u
@@ -1003,10 +1004,17 @@ struct vkd3d_queue
VkSemaphore old_vk_semaphores[VKD3D_MAX_VK_SYNC_OBJECTS];
};
+struct vkd3d_queue_array
+{
+ struct vkd3d_queue *queues[VKD3D_MAX_QUEUE_CREATE_COUNT];
+ LONG *index_ptr;
+ LONG index;
+};
+
VkQueue vkd3d_queue_acquire(struct vkd3d_queue *queue) DECLSPEC_HIDDEN;
HRESULT vkd3d_queue_create(struct d3d12_device *device,
uint32_t family_index, const VkQueueFamilyProperties *properties,
- struct vkd3d_queue **queue) DECLSPEC_HIDDEN;
+ struct vkd3d_queue_array *queue_array, uint32_t queue_index) DECLSPEC_HIDDEN;
void vkd3d_queue_destroy(struct vkd3d_queue *queue, struct d3d12_device *device) DECLSPEC_HIDDEN;
void vkd3d_queue_release(struct vkd3d_queue *queue) DECLSPEC_HIDDEN;
@@ -1134,9 +1142,9 @@ struct d3d12_device
struct vkd3d_vulkan_info vk_info;
- struct vkd3d_queue *direct_queue;
- struct vkd3d_queue *compute_queue;
- struct vkd3d_queue *copy_queue;
+ struct vkd3d_queue_array direct_queues;
+ struct vkd3d_queue_array compute_queues;
+ struct vkd3d_queue_array copy_queues;
uint32_t queue_family_indices[VKD3D_MAX_QUEUE_FAMILY_COUNT];
unsigned int queue_family_count;
--
2.24.0
Dec. 12, 2019
[PATCH vkd3d 1/2] vkd3d: Map the copy queue to the compute queue if necessary and possible.
by Conor McCarthy
The current implementation maps copy to direct unless a dedicated copy
queue is present. Compute queues are often more lightly loaded and there
is usually more than one available.
Signed-off-by: Conor McCarthy <cmccarthy(a)codeweavers.com>
---
libs/vkd3d/device.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c
index 757d4ac..ad32ff2 100644
--- a/libs/vkd3d/device.c
+++ b/libs/vkd3d/device.c
@@ -1667,8 +1667,16 @@ static HRESULT vkd3d_select_queues(const struct vkd3d_instance *vkd3d_instance,
}
if (info->family_index[VKD3D_QUEUE_FAMILY_TRANSFER] == ~0u)
{
- info->family_index[VKD3D_QUEUE_FAMILY_TRANSFER] = info->family_index[VKD3D_QUEUE_FAMILY_DIRECT];
- info->vk_properties[VKD3D_QUEUE_FAMILY_TRANSFER] = info->vk_properties[VKD3D_QUEUE_FAMILY_DIRECT];
+ if (info->vk_properties[VKD3D_QUEUE_FAMILY_COMPUTE].queueFlags & VK_QUEUE_TRANSFER_BIT)
+ {
+ info->family_index[VKD3D_QUEUE_FAMILY_TRANSFER] = info->family_index[VKD3D_QUEUE_FAMILY_COMPUTE];
+ info->vk_properties[VKD3D_QUEUE_FAMILY_TRANSFER] = info->vk_properties[VKD3D_QUEUE_FAMILY_COMPUTE];
+ }
+ else
+ {
+ info->family_index[VKD3D_QUEUE_FAMILY_TRANSFER] = info->family_index[VKD3D_QUEUE_FAMILY_DIRECT];
+ info->vk_properties[VKD3D_QUEUE_FAMILY_TRANSFER] = info->vk_properties[VKD3D_QUEUE_FAMILY_DIRECT];
+ }
}
/* Compact the array. */
--
2.24.0
Dec. 12, 2019
Re: [PATCH v3 4/4] kernel32/tests: Test std handle inheritance in test_parent_process_attribute().
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=62020
Your paranoid android.
=== w1064v1507 (32 bit report) ===
kernel32:
0e38:process:proce 1 sts.c:2925: Test failed: WaitFoerSinglesObject returnted 258
Report errors:
kernel32:process is missing some failure messages
=== wvistau64 (64 bit report) ===
kernel32:
process.c:1228: Test failed: expected 1, got 0
process.c:1231: Test failed: Child process termination
process.c:1235: Test failed: Toolhelp:cntUsage expected 0, but got 1
process.c:1236: Test failed: Toolhelp:th32DefaultHeapID expected 0, but got 1
process.c:1237: Test failed: Toolhelp:th32ModuleID expected 0, but got 1
process.c:1238: Test failed: Toolhelp:th32ParentProcessID expected 1428, but got 0
process.c:1240: Test failed: Toolhelp:dwFlags expected 0, but got 1
Dec. 12, 2019
Re: [PATCH v3 3/4] kernel32/tests: Test invalid parent handle in test_parent_process_attribute().
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=62019
Your paranoid android.
=== wvistau64 (64 bit report) ===
kernel32:
process.c:1226: Test failed: expected 1, got 0
process.c:1229: Test failed: Child process termination
process.c:1233: Test failed: Toolhelp:cntUsage expected 0, but got 1
process.c:1234: Test failed: Toolhelp:th32DefaultHeapID expected 0, but got 1
process.c:1235: Test failed: Toolhelp:th32ModuleID expected 0, but got 1
process.c:1236: Test failed: Toolhelp:th32ParentProcessID expected 1428, but got 0
process.c:1238: Test failed: Toolhelp:dwFlags expected 0, but got 1
Dec. 12, 2019
[PATCH] include: Add missing defines for tokens in winnt.h
by Vijay Kiran Kamuju
Signed-off-by: Vijay Kiran Kamuju <infyquest(a)gmail.com>
---
include/winnt.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/winnt.h b/include/winnt.h
index 1db7fdd28e..56734f178d 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -4177,6 +4177,11 @@ typedef enum _TOKEN_INFORMATION_CLASS {
MaxTokenInfoClass
} TOKEN_INFORMATION_CLASS;
+#define DISABLE_MAX_PRIVILEGE 0x1
+#define SANDBOX_INERT 0x2
+#define LUA_TOKEN 0x4
+#define WRITE_RESTRICTED 0x8
+
#define TOKEN_TOKEN_ADJUST_DEFAULT 0x0080
#define TOKEN_ADJUST_GROUPS 0x0040
#define TOKEN_ADJUST_PRIVILEGES 0x0020
--
2.21.0
Dec. 12, 2019
[PATCH] ole32/tests: Fix return value trace.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/ole32/tests/clipboard.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/ole32/tests/clipboard.c b/dlls/ole32/tests/clipboard.c
index 8901758034..b97c2646bf 100644
--- a/dlls/ole32/tests/clipboard.c
+++ b/dlls/ole32/tests/clipboard.c
@@ -1014,7 +1014,8 @@ static void test_set_clipboard(void)
test_cf_dataobject(data_cmpl);
test_enum_fmtetc(data_cmpl);
- ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
+ hr = OleSetClipboard(NULL);
+ ok(hr == S_OK, "failed to clear clipboard, hr = 0x%08x.\n", hr);
test_no_cf_dataobject();
test_enum_fmtetc(NULL);
--
2.24.0
Dec. 12, 2019
Re: [PATCH 4/5] ole32: Get rid of casts in GUID serialization helper.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=62013
Your paranoid android.
=== debian10 (32 bit Chinese:China report) ===
ole32:
clipboard.c:1484: Test failed: got 800401d0
clipboard.c:1485: Test failed: got 0
Dec. 12, 2019
[PATCH v3 4/4] kernel32/tests: Test std handle inheritance in test_parent_process_attribute().
by Paul Gofman
Signed-off-by: Paul Gofman <gofmanp(a)gmail.com>
---
v2:
- added test;
v3:
- no changes.
dlls/kernel32/tests/process.c | 55 ++++++++++++++++++++++++++++-------
1 file changed, 45 insertions(+), 10 deletions(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c
index 1194c54202..92838c09ff 100644
--- a/dlls/kernel32/tests/process.c
+++ b/dlls/kernel32/tests/process.c
@@ -92,6 +92,7 @@ static SIZE_T (WINAPI *pGetLargePageMinimum)(void);
static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
+static DWORD (WINAPI *pGetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD, DWORD);
/* ############################### */
static char base[MAX_PATH];
@@ -259,6 +260,7 @@ static BOOL init(void)
pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList");
pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute");
pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList");
+ pGetFinalPathNameByHandleA = (void *)GetProcAddress(hkernel32, "GetFinalPathNameByHandleA");
return TRUE;
}
@@ -3827,7 +3829,7 @@ static void test_ProcThreadAttributeList(void)
* level 2: Process created by level 1 process with handle inheritance and level 0
* process parent substitute.
* level 255: Process created by level 1 process during invalid parent handles testing. */
-void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
+void test_parent_process_attribute(unsigned int level, HANDLE read_pipe, HANDLE creator_stdhandle)
{
PROCESS_BASIC_INFORMATION pbi;
char buffer[MAX_PATH + 64];
@@ -3837,7 +3839,9 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
STARTUPINFOEXA si;
DWORD parent_id;
NTSTATUS status;
+ DWORD exit_code;
ULONG pbi_size;
+ HANDLE hstderr;
HANDLE parent;
DWORD size;
BOOL ret;
@@ -3885,8 +3889,24 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
if (level == 2)
{
+ char file_path[MAX_PATH];
+
ok(parent_id == parent_data.parent_id, "Got parent id %u, parent_data.parent_id %u.\n",
parent_id, parent_data.parent_id);
+
+ GetStartupInfoA(&si.StartupInfo);
+ hstderr = si.StartupInfo.hStdError;
+
+ /* On Windows, std handle values are copied from creator process but seems not to be inherited from it.
+ * Some operation on such handle may sometimes succeed, but various way of quering information
+ * from such handle suggest that the handle refers to some other object.
+ * Windows seem to just keep the handle value, even for invalid handle. It does not always work exacly
+ * like that in Wine now due to special handling of console handles in kernelbase/process.c:create_process_params()
+ * and initialization in dlls/msvcrt: msvcrt_init_io(). */
+ ok(hstderr == creator_stdhandle, "Unexpected hstderr %p, creator_hstdhandle %p.\n",
+ hstderr, creator_stdhandle);
+ size = pGetFinalPathNameByHandleA(hstderr, file_path, sizeof(file_path), FILE_NAME_NORMALIZED);
+ ok(!size, "Got unexpected size %u.\n", size);
return;
}
@@ -3902,7 +3922,7 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
- sprintf(buffer, "\"%s\" tests/process.c parent %u %p", selfname, 255, read_pipe);
+ sprintf(buffer, "\"%s\" tests/process.c parent %u %p %p", selfname, 255, read_pipe, NULL);
#if 0
/* Crashes on some Windows installations, otherwise successfully creates process. */
@@ -3988,9 +4008,17 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
&parent, sizeof(parent), NULL, NULL);
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+
+ hstderr = CreateFileA("stderr_1.tmp", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ ok(hstderr != INVALID_HANDLE_VALUE, "Could not create file, GetLastError() %u.\n", GetLastError());
+ si.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+ si.StartupInfo.hStdError = hstderr;
+ si.StartupInfo.hStdOutput = creator_stdhandle;
}
- sprintf(buffer, "\"%s\" tests/process.c parent %u %p", selfname, level + 1, read_pipe);
+ sprintf(buffer, "\"%s\" tests/process.c parent %u %p %p", selfname, level + 1, read_pipe,
+ level ? hstderr : GetStdHandle(STD_OUTPUT_HANDLE));
ret = CreateProcessA(NULL, buffer, NULL, NULL, level == 1, level == 1 ? EXTENDED_STARTUPINFO_PRESENT : 0,
NULL, NULL, (STARTUPINFOA *)&si, &info);
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
@@ -4008,10 +4036,16 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
/* wait for child to terminate */
ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
+ GetExitCodeProcess(info.hProcess, &exit_code);
+ ok(!exit_code, "Child test failed, exit_code %#x.\n", exit_code);
+
CloseHandle(info.hThread);
CloseHandle(info.hProcess);
-
- if (!level)
+ if (level)
+ {
+ CloseHandle(hstderr);
+ }
+ else
{
CloseHandle(read_pipe);
CloseHandle(write_pipe);
@@ -4062,12 +4096,13 @@ START_TEST(process)
CloseHandle(info.hThread);
return;
}
- else if (!strcmp(myARGV[2], "parent") && myARGC >= 5)
+ else if (!strcmp(myARGV[2], "parent") && myARGC >= 6)
{
- HANDLE h;
+ HANDLE h1, h2;
- sscanf(myARGV[4], "%p", &h);
- test_parent_process_attribute(atoi(myARGV[3]), h);
+ sscanf(myARGV[4], "%p", &h1);
+ sscanf(myARGV[5], "%p", &h2);
+ test_parent_process_attribute(atoi(myARGV[3]), h1, h2);
return;
}
@@ -4136,5 +4171,5 @@ START_TEST(process)
test_jobInheritance(job);
test_BreakawayOk(job);
CloseHandle(job);
- test_parent_process_attribute(0, NULL);
+ test_parent_process_attribute(0, NULL, NULL);
}
--
2.23.0
Dec. 12, 2019
[PATCH v3 3/4] kernel32/tests: Test invalid parent handle in test_parent_process_attribute().
by Paul Gofman
Signed-off-by: Paul Gofman <gofmanp(a)gmail.com>
---
v2:
- no changes;
v3:
- mark failed child process creation for GetCurrentProcess() parent handle
as broken instead of successful creation;
- replace test with INVALID_HANDLE_VALUE parent (which is the same as GetCurrentProcess())
with OpenProcess(..., GetCurrentProcessId()) handle.
dlls/kernel32/tests/process.c | 85 ++++++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c
index 6d7a9a74c3..1194c54202 100644
--- a/dlls/kernel32/tests/process.c
+++ b/dlls/kernel32/tests/process.c
@@ -3825,7 +3825,8 @@ static void test_ProcThreadAttributeList(void)
/* level 0: Main test process
* level 1: Process created by level 0 process without handle inheritance
* level 2: Process created by level 1 process with handle inheritance and level 0
- * process parent substitute. */
+ * process parent substitute.
+ * level 255: Process created by level 1 process during invalid parent handles testing. */
void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
{
PROCESS_BASIC_INFORMATION pbi;
@@ -3848,6 +3849,9 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
}
parent_data;
+ if (level == 255)
+ return;
+
if (!pInitializeProcThreadAttributeList)
{
win_skip("No support for ProcThreadAttributeList.\n");
@@ -3891,11 +3895,90 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
if (level)
{
+ HANDLE handle;
SIZE_T size;
ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size);
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+
+ sprintf(buffer, "\"%s\" tests/process.c parent %u %p", selfname, 255, read_pipe);
+
+#if 0
+ /* Crashes on some Windows installations, otherwise successfully creates process. */
+ ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT,
+ NULL, NULL, (STARTUPINFOA *)&si, &info);
+ ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
+ CloseHandle(info.hThread);
+ CloseHandle(info.hProcess);
+#endif
+ si.lpAttributeList = heap_alloc(size);
+ ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
+ ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ handle = OpenProcess(PROCESS_CREATE_PROCESS, TRUE, GetCurrentProcessId());
+ ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
+ &handle, sizeof(handle), NULL, NULL);
+ ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
+ NULL, NULL, (STARTUPINFOA *)&si, &info);
+ ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
+ CloseHandle(info.hThread);
+ CloseHandle(info.hProcess);
+ CloseHandle(handle);
+ pDeleteProcThreadAttributeList(si.lpAttributeList);
+ heap_free(si.lpAttributeList);
+
+ si.lpAttributeList = heap_alloc(size);
+ ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
+ ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ handle = (HANDLE)0xdeadbeef;
+ ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
+ &handle, sizeof(handle), NULL, NULL);
+ ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
+ NULL, NULL, (STARTUPINFOA *)&si, &info);
+ ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %u.\n",
+ ret, GetLastError());
+ pDeleteProcThreadAttributeList(si.lpAttributeList);
+ heap_free(si.lpAttributeList);
+
+ si.lpAttributeList = heap_alloc(size);
+ ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
+ ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ handle = NULL;
+ ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
+ &handle, sizeof(handle), NULL, NULL);
+ ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
+ NULL, NULL, (STARTUPINFOA *)&si, &info);
+ ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %u.\n",
+ ret, GetLastError());
+ pDeleteProcThreadAttributeList(si.lpAttributeList);
+ heap_free(si.lpAttributeList);
+
+ si.lpAttributeList = heap_alloc(size);
+ ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
+ ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ handle = GetCurrentProcess();
+ ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
+ &handle, sizeof(handle), NULL, NULL);
+ ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
+ NULL, NULL, (STARTUPINFOA *)&si, &info);
+ /* Broken on Vista / w7 / w10. */
+ ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_HANDLE),
+ "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
+ if (ret)
+ {
+ ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
+ CloseHandle(info.hThread);
+ CloseHandle(info.hProcess);
+ }
+ pDeleteProcThreadAttributeList(si.lpAttributeList);
+ heap_free(si.lpAttributeList);
+
si.lpAttributeList = heap_alloc(size);
ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
--
2.23.0
Dec. 12, 2019
[PATCH v3 2/4] ntdll: Support creating processes with specified parent.
by Paul Gofman
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47817
Signed-off-by: Paul Gofman <gofmanp(a)gmail.com>
---
v2:
- don't use arbitrary thread as parent;
v3:
- don't check for current process pseudo handle value in RtlCreateUserProcess().
dlls/kernel32/tests/process.c | 4 ++--
dlls/ntdll/process.c | 5 +++--
include/wine/server_protocol.h | 4 +++-
server/console.c | 32 ++++++++++++++++----------------
server/process.c | 30 ++++++++++++++++++++++++------
server/process.h | 3 ++-
server/protocol.def | 1 +
server/request.h | 17 +++++++++--------
server/trace.c | 3 ++-
server/user.h | 3 ++-
server/winstation.c | 24 ++++++++++++++++--------
11 files changed, 80 insertions(+), 46 deletions(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c
index 3efbfa2402..6d7a9a74c3 100644
--- a/dlls/kernel32/tests/process.c
+++ b/dlls/kernel32/tests/process.c
@@ -3874,14 +3874,14 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
memset(&parent_data, 0, sizeof(parent_data));
ret = ReadFile(read_pipe, &parent_data, sizeof(parent_data), &size, NULL);
- todo_wine_if(level == 2) ok((level == 2 && ret) || (level == 1 && !ret && GetLastError() == ERROR_INVALID_HANDLE),
+ ok((level == 2 && ret) || (level == 1 && !ret && GetLastError() == ERROR_INVALID_HANDLE),
"Got unexpected ret %#x, level %u, GetLastError() %u.\n",
ret, level, GetLastError());
}
if (level == 2)
{
- todo_wine ok(parent_id == parent_data.parent_id, "Got parent id %u, parent_data.parent_id %u.\n",
+ ok(parent_id == parent_data.parent_id, "Got parent id %u, parent_data.parent_id %u.\n",
parent_id, parent_data.parent_id);
return;
}
diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
index 52d7ea429e..a4a2f17b4f 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -1667,8 +1667,8 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes,
RtlNormalizeProcessParams( params );
- TRACE( "%s image %s cmdline %s\n", debugstr_us( path ),
- debugstr_us( ¶ms->ImagePathName ), debugstr_us( ¶ms->CommandLine ));
+ TRACE("path %s, image %s, cmdline %s, parent %p.\n", debugstr_us(path),
+ debugstr_us(¶ms->ImagePathName), debugstr_us(¶ms->CommandLine), parent);
if ((status = get_pe_file_info( path, attributes, &file_handle, &pe_info )))
{
@@ -1709,6 +1709,7 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes,
SERVER_START_REQ( new_process )
{
+ req->parent_process = wine_server_obj_handle(parent);
req->inherit_all = inherit;
req->create_flags = params->DebugFlags; /* hack: creation flags stored in DebugFlags for now */
req->socket_fd = socketfd[1];
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index aaa5fd2e33..98ecd98b08 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -769,6 +769,7 @@ struct rawinput_device
struct new_process_request
{
struct request_header __header;
+ obj_handle_t parent_process;
int inherit_all;
unsigned int create_flags;
int socket_fd;
@@ -779,6 +780,7 @@ struct new_process_request
/* VARARG(objattr,object_attributes); */
/* VARARG(info,startup_info,info_size); */
/* VARARG(env,unicode_str); */
+ char __pad_44[4];
};
struct new_process_reply
{
@@ -6702,6 +6704,6 @@ union generic_reply
struct resume_process_reply resume_process_reply;
};
-#define SERVER_PROTOCOL_VERSION 593
+#define SERVER_PROTOCOL_VERSION 594
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/console.c b/server/console.c
index 59f8843a75..691a0bf05a 100644
--- a/server/console.c
+++ b/server/console.c
@@ -504,37 +504,37 @@ int free_console( struct process *process )
* 2/ parent is a renderer which launches process, and process should attach to the console
* rendered by parent
*/
-void inherit_console(struct thread *parent_thread, struct process *process, obj_handle_t hconin)
+void inherit_console(struct thread *parent_thread, struct process *parent, struct process *process,
+ obj_handle_t hconin)
{
int done = 0;
- struct process* parent = parent_thread->process;
/* if parent is a renderer, then attach current process to its console
* a bit hacky....
*/
- if (hconin)
+ if (hconin && parent_thread)
{
- struct console_input* console;
+ struct console_input *console;
/* FIXME: should we check some access rights ? */
- if ((console = (struct console_input*)get_handle_obj( parent, hconin,
- 0, &console_input_ops )))
- {
+ if ((console = (struct console_input *)get_handle_obj( parent, hconin,
+ 0, &console_input_ops )))
+ {
if (console->renderer == parent_thread)
- {
- process->console = (struct console_input*)grab_object( console );
- process->console->num_proc++;
- done = 1;
- }
- release_object( console );
- }
+ {
+ process->console = (struct console_input*)grab_object( console );
+ process->console->num_proc++;
+ done = 1;
+ }
+ release_object( console );
+ }
else clear_error(); /* ignore error */
}
/* otherwise, if parent has a console, attach child to this console */
if (!done && parent->console)
{
- process->console = (struct console_input*)grab_object( parent->console );
- process->console->num_proc++;
+ process->console = (struct console_input*)grab_object( parent->console );
+ process->console->num_proc++;
}
}
diff --git a/server/process.c b/server/process.c
index 16bb5d57e7..00ea45b068 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1117,6 +1117,7 @@ DECL_HANDLER(new_process)
const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
struct process *process = NULL;
struct process *parent = current->process;
+ struct thread *parent_thread = current;
int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
if (socket_fd == -1)
@@ -1148,11 +1149,26 @@ DECL_HANDLER(new_process)
return;
}
+ if (req->parent_process)
+ {
+ if (!(parent = get_process_from_handle( req->parent_process, PROCESS_CREATE_PROCESS)))
+ {
+ set_error(STATUS_INVALID_HANDLE);
+ close(socket_fd);
+ return;
+ }
+ parent_thread = NULL;
+ }
+
if (parent->job && (req->create_flags & CREATE_BREAKAWAY_FROM_JOB) &&
!(parent->job->limit_flags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)))
{
set_error( STATUS_ACCESS_DENIED );
close( socket_fd );
+
+ if (req->parent_process)
+ release_object(parent);
+
return;
}
@@ -1222,7 +1238,7 @@ DECL_HANDLER(new_process)
}
/* connect to the window station */
- connect_process_winstation( process, current );
+ connect_process_winstation( process, parent_thread, parent );
/* set the process console */
if (!(req->create_flags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)))
@@ -1231,7 +1247,7 @@ DECL_HANDLER(new_process)
* like if hConOut and hConIn are console handles, then they should be on the same
* physical console
*/
- inherit_console( current, process, req->inherit_all ? info->data->hstdin : 0 );
+ inherit_console( parent_thread, parent, process, req->inherit_all ? info->data->hstdin : 0 );
}
if (!req->inherit_all && !(req->create_flags & CREATE_NEW_CONSOLE))
@@ -1246,16 +1262,15 @@ DECL_HANDLER(new_process)
if (get_error() == STATUS_INVALID_HANDLE ||
get_error() == STATUS_OBJECT_TYPE_MISMATCH) clear_error();
}
-
/* attach to the debugger if requested */
if (req->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
{
set_process_debugger( process, current );
process->debug_children = !(req->create_flags & DEBUG_ONLY_THIS_PROCESS);
}
- else if (parent->debugger && parent->debug_children)
+ else if (current->process->debugger && current->process->debug_children)
{
- set_process_debugger( process, parent->debugger );
+ set_process_debugger( process, current->process->debugger );
/* debug_children is set to 1 by default */
}
@@ -1265,9 +1280,12 @@ DECL_HANDLER(new_process)
info->process = (struct process *)grab_object( process );
reply->info = alloc_handle( current->process, info, SYNCHRONIZE, 0 );
reply->pid = get_process_id( process );
- reply->handle = alloc_handle_no_access_check( parent, process, req->access, objattr->attributes );
+ reply->handle = alloc_handle_no_access_check( current->process, process, req->access, objattr->attributes );
done:
+ if (req->parent_process)
+ release_object(parent);
+
if (process) release_object( process );
release_object( info );
}
diff --git a/server/process.h b/server/process.h
index 20ff6beda6..d8453eeaf2 100644
--- a/server/process.h
+++ b/server/process.h
@@ -141,7 +141,8 @@ extern struct process_snapshot *process_snap( int *count );
extern void enum_processes( int (*cb)(struct process*, void*), void *user);
/* console functions */
-extern void inherit_console(struct thread *parent_thread, struct process *process, obj_handle_t hconin);
+extern void inherit_console(struct thread *parent_thread, struct process *parent,
+ struct process *process, obj_handle_t hconin);
extern int free_console( struct process *process );
extern struct thread *console_get_renderer( struct console_input *console );
diff --git a/server/protocol.def b/server/protocol.def
index 1cb1fea602..7f9ec3a149 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -783,6 +783,7 @@ struct rawinput_device
/* Create a new process from the context of the parent */
@REQ(new_process)
+ obj_handle_t parent_process; /* parent process */
int inherit_all; /* inherit all handles from parent */
unsigned int create_flags; /* creation flags */
int socket_fd; /* file descriptor for process socket */
diff --git a/server/request.h b/server/request.h
index 90a3180a6c..9f36bcb711 100644
--- a/server/request.h
+++ b/server/request.h
@@ -745,14 +745,15 @@ C_ASSERT( sizeof(unsigned char) == 1 );
C_ASSERT( sizeof(unsigned int) == 4 );
C_ASSERT( sizeof(unsigned short) == 2 );
C_ASSERT( sizeof(user_handle_t) == 4 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, inherit_all) == 12 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, create_flags) == 16 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, socket_fd) == 20 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, exe_file) == 24 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, access) == 28 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 32 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 36 );
-C_ASSERT( sizeof(struct new_process_request) == 40 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, parent_process) == 12 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, inherit_all) == 16 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, create_flags) == 20 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, socket_fd) == 24 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, exe_file) == 28 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, access) == 32 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 36 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 40 );
+C_ASSERT( sizeof(struct new_process_request) == 48 );
C_ASSERT( FIELD_OFFSET(struct new_process_reply, info) == 8 );
C_ASSERT( FIELD_OFFSET(struct new_process_reply, pid) == 12 );
C_ASSERT( FIELD_OFFSET(struct new_process_reply, handle) == 16 );
diff --git a/server/trace.c b/server/trace.c
index 5b1d3ddea9..47f66b582c 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1243,7 +1243,8 @@ typedef void (*dump_func)( const void *req );
static void dump_new_process_request( const struct new_process_request *req )
{
- fprintf( stderr, " inherit_all=%d", req->inherit_all );
+ fprintf( stderr, " parent_process=%04x", req->parent_process );
+ fprintf( stderr, ", inherit_all=%d", req->inherit_all );
fprintf( stderr, ", create_flags=%08x", req->create_flags );
fprintf( stderr, ", socket_fd=%d", req->socket_fd );
fprintf( stderr, ", exe_file=%04x", req->exe_file );
diff --git a/server/user.h b/server/user.h
index eb1b7ce1e4..35184d8780 100644
--- a/server/user.h
+++ b/server/user.h
@@ -183,7 +183,8 @@ extern client_ptr_t get_class_client_ptr( struct window_class *class );
extern struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern struct winstation *get_process_winstation( struct process *process, unsigned int access );
extern struct desktop *get_thread_desktop( struct thread *thread, unsigned int access );
-extern void connect_process_winstation( struct process *process, struct thread *parent );
+extern void connect_process_winstation( struct process *process, struct thread *parent_thread,
+ struct process *parent_process );
extern void set_process_default_desktop( struct process *process, struct desktop *desktop,
obj_handle_t handle );
extern void close_process_desktop( struct process *process );
diff --git a/server/winstation.c b/server/winstation.c
index a09ca03e3b..f7932a9dc6 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -372,7 +372,8 @@ void set_process_default_desktop( struct process *process, struct desktop *deskt
}
/* connect a process to its window station */
-void connect_process_winstation( struct process *process, struct thread *parent )
+void connect_process_winstation( struct process *process, struct thread *parent_thread,
+ struct process *parent_process)
{
struct winstation *winstation = NULL;
struct desktop *desktop = NULL;
@@ -383,9 +384,9 @@ void connect_process_winstation( struct process *process, struct thread *parent
{
winstation = (struct winstation *)get_handle_obj( process, handle, 0, &winstation_ops );
}
- else if (parent && parent->process->winstation)
+ else if (parent_process->winstation)
{
- handle = duplicate_handle( parent->process, parent->process->winstation,
+ handle = duplicate_handle( parent_process, parent_process->winstation,
process, 0, 0, DUP_HANDLE_SAME_ACCESS );
winstation = (struct winstation *)get_handle_obj( process, handle, 0, &winstation_ops );
}
@@ -397,14 +398,21 @@ void connect_process_winstation( struct process *process, struct thread *parent
desktop = get_desktop_obj( process, handle, 0 );
if (!desktop || desktop->winstation != winstation) goto done;
}
- else if (parent && parent->desktop)
+ else
{
- desktop = get_desktop_obj( parent->process, parent->desktop, 0 );
+ if (parent_thread && parent_thread->desktop)
+ handle = parent_thread->desktop;
+ else if (parent_process->desktop)
+ handle = parent_process->desktop;
+ else
+ goto done;
+
+ desktop = get_desktop_obj( parent_process, handle, 0 );
+
if (!desktop || desktop->winstation != winstation) goto done;
- handle = duplicate_handle( parent->process, parent->desktop,
- process, 0, 0, DUP_HANDLE_SAME_ACCESS );
- }
+ handle = duplicate_handle( parent_process, handle, process, 0, 0, DUP_HANDLE_SAME_ACCESS );
+ }
if (handle) set_process_default_desktop( process, desktop, handle );
done:
--
2.23.0
Dec. 12, 2019