eeb4686f156b1107eabbf6aae2969d2a962f8fb5
[reactos.git] / modules / rostests / winetests / ole32 / compobj.c
1 /*
2 * Component Object Tests
3 *
4 * Copyright 2005 Robert Shearman
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 #include <dde.h>
24 #include <ctxtcall.h>
25 #include <initguid.h>
26
27 extern const IID GUID_NULL;
28
29 #define DEFINE_EXPECT(func) \
30 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
31
32 #define SET_EXPECT(func) \
33 expect_ ## func = TRUE
34
35 #define CHECK_EXPECT2(func) \
36 do { \
37 ok(expect_ ##func, "unexpected call " #func "\n"); \
38 called_ ## func = TRUE; \
39 }while(0)
40
41 #define CHECK_EXPECT(func) \
42 do { \
43 CHECK_EXPECT2(func); \
44 expect_ ## func = FALSE; \
45 }while(0)
46
47 #define CHECK_CALLED(func) \
48 do { \
49 ok(called_ ## func, "expected " #func "\n"); \
50 expect_ ## func = called_ ## func = FALSE; \
51 }while(0)
52
53 DEFINE_EXPECT(CreateStub);
54
55 /* functions that are not present on all versions of Windows */
56 static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
57 static HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv);
58 static HRESULT (WINAPI * pCoSwitchCallContext)(IUnknown *pObject, IUnknown **ppOldObject);
59 static HRESULT (WINAPI * pCoGetTreatAsClass)(REFCLSID clsidOld, LPCLSID pClsidNew);
60 static HRESULT (WINAPI * pCoTreatAsClass)(REFCLSID clsidOld, REFCLSID pClsidNew);
61 static HRESULT (WINAPI * pCoGetContextToken)(ULONG_PTR *token);
62 static HRESULT (WINAPI * pCoGetApartmentType)(APTTYPE *type, APTTYPEQUALIFIER *qualifier);
63 static LONG (WINAPI * pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
64 static LONG (WINAPI * pRegOverridePredefKey)(HKEY key, HKEY override);
65
66 static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
67 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
68 static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
69 static BOOL (WINAPI *pIsWow64Process)(HANDLE, LPBOOL);
70 static void (WINAPI *pReleaseActCtx)(HANDLE);
71
72 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
73 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
74 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
75
76 static const CLSID CLSID_non_existent = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
77 static const CLSID CLSID_StdFont = { 0x0be35203, 0x8f91, 0x11ce, { 0x9d, 0xe3, 0x00, 0xaa, 0x00, 0x4b, 0xb8, 0x51 } };
78 static const GUID IID_Testiface = { 0x22222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
79 static const GUID IID_Testiface2 = { 0x32222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
80 static const GUID IID_Testiface3 = { 0x42222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
81 static const GUID IID_Testiface4 = { 0x52222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
82 static const GUID IID_Testiface5 = { 0x62222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
83 static const GUID IID_Testiface6 = { 0x72222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
84 static const GUID IID_TestPS = { 0x66666666, 0x8888, 0x7777, { 0x66, 0x66, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 } };
85
86 DEFINE_GUID(CLSID_InProcFreeMarshaler, 0x0000033a,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
87 DEFINE_GUID(CLSID_testclsid, 0xacd014c7,0x9535,0x4fac,0x8b,0x53,0xa4,0x8c,0xa7,0xf4,0xd7,0x26);
88 DEFINE_GUID(CLSID_GlobalOptions, 0x0000034b,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
89
90 static const WCHAR stdfont[] = {'S','t','d','F','o','n','t',0};
91 static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
92 static const WCHAR wszCLSID_StdFont[] =
93 {
94 '{','0','b','e','3','5','2','0','3','-','8','f','9','1','-','1','1','c','e','-',
95 '9','d','e','3','-','0','0','a','a','0','0','4','b','b','8','5','1','}',0
96 };
97 static const WCHAR progidW[] = {'P','r','o','g','I','d','.','P','r','o','g','I','d',0};
98 static const WCHAR cf_brokenW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
99 'c','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}','a',0};
100
101 DEFINE_GUID(IID_IWineTest, 0x5201163f, 0x8164, 0x4fd0, 0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd);
102 DEFINE_GUID(CLSID_WineOOPTest, 0x5201163f, 0x8164, 0x4fd0, 0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd);
103
104 static LONG cLocks;
105
106 static void LockModule(void)
107 {
108 InterlockedIncrement(&cLocks);
109 }
110
111 static void UnlockModule(void)
112 {
113 InterlockedDecrement(&cLocks);
114 }
115
116 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
117 LPCLASSFACTORY iface,
118 REFIID riid,
119 LPVOID *ppvObj)
120 {
121 if (ppvObj == NULL) return E_POINTER;
122
123 if (IsEqualGUID(riid, &IID_IUnknown) ||
124 IsEqualGUID(riid, &IID_IClassFactory))
125 {
126 *ppvObj = iface;
127 IClassFactory_AddRef(iface);
128 return S_OK;
129 }
130
131 *ppvObj = NULL;
132 return E_NOINTERFACE;
133 }
134
135 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
136 {
137 LockModule();
138 return 2; /* non-heap-based object */
139 }
140
141 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
142 {
143 UnlockModule();
144 return 1; /* non-heap-based object */
145 }
146
147 static IID create_instance_iid;
148 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
149 LPCLASSFACTORY iface,
150 IUnknown *pUnkOuter,
151 REFIID riid,
152 LPVOID *ppvObj)
153 {
154 *ppvObj = NULL;
155 create_instance_iid = *riid;
156 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
157 return E_NOINTERFACE;
158 }
159
160 static HRESULT WINAPI Test_IClassFactory_LockServer(
161 LPCLASSFACTORY iface,
162 BOOL fLock)
163 {
164 return S_OK;
165 }
166
167 static const IClassFactoryVtbl TestClassFactory_Vtbl =
168 {
169 Test_IClassFactory_QueryInterface,
170 Test_IClassFactory_AddRef,
171 Test_IClassFactory_Release,
172 Test_IClassFactory_CreateInstance,
173 Test_IClassFactory_LockServer
174 };
175
176 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
177
178 static WCHAR manifest_path[MAX_PATH];
179
180 static BOOL create_manifest_file(const char *filename, const char *manifest)
181 {
182 int manifest_len;
183 DWORD size;
184 HANDLE file;
185 WCHAR path[MAX_PATH];
186
187 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
188 GetFullPathNameW(path, sizeof(manifest_path)/sizeof(WCHAR), manifest_path, NULL);
189
190 manifest_len = strlen(manifest);
191 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
192 FILE_ATTRIBUTE_NORMAL, NULL);
193 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
194 if(file == INVALID_HANDLE_VALUE)
195 return FALSE;
196 WriteFile(file, manifest, manifest_len, &size, NULL);
197 CloseHandle(file);
198
199 return TRUE;
200 }
201
202 static HANDLE activate_context(const char *manifest, ULONG_PTR *cookie)
203 {
204 WCHAR path[MAX_PATH];
205 ACTCTXW actctx;
206 HANDLE handle;
207 BOOL ret;
208
209 if (!pCreateActCtxW) return NULL;
210
211 create_manifest_file("file.manifest", manifest);
212
213 MultiByteToWideChar( CP_ACP, 0, "file.manifest", -1, path, MAX_PATH );
214 memset(&actctx, 0, sizeof(ACTCTXW));
215 actctx.cbSize = sizeof(ACTCTXW);
216 actctx.lpSource = path;
217
218 handle = pCreateActCtxW(&actctx);
219 ok(handle != INVALID_HANDLE_VALUE || broken(handle == INVALID_HANDLE_VALUE) /* some old XP/2k3 versions */,
220 "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
221 if (handle == INVALID_HANDLE_VALUE)
222 {
223 win_skip("activation context generation failed, some tests will be skipped\n");
224 handle = NULL;
225 }
226
227 ok(actctx.cbSize == sizeof(ACTCTXW), "actctx.cbSize=%d\n", actctx.cbSize);
228 ok(actctx.dwFlags == 0, "actctx.dwFlags=%d\n", actctx.dwFlags);
229 ok(actctx.lpSource == path, "actctx.lpSource=%p\n", actctx.lpSource);
230 ok(actctx.wProcessorArchitecture == 0, "actctx.wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
231 ok(actctx.wLangId == 0, "actctx.wLangId=%d\n", actctx.wLangId);
232 ok(actctx.lpAssemblyDirectory == NULL, "actctx.lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
233 ok(actctx.lpResourceName == NULL, "actctx.lpResourceName=%p\n", actctx.lpResourceName);
234 ok(actctx.lpApplicationName == NULL, "actctx.lpApplicationName=%p\n", actctx.lpApplicationName);
235 ok(actctx.hModule == NULL, "actctx.hModule=%p\n", actctx.hModule);
236
237 DeleteFileA("file.manifest");
238
239 if (handle)
240 {
241 ret = pActivateActCtx(handle, cookie);
242 ok(ret, "ActivateActCtx failed: %u\n", GetLastError());
243 }
244
245 return handle;
246 }
247
248 static const char actctx_manifest[] =
249 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
250 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\""
251 " publicKeyToken=\"6595b6414666f1df\" />"
252 "<file name=\"testlib.dll\">"
253 " <comClass"
254 " clsid=\"{0000033a-0000-0000-c000-000000000046}\""
255 " progid=\"FTMarshal\""
256 " />"
257 " <comClass"
258 " clsid=\"{5201163f-8164-4fd0-a1a2-5d5a3654d3bd}\""
259 " progid=\"WineOOPTest\""
260 " />"
261 " <comClass description=\"Test com class\""
262 " clsid=\"{12345678-1234-1234-1234-56789abcdef0}\""
263 " progid=\"ProgId.ProgId\""
264 " miscStatusIcon=\"recomposeonresize\""
265 " />"
266 " <comClass description=\"CustomFont Description\" clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb851}\""
267 " progid=\"CustomFont\""
268 " miscStatusIcon=\"recomposeonresize\""
269 " miscStatusContent=\"insideout\""
270 " />"
271 " <comClass description=\"StdFont Description\" clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb852}\""
272 " progid=\"StdFont\""
273 " />"
274 " <comClass clsid=\"{62222222-1234-1234-1234-56789abcdef0}\" >"
275 " <progid>ProgId.ProgId.1</progid>"
276 " </comClass>"
277 " <comInterfaceProxyStub "
278 " name=\"Iifaceps\""
279 " iid=\"{22222222-1234-1234-1234-56789abcdef0}\""
280 " proxyStubClsid32=\"{66666666-8888-7777-6666-555555555555}\""
281 " />"
282 "</file>"
283 " <comInterfaceExternalProxyStub "
284 " name=\"Iifaceps2\""
285 " iid=\"{32222222-1234-1234-1234-56789abcdef0}\""
286 " />"
287 " <comInterfaceExternalProxyStub "
288 " name=\"Iifaceps3\""
289 " iid=\"{42222222-1234-1234-1234-56789abcdef0}\""
290 " proxyStubClsid32=\"{66666666-8888-7777-6666-555555555555}\""
291 " />"
292 " <comInterfaceExternalProxyStub "
293 " name=\"Iifaceps4\""
294 " iid=\"{52222222-1234-1234-1234-56789abcdef0}\""
295 " proxyStubClsid32=\"{00000000-0000-0000-0000-000000000000}\""
296 " />"
297 " <clrClass "
298 " clsid=\"{72222222-1234-1234-1234-56789abcdef0}\""
299 " name=\"clrclass\""
300 " >"
301 " <progid>clrprogid.1</progid>"
302 " </clrClass>"
303 "</assembly>";
304
305 DEFINE_GUID(CLSID_Testclass, 0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0);
306
307 static void test_ProgIDFromCLSID(void)
308 {
309 ULONG_PTR cookie = 0;
310 LPWSTR progid;
311 HANDLE handle;
312 HRESULT hr;
313
314 hr = ProgIDFromCLSID(&CLSID_StdFont, &progid);
315 ok(hr == S_OK, "ProgIDFromCLSID failed with error 0x%08x\n", hr);
316 if (hr == S_OK)
317 {
318 ok(!lstrcmpiW(progid, stdfont), "Didn't get expected prog ID\n");
319 CoTaskMemFree(progid);
320 }
321
322 progid = (LPWSTR)0xdeadbeef;
323 hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
324 ok(hr == REGDB_E_CLASSNOTREG, "ProgIDFromCLSID returned %08x\n", hr);
325 ok(progid == NULL, "ProgIDFromCLSID returns with progid %p\n", progid);
326
327 hr = ProgIDFromCLSID(&CLSID_StdFont, NULL);
328 ok(hr == E_INVALIDARG, "ProgIDFromCLSID should return E_INVALIDARG instead of 0x%08x\n", hr);
329
330 if ((handle = activate_context(actctx_manifest, &cookie)))
331 {
332 static const WCHAR customfontW[] = {'C','u','s','t','o','m','F','o','n','t',0};
333
334 hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
335 ok(hr == S_OK, "got 0x%08x\n", hr);
336 ok(!lstrcmpiW(progid, progidW), "got %s\n", wine_dbgstr_w(progid));
337 CoTaskMemFree(progid);
338
339 /* try something registered and redirected */
340 progid = NULL;
341 hr = ProgIDFromCLSID(&CLSID_StdFont, &progid);
342 ok(hr == S_OK, "got 0x%08x\n", hr);
343 ok(!lstrcmpiW(progid, customfontW), "got wrong progid %s\n", wine_dbgstr_w(progid));
344 CoTaskMemFree(progid);
345
346 /* classes without default progid, progid list is not used */
347 progid = (void *)0xdeadbeef;
348 hr = ProgIDFromCLSID(&IID_Testiface5, &progid);
349 ok(hr == REGDB_E_CLASSNOTREG && progid == NULL, "got 0x%08x, progid %p\n", hr, progid);
350
351 progid = (void *)0xdeadbeef;
352 hr = ProgIDFromCLSID(&IID_Testiface6, &progid);
353 ok(hr == REGDB_E_CLASSNOTREG && progid == NULL, "got 0x%08x, progid %p\n", hr, progid);
354
355 pDeactivateActCtx(0, cookie);
356 pReleaseActCtx(handle);
357 }
358 }
359
360 static void test_CLSIDFromProgID(void)
361 {
362 ULONG_PTR cookie = 0;
363 HANDLE handle;
364 CLSID clsid;
365 HRESULT hr = CLSIDFromProgID(stdfont, &clsid);
366 ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08x\n", hr);
367 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
368
369 hr = CLSIDFromString(stdfont, &clsid);
370 ok_ole_success(hr, "CLSIDFromString");
371 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
372
373 /* test some failure cases */
374
375 hr = CLSIDFromProgID(wszNonExistent, NULL);
376 ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
377
378 hr = CLSIDFromProgID(NULL, &clsid);
379 ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
380
381 memset(&clsid, 0xcc, sizeof(clsid));
382 hr = CLSIDFromProgID(wszNonExistent, &clsid);
383 ok(hr == CO_E_CLASSSTRING, "CLSIDFromProgID on nonexistent ProgID should have returned CO_E_CLASSSTRING instead of 0x%08x\n", hr);
384 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "CLSIDFromProgID should have set clsid to all-zeros on failure\n");
385
386 /* fails without proper context */
387 memset(&clsid, 0xcc, sizeof(clsid));
388 hr = CLSIDFromProgID(progidW, &clsid);
389 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
390 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "wrong clsid\n");
391
392 if ((handle = activate_context(actctx_manifest, &cookie)))
393 {
394 GUID clsid1;
395
396 memset(&clsid, 0xcc, sizeof(clsid));
397 hr = CLSIDFromProgID(wszNonExistent, &clsid);
398 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
399 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "should have zero CLSID on failure\n");
400
401 /* CLSIDFromString() doesn't check activation context */
402 hr = CLSIDFromString(progidW, &clsid);
403 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
404
405 clsid = CLSID_NULL;
406 hr = CLSIDFromProgID(progidW, &clsid);
407 ok(hr == S_OK, "got 0x%08x\n", hr);
408 /* it returns generated CLSID here */
409 ok(!IsEqualCLSID(&clsid, &CLSID_non_existent) && !IsEqualCLSID(&clsid, &CLSID_NULL),
410 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
411
412 /* duplicate progid present in context - returns generated guid here too */
413 clsid = CLSID_NULL;
414 hr = CLSIDFromProgID(stdfont, &clsid);
415 ok(hr == S_OK, "got 0x%08x\n", hr);
416 clsid1 = CLSID_StdFont;
417 /* that's where it differs from StdFont */
418 clsid1.Data4[7] = 0x52;
419 ok(!IsEqualCLSID(&clsid, &CLSID_StdFont) && !IsEqualCLSID(&clsid, &CLSID_NULL) && !IsEqualCLSID(&clsid, &clsid1),
420 "got %s\n", wine_dbgstr_guid(&clsid));
421
422 pDeactivateActCtx(0, cookie);
423 pReleaseActCtx(handle);
424 }
425 }
426
427 static void test_CLSIDFromString(void)
428 {
429 CLSID clsid;
430 WCHAR wszCLSID_Broken[50];
431 UINT i;
432
433 HRESULT hr = CLSIDFromString(wszCLSID_StdFont, &clsid);
434 ok_ole_success(hr, "CLSIDFromString");
435 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
436
437 memset(&clsid, 0xab, sizeof(clsid));
438 hr = CLSIDFromString(NULL, &clsid);
439 ok(hr == S_OK, "got 0x%08x\n", hr);
440 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
441
442 /* string is longer, but starts with a valid CLSID */
443 memset(&clsid, 0, sizeof(clsid));
444 hr = CLSIDFromString(cf_brokenW, &clsid);
445 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
446 ok(IsEqualCLSID(&clsid, &IID_IClassFactory), "got %s\n", wine_dbgstr_guid(&clsid));
447
448 lstrcpyW(wszCLSID_Broken, wszCLSID_StdFont);
449 for(i = lstrlenW(wszCLSID_StdFont); i < 49; i++)
450 wszCLSID_Broken[i] = 'A';
451 wszCLSID_Broken[i] = '\0';
452
453 memset(&clsid, 0, sizeof(CLSID));
454 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
455 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
456 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
457
458 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)-1] = 'A';
459 memset(&clsid, 0, sizeof(CLSID));
460 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
461 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
462 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
463
464 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)] = '\0';
465 memset(&clsid, 0, sizeof(CLSID));
466 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
467 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
468 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
469
470 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)-1] = '\0';
471 memset(&clsid, 0, sizeof(CLSID));
472 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
473 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
474 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
475
476 memset(&clsid, 0xcc, sizeof(CLSID));
477 hr = CLSIDFromString(wszCLSID_Broken+1, &clsid);
478 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
479 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
480
481 wszCLSID_Broken[9] = '*';
482 memset(&clsid, 0xcc, sizeof(CLSID));
483 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
484 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
485 ok(clsid.Data1 == CLSID_StdFont.Data1, "Got %08x\n", clsid.Data1);
486 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
487
488 wszCLSID_Broken[3] = '*';
489 memset(&clsid, 0xcc, sizeof(CLSID));
490 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
491 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
492 ok(clsid.Data1 == 0xb, "Got %08x\n", clsid.Data1);
493 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
494
495 wszCLSID_Broken[3] = '\0';
496 memset(&clsid, 0xcc, sizeof(CLSID));
497 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
498 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
499 ok(clsid.Data1 == 0xb, "Got %08x\n", clsid.Data1);
500 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
501 }
502
503 static void test_IIDFromString(void)
504 {
505 static const WCHAR cfW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
506 'c','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
507 static const WCHAR brokenW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
508 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
509 static const WCHAR broken2W[] = {'{','0','0','0','0','0','0','0','1','=','0','0','0','0','-','0','0','0','0','-',
510 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
511 static const WCHAR broken3W[] = {'b','r','o','k','e','n','0','0','1','=','0','0','0','0','-','0','0','0','0','-',
512 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
513 HRESULT hr;
514 IID iid;
515
516 hr = IIDFromString(wszCLSID_StdFont, &iid);
517 ok(hr == S_OK, "got 0x%08x\n", hr);
518 ok(IsEqualIID(&iid, &CLSID_StdFont), "got iid %s\n", wine_dbgstr_guid(&iid));
519
520 memset(&iid, 0xab, sizeof(iid));
521 hr = IIDFromString(NULL, &iid);
522 ok(hr == S_OK, "got 0x%08x\n", hr);
523 ok(IsEqualIID(&iid, &CLSID_NULL), "got iid %s\n", wine_dbgstr_guid(&iid));
524
525 hr = IIDFromString(cfW, &iid);
526 ok(hr == S_OK, "got 0x%08x\n", hr);
527 ok(IsEqualIID(&iid, &IID_IClassFactory), "got iid %s\n", wine_dbgstr_guid(&iid));
528
529 /* string starts with a valid IID but is longer */
530 memset(&iid, 0xab, sizeof(iid));
531 hr = IIDFromString(cf_brokenW, &iid);
532 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
533 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
534
535 /* invalid IID in a valid format */
536 memset(&iid, 0xab, sizeof(iid));
537 hr = IIDFromString(brokenW, &iid);
538 ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
539 ok(iid.Data1 == 0x00000001, "Got %08x\n", iid.Data1);
540
541 memset(&iid, 0xab, sizeof(iid));
542 hr = IIDFromString(broken2W, &iid);
543 ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
544 ok(iid.Data1 == 0x00000001, "Got %08x\n", iid.Data1);
545
546 /* format is broken, but string length is okay */
547 memset(&iid, 0xab, sizeof(iid));
548 hr = IIDFromString(broken3W, &iid);
549 ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
550 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
551
552 /* invalid string */
553 memset(&iid, 0xab, sizeof(iid));
554 hr = IIDFromString(wszNonExistent, &iid);
555 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
556 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
557
558 /* valid ProgID */
559 memset(&iid, 0xab, sizeof(iid));
560 hr = IIDFromString(stdfont, &iid);
561 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
562 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
563 }
564
565 static void test_StringFromGUID2(void)
566 {
567 WCHAR str[50];
568 int len;
569
570 /* invalid pointer */
571 SetLastError(0xdeadbeef);
572 len = StringFromGUID2(NULL,str,50);
573 ok(len == 0, "len: %d (expected 0)\n", len);
574 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %x\n", GetLastError());
575
576 /* Test corner cases for buffer size */
577 len = StringFromGUID2(&CLSID_StdFont,str,50);
578 ok(len == 39, "len: %d (expected 39)\n", len);
579 ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n");
580
581 memset(str,0,sizeof str);
582 len = StringFromGUID2(&CLSID_StdFont,str,39);
583 ok(len == 39, "len: %d (expected 39)\n", len);
584 ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n");
585
586 len = StringFromGUID2(&CLSID_StdFont,str,38);
587 ok(len == 0, "len: %d (expected 0)\n", len);
588
589 len = StringFromGUID2(&CLSID_StdFont,str,30);
590 ok(len == 0, "len: %d (expected 0)\n", len);
591 }
592
593 struct info
594 {
595 HANDLE wait, stop;
596 };
597
598 static DWORD CALLBACK ole_initialize_thread(LPVOID pv)
599 {
600 HRESULT hr;
601 struct info *info = pv;
602
603 hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
604
605 SetEvent(info->wait);
606 WaitForSingleObject(info->stop, 10000);
607
608 CoUninitialize();
609 return hr;
610 }
611
612 #define test_apt_type(t, q, t_t, t_q) _test_apt_type(t, q, t_t, t_q, __LINE__)
613 static void _test_apt_type(APTTYPE expected_type, APTTYPEQUALIFIER expected_qualifier, BOOL todo_type,
614 BOOL todo_qualifier, int line)
615 {
616 APTTYPEQUALIFIER qualifier = ~0u;
617 APTTYPE type = ~0u;
618 HRESULT hr;
619
620 if (!pCoGetApartmentType)
621 return;
622
623 hr = pCoGetApartmentType(&type, &qualifier);
624 ok_(__FILE__, line)(hr == S_OK || hr == CO_E_NOTINITIALIZED, "Unexpected return code: 0x%08x\n", hr);
625 todo_wine_if(todo_type)
626 ok_(__FILE__, line)(type == expected_type, "Wrong apartment type %d, expected %d\n", type, expected_type);
627 todo_wine_if(todo_qualifier)
628 ok_(__FILE__, line)(qualifier == expected_qualifier, "Wrong apartment qualifier %d, expected %d\n", qualifier,
629 expected_qualifier);
630 }
631
632 static void test_CoCreateInstance(void)
633 {
634 HRESULT hr;
635 HANDLE thread;
636 DWORD tid, exitcode;
637 IUnknown *pUnk;
638 struct info info;
639 REFCLSID rclsid = &CLSID_InternetZoneManager;
640
641 pUnk = (IUnknown *)0xdeadbeef;
642 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
643 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
644 ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
645
646 OleInitialize(NULL);
647
648 /* test errors returned for non-registered clsids */
649 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
650 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
651 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pUnk);
652 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc handler should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
653 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_LOCAL_SERVER, &IID_IUnknown, (void **)&pUnk);
654 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered local server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
655 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_REMOTE_SERVER, &IID_IUnknown, (void **)&pUnk);
656 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered remote server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
657
658 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
659 if(hr == REGDB_E_CLASSNOTREG)
660 {
661 skip("IE not installed so can't test CoCreateInstance\n");
662 OleUninitialize();
663 return;
664 }
665
666 ok_ole_success(hr, "CoCreateInstance");
667 if(pUnk) IUnknown_Release(pUnk);
668 OleUninitialize();
669
670 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
671 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
672
673 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
674 thread has already done so */
675
676 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
677
678 info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
679 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
680
681 info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
682 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
683
684 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
685 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
686
687 ok( !WaitForSingleObject(info.wait, 10000 ), "wait timed out\n" );
688
689 test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
690
691 pUnk = (IUnknown *)0xdeadbeef;
692 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
693 ok(hr == S_OK, "CoCreateInstance should have returned S_OK instead of 0x%08x\n", hr);
694 if (pUnk) IUnknown_Release(pUnk);
695
696 SetEvent(info.stop);
697 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
698
699 GetExitCodeThread(thread, &exitcode);
700 hr = exitcode;
701 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
702
703 CloseHandle(thread);
704 CloseHandle(info.wait);
705 CloseHandle(info.stop);
706
707 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
708 }
709
710 static void test_CoGetClassObject(void)
711 {
712 HRESULT hr;
713 HANDLE thread, handle;
714 DWORD tid, exitcode;
715 ULONG_PTR cookie;
716 IUnknown *pUnk;
717 struct info info;
718 REFCLSID rclsid = &CLSID_InternetZoneManager;
719 HKEY hkey;
720 LONG res;
721
722 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
723 ok(hr == CO_E_NOTINITIALIZED, "CoGetClassObject should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
724 ok(pUnk == NULL, "CoGetClassObject should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
725
726 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL);
727 ok(hr == E_INVALIDARG ||
728 broken(hr == CO_E_NOTINITIALIZED), /* win9x */
729 "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr);
730
731 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
732 thread has already done so */
733
734 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
735
736 info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
737 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
738
739 info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
740 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
741
742 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
743 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
744
745 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
746
747 test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
748
749 pUnk = (IUnknown *)0xdeadbeef;
750 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
751 if(hr == REGDB_E_CLASSNOTREG)
752 skip("IE not installed so can't test CoGetClassObject\n");
753 else
754 {
755 ok(hr == S_OK, "CoGetClassObject should have returned S_OK instead of 0x%08x\n", hr);
756 if (pUnk) IUnknown_Release(pUnk);
757 }
758
759 SetEvent(info.stop);
760 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
761
762 GetExitCodeThread(thread, &exitcode);
763 hr = exitcode;
764 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
765
766 CloseHandle(thread);
767 CloseHandle(info.wait);
768 CloseHandle(info.stop);
769
770 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
771
772 if (!pRegOverridePredefKey)
773 {
774 win_skip("RegOverridePredefKey not available\n");
775 return;
776 }
777
778 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
779
780 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
781 if (hr == S_OK)
782 {
783 IUnknown_Release(pUnk);
784
785 res = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
786 KEY_ALL_ACCESS, NULL, &hkey, NULL);
787 ok(!res, "RegCreateKeyEx returned %d\n", res);
788
789 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, hkey);
790 ok(!res, "RegOverridePredefKey returned %d\n", res);
791
792 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
793 ok(hr == S_OK, "CoGetClassObject should have returned S_OK instead of 0x%08x\n", hr);
794
795 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
796 ok(!res, "RegOverridePredefKey returned %d\n", res);
797
798 if (hr == S_OK) IUnknown_Release(pUnk);
799 RegCloseKey(hkey);
800 }
801
802 hr = CoGetClassObject(&CLSID_InProcFreeMarshaler, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
803 ok(hr == S_OK, "got 0x%08x\n", hr);
804 IUnknown_Release(pUnk);
805
806 /* context redefines FreeMarshaler CLSID */
807 if ((handle = activate_context(actctx_manifest, &cookie)))
808 {
809 hr = CoGetClassObject(&CLSID_InProcFreeMarshaler, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
810 ok(hr == S_OK, "got 0x%08x\n", hr);
811 IUnknown_Release(pUnk);
812
813 pDeactivateActCtx(0, cookie);
814 pReleaseActCtx(handle);
815 }
816
817 CoUninitialize();
818 }
819
820 static void test_CoCreateInstanceEx(void)
821 {
822 MULTI_QI qi_res = { &IID_IMoniker };
823 DWORD cookie;
824 HRESULT hr;
825
826 CoInitialize(NULL);
827
828 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
829 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie);
830 ok_ole_success(hr, "CoRegisterClassObject");
831
832 create_instance_iid = IID_NULL;
833 hr = CoCreateInstanceEx(&CLSID_WineOOPTest, NULL, CLSCTX_INPROC_SERVER, NULL, 1, &qi_res);
834 ok(hr == E_NOINTERFACE, "CoCreateInstanceEx failed: %08x\n", hr);
835 ok(IsEqualGUID(&create_instance_iid, qi_res.pIID), "Unexpected CreateInstance iid %s\n",
836 wine_dbgstr_guid(&create_instance_iid));
837
838 hr = CoRevokeClassObject(cookie);
839 ok_ole_success(hr, "CoRevokeClassObject");
840
841 CoUninitialize();
842 }
843
844 static ATOM register_dummy_class(void)
845 {
846 WNDCLASSA wc =
847 {
848 0,
849 DefWindowProcA,
850 0,
851 0,
852 GetModuleHandleA(NULL),
853 NULL,
854 LoadCursorA(NULL, (LPSTR)IDC_ARROW),
855 (HBRUSH)(COLOR_BTNFACE+1),
856 NULL,
857 "WineOleTestClass",
858 };
859
860 return RegisterClassA(&wc);
861 }
862
863 static void test_ole_menu(void)
864 {
865 HWND hwndFrame;
866 HRESULT hr;
867
868 hwndFrame = CreateWindowA((LPCSTR)MAKEINTATOM(register_dummy_class()), "Test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
869 hr = OleSetMenuDescriptor(NULL, hwndFrame, NULL, NULL, NULL);
870 todo_wine ok_ole_success(hr, "OleSetMenuDescriptor");
871
872 DestroyWindow(hwndFrame);
873 }
874
875
876 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
877 {
878 if (ppvObj == NULL) return E_POINTER;
879
880 if (IsEqualGUID(riid, &IID_IUnknown) ||
881 IsEqualGUID(riid, &IID_IClassFactory))
882 {
883 *ppvObj = iface;
884 IMessageFilter_AddRef(iface);
885 return S_OK;
886 }
887
888 return E_NOINTERFACE;
889 }
890
891 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
892 {
893 return 2; /* non-heap object */
894 }
895
896 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
897 {
898 return 1; /* non-heap object */
899 }
900
901 static DWORD WINAPI MessageFilter_HandleInComingCall(
902 IMessageFilter *iface,
903 DWORD dwCallType,
904 HTASK threadIDCaller,
905 DWORD dwTickCount,
906 LPINTERFACEINFO lpInterfaceInfo)
907 {
908 trace("HandleInComingCall\n");
909 return SERVERCALL_ISHANDLED;
910 }
911
912 static DWORD WINAPI MessageFilter_RetryRejectedCall(
913 IMessageFilter *iface,
914 HTASK threadIDCallee,
915 DWORD dwTickCount,
916 DWORD dwRejectType)
917 {
918 trace("RetryRejectedCall\n");
919 return 0;
920 }
921
922 static DWORD WINAPI MessageFilter_MessagePending(
923 IMessageFilter *iface,
924 HTASK threadIDCallee,
925 DWORD dwTickCount,
926 DWORD dwPendingType)
927 {
928 trace("MessagePending\n");
929 return PENDINGMSG_WAITNOPROCESS;
930 }
931
932 static const IMessageFilterVtbl MessageFilter_Vtbl =
933 {
934 MessageFilter_QueryInterface,
935 MessageFilter_AddRef,
936 MessageFilter_Release,
937 MessageFilter_HandleInComingCall,
938 MessageFilter_RetryRejectedCall,
939 MessageFilter_MessagePending
940 };
941
942 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
943
944 static void test_CoRegisterMessageFilter(void)
945 {
946 HRESULT hr;
947 IMessageFilter *prev_filter;
948
949 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
950 ok(hr == CO_E_NOT_SUPPORTED,
951 "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
952 hr);
953
954 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
955 prev_filter = (IMessageFilter *)0xdeadbeef;
956 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
957 ok(hr == CO_E_NOT_SUPPORTED,
958 "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
959 hr);
960 ok(prev_filter == (IMessageFilter *)0xdeadbeef,
961 "prev_filter should have been set to %p\n", prev_filter);
962 CoUninitialize();
963
964 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
965
966 hr = CoRegisterMessageFilter(NULL, NULL);
967 ok_ole_success(hr, "CoRegisterMessageFilter");
968
969 prev_filter = (IMessageFilter *)0xdeadbeef;
970 hr = CoRegisterMessageFilter(NULL, &prev_filter);
971 ok_ole_success(hr, "CoRegisterMessageFilter");
972 ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
973
974 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
975 ok_ole_success(hr, "CoRegisterMessageFilter");
976 ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
977
978 hr = CoRegisterMessageFilter(NULL, NULL);
979 ok_ole_success(hr, "CoRegisterMessageFilter");
980
981 CoUninitialize();
982 }
983
984 static IUnknown Test_Unknown;
985
986 static HRESULT WINAPI EnumOLEVERB_QueryInterface(IEnumOLEVERB *iface, REFIID riid, void **ppv)
987 {
988 return IUnknown_QueryInterface(&Test_Unknown, riid, ppv);
989 }
990
991 static ULONG WINAPI EnumOLEVERB_AddRef(IEnumOLEVERB *iface)
992 {
993 return 2;
994 }
995
996 static ULONG WINAPI EnumOLEVERB_Release(IEnumOLEVERB *iface)
997 {
998 return 1;
999 }
1000
1001 static HRESULT WINAPI EnumOLEVERB_Next(IEnumOLEVERB *iface, ULONG celt, OLEVERB *rgelt, ULONG *fetched)
1002 {
1003 ok(0, "unexpected call\n");
1004 return E_NOTIMPL;
1005 }
1006
1007 static HRESULT WINAPI EnumOLEVERB_Skip(IEnumOLEVERB *iface, ULONG celt)
1008 {
1009 ok(0, "unexpected call\n");
1010 return E_NOTIMPL;
1011 }
1012
1013 static HRESULT WINAPI EnumOLEVERB_Reset(IEnumOLEVERB *iface)
1014 {
1015 ok(0, "unexpected call\n");
1016 return E_NOTIMPL;
1017 }
1018
1019 static HRESULT WINAPI EnumOLEVERB_Clone(IEnumOLEVERB *iface, IEnumOLEVERB **ppenum)
1020 {
1021 ok(0, "unexpected call\n");
1022 return E_NOTIMPL;
1023 }
1024
1025 static const IEnumOLEVERBVtbl EnumOLEVERBVtbl = {
1026 EnumOLEVERB_QueryInterface,
1027 EnumOLEVERB_AddRef,
1028 EnumOLEVERB_Release,
1029 EnumOLEVERB_Next,
1030 EnumOLEVERB_Skip,
1031 EnumOLEVERB_Reset,
1032 EnumOLEVERB_Clone
1033 };
1034
1035 static IEnumOLEVERB EnumOLEVERB = { &EnumOLEVERBVtbl };
1036
1037 static HRESULT WINAPI Test_IUnknown_QueryInterface(
1038 IUnknown *iface,
1039 REFIID riid,
1040 LPVOID *ppvObj)
1041 {
1042 if (ppvObj == NULL) return E_POINTER;
1043
1044 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IWineTest)) {
1045 *ppvObj = iface;
1046 }else if(IsEqualIID(riid, &IID_IEnumOLEVERB)) {
1047 *ppvObj = &EnumOLEVERB;
1048 }else {
1049 *ppvObj = NULL;
1050 return E_NOINTERFACE;
1051 }
1052
1053 IUnknown_AddRef((IUnknown*)*ppvObj);
1054 return S_OK;
1055 }
1056
1057 static ULONG WINAPI Test_IUnknown_AddRef(IUnknown *iface)
1058 {
1059 return 2; /* non-heap-based object */
1060 }
1061
1062 static ULONG WINAPI Test_IUnknown_Release(IUnknown *iface)
1063 {
1064 return 1; /* non-heap-based object */
1065 }
1066
1067 static const IUnknownVtbl TestUnknown_Vtbl =
1068 {
1069 Test_IUnknown_QueryInterface,
1070 Test_IUnknown_AddRef,
1071 Test_IUnknown_Release,
1072 };
1073
1074 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
1075
1076 static IPSFactoryBuffer *ps_factory_buffer;
1077
1078 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(
1079 IPSFactoryBuffer * This,
1080 /* [in] */ REFIID riid,
1081 /* [iid_is][out] */ void **ppvObject)
1082 {
1083 if (IsEqualIID(riid, &IID_IUnknown) ||
1084 IsEqualIID(riid, &IID_IPSFactoryBuffer))
1085 {
1086 *ppvObject = This;
1087 IPSFactoryBuffer_AddRef(This);
1088 return S_OK;
1089 }
1090 return E_NOINTERFACE;
1091 }
1092
1093 static ULONG WINAPI PSFactoryBuffer_AddRef(
1094 IPSFactoryBuffer * This)
1095 {
1096 return 2;
1097 }
1098
1099 static ULONG WINAPI PSFactoryBuffer_Release(
1100 IPSFactoryBuffer * This)
1101 {
1102 return 1;
1103 }
1104
1105 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(
1106 IPSFactoryBuffer * This,
1107 /* [in] */ IUnknown *pUnkOuter,
1108 /* [in] */ REFIID riid,
1109 /* [out] */ IRpcProxyBuffer **ppProxy,
1110 /* [out] */ void **ppv)
1111 {
1112 return E_NOTIMPL;
1113 }
1114
1115 static HRESULT WINAPI PSFactoryBuffer_CreateStub(
1116 IPSFactoryBuffer * This,
1117 /* [in] */ REFIID riid,
1118 /* [unique][in] */ IUnknown *pUnkServer,
1119 /* [out] */ IRpcStubBuffer **ppStub)
1120 {
1121 CHECK_EXPECT(CreateStub);
1122
1123 ok(pUnkServer == (IUnknown*)&Test_Unknown, "unexpected pUnkServer %p\n", pUnkServer);
1124 if(!ps_factory_buffer)
1125 return E_NOTIMPL;
1126
1127 return IPSFactoryBuffer_CreateStub(ps_factory_buffer, &IID_IEnumOLEVERB, pUnkServer, ppStub);
1128 }
1129
1130 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
1131 {
1132 PSFactoryBuffer_QueryInterface,
1133 PSFactoryBuffer_AddRef,
1134 PSFactoryBuffer_Release,
1135 PSFactoryBuffer_CreateProxy,
1136 PSFactoryBuffer_CreateStub
1137 };
1138
1139 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
1140
1141 static const CLSID CLSID_WineTestPSFactoryBuffer =
1142 {
1143 0x52011640,
1144 0x8164,
1145 0x4fd0,
1146 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
1147 }; /* 52011640-8164-4fd0-a1a2-5d5a3654d3bd */
1148
1149 static DWORD CALLBACK register_ps_clsid_thread(void *context)
1150 {
1151 HRESULT hr;
1152 CLSID clsid = {0};
1153
1154 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1155
1156 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1157 ok_ole_success(hr, "CoGetPSClsid");
1158 ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
1159 wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
1160
1161 /* test registering a PSClsid in an apartment which is then destroyed */
1162 hr = CoRegisterPSClsid(&IID_TestPS, &clsid);
1163 ok_ole_success(hr, "CoRegisterPSClsid");
1164
1165 CoUninitialize();
1166
1167 return hr;
1168 }
1169
1170 static void test_CoRegisterPSClsid(void)
1171 {
1172 HRESULT hr;
1173 DWORD dwRegistrationKey;
1174 IStream *stream;
1175 CLSID clsid;
1176 HANDLE thread;
1177 DWORD tid;
1178
1179 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
1180 ok(hr == CO_E_NOTINITIALIZED, "CoRegisterPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1181
1182 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1183
1184 hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
1185 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &dwRegistrationKey);
1186 ok_ole_success(hr, "CoRegisterClassObject");
1187
1188 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
1189 ok_ole_success(hr, "CoRegisterPSClsid");
1190
1191 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1192 ok_ole_success(hr, "CoGetPSClsid");
1193 ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
1194 wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
1195
1196 thread = CreateThread(NULL, 0, register_ps_clsid_thread, NULL, 0, &tid);
1197 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1198 ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
1199 CloseHandle(thread);
1200
1201 hr = CoGetPSClsid(&IID_TestPS, &clsid);
1202 ok_ole_success(hr, "CoGetPSClsid");
1203 ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
1204 wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
1205
1206 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1207 ok_ole_success(hr, "CreateStreamOnHGlobal");
1208
1209 SET_EXPECT(CreateStub);
1210 hr = CoMarshalInterface(stream, &IID_IWineTest, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1211 ok(hr == E_NOTIMPL, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1212 CHECK_CALLED(CreateStub);
1213
1214 hr = CoGetPSClsid(&IID_IEnumOLEVERB, &clsid);
1215 ok_ole_success(hr, "CoGetPSClsid");
1216
1217 hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (void **)&ps_factory_buffer);
1218 ok_ole_success(hr, "CoGetClassObject");
1219
1220 hr = CoRegisterPSClsid(&IID_IEnumOLEVERB, &CLSID_WineTestPSFactoryBuffer);
1221 ok_ole_success(hr, "CoRegisterPSClsid");
1222
1223 SET_EXPECT(CreateStub);
1224 hr = CoMarshalInterface(stream, &IID_IEnumOLEVERB, (IUnknown*)&EnumOLEVERB, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1225 ok(hr == S_OK, "CoMarshalInterface should have returned S_OK instead of 0x%08x\n", hr);
1226 CHECK_CALLED(CreateStub);
1227
1228 hr = CoMarshalInterface(stream, &IID_IEnumOLEVERB, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1229 ok(hr == S_OK, "CoMarshalInterface should have returned S_OK instead of 0x%08x\n", hr);
1230
1231 IStream_Release(stream);
1232 IPSFactoryBuffer_Release(ps_factory_buffer);
1233 ps_factory_buffer = NULL;
1234
1235 hr = CoRevokeClassObject(dwRegistrationKey);
1236 ok_ole_success(hr, "CoRevokeClassObject");
1237
1238 CoUninitialize();
1239
1240 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1241
1242 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1243 ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08x\n", hr);
1244
1245 hr = CoGetPSClsid(&IID_TestPS, &clsid);
1246 ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08x\n", hr);
1247
1248 CoUninitialize();
1249
1250 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1251
1252 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
1253 ok_ole_success(hr, "CoRegisterPSClsid");
1254
1255 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1256 ok_ole_success(hr, "CoGetPSClsid");
1257 ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
1258 wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
1259
1260 thread = CreateThread(NULL, 0, register_ps_clsid_thread, NULL, 0, &tid);
1261 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1262 ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
1263 CloseHandle(thread);
1264
1265 hr = CoGetPSClsid(&IID_TestPS, &clsid);
1266 ok_ole_success(hr, "CoGetPSClsid");
1267 ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
1268 wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
1269
1270 CoUninitialize();
1271 }
1272
1273 static void test_CoGetPSClsid(void)
1274 {
1275 ULONG_PTR cookie;
1276 HANDLE handle;
1277 HRESULT hr;
1278 CLSID clsid;
1279 HKEY hkey;
1280 LONG res;
1281 const BOOL is_win64 = (sizeof(void*) != sizeof(int));
1282 BOOL is_wow64 = FALSE;
1283
1284 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1285 ok(hr == CO_E_NOTINITIALIZED,
1286 "CoGetPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n",
1287 hr);
1288
1289 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1290
1291 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1292 ok_ole_success(hr, "CoGetPSClsid");
1293
1294 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1295 ok(hr == REGDB_E_IIDNOTREG,
1296 "CoGetPSClsid for random IID returned 0x%08x instead of REGDB_E_IIDNOTREG\n",
1297 hr);
1298
1299 hr = CoGetPSClsid(&IID_IClassFactory, NULL);
1300 ok(hr == E_INVALIDARG,
1301 "CoGetPSClsid for null clsid returned 0x%08x instead of E_INVALIDARG\n",
1302 hr);
1303
1304 if (!pRegOverridePredefKey)
1305 {
1306 win_skip("RegOverridePredefKey not available\n");
1307 CoUninitialize();
1308 return;
1309 }
1310 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1311 ok_ole_success(hr, "CoGetPSClsid");
1312
1313 res = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
1314 KEY_ALL_ACCESS, NULL, &hkey, NULL);
1315 ok(!res, "RegCreateKeyEx returned %d\n", res);
1316
1317 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, hkey);
1318 ok(!res, "RegOverridePredefKey returned %d\n", res);
1319
1320 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1321 ok_ole_success(hr, "CoGetPSClsid");
1322
1323 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
1324 ok(!res, "RegOverridePredefKey returned %d\n", res);
1325
1326 RegCloseKey(hkey);
1327
1328 /* not registered CLSID */
1329 hr = CoGetPSClsid(&IID_Testiface, &clsid);
1330 ok(hr == REGDB_E_IIDNOTREG, "got 0x%08x\n", hr);
1331
1332 if ((handle = activate_context(actctx_manifest, &cookie)))
1333 {
1334 memset(&clsid, 0, sizeof(clsid));
1335 hr = CoGetPSClsid(&IID_Testiface, &clsid);
1336 ok(hr == S_OK, "got 0x%08x\n", hr);
1337 ok(IsEqualGUID(&clsid, &IID_Testiface), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1338
1339 memset(&clsid, 0, sizeof(clsid));
1340 hr = CoGetPSClsid(&IID_Testiface2, &clsid);
1341 ok(hr == S_OK, "got 0x%08x\n", hr);
1342 ok(IsEqualGUID(&clsid, &IID_Testiface2), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1343
1344 memset(&clsid, 0, sizeof(clsid));
1345 hr = CoGetPSClsid(&IID_Testiface3, &clsid);
1346 ok(hr == S_OK, "got 0x%08x\n", hr);
1347 ok(IsEqualGUID(&clsid, &IID_TestPS), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1348
1349 memset(&clsid, 0xaa, sizeof(clsid));
1350 hr = CoGetPSClsid(&IID_Testiface4, &clsid);
1351 ok(hr == S_OK, "got 0x%08x\n", hr);
1352 ok(IsEqualGUID(&clsid, &GUID_NULL), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1353
1354 /* register same interface and try to get CLSID back */
1355 hr = CoRegisterPSClsid(&IID_Testiface, &IID_Testiface4);
1356 ok(hr == S_OK, "got 0x%08x\n", hr);
1357 memset(&clsid, 0, sizeof(clsid));
1358 hr = CoGetPSClsid(&IID_Testiface, &clsid);
1359 ok(hr == S_OK, "got 0x%08x\n", hr);
1360 ok(IsEqualGUID(&clsid, &IID_Testiface4), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1361
1362 pDeactivateActCtx(0, cookie);
1363 pReleaseActCtx(handle);
1364 }
1365
1366 if (pRegDeleteKeyExA &&
1367 (is_win64 ||
1368 (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
1369 {
1370 static GUID IID_DeadBeef = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
1371 static const char clsidDeadBeef[] = "{deadbeef-dead-beef-dead-beefdeadbeef}";
1372 static const char clsidA[] = "{66666666-8888-7777-6666-555555555555}";
1373 HKEY hkey_iface, hkey_psclsid;
1374 REGSAM opposite = is_win64 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
1375
1376 hr = CoGetPSClsid(&IID_DeadBeef, &clsid);
1377 ok(hr == REGDB_E_IIDNOTREG, "got 0x%08x\n", hr);
1378
1379 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, "Interface",
1380 0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, &hkey_iface, NULL);
1381 ok(!res, "RegCreateKeyEx returned %d\n", res);
1382 res = RegCreateKeyExA(hkey_iface, clsidDeadBeef,
1383 0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, &hkey, NULL);
1384 if (res == ERROR_ACCESS_DENIED)
1385 {
1386 win_skip("Failed to create a key, skipping some of CoGetPSClsid() tests\n");
1387 goto cleanup;
1388 }
1389
1390 ok(!res, "RegCreateKeyEx returned %d\n", res);
1391 res = RegCreateKeyExA(hkey, "ProxyStubClsid32",
1392 0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, &hkey_psclsid, NULL);
1393 ok(!res, "RegCreateKeyEx returned %d\n", res);
1394 res = RegSetValueExA(hkey_psclsid, NULL, 0, REG_SZ, (const BYTE *)clsidA, strlen(clsidA)+1);
1395 ok(!res, "RegSetValueEx returned %d\n", res);
1396 RegCloseKey(hkey_psclsid);
1397
1398 hr = CoGetPSClsid(&IID_DeadBeef, &clsid);
1399 ok_ole_success(hr, "CoGetPSClsid");
1400 ok(IsEqualGUID(&clsid, &IID_TestPS), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1401
1402 res = pRegDeleteKeyExA(hkey, "ProxyStubClsid32", opposite, 0);
1403 ok(!res, "RegDeleteKeyEx returned %d\n", res);
1404 RegCloseKey(hkey);
1405 res = pRegDeleteKeyExA(hkey_iface, clsidDeadBeef, opposite, 0);
1406 ok(!res, "RegDeleteKeyEx returned %d\n", res);
1407
1408 cleanup:
1409 RegCloseKey(hkey_iface);
1410 }
1411
1412 CoUninitialize();
1413 }
1414
1415 /* basic test, mainly for invalid arguments. see marshal.c for more */
1416 static void test_CoUnmarshalInterface(void)
1417 {
1418 IUnknown *pProxy;
1419 IStream *pStream;
1420 HRESULT hr;
1421
1422 hr = CoUnmarshalInterface(NULL, &IID_IUnknown, (void **)&pProxy);
1423 ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1424
1425 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1426 ok_ole_success(hr, "CreateStreamOnHGlobal");
1427
1428 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1429 todo_wine
1430 ok(hr == CO_E_NOTINITIALIZED, "CoUnmarshalInterface should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1431
1432 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1433
1434 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1435 ok(hr == STG_E_READFAULT, "CoUnmarshalInterface should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
1436
1437 CoUninitialize();
1438
1439 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, NULL);
1440 ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1441
1442 IStream_Release(pStream);
1443 }
1444
1445 static void test_CoGetInterfaceAndReleaseStream(void)
1446 {
1447 HRESULT hr;
1448 IUnknown *pUnk;
1449
1450 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1451
1452 hr = CoGetInterfaceAndReleaseStream(NULL, &IID_IUnknown, (void**)&pUnk);
1453 ok(hr == E_INVALIDARG, "hr %08x\n", hr);
1454
1455 CoUninitialize();
1456 }
1457
1458 /* basic test, mainly for invalid arguments. see marshal.c for more */
1459 static void test_CoMarshalInterface(void)
1460 {
1461 IStream *pStream;
1462 HRESULT hr;
1463 static const LARGE_INTEGER llZero;
1464
1465 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1466
1467 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1468 ok_ole_success(hr, "CreateStreamOnHGlobal");
1469
1470 hr = CoMarshalInterface(pStream, &IID_IUnknown, NULL, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1471 ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1472
1473 hr = CoMarshalInterface(NULL, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1474 ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1475
1476 hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1477 ok_ole_success(hr, "CoMarshalInterface");
1478
1479 /* stream not rewound */
1480 hr = CoReleaseMarshalData(pStream);
1481 ok(hr == STG_E_READFAULT, "CoReleaseMarshalData should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
1482
1483 hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1484 ok_ole_success(hr, "IStream_Seek");
1485
1486 hr = CoReleaseMarshalData(pStream);
1487 ok_ole_success(hr, "CoReleaseMarshalData");
1488
1489 IStream_Release(pStream);
1490
1491 CoUninitialize();
1492 }
1493
1494 static void test_CoMarshalInterThreadInterfaceInStream(void)
1495 {
1496 IStream *pStream;
1497 HRESULT hr;
1498 IClassFactory *pProxy;
1499
1500 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1501
1502 cLocks = 0;
1503
1504 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, NULL);
1505 ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1506
1507 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, NULL, &pStream);
1508 ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1509
1510 ok_no_locks();
1511
1512 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, &pStream);
1513 ok_ole_success(hr, "CoMarshalInterThreadInterfaceInStream");
1514
1515 ok_more_than_one_lock();
1516
1517 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1518 ok_ole_success(hr, "CoUnmarshalInterface");
1519
1520 IClassFactory_Release(pProxy);
1521 IStream_Release(pStream);
1522
1523 ok_no_locks();
1524
1525 CoUninitialize();
1526 }
1527
1528 static void test_CoRegisterClassObject(void)
1529 {
1530 ULONG_PTR ctxcookie;
1531 HANDLE handle;
1532 DWORD cookie;
1533 HRESULT hr;
1534 IClassFactory *pcf;
1535
1536 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1537
1538 /* CLSCTX_INPROC_SERVER */
1539 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1540 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1541 ok_ole_success(hr, "CoRegisterClassObject");
1542 hr = CoRevokeClassObject(cookie);
1543 ok_ole_success(hr, "CoRevokeClassObject");
1544
1545 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1546 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1547 ok_ole_success(hr, "CoRegisterClassObject");
1548 hr = CoRevokeClassObject(cookie);
1549 ok_ole_success(hr, "CoRevokeClassObject");
1550
1551 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1552 CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
1553 ok_ole_success(hr, "CoRegisterClassObject");
1554 hr = CoRevokeClassObject(cookie);
1555 ok_ole_success(hr, "CoRevokeClassObject");
1556
1557 /* CLSCTX_LOCAL_SERVER */
1558 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1559 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
1560 ok_ole_success(hr, "CoRegisterClassObject");
1561 hr = CoRevokeClassObject(cookie);
1562 ok_ole_success(hr, "CoRevokeClassObject");
1563
1564 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1565 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1566 ok_ole_success(hr, "CoRegisterClassObject");
1567 hr = CoRevokeClassObject(cookie);
1568 ok_ole_success(hr, "CoRevokeClassObject");
1569
1570 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1571 CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
1572 ok_ole_success(hr, "CoRegisterClassObject");
1573 hr = CoRevokeClassObject(cookie);
1574 ok_ole_success(hr, "CoRevokeClassObject");
1575
1576 /* CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER */
1577 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1578 CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
1579 ok_ole_success(hr, "CoRegisterClassObject");
1580 hr = CoRevokeClassObject(cookie);
1581 ok_ole_success(hr, "CoRevokeClassObject");
1582
1583 /* test whether an object that doesn't support IClassFactory can be
1584 * registered for CLSCTX_LOCAL_SERVER */
1585 hr = CoRegisterClassObject(&CLSID_WineOOPTest, &Test_Unknown,
1586 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
1587 ok_ole_success(hr, "CoRegisterClassObject");
1588 hr = CoRevokeClassObject(cookie);
1589 ok_ole_success(hr, "CoRevokeClassObject");
1590
1591 /* test whether registered class becomes invalid when apartment is destroyed */
1592 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1593 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1594 ok_ole_success(hr, "CoRegisterClassObject");
1595
1596 CoUninitialize();
1597 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1598
1599 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL,
1600 &IID_IClassFactory, (void **)&pcf);
1601 ok(hr == REGDB_E_CLASSNOTREG, "object registered in an apartment shouldn't accessible after it is destroyed\n");
1602
1603 /* crashes with at least win9x DCOM! */
1604 if (0)
1605 CoRevokeClassObject(cookie);
1606
1607 /* test that object is accessible */
1608 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory, CLSCTX_INPROC_SERVER,
1609 REGCLS_MULTIPLEUSE, &cookie);
1610 ok(hr == S_OK, "got 0x%08x\n", hr);
1611
1612 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
1613 ok(hr == S_OK, "got 0x%08x\n", hr);
1614 IClassFactory_Release(pcf);
1615
1616 /* context now contains CLSID_WineOOPTest, test if registered one could still be used */
1617 if ((handle = activate_context(actctx_manifest, &ctxcookie)))
1618 {
1619 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
1620 todo_wine
1621 ok(hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), "got 0x%08x\n", hr);
1622
1623 pDeactivateActCtx(0, ctxcookie);
1624 pReleaseActCtx(handle);
1625 }
1626
1627 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
1628 ok(hr == S_OK, "got 0x%08x\n", hr);
1629 IClassFactory_Release(pcf);
1630
1631 hr = CoRevokeClassObject(cookie);
1632 ok(hr == S_OK, "got 0x%08x\n", hr);
1633
1634 CoUninitialize();
1635 }
1636
1637 static HRESULT get_class_object(CLSCTX clsctx)
1638 {
1639 HRESULT hr;
1640 IClassFactory *pcf;
1641
1642 hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
1643 (void **)&pcf);
1644
1645 if (SUCCEEDED(hr))
1646 IClassFactory_Release(pcf);
1647
1648 return hr;
1649 }
1650
1651 static DWORD CALLBACK get_class_object_thread(LPVOID pv)
1652 {
1653 CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
1654 HRESULT hr;
1655
1656 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1657
1658 hr = get_class_object(clsctx);
1659
1660 CoUninitialize();
1661
1662 return hr;
1663 }
1664
1665 static DWORD CALLBACK get_class_object_proxy_thread(LPVOID pv)
1666 {
1667 CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
1668 HRESULT hr;
1669 IClassFactory *pcf;
1670 IMultiQI *pMQI;
1671
1672 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1673
1674 hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
1675 (void **)&pcf);
1676
1677 if (SUCCEEDED(hr))
1678 {
1679 hr = IClassFactory_QueryInterface(pcf, &IID_IMultiQI, (void **)&pMQI);
1680 if (SUCCEEDED(hr))
1681 IMultiQI_Release(pMQI);
1682 IClassFactory_Release(pcf);
1683 }
1684
1685 CoUninitialize();
1686
1687 return hr;
1688 }
1689
1690 static DWORD CALLBACK register_class_object_thread(LPVOID pv)
1691 {
1692 HRESULT hr;
1693 DWORD cookie;
1694
1695 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1696
1697 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1698 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1699
1700 CoUninitialize();
1701
1702 return hr;
1703 }
1704
1705 static DWORD CALLBACK revoke_class_object_thread(LPVOID pv)
1706 {
1707 DWORD cookie = (DWORD_PTR)pv;
1708 HRESULT hr;
1709
1710 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1711
1712 hr = CoRevokeClassObject(cookie);
1713
1714 CoUninitialize();
1715
1716 return hr;
1717 }
1718
1719 static void test_registered_object_thread_affinity(void)
1720 {
1721 HRESULT hr;
1722 DWORD cookie;
1723 HANDLE thread;
1724 DWORD tid;
1725 DWORD exitcode;
1726
1727 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1728
1729 /* CLSCTX_INPROC_SERVER */
1730
1731 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1732 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1733 ok_ole_success(hr, "CoRegisterClassObject");
1734
1735 thread = CreateThread(NULL, 0, get_class_object_thread, (LPVOID)CLSCTX_INPROC_SERVER, 0, &tid);
1736 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1737 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1738 GetExitCodeThread(thread, &exitcode);
1739 hr = exitcode;
1740 ok(hr == REGDB_E_CLASSNOTREG, "CoGetClassObject on inproc object "
1741 "registered in different thread should return REGDB_E_CLASSNOTREG "
1742 "instead of 0x%08x\n", hr);
1743
1744 hr = get_class_object(CLSCTX_INPROC_SERVER);
1745 ok(hr == S_OK, "CoGetClassObject on inproc object registered in same "
1746 "thread should return S_OK instead of 0x%08x\n", hr);
1747
1748 thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
1749 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1750 ok ( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1751 GetExitCodeThread(thread, &exitcode);
1752 hr = exitcode;
1753 ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different thread should return S_OK instead of 0x%08x\n", hr);
1754
1755 hr = CoRevokeClassObject(cookie);
1756 ok_ole_success(hr, "CoRevokeClassObject");
1757
1758 /* CLSCTX_LOCAL_SERVER */
1759
1760 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1761 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1762 ok_ole_success(hr, "CoRegisterClassObject");
1763
1764 thread = CreateThread(NULL, 0, get_class_object_proxy_thread, (LPVOID)CLSCTX_LOCAL_SERVER, 0, &tid);
1765 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1766 while (MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)
1767 {
1768 MSG msg;
1769 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
1770 {
1771 TranslateMessage(&msg);
1772 DispatchMessageA(&msg);
1773 }
1774 }
1775 GetExitCodeThread(thread, &exitcode);
1776 hr = exitcode;
1777 ok(hr == S_OK, "CoGetClassObject on local server object "
1778 "registered in different thread should return S_OK "
1779 "instead of 0x%08x\n", hr);
1780
1781 hr = get_class_object(CLSCTX_LOCAL_SERVER);
1782 ok(hr == S_OK, "CoGetClassObject on local server object registered in same "
1783 "thread should return S_OK instead of 0x%08x\n", hr);
1784
1785 thread = CreateThread(NULL, 0, revoke_class_object_thread, (LPVOID)(DWORD_PTR)cookie, 0, &tid);
1786 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1787 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1788 GetExitCodeThread(thread, &exitcode);
1789 hr = exitcode;
1790 ok(hr == RPC_E_WRONG_THREAD || broken(hr == S_OK) /* win8 */, "CoRevokeClassObject called from different "
1791 "thread to where registered should return RPC_E_WRONG_THREAD instead of 0x%08x\n", hr);
1792
1793 thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
1794 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1795 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1796 GetExitCodeThread(thread, &exitcode);
1797 hr = exitcode;
1798 ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different "
1799 "thread should return S_OK instead of 0x%08x\n", hr);
1800
1801 hr = CoRevokeClassObject(cookie);
1802 ok_ole_success(hr, "CoRevokeClassObject");
1803
1804 CoUninitialize();
1805 }
1806
1807 static DWORD CALLBACK free_libraries_thread(LPVOID p)
1808 {
1809 CoFreeUnusedLibraries();
1810 return 0;
1811 }
1812
1813 static inline BOOL is_module_loaded(const char *module)
1814 {
1815 return GetModuleHandleA(module) != 0;
1816 }
1817
1818 static void test_CoFreeUnusedLibraries(void)
1819 {
1820 HRESULT hr;
1821 IUnknown *pUnk;
1822 DWORD tid;
1823 HANDLE thread;
1824
1825 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1826
1827 ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1828
1829 hr = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pUnk);
1830 if (hr == REGDB_E_CLASSNOTREG)
1831 {
1832 skip("IE not installed so can't run CoFreeUnusedLibraries test\n");
1833 CoUninitialize();
1834 return;
1835 }
1836 ok_ole_success(hr, "CoCreateInstance");
1837
1838 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1839
1840 ok(pUnk != NULL ||
1841 broken(pUnk == NULL), /* win9x */
1842 "Expected a valid pointer\n");
1843 if (pUnk)
1844 IUnknown_Release(pUnk);
1845
1846 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1847
1848 thread = CreateThread(NULL, 0, free_libraries_thread, NULL, 0, &tid);
1849 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1850 CloseHandle(thread);
1851
1852 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1853
1854 CoFreeUnusedLibraries();
1855
1856 ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1857
1858 CoUninitialize();
1859 }
1860
1861 static void test_CoGetObjectContext(void)
1862 {
1863 HRESULT hr;
1864 ULONG refs;
1865 IComThreadingInfo *pComThreadingInfo, *threadinginfo2;
1866 IContextCallback *pContextCallback;
1867 IObjContext *pObjContext;
1868 APTTYPE apttype;
1869 THDTYPE thdtype;
1870 struct info info;
1871 HANDLE thread;
1872 DWORD tid, exitcode;
1873 GUID id, id2;
1874
1875 if (!pCoGetObjectContext)
1876 {
1877 win_skip("CoGetObjectContext not present\n");
1878 return;
1879 }
1880
1881 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1882 ok(hr == CO_E_NOTINITIALIZED, "CoGetObjectContext should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1883 ok(pComThreadingInfo == NULL, "pComThreadingInfo should have been set to NULL\n");
1884
1885 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
1886 thread has already done so */
1887
1888 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
1889
1890 info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
1891 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
1892
1893 info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
1894 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
1895
1896 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
1897 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1898
1899 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
1900
1901 test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
1902
1903 pComThreadingInfo = NULL;
1904 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1905 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1906
1907 threadinginfo2 = NULL;
1908 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&threadinginfo2);
1909 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1910 ok(pComThreadingInfo == threadinginfo2, "got different instance\n");
1911 IComThreadingInfo_Release(threadinginfo2);
1912
1913 hr = IComThreadingInfo_GetCurrentLogicalThreadId(pComThreadingInfo, NULL);
1914 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1915
1916 id = id2 = GUID_NULL;
1917 hr = IComThreadingInfo_GetCurrentLogicalThreadId(pComThreadingInfo, &id);
1918 ok(hr == S_OK, "got 0x%08x\n", hr);
1919
1920 hr = CoGetCurrentLogicalThreadId(&id2);
1921 ok(IsEqualGUID(&id, &id2), "got %s, expected %s\n", wine_dbgstr_guid(&id), wine_dbgstr_guid(&id2));
1922
1923 IComThreadingInfo_Release(pComThreadingInfo);
1924
1925 SetEvent(info.stop);
1926 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1927
1928 GetExitCodeThread(thread, &exitcode);
1929 hr = exitcode;
1930 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
1931
1932 CloseHandle(thread);
1933 CloseHandle(info.wait);
1934 CloseHandle(info.stop);
1935
1936 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
1937
1938 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1939
1940 test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
1941
1942 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1943 ok_ole_success(hr, "CoGetObjectContext");
1944
1945 hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1946 ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1947 ok(apttype == APTTYPE_MAINSTA, "apartment type should be APTTYPE_MAINSTA instead of %d\n", apttype);
1948
1949 hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1950 ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1951 ok(thdtype == THDTYPE_PROCESSMESSAGES, "thread type should be THDTYPE_PROCESSMESSAGES instead of %d\n", thdtype);
1952
1953 refs = IComThreadingInfo_Release(pComThreadingInfo);
1954 ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1955
1956 hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1957 ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1958
1959 refs = IContextCallback_Release(pContextCallback);
1960 ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1961
1962 CoUninitialize();
1963
1964 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1965
1966 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1967 ok_ole_success(hr, "CoGetObjectContext");
1968
1969 hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1970 ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1971 ok(apttype == APTTYPE_MTA, "apartment type should be APTTYPE_MTA instead of %d\n", apttype);
1972
1973 hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1974 ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1975 ok(thdtype == THDTYPE_BLOCKMESSAGES, "thread type should be THDTYPE_BLOCKMESSAGES instead of %d\n", thdtype);
1976
1977 refs = IComThreadingInfo_Release(pComThreadingInfo);
1978 ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1979
1980 hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1981 ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1982
1983 refs = IContextCallback_Release(pContextCallback);
1984 ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1985
1986 hr = pCoGetObjectContext(&IID_IObjContext, (void **)&pObjContext);
1987 ok_ole_success(hr, "CoGetObjectContext");
1988
1989 refs = IObjContext_Release(pObjContext);
1990 ok(refs == 0, "pObjContext should have 0 refs instead of %d refs\n", refs);
1991
1992 CoUninitialize();
1993 }
1994
1995 typedef struct {
1996 IUnknown IUnknown_iface;
1997 LONG refs;
1998 } Test_CallContext;
1999
2000 static inline Test_CallContext *impl_from_IUnknown(IUnknown *iface)
2001 {
2002 return CONTAINING_RECORD(iface, Test_CallContext, IUnknown_iface);
2003 }
2004
2005 static HRESULT WINAPI Test_CallContext_QueryInterface(
2006 IUnknown *iface,
2007 REFIID riid,
2008 LPVOID *ppvObj)
2009 {
2010 if (ppvObj == NULL) return E_POINTER;
2011
2012 if (IsEqualGUID(riid, &IID_IUnknown))
2013 {
2014 *ppvObj = iface;
2015 IUnknown_AddRef(iface);
2016 return S_OK;
2017 }
2018
2019 *ppvObj = NULL;
2020 return E_NOINTERFACE;
2021 }
2022
2023 static ULONG WINAPI Test_CallContext_AddRef(IUnknown *iface)
2024 {
2025 Test_CallContext *This = impl_from_IUnknown(iface);
2026 return InterlockedIncrement(&This->refs);
2027 }
2028
2029 static ULONG WINAPI Test_CallContext_Release(IUnknown *iface)
2030 {
2031 Test_CallContext *This = impl_from_IUnknown(iface);
2032 ULONG refs = InterlockedDecrement(&This->refs);
2033 if (!refs)
2034 HeapFree(GetProcessHeap(), 0, This);
2035 return refs;
2036 }
2037
2038 static const IUnknownVtbl TestCallContext_Vtbl =
2039 {
2040 Test_CallContext_QueryInterface,
2041 Test_CallContext_AddRef,
2042 Test_CallContext_Release
2043 };
2044
2045 static void test_CoGetCallContext(void)
2046 {
2047 HRESULT hr;
2048 ULONG refs;
2049 IUnknown *pUnk;
2050 Test_CallContext *test_object;
2051
2052 if (!pCoSwitchCallContext)
2053 {
2054 skip("CoSwitchCallContext not present\n");
2055 return;
2056 }
2057
2058 CoInitialize(NULL);
2059
2060 test_object = HeapAlloc(GetProcessHeap(), 0, sizeof(Test_CallContext));
2061 test_object->IUnknown_iface.lpVtbl = &TestCallContext_Vtbl;
2062 test_object->refs = 1;
2063
2064 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
2065 ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
2066
2067 pUnk = (IUnknown*)0xdeadbeef;
2068 hr = pCoSwitchCallContext(&test_object->IUnknown_iface, &pUnk);
2069 ok_ole_success(hr, "CoSwitchCallContext");
2070 ok(pUnk == NULL, "expected NULL, got %p\n", pUnk);
2071 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
2072 ok(refs == 2, "Expected refcount 2, got %d\n", refs);
2073 IUnknown_Release(&test_object->IUnknown_iface);
2074
2075 pUnk = (IUnknown*)0xdeadbeef;
2076 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
2077 ok_ole_success(hr, "CoGetCallContext");
2078 ok(pUnk == &test_object->IUnknown_iface, "expected %p, got %p\n",
2079 &test_object->IUnknown_iface, pUnk);
2080 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
2081 ok(refs == 3, "Expected refcount 3, got %d\n", refs);
2082 IUnknown_Release(&test_object->IUnknown_iface);
2083 IUnknown_Release(pUnk);
2084
2085 pUnk = (IUnknown*)0xdeadbeef;
2086 hr = pCoSwitchCallContext(NULL, &pUnk);
2087 ok_ole_success(hr, "CoSwitchCallContext");
2088 ok(pUnk == &test_object->IUnknown_iface, "expected %p, got %p\n",
2089 &test_object->IUnknown_iface, pUnk);
2090 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
2091 ok(refs == 2, "Expected refcount 2, got %d\n", refs);
2092 IUnknown_Release(&test_object->IUnknown_iface);
2093
2094 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
2095 ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
2096
2097 IUnknown_Release(&test_object->IUnknown_iface);
2098
2099 CoUninitialize();
2100 }
2101
2102 static void test_CoGetContextToken(void)
2103 {
2104 HRESULT hr;
2105 ULONG refs;
2106 ULONG_PTR token, token2;
2107 IObjContext *ctx;
2108 struct info info;
2109 HANDLE thread;
2110 DWORD tid, exitcode;
2111
2112 if (!pCoGetContextToken)
2113 {
2114 win_skip("CoGetContextToken not present\n");
2115 return;
2116 }
2117
2118 token = 0xdeadbeef;
2119 hr = pCoGetContextToken(&token);
2120 ok(hr == CO_E_NOTINITIALIZED, "Expected CO_E_NOTINITIALIZED, got 0x%08x\n", hr);
2121 ok(token == 0xdeadbeef, "Expected 0, got 0x%lx\n", token);
2122
2123 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
2124 thread has already done so */
2125
2126 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
2127
2128 info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
2129 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
2130
2131 info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
2132 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
2133
2134 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
2135 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
2136
2137 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
2138
2139 test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
2140
2141 token = 0;
2142 hr = pCoGetContextToken(&token);
2143 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
2144
2145 token2 = 0;
2146 hr = pCoGetContextToken(&token2);
2147 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
2148 ok(token == token2, "got different token\n");
2149
2150 SetEvent(info.stop);
2151 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2152
2153 GetExitCodeThread(thread, &exitcode);
2154 hr = exitcode;
2155 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
2156
2157 CloseHandle(thread);
2158 CloseHandle(info.wait);
2159 CloseHandle(info.stop);
2160
2161 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
2162
2163 CoInitialize(NULL);
2164
2165 test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
2166
2167 hr = pCoGetContextToken(NULL);
2168 ok(hr == E_POINTER, "Expected E_POINTER, got 0x%08x\n", hr);
2169
2170 token = 0;
2171 hr = pCoGetContextToken(&token);
2172 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
2173 ok(token, "Expected token != 0\n");
2174
2175 token2 = 0;
2176 hr = pCoGetContextToken(&token2);
2177 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
2178 ok(token2 == token, "got different token\n");
2179
2180 refs = IUnknown_AddRef((IUnknown *)token);
2181 ok(refs == 1, "Expected 1, got %u\n", refs);
2182
2183 hr = pCoGetObjectContext(&IID_IObjContext, (void **)&ctx);
2184 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
2185 ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
2186
2187 refs = IObjContext_AddRef(ctx);
2188 ok(refs == 3, "Expected 3, got %u\n", refs);
2189
2190 refs = IObjContext_Release(ctx);
2191 ok(refs == 2, "Expected 2, got %u\n", refs);
2192
2193 refs = IUnknown_Release((IUnknown *)token);
2194 ok(refs == 1, "Expected 1, got %u\n", refs);
2195
2196 /* CoGetContextToken does not add a reference */
2197 token = 0;
2198 hr = pCoGetContextToken(&token);
2199 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
2200 ok(token, "Expected token != 0\n");
2201 ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
2202
2203 refs = IObjContext_AddRef(ctx);
2204 ok(refs == 2, "Expected 1, got %u\n", refs);
2205
2206 refs = IObjContext_Release(ctx);
2207 ok(refs == 1, "Expected 0, got %u\n", refs);
2208
2209 refs = IObjContext_Release(ctx);
2210 ok(refs == 0, "Expected 0, got %u\n", refs);
2211
2212 CoUninitialize();
2213 }
2214
2215 static void test_TreatAsClass(void)
2216 {
2217 HRESULT hr;
2218 CLSID out;
2219 static GUID deadbeef = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
2220 static const char deadbeefA[] = "{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF}";
2221 IInternetProtocol *pIP = NULL;
2222 HKEY clsidkey, deadbeefkey;
2223 LONG lr;
2224
2225 if (!pCoGetTreatAsClass)
2226 {
2227 win_skip("CoGetTreatAsClass not present\n");
2228 return;
2229 }
2230
2231 hr = pCoGetTreatAsClass(&deadbeef,&out);
2232 ok (hr == S_FALSE, "expected S_FALSE got %x\n",hr);
2233 ok (IsEqualGUID(&out,&deadbeef), "expected to get same clsid back\n");
2234
2235 hr = pCoGetTreatAsClass(NULL, &out);
2236 ok(hr == E_INVALIDARG, "expected E_INVALIDARG got %08x\n", hr);
2237 ok(IsEqualGUID(&out, &deadbeef), "expected no change to the clsid\n");
2238
2239 hr = pCoGetTreatAsClass(&deadbeef, NULL);
2240 ok(hr == E_INVALIDARG, "expected E_INVALIDARG got %08x\n", hr);
2241
2242 lr = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &clsidkey);
2243 ok(!lr, "Couldn't open CLSID key, error %d\n", lr);
2244
2245 lr = RegCreateKeyExA(clsidkey, deadbeefA, 0, NULL, 0, KEY_WRITE, NULL, &deadbeefkey, NULL);
2246 if (lr) {
2247 win_skip("CoGetTreatAsClass() tests will be skipped (failed to create a test key, error %d)\n", lr);
2248 RegCloseKey(clsidkey);
2249 return;
2250 }
2251
2252 hr = pCoTreatAsClass(&deadbeef, &deadbeef);
2253 ok(hr == REGDB_E_WRITEREGDB, "CoTreatAsClass gave wrong error: %08x\n", hr);
2254
2255 hr = pCoTreatAsClass(&deadbeef, &CLSID_FileProtocol);
2256 if(hr == REGDB_E_WRITEREGDB){
2257 win_skip("Insufficient privileges to use CoTreatAsClass\n");
2258 goto exit;
2259 }
2260 ok(hr == S_OK, "CoTreatAsClass failed: %08x\n", hr);
2261
2262 hr = pCoGetTreatAsClass(&deadbeef, &out);
2263 ok(hr == S_OK, "CoGetTreatAsClass failed: %08x\n",hr);
2264 ok(IsEqualGUID(&out, &CLSID_FileProtocol), "expected to get substituted clsid\n");
2265
2266 OleInitialize(NULL);
2267
2268 hr = CoCreateInstance(&deadbeef, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pIP);
2269 if(hr == REGDB_E_CLASSNOTREG)
2270 {
2271 win_skip("IE not installed so can't test CoCreateInstance\n");
2272 goto exit;
2273 }
2274
2275 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
2276 if(pIP){
2277 IInternetProtocol_Release(pIP);
2278 pIP = NULL;
2279 }
2280
2281 hr = pCoTreatAsClass(&deadbeef, &CLSID_NULL);
2282 ok(hr == S_OK, "CoTreatAsClass failed: %08x\n", hr);
2283
2284 hr = pCoGetTreatAsClass(&deadbeef, &out);
2285 ok(hr == S_FALSE, "expected S_FALSE got %08x\n", hr);
2286 ok(IsEqualGUID(&out, &deadbeef), "expected to get same clsid back\n");
2287
2288 /* bizarrely, native's CoTreatAsClass takes some time to take effect in CoCreateInstance */
2289 Sleep(200);
2290
2291 hr = CoCreateInstance(&deadbeef, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pIP);
2292 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance gave wrong error: %08x\n", hr);
2293
2294 if(pIP)
2295 IInternetProtocol_Release(pIP);
2296
2297 exit:
2298 OleUninitialize();
2299 RegCloseKey(deadbeefkey);
2300 RegDeleteKeyA(clsidkey, deadbeefA);
2301 RegCloseKey(clsidkey);
2302 }
2303
2304 static void test_CoInitializeEx(void)
2305 {
2306 HRESULT hr;
2307
2308 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2309 ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
2310
2311 /* Calling OleInitialize for the first time should yield S_OK even with
2312 * apartment already initialized by previous CoInitialize(Ex) calls. */
2313 hr = OleInitialize(NULL);
2314 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
2315
2316 /* Subsequent calls to OleInitialize should return S_FALSE */
2317 hr = OleInitialize(NULL);
2318 ok(hr == S_FALSE, "Expected S_FALSE, hr = 0x%08x\n", hr);
2319
2320 /* Cleanup */
2321 CoUninitialize();
2322 OleUninitialize();
2323 OleUninitialize();
2324 }
2325
2326 static void test_OleInitialize_InitCounting(void)
2327 {
2328 HRESULT hr;
2329 IUnknown *pUnk;
2330 REFCLSID rclsid = &CLSID_InternetZoneManager;
2331
2332 /* 1. OleInitialize fails but OleUninitialize is still called: apartment stays initialized */
2333 hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
2334 ok(hr == S_OK, "CoInitializeEx(COINIT_MULTITHREADED) failed with error 0x%08x\n", hr);
2335
2336 hr = OleInitialize(NULL);
2337 ok(hr == RPC_E_CHANGED_MODE, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", RPC_E_CHANGED_MODE, hr);
2338 OleUninitialize();
2339
2340 pUnk = (IUnknown *)0xdeadbeef;
2341 hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
2342 ok(hr == S_OK, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
2343 if (pUnk) IUnknown_Release(pUnk);
2344
2345 CoUninitialize();
2346
2347 /* 2. Extra multiple OleUninitialize: apartment stays initialized until CoUninitialize */
2348 hr = CoInitialize(NULL);
2349 ok(hr == S_OK, "CoInitialize() failed with error 0x%08x\n", hr);
2350
2351 hr = OleInitialize(NULL);
2352 ok(hr == S_OK, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
2353 OleUninitialize();
2354 OleUninitialize();
2355 OleUninitialize();
2356
2357 pUnk = (IUnknown *)0xdeadbeef;
2358 hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
2359 ok(hr == S_OK, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
2360 if (pUnk) IUnknown_Release(pUnk);
2361
2362 CoUninitialize();
2363
2364 pUnk = (IUnknown *)0xdeadbeef;
2365 hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
2366 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", CO_E_NOTINITIALIZED, hr);
2367 if (pUnk) IUnknown_Release(pUnk);
2368
2369 /* 3. CoUninitialize does not formally deinit Ole */
2370 hr = CoInitialize(NULL);
2371 ok(hr == S_OK, "CoInitialize() failed with error 0x%08x\n", hr);
2372
2373 hr = OleInitialize(NULL);
2374 ok(hr == S_OK, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
2375
2376 CoUninitialize();
2377 CoUninitialize();
2378
2379 pUnk = (IUnknown *)0xdeadbeef;
2380 hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
2381 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", CO_E_NOTINITIALIZED, hr);
2382 /* COM is not initialized anymore */
2383 if (pUnk) IUnknown_Release(pUnk);
2384
2385 hr = OleInitialize(NULL);
2386 ok(hr == S_FALSE, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", S_FALSE, hr);
2387 /* ... but native OleInit returns S_FALSE as if Ole is considered initialized */
2388
2389 OleUninitialize();
2390
2391 }
2392
2393 static void test_OleRegGetMiscStatus(void)
2394 {
2395 ULONG_PTR cookie;
2396 HANDLE handle;
2397 DWORD status;
2398 HRESULT hr;
2399
2400 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_ICON, NULL);
2401 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2402
2403 status = 0xdeadbeef;
2404 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_ICON, &status);
2405 ok(hr == REGDB_E_CLASSNOTREG, "got 0x%08x\n", hr);
2406 ok(status == 0, "got 0x%08x\n", status);
2407
2408 status = -1;
2409 hr = OleRegGetMiscStatus(&CLSID_StdFont, DVASPECT_ICON, &status);
2410 ok(hr == S_OK, "got 0x%08x\n", hr);
2411 ok(status == 0, "got 0x%08x\n", status);
2412
2413 if ((handle = activate_context(actctx_manifest, &cookie)))
2414 {
2415 status = 0;
2416 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_ICON, &status);
2417 ok(hr == S_OK, "got 0x%08x\n", hr);
2418 ok(status == OLEMISC_RECOMPOSEONRESIZE, "got 0x%08x\n", status);
2419
2420 /* context data takes precedence over registration info */
2421 status = 0;
2422 hr = OleRegGetMiscStatus(&CLSID_StdFont, DVASPECT_ICON, &status);
2423 ok(hr == S_OK, "got 0x%08x\n", hr);
2424 ok(status == OLEMISC_RECOMPOSEONRESIZE, "got 0x%08x\n", status);
2425
2426 /* there's no such attribute in context */
2427 status = -1;
2428 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_DOCPRINT, &status);
2429 ok(hr == S_OK, "got 0x%08x\n", hr);
2430 ok(status == 0, "got 0x%08x\n", status);
2431
2432 pDeactivateActCtx(0, cookie);
2433 pReleaseActCtx(handle);
2434 }
2435 }
2436
2437 static void test_OleRegGetUserType(void)
2438 {
2439 static const WCHAR stdfont_usertypeW[] = {'S','t','a','n','d','a','r','d',' ','F','o','n','t',0};
2440 static const WCHAR stdfont2_usertypeW[] = {'C','L','S','I','D','_','S','t','d','F','o','n','t',0};
2441 static const WCHAR clsidkeyW[] = {'C','L','S','I','D',0};
2442 static const WCHAR defvalueW[] = {'D','e','f','a','u','l','t',' ','N','a','m','e',0};
2443 static const WCHAR auxvalue0W[] = {'A','u','x',' ','N','a','m','e',' ','0',0};
2444 static const WCHAR auxvalue2W[] = {'A','u','x',' ','N','a','m','e',' ','2',0};
2445 static const WCHAR auxvalue3W[] = {'A','u','x',' ','N','a','m','e',' ','3',0};
2446 static const WCHAR auxvalue4W[] = {'A','u','x',' ','N','a','m','e',' ','4',0};
2447
2448 static const char auxvalues[][16] = {
2449 "Aux Name 0",
2450 "Aux Name 1",
2451 "Aux Name 2",
2452 "Aux Name 3",
2453 "Aux Name 4"
2454 };
2455
2456 HKEY clsidhkey, hkey, auxhkey, classkey;
2457 DWORD form, ret, disposition;
2458 WCHAR clsidW[39];
2459 ULONG_PTR cookie;
2460 HANDLE handle;
2461 HRESULT hr;
2462 WCHAR *str;
2463 int i;
2464
2465 for (form = 0; form <= USERCLASSTYPE_APPNAME+1; form++) {
2466 hr = OleRegGetUserType(&CLSID_Testclass, form, NULL);
2467 ok(hr == E_INVALIDARG, "form %u: got 0x%08x\n", form, hr);
2468
2469 str = (void*)0xdeadbeef;
2470 hr = OleRegGetUserType(&CLSID_Testclass, form, &str);
2471 ok(hr == REGDB_E_CLASSNOTREG, "form %u: got 0x%08x\n", form, hr);
2472 ok(str == NULL, "form %u: got %p\n", form, str);
2473
2474 /* same string returned for StdFont for all form types */
2475 str = NULL;
2476 hr = OleRegGetUserType(&CLSID_StdFont, form, &str);
2477 ok(hr == S_OK, "form %u: got 0x%08x\n", form, hr);
2478 ok(!lstrcmpW(str, stdfont_usertypeW) || !lstrcmpW(str, stdfont2_usertypeW) /* winxp */,
2479 "form %u, got %s\n", form, wine_dbgstr_w(str));
2480 CoTaskMemFree(str);
2481 }
2482
2483 if ((handle = activate_context(actctx_manifest, &cookie)))
2484 {
2485 for (form = 0; form <= USERCLASSTYPE_APPNAME+1; form++) {
2486 str = (void*)0xdeadbeef;
2487 hr = OleRegGetUserType(&CLSID_Testclass, form, &str);
2488 ok(hr == REGDB_E_CLASSNOTREG, "form %u: got 0x%08x\n", form, hr);
2489 ok(str == NULL, "form %u: got %s\n", form, wine_dbgstr_w(str));
2490
2491 /* same string returned for StdFont for all form types */
2492 str = NULL;
2493 hr = OleRegGetUserType(&CLSID_StdFont, form, &str);
2494 ok(hr == S_OK, "form %u: got 0x%08x\n", form, hr);
2495 ok(!lstrcmpW(str, stdfont_usertypeW) || !lstrcmpW(str, stdfont2_usertypeW) /* winxp */,
2496 "form %u, got %s\n", form, wine_dbgstr_w(str));
2497 CoTaskMemFree(str);
2498 }
2499
2500 pDeactivateActCtx(0, cookie);
2501 pReleaseActCtx(handle);
2502 }
2503
2504 /* test using registered CLSID */
2505 StringFromGUID2(&CLSID_non_existent, clsidW, sizeof(clsidW)/sizeof(clsidW[0]));
2506
2507 ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsidkeyW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &clsidhkey, &disposition);
2508 if (!ret)
2509 {
2510 ret = RegCreateKeyExW(clsidhkey, clsidW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &classkey, NULL);
2511 if (ret)
2512 RegCloseKey(clsidhkey);
2513 }
2514
2515 if (ret == ERROR_ACCESS_DENIED)
2516 {
2517 win_skip("Failed to create test key, skipping some of OleRegGetUserType() tests.\n");
2518 return;
2519 }
2520
2521 ok(!ret, "failed to create a key, error %d\n", ret);
2522
2523 ret = RegSetValueExW(classkey, NULL, 0, REG_SZ, (const BYTE*)defvalueW, sizeof(defvalueW));
2524 ok(!ret, "got error %d\n", ret);
2525
2526 ret = RegCreateKeyExA(classkey, "AuxUserType", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &auxhkey, NULL);
2527 ok(!ret, "got error %d\n", ret);
2528
2529 /* populate AuxUserType */
2530 for (i = 0; i <= 4; i++) {
2531 char name[16];
2532
2533 sprintf(name, "AuxUserType\\%d", i);
2534 ret = RegCreateKeyExA(classkey, name, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2535 ok(!ret, "got error %d\n", ret);
2536
2537 ret = RegSetValueExA(hkey, NULL, 0, REG_SZ, (const BYTE*)auxvalues[i], strlen(auxvalues[i]));
2538 ok(!ret, "got error %d\n", ret);
2539 RegCloseKey(hkey);
2540 }
2541
2542 str = NULL;
2543 hr = OleRegGetUserType(&CLSID_non_existent, 0, &str);
2544 ok(hr == S_OK, "got 0x%08x\n", hr);
2545 ok(!lstrcmpW(str, auxvalue0W), "got %s\n", wine_dbgstr_w(str));
2546 CoTaskMemFree(str);
2547
2548 str = NULL;
2549 hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_FULL, &str);
2550 ok(hr == S_OK, "got 0x%08x\n", hr);
2551 ok(!lstrcmpW(str, defvalueW), "got %s\n", wine_dbgstr_w(str));
2552 CoTaskMemFree(str);
2553
2554 str = NULL;
2555 hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_SHORT, &str);
2556 ok(hr == S_OK, "got 0x%08x\n", hr);
2557 ok(!lstrcmpW(str, auxvalue2W), "got %s\n", wine_dbgstr_w(str));
2558 CoTaskMemFree(str);
2559
2560 str = NULL;
2561 hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME, &str);
2562 ok(hr == S_OK, "got 0x%08x\n", hr);
2563 ok(!lstrcmpW(str, auxvalue3W), "got %s\n", wine_dbgstr_w(str));
2564 CoTaskMemFree(str);
2565
2566 str = NULL;
2567 hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME+1, &str);
2568 ok(hr == S_OK, "got 0x%08x\n", hr);
2569 ok(!lstrcmpW(str, auxvalue4W), "got %s\n", wine_dbgstr_w(str));
2570 CoTaskMemFree(str);
2571
2572 str = NULL;
2573 hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME+2, &str);
2574 ok(hr == S_OK, "got 0x%08x\n", hr);
2575 ok(!lstrcmpW(str, defvalueW), "got %s\n", wine_dbgstr_w(str));
2576 CoTaskMemFree(str);
2577
2578 /* registry cleanup */
2579 for (i = 0; i <= 4; i++)
2580 {
2581 char name[2];
2582 sprintf(name, "%d", i);
2583 RegDeleteKeyA(auxhkey, name);
2584 }
2585 RegCloseKey(auxhkey);
2586 RegDeleteKeyA(classkey, "AuxUserType");
2587 RegCloseKey(classkey);
2588 RegDeleteKeyW(clsidhkey, clsidW);
2589 RegCloseKey(clsidhkey);
2590 if (disposition == REG_CREATED_NEW_KEY)
2591 RegDeleteKeyA(HKEY_CLASSES_ROOT, "CLSID");
2592 }
2593
2594 static void test_CoCreateGuid(void)
2595 {
2596 HRESULT hr;
2597
2598 hr = CoCreateGuid(NULL);
2599 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2600 }
2601
2602 static void CALLBACK apc_test_proc(ULONG_PTR param)
2603 {
2604 /* nothing */
2605 }
2606
2607 static DWORD CALLBACK release_semaphore_thread( LPVOID arg )
2608 {
2609 HANDLE handle = arg;
2610 if (WaitForSingleObject(handle, 200) == WAIT_TIMEOUT)
2611 ReleaseSemaphore(handle, 1, NULL);
2612 return 0;
2613 }
2614
2615 static DWORD CALLBACK send_message_thread(LPVOID arg)
2616 {
2617 HWND hWnd = arg;
2618 Sleep(50);
2619 SendMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2620 return 0;
2621 }
2622
2623 static DWORD CALLBACK post_message_thread(LPVOID arg)
2624 {
2625 HWND hWnd = arg;
2626 Sleep(50);
2627 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2628 return 0;
2629 }
2630
2631 static const char cls_name[] = "cowait_test_class";
2632 static DWORD CALLBACK test_CoWaitForMultipleHandles_thread(LPVOID arg)
2633 {
2634 HANDLE *handles = arg;
2635 BOOL success;
2636 DWORD index;
2637 HRESULT hr;
2638 HWND hWnd;
2639 MSG msg;
2640
2641 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2642 ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
2643
2644 hWnd = CreateWindowExA(0, cls_name, "Test (thread)", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
2645 ok(hWnd != 0, "CreateWindowExA failed %u\n", GetLastError());
2646
2647 index = 0xdeadbeef;
2648 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2649 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2650 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2651 ok(index==0 || index==0xdeadbeef/* Win 8 */, "expected index 0, got %u\n", index);
2652 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2653 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2654
2655 index = 0xdeadbeef;
2656 PostMessageA(hWnd, WM_USER, 0, 0);
2657 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2658 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2659 ok(index==0 || index==0xdeadbeef/* Win 8 */, "expected index 0, got %u\n", index);
2660 success = PeekMessageA(&msg, hWnd, WM_USER, WM_USER, PM_REMOVE);
2661 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2662
2663 DestroyWindow(hWnd);
2664 CoUninitialize();
2665 return 0;
2666 }
2667
2668 static void test_CoWaitForMultipleHandles(void)
2669 {
2670 HANDLE handles[2], thread;
2671 DWORD index, tid;
2672 WNDCLASSEXA wc;
2673 BOOL success;
2674 HRESULT hr;
2675 HWND hWnd;
2676 MSG msg;
2677
2678 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2679 ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
2680
2681 memset(&wc, 0, sizeof(wc));
2682 wc.cbSize = sizeof(wc);
2683 wc.style = CS_VREDRAW | CS_HREDRAW;
2684 wc.hInstance = GetModuleHandleA(0);
2685 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
2686 wc.hbrBackground = NULL;
2687 wc.lpszClassName = cls_name;
2688 wc.lpfnWndProc = DefWindowProcA;
2689 success = RegisterClassExA(&wc) != 0;
2690 ok(success, "RegisterClassExA failed %u\n", GetLastError());
2691
2692 hWnd = CreateWindowExA(0, cls_name, "Test", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
2693 ok(hWnd != 0, "CreateWindowExA failed %u\n", GetLastError());
2694 handles[0] = CreateSemaphoreA(NULL, 1, 1, NULL);
2695 ok(handles[0] != 0, "CreateSemaphoreA failed %u\n", GetLastError());
2696 handles[1] = CreateSemaphoreA(NULL, 1, 1, NULL);
2697 ok(handles[1] != 0, "CreateSemaphoreA failed %u\n", GetLastError());
2698
2699 /* test without flags */
2700
2701 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2702 hr = CoWaitForMultipleHandles(0, 50, 0, handles, NULL);
2703 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
2704 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2705 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2706
2707 index = 0xdeadbeef;
2708 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2709 hr = CoWaitForMultipleHandles(0, 50, 0, NULL, &index);
2710 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
2711 ok(index == 0, "expected index 0, got %u\n", index);
2712 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2713 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2714
2715 index = 0xdeadbeef;
2716 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2717 hr = CoWaitForMultipleHandles(0, 50, 0, handles, &index);
2718 ok(hr == RPC_E_NO_SYNC, "expected RPC_E_NO_SYNC, got 0x%08x\n", hr);
2719 ok(index == 0, "expected index 0, got %u\n", index);
2720 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2721 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2722
2723 index = 0xdeadbeef;
2724 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2725 hr = CoWaitForMultipleHandles(0, 50, 1, handles, &index);
2726 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2727 ok(index == 0, "expected index 0, got %u\n", index);
2728 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2729 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2730
2731 index = 0xdeadbeef;
2732 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2733 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2734 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2735 ok(index == 1, "expected index 1, got %u\n", index);
2736 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2737 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2738
2739 index = 0xdeadbeef;
2740 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2741 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2742 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2743 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2744 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2745 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2746
2747 /* test PostMessageA/SendMessageA from a different thread */
2748
2749 index = 0xdeadbeef;
2750 thread = CreateThread(NULL, 0, post_message_thread, hWnd, 0, &tid);
2751 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2752 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2753 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2754 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2755 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2756 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2757 index = WaitForSingleObject(thread, 200);
2758 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2759 CloseHandle(thread);
2760
2761 index = 0xdeadbeef;
2762 thread = CreateThread(NULL, 0, send_message_thread, hWnd, 0, &tid);
2763 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2764 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2765 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2766 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2767 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2768 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2769 index = WaitForSingleObject(thread, 200);
2770 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2771 CloseHandle(thread);
2772
2773 ReleaseSemaphore(handles[0], 1, NULL);
2774 ReleaseSemaphore(handles[1], 1, NULL);
2775
2776 /* test with COWAIT_WAITALL */
2777
2778 index = 0xdeadbeef;
2779 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2780 hr = CoWaitForMultipleHandles(COWAIT_WAITALL, 50, 2, handles, &index);
2781 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2782 ok(index == 0, "expected index 0, got %u\n", index);
2783 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2784 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2785
2786 index = 0xdeadbeef;
2787 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2788 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2789 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2790 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2791 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2792 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2793
2794 ReleaseSemaphore(handles[0], 1, NULL);
2795 ReleaseSemaphore(handles[1], 1, NULL);
2796
2797 /* test with COWAIT_ALERTABLE */
2798
2799 index = 0xdeadbeef;
2800 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2801 hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 1, handles, &index);
2802 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2803 ok(index == 0, "expected index 0, got %u\n", index);
2804 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2805 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2806
2807 index = 0xdeadbeef;
2808 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2809 hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 2, handles, &index);
2810 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2811 ok(index == 1, "expected index 1, got %u\n", index);
2812 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2813 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2814
2815 index = 0xdeadbeef;
2816 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2817 hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 2, handles, &index);
2818 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2819 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2820 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2821 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2822
2823 index = 0xdeadbeef;
2824 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2825 success = QueueUserAPC(apc_test_proc, GetCurrentThread(), 0);
2826 ok(success, "QueueUserAPC failed %u\n", GetLastError());
2827 hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 2, handles, &index);
2828 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2829 ok(index == WAIT_IO_COMPLETION, "expected index WAIT_IO_COMPLETION, got %u\n", index);
2830 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2831 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2832
2833 /* test with COWAIT_INPUTAVAILABLE (semaphores are still locked) */
2834
2835 index = 0xdeadbeef;
2836 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2837 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_NOREMOVE);
2838 ok(success, "PeekMessageA returned FALSE\n");
2839 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2840 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2841 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2842 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2843 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2844
2845 index = 0xdeadbeef;
2846 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2847 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_NOREMOVE);
2848 ok(success, "PeekMessageA returned FALSE\n");
2849 thread = CreateThread(NULL, 0, release_semaphore_thread, handles[1], 0, &tid);
2850 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2851 hr = CoWaitForMultipleHandles(COWAIT_INPUTAVAILABLE, 50, 2, handles, &index);
2852 ok(hr == RPC_S_CALLPENDING || broken(hr == E_INVALIDARG) || broken(hr == S_OK) /* Win 8 */,
2853 "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2854 if (hr != S_OK) ReleaseSemaphore(handles[1], 1, NULL);
2855 ok(index == 0 || broken(index == 1) /* Win 8 */, "expected index 0, got %u\n", index);
2856 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2857 ok(!success || broken(success && hr == E_INVALIDARG),
2858 "CoWaitForMultipleHandles didn't pump any messages\n");
2859 index = WaitForSingleObject(thread, 200);
2860 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2861 CloseHandle(thread);
2862
2863 /* test behaviour of WM_QUIT (semaphores are still locked) */
2864
2865 PostMessageA(hWnd, WM_QUIT, 40, 0);
2866 memset(&msg, 0, sizeof(msg));
2867 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2868 ok(success, "PeekMessageA failed, error %u\n", GetLastError());
2869 ok(msg.message == WM_QUIT, "expected msg.message = WM_QUIT, got %u\n", msg.message);
2870 ok(msg.wParam == 40, "expected msg.wParam = 40, got %lu\n", msg.wParam);
2871 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2872 ok(!success, "PeekMessageA succeeded\n");
2873
2874 index = 0xdeadbeef;
2875 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2876 PostMessageA(hWnd, WM_QUIT, 41, 0);
2877 thread = CreateThread(NULL, 0, post_message_thread, hWnd, 0, &tid);
2878 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2879 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2880 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2881 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2882 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2883 todo_wine
2884 ok(success || broken(!success) /* Win 2000/XP/8 */, "PeekMessageA failed, error %u\n", GetLastError());
2885 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2886 ok(!success, "PeekMessageA succeeded\n");
2887 memset(&msg, 0, sizeof(msg));
2888 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2889 todo_wine
2890 ok(!success || broken(success) /* Win 2000/XP/8 */, "PeekMessageA succeeded\n");
2891 if (success)
2892 {
2893 ok(msg.message == WM_QUIT, "expected msg.message = WM_QUIT, got %u\n", msg.message);
2894 ok(msg.wParam == 41, "expected msg.wParam = 41, got %lu\n", msg.wParam);
2895 }
2896 index = WaitForSingleObject(thread, 200);
2897 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2898 CloseHandle(thread);
2899
2900 index = 0xdeadbeef;
2901 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2902 PostMessageA(hWnd, WM_QUIT, 42, 0);
2903 thread = CreateThread(NULL, 0, send_message_thread, hWnd, 0, &tid);
2904 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2905 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2906 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2907 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2908 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2909 ok(!success, "CoWaitForMultipleHandles didn't pump all WM_DDE_FIRST messages\n");
2910 memset(&msg, 0, sizeof(msg));
2911 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2912 ok(success, "PeekMessageA failed, error %u\n", GetLastError());
2913 ok(msg.message == WM_QUIT, "expected msg.message = WM_QUIT, got %u\n", msg.message);
2914 ok(msg.wParam == 42, "expected msg.wParam = 42, got %lu\n", msg.wParam);
2915 index = WaitForSingleObject(thread, 200);
2916 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2917 CloseHandle(thread);
2918
2919 PostQuitMessage(43);
2920 memset(&msg, 0, sizeof(msg));
2921 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2922 ok(success || broken(!success) /* Win 8 */, "PeekMessageA failed, error %u\n", GetLastError());
2923 if (!success)
2924 win_skip("PostQuitMessage didn't queue a WM_QUIT message, skipping tests\n");
2925 else
2926 {
2927 ok(msg.message == WM_QUIT, "expected msg.message = WM_QUIT, got %u\n", msg.message);
2928 ok(msg.wParam == 43, "expected msg.wParam = 43, got %lu\n", msg.wParam);
2929 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2930 ok(!success, "PeekMessageA succeeded\n");
2931
2932 index = 0xdeadbeef;
2933 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2934 PostQuitMessage(44);
2935 thread = CreateThread(NULL, 0, post_message_thread, hWnd, 0, &tid);
2936 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2937 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2938 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2939 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2940 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2941 ok(success, "PeekMessageA failed, error %u\n", GetLastError());
2942 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2943 todo_wine
2944 ok(!success, "PeekMessageA succeeded\n");
2945 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2946 todo_wine
2947 ok(!success, "CoWaitForMultipleHandles didn't remove WM_QUIT messages\n");
2948 index = WaitForSingleObject(thread, 200);
2949 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2950 CloseHandle(thread);
2951
2952 index = 0xdeadbeef;
2953 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2954 PostQuitMessage(45);
2955 thread = CreateThread(NULL, 0, send_message_thread, hWnd, 0, &tid);
2956 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2957 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2958 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2959 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2960 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2961 ok(success, "PeekMessageA failed, error %u\n", GetLastError());
2962 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2963 todo_wine
2964 ok(!success, "PeekMessageA succeeded\n");
2965 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2966 ok(!success, "CoWaitForMultipleHandles didn't remove WM_QUIT messages\n");
2967 index = WaitForSingleObject(thread, 200);
2968 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2969 CloseHandle(thread);
2970 }
2971
2972 /* test message pumping when CoWaitForMultipleHandles is called from non main apartment thread */
2973 thread = CreateThread(NULL, 0, test_CoWaitForMultipleHandles_thread, handles, 0, &tid);
2974 index = WaitForSingleObject(thread, 500);
2975 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2976 CloseHandle(thread);
2977
2978 CloseHandle(handles[0]);
2979 CloseHandle(handles[1]);
2980 DestroyWindow(hWnd);
2981
2982 success = UnregisterClassA(cls_name, GetModuleHandleA(0));
2983 ok(success, "UnregisterClass failed %u\n", GetLastError());
2984
2985 CoUninitialize();
2986 }
2987
2988 static void test_CoGetMalloc(void)
2989 {
2990 IMalloc *imalloc;
2991 HRESULT hr;
2992
2993 if (0) /* crashes on native */
2994 hr = CoGetMalloc(0, NULL);
2995
2996 imalloc = (void*)0xdeadbeef;
2997 hr = CoGetMalloc(0, &imalloc);
2998 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2999 ok(imalloc == NULL, "got %p\n", imalloc);
3000
3001 imalloc = (void*)0xdeadbeef;
3002 hr = CoGetMalloc(MEMCTX_SHARED, &imalloc);
3003 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3004 ok(imalloc == NULL, "got %p\n", imalloc);
3005
3006 imalloc = (void*)0xdeadbeef;
3007 hr = CoGetMalloc(MEMCTX_MACSYSTEM, &imalloc);
3008 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3009 ok(imalloc == NULL, "got %p\n", imalloc);
3010
3011 imalloc = (void*)0xdeadbeef;
3012 hr = CoGetMalloc(MEMCTX_UNKNOWN, &imalloc);
3013 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3014 ok(imalloc == NULL, "got %p\n", imalloc);
3015
3016 imalloc = (void*)0xdeadbeef;