33a7585365311a19509ff63cfed88865f08348e8
[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 #define COBJMACROS
22 #define CONST_VTABLE
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #define USE_COM_CONTEXT_DEF
30 #include "objbase.h"
31 #include "shlguid.h"
32 #include "urlmon.h" /* for CLSID_FileProtocol */
33 #include "dde.h"
34 #include "cguid.h"
35
36 #include "ctxtcall.h"
37
38 #include "wine/test.h"
39 #include "initguid.h"
40
41 #define DEFINE_EXPECT(func) \
42 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
43
44 #define SET_EXPECT(func) \
45 expect_ ## func = TRUE
46
47 #define CHECK_EXPECT2(func) \
48 do { \
49 ok(expect_ ##func, "unexpected call " #func "\n"); \
50 called_ ## func = TRUE; \
51 }while(0)
52
53 #define CHECK_EXPECT(func) \
54 do { \
55 CHECK_EXPECT2(func); \
56 expect_ ## func = FALSE; \
57 }while(0)
58
59 #define CHECK_CALLED(func) \
60 do { \
61 ok(called_ ## func, "expected " #func "\n"); \
62 expect_ ## func = called_ ## func = FALSE; \
63 }while(0)
64
65 DEFINE_EXPECT(CreateStub);
66
67 /* functions that are not present on all versions of Windows */
68 static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
69 static HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv);
70 static HRESULT (WINAPI * pCoSwitchCallContext)(IUnknown *pObject, IUnknown **ppOldObject);
71 static HRESULT (WINAPI * pCoGetTreatAsClass)(REFCLSID clsidOld, LPCLSID pClsidNew);
72 static HRESULT (WINAPI * pCoTreatAsClass)(REFCLSID clsidOld, REFCLSID pClsidNew);
73 static HRESULT (WINAPI * pCoGetContextToken)(ULONG_PTR *token);
74 static HRESULT (WINAPI * pCoGetApartmentType)(APTTYPE *type, APTTYPEQUALIFIER *qualifier);
75 static LONG (WINAPI * pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
76 static LONG (WINAPI * pRegOverridePredefKey)(HKEY key, HKEY override);
77
78 static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
79 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
80 static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
81 static BOOL (WINAPI *pIsWow64Process)(HANDLE, LPBOOL);
82 static void (WINAPI *pReleaseActCtx)(HANDLE);
83
84 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
85 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
86 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
87
88 static const CLSID CLSID_non_existent = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
89 static const CLSID CLSID_StdFont = { 0x0be35203, 0x8f91, 0x11ce, { 0x9d, 0xe3, 0x00, 0xaa, 0x00, 0x4b, 0xb8, 0x51 } };
90 static const GUID IID_Testiface = { 0x22222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
91 static const GUID IID_Testiface2 = { 0x32222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
92 static const GUID IID_Testiface3 = { 0x42222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
93 static const GUID IID_Testiface4 = { 0x52222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
94 static const GUID IID_Testiface5 = { 0x62222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
95 static const GUID IID_Testiface6 = { 0x72222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
96 static const GUID IID_TestPS = { 0x66666666, 0x8888, 0x7777, { 0x66, 0x66, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 } };
97
98 DEFINE_GUID(CLSID_testclsid, 0xacd014c7,0x9535,0x4fac,0x8b,0x53,0xa4,0x8c,0xa7,0xf4,0xd7,0x26);
99
100 static const WCHAR stdfont[] = {'S','t','d','F','o','n','t',0};
101 static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
102 static const WCHAR wszCLSID_StdFont[] =
103 {
104 '{','0','b','e','3','5','2','0','3','-','8','f','9','1','-','1','1','c','e','-',
105 '9','d','e','3','-','0','0','a','a','0','0','4','b','b','8','5','1','}',0
106 };
107 static const WCHAR progidW[] = {'P','r','o','g','I','d','.','P','r','o','g','I','d',0};
108 static const WCHAR cf_brokenW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
109 'c','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}','a',0};
110
111 DEFINE_GUID(IID_IWineTest, 0x5201163f, 0x8164, 0x4fd0, 0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd);
112 DEFINE_GUID(CLSID_WineOOPTest, 0x5201163f, 0x8164, 0x4fd0, 0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd);
113
114 static LONG cLocks;
115
116 static void LockModule(void)
117 {
118 InterlockedIncrement(&cLocks);
119 }
120
121 static void UnlockModule(void)
122 {
123 InterlockedDecrement(&cLocks);
124 }
125
126 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
127 LPCLASSFACTORY iface,
128 REFIID riid,
129 LPVOID *ppvObj)
130 {
131 if (ppvObj == NULL) return E_POINTER;
132
133 if (IsEqualGUID(riid, &IID_IUnknown) ||
134 IsEqualGUID(riid, &IID_IClassFactory))
135 {
136 *ppvObj = iface;
137 IClassFactory_AddRef(iface);
138 return S_OK;
139 }
140
141 *ppvObj = NULL;
142 return E_NOINTERFACE;
143 }
144
145 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
146 {
147 LockModule();
148 return 2; /* non-heap-based object */
149 }
150
151 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
152 {
153 UnlockModule();
154 return 1; /* non-heap-based object */
155 }
156
157 static IID create_instance_iid;
158 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
159 LPCLASSFACTORY iface,
160 IUnknown *pUnkOuter,
161 REFIID riid,
162 LPVOID *ppvObj)
163 {
164 *ppvObj = NULL;
165 create_instance_iid = *riid;
166 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
167 return E_NOINTERFACE;
168 }
169
170 static HRESULT WINAPI Test_IClassFactory_LockServer(
171 LPCLASSFACTORY iface,
172 BOOL fLock)
173 {
174 return S_OK;
175 }
176
177 static const IClassFactoryVtbl TestClassFactory_Vtbl =
178 {
179 Test_IClassFactory_QueryInterface,
180 Test_IClassFactory_AddRef,
181 Test_IClassFactory_Release,
182 Test_IClassFactory_CreateInstance,
183 Test_IClassFactory_LockServer
184 };
185
186 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
187
188 static WCHAR manifest_path[MAX_PATH];
189
190 static BOOL create_manifest_file(const char *filename, const char *manifest)
191 {
192 int manifest_len;
193 DWORD size;
194 HANDLE file;
195 WCHAR path[MAX_PATH];
196
197 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
198 GetFullPathNameW(path, ARRAY_SIZE(manifest_path), manifest_path, NULL);
199
200 manifest_len = strlen(manifest);
201 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
202 FILE_ATTRIBUTE_NORMAL, NULL);
203 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
204 if(file == INVALID_HANDLE_VALUE)
205 return FALSE;
206 WriteFile(file, manifest, manifest_len, &size, NULL);
207 CloseHandle(file);
208
209 return TRUE;
210 }
211
212 static HANDLE activate_context(const char *manifest, ULONG_PTR *cookie)
213 {
214 WCHAR path[MAX_PATH];
215 ACTCTXW actctx;
216 HANDLE handle;
217 BOOL ret;
218
219 if (!pCreateActCtxW) return NULL;
220
221 create_manifest_file("file.manifest", manifest);
222
223 MultiByteToWideChar( CP_ACP, 0, "file.manifest", -1, path, MAX_PATH );
224 memset(&actctx, 0, sizeof(ACTCTXW));
225 actctx.cbSize = sizeof(ACTCTXW);
226 actctx.lpSource = path;
227
228 handle = pCreateActCtxW(&actctx);
229 ok(handle != INVALID_HANDLE_VALUE || broken(handle == INVALID_HANDLE_VALUE) /* some old XP/2k3 versions */,
230 "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
231 if (handle == INVALID_HANDLE_VALUE)
232 {
233 win_skip("activation context generation failed, some tests will be skipped\n");
234 handle = NULL;
235 }
236
237 ok(actctx.cbSize == sizeof(ACTCTXW), "actctx.cbSize=%d\n", actctx.cbSize);
238 ok(actctx.dwFlags == 0, "actctx.dwFlags=%d\n", actctx.dwFlags);
239 ok(actctx.lpSource == path, "actctx.lpSource=%p\n", actctx.lpSource);
240 ok(actctx.wProcessorArchitecture == 0, "actctx.wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
241 ok(actctx.wLangId == 0, "actctx.wLangId=%d\n", actctx.wLangId);
242 ok(actctx.lpAssemblyDirectory == NULL, "actctx.lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
243 ok(actctx.lpResourceName == NULL, "actctx.lpResourceName=%p\n", actctx.lpResourceName);
244 ok(actctx.lpApplicationName == NULL, "actctx.lpApplicationName=%p\n", actctx.lpApplicationName);
245 ok(actctx.hModule == NULL, "actctx.hModule=%p\n", actctx.hModule);
246
247 DeleteFileA("file.manifest");
248
249 if (handle)
250 {
251 ret = pActivateActCtx(handle, cookie);
252 ok(ret, "ActivateActCtx failed: %u\n", GetLastError());
253 }
254
255 return handle;
256 }
257
258 static const char actctx_manifest[] =
259 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
260 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\""
261 " publicKeyToken=\"6595b6414666f1df\" />"
262 "<file name=\"testlib.dll\">"
263 " <comClass"
264 " clsid=\"{0000033a-0000-0000-c000-000000000046}\""
265 " progid=\"FTMarshal\""
266 " />"
267 " <comClass"
268 " clsid=\"{5201163f-8164-4fd0-a1a2-5d5a3654d3bd}\""
269 " progid=\"WineOOPTest\""
270 " />"
271 " <comClass description=\"Test com class\""
272 " clsid=\"{12345678-1234-1234-1234-56789abcdef0}\""
273 " progid=\"ProgId.ProgId\""
274 " miscStatusIcon=\"recomposeonresize\""
275 " />"
276 " <comClass description=\"CustomFont Description\" clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb851}\""
277 " progid=\"CustomFont\""
278 " miscStatusIcon=\"recomposeonresize\""
279 " miscStatusContent=\"insideout\""
280 " />"
281 " <comClass description=\"StdFont Description\" clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb852}\""
282 " progid=\"StdFont\""
283 " />"
284 " <comClass clsid=\"{62222222-1234-1234-1234-56789abcdef0}\" >"
285 " <progid>ProgId.ProgId.1</progid>"
286 " </comClass>"
287 " <comInterfaceProxyStub "
288 " name=\"Iifaceps\""
289 " iid=\"{22222222-1234-1234-1234-56789abcdef0}\""
290 " proxyStubClsid32=\"{66666666-8888-7777-6666-555555555555}\""
291 " />"
292 "</file>"
293 " <comInterfaceExternalProxyStub "
294 " name=\"Iifaceps2\""
295 " iid=\"{32222222-1234-1234-1234-56789abcdef0}\""
296 " />"
297 " <comInterfaceExternalProxyStub "
298 " name=\"Iifaceps3\""
299 " iid=\"{42222222-1234-1234-1234-56789abcdef0}\""
300 " proxyStubClsid32=\"{66666666-8888-7777-6666-555555555555}\""
301 " />"
302 " <comInterfaceExternalProxyStub "
303 " name=\"Iifaceps4\""
304 " iid=\"{52222222-1234-1234-1234-56789abcdef0}\""
305 " proxyStubClsid32=\"{00000000-0000-0000-0000-000000000000}\""
306 " />"
307 " <clrClass "
308 " clsid=\"{72222222-1234-1234-1234-56789abcdef0}\""
309 " name=\"clrclass\""
310 " >"
311 " <progid>clrprogid.1</progid>"
312 " </clrClass>"
313 "</assembly>";
314
315 DEFINE_GUID(CLSID_Testclass, 0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0);
316
317 static void test_ProgIDFromCLSID(void)
318 {
319 ULONG_PTR cookie = 0;
320 LPWSTR progid;
321 HANDLE handle;
322 HRESULT hr;
323
324 hr = ProgIDFromCLSID(&CLSID_StdFont, &progid);
325 ok(hr == S_OK, "ProgIDFromCLSID failed with error 0x%08x\n", hr);
326 if (hr == S_OK)
327 {
328 ok(!lstrcmpiW(progid, stdfont), "Didn't get expected prog ID\n");
329 CoTaskMemFree(progid);
330 }
331
332 progid = (LPWSTR)0xdeadbeef;
333 hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
334 ok(hr == REGDB_E_CLASSNOTREG, "ProgIDFromCLSID returned %08x\n", hr);
335 ok(progid == NULL, "ProgIDFromCLSID returns with progid %p\n", progid);
336
337 hr = ProgIDFromCLSID(&CLSID_StdFont, NULL);
338 ok(hr == E_INVALIDARG, "ProgIDFromCLSID should return E_INVALIDARG instead of 0x%08x\n", hr);
339
340 if ((handle = activate_context(actctx_manifest, &cookie)))
341 {
342 static const WCHAR customfontW[] = {'C','u','s','t','o','m','F','o','n','t',0};
343
344 hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
345 ok(hr == S_OK, "got 0x%08x\n", hr);
346 ok(!lstrcmpiW(progid, progidW), "got %s\n", wine_dbgstr_w(progid));
347 CoTaskMemFree(progid);
348
349 /* try something registered and redirected */
350 progid = NULL;
351 hr = ProgIDFromCLSID(&CLSID_StdFont, &progid);
352 ok(hr == S_OK, "got 0x%08x\n", hr);
353 ok(!lstrcmpiW(progid, customfontW), "got wrong progid %s\n", wine_dbgstr_w(progid));
354 CoTaskMemFree(progid);
355
356 /* classes without default progid, progid list is not used */
357 progid = (void *)0xdeadbeef;
358 hr = ProgIDFromCLSID(&IID_Testiface5, &progid);
359 ok(hr == REGDB_E_CLASSNOTREG && progid == NULL, "got 0x%08x, progid %p\n", hr, progid);
360
361 progid = (void *)0xdeadbeef;
362 hr = ProgIDFromCLSID(&IID_Testiface6, &progid);
363 ok(hr == REGDB_E_CLASSNOTREG && progid == NULL, "got 0x%08x, progid %p\n", hr, progid);
364
365 pDeactivateActCtx(0, cookie);
366 pReleaseActCtx(handle);
367 }
368 }
369
370 static void test_CLSIDFromProgID(void)
371 {
372 ULONG_PTR cookie = 0;
373 HANDLE handle;
374 CLSID clsid;
375 HRESULT hr = CLSIDFromProgID(stdfont, &clsid);
376 ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08x\n", hr);
377 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
378
379 hr = CLSIDFromString(stdfont, &clsid);
380 ok_ole_success(hr, "CLSIDFromString");
381 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
382
383 /* test some failure cases */
384
385 hr = CLSIDFromProgID(wszNonExistent, NULL);
386 ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
387
388 hr = CLSIDFromProgID(NULL, &clsid);
389 ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
390
391 memset(&clsid, 0xcc, sizeof(clsid));
392 hr = CLSIDFromProgID(wszNonExistent, &clsid);
393 ok(hr == CO_E_CLASSSTRING, "CLSIDFromProgID on nonexistent ProgID should have returned CO_E_CLASSSTRING instead of 0x%08x\n", hr);
394 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "CLSIDFromProgID should have set clsid to all-zeros on failure\n");
395
396 /* fails without proper context */
397 memset(&clsid, 0xcc, sizeof(clsid));
398 hr = CLSIDFromProgID(progidW, &clsid);
399 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
400 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "wrong clsid\n");
401
402 if ((handle = activate_context(actctx_manifest, &cookie)))
403 {
404 GUID clsid1;
405
406 memset(&clsid, 0xcc, sizeof(clsid));
407 hr = CLSIDFromProgID(wszNonExistent, &clsid);
408 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
409 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "should have zero CLSID on failure\n");
410
411 /* CLSIDFromString() doesn't check activation context */
412 hr = CLSIDFromString(progidW, &clsid);
413 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
414
415 clsid = CLSID_NULL;
416 hr = CLSIDFromProgID(progidW, &clsid);
417 ok(hr == S_OK, "got 0x%08x\n", hr);
418 /* it returns generated CLSID here */
419 ok(!IsEqualCLSID(&clsid, &CLSID_non_existent) && !IsEqualCLSID(&clsid, &CLSID_NULL),
420 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
421
422 /* duplicate progid present in context - returns generated guid here too */
423 clsid = CLSID_NULL;
424 hr = CLSIDFromProgID(stdfont, &clsid);
425 ok(hr == S_OK, "got 0x%08x\n", hr);
426 clsid1 = CLSID_StdFont;
427 /* that's where it differs from StdFont */
428 clsid1.Data4[7] = 0x52;
429 ok(!IsEqualCLSID(&clsid, &CLSID_StdFont) && !IsEqualCLSID(&clsid, &CLSID_NULL) && !IsEqualCLSID(&clsid, &clsid1),
430 "got %s\n", wine_dbgstr_guid(&clsid));
431
432 pDeactivateActCtx(0, cookie);
433 pReleaseActCtx(handle);
434 }
435 }
436
437 static void test_CLSIDFromString(void)
438 {
439 CLSID clsid;
440 WCHAR wszCLSID_Broken[50];
441 UINT i;
442
443 HRESULT hr = CLSIDFromString(wszCLSID_StdFont, &clsid);
444 ok_ole_success(hr, "CLSIDFromString");
445 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
446
447 memset(&clsid, 0xab, sizeof(clsid));
448 hr = CLSIDFromString(NULL, &clsid);
449 ok(hr == S_OK, "got 0x%08x\n", hr);
450 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
451
452 /* string is longer, but starts with a valid CLSID */
453 memset(&clsid, 0, sizeof(clsid));
454 hr = CLSIDFromString(cf_brokenW, &clsid);
455 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
456 ok(IsEqualCLSID(&clsid, &IID_IClassFactory), "got %s\n", wine_dbgstr_guid(&clsid));
457
458 lstrcpyW(wszCLSID_Broken, wszCLSID_StdFont);
459 for(i = lstrlenW(wszCLSID_StdFont); i < 49; i++)
460 wszCLSID_Broken[i] = 'A';
461 wszCLSID_Broken[i] = '\0';
462
463 memset(&clsid, 0, sizeof(CLSID));
464 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
465 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
466 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
467
468 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)-1] = 'A';
469 memset(&clsid, 0, sizeof(CLSID));
470 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
471 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
472 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
473
474 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)] = '\0';
475 memset(&clsid, 0, sizeof(CLSID));
476 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
477 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
478 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
479
480 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)-1] = '\0';
481 memset(&clsid, 0, sizeof(CLSID));
482 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
483 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
484 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
485
486 memset(&clsid, 0xcc, sizeof(CLSID));
487 hr = CLSIDFromString(wszCLSID_Broken+1, &clsid);
488 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
489 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
490
491 wszCLSID_Broken[9] = '*';
492 memset(&clsid, 0xcc, sizeof(CLSID));
493 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
494 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
495 ok(clsid.Data1 == CLSID_StdFont.Data1, "Got %08x\n", clsid.Data1);
496 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
497
498 wszCLSID_Broken[3] = '*';
499 memset(&clsid, 0xcc, sizeof(CLSID));
500 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
501 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
502 ok(clsid.Data1 == 0xb, "Got %08x\n", clsid.Data1);
503 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
504
505 wszCLSID_Broken[3] = '\0';
506 memset(&clsid, 0xcc, sizeof(CLSID));
507 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
508 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
509 ok(clsid.Data1 == 0xb, "Got %08x\n", clsid.Data1);
510 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
511 }
512
513 static void test_IIDFromString(void)
514 {
515 static const WCHAR cfW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
516 'c','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
517 static const WCHAR brokenW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
518 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
519 static const WCHAR broken2W[] = {'{','0','0','0','0','0','0','0','1','=','0','0','0','0','-','0','0','0','0','-',
520 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
521 static const WCHAR broken3W[] = {'b','r','o','k','e','n','0','0','1','=','0','0','0','0','-','0','0','0','0','-',
522 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
523 HRESULT hr;
524 IID iid;
525
526 hr = IIDFromString(wszCLSID_StdFont, &iid);
527 ok(hr == S_OK, "got 0x%08x\n", hr);
528 ok(IsEqualIID(&iid, &CLSID_StdFont), "got iid %s\n", wine_dbgstr_guid(&iid));
529
530 memset(&iid, 0xab, sizeof(iid));
531 hr = IIDFromString(NULL, &iid);
532 ok(hr == S_OK, "got 0x%08x\n", hr);
533 ok(IsEqualIID(&iid, &CLSID_NULL), "got iid %s\n", wine_dbgstr_guid(&iid));
534
535 hr = IIDFromString(cfW, &iid);
536 ok(hr == S_OK, "got 0x%08x\n", hr);
537 ok(IsEqualIID(&iid, &IID_IClassFactory), "got iid %s\n", wine_dbgstr_guid(&iid));
538
539 /* string starts with a valid IID but is longer */
540 memset(&iid, 0xab, sizeof(iid));
541 hr = IIDFromString(cf_brokenW, &iid);
542 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
543 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
544
545 /* invalid IID in a valid format */
546 memset(&iid, 0xab, sizeof(iid));
547 hr = IIDFromString(brokenW, &iid);
548 ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
549 ok(iid.Data1 == 0x00000001, "Got %08x\n", iid.Data1);
550
551 memset(&iid, 0xab, sizeof(iid));
552 hr = IIDFromString(broken2W, &iid);
553 ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
554 ok(iid.Data1 == 0x00000001, "Got %08x\n", iid.Data1);
555
556 /* format is broken, but string length is okay */
557 memset(&iid, 0xab, sizeof(iid));
558 hr = IIDFromString(broken3W, &iid);
559 ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
560 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
561
562 /* invalid string */
563 memset(&iid, 0xab, sizeof(iid));
564 hr = IIDFromString(wszNonExistent, &iid);
565 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
566 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
567
568 /* valid ProgID */
569 memset(&iid, 0xab, sizeof(iid));
570 hr = IIDFromString(stdfont, &iid);
571 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
572 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
573 }
574
575 static void test_StringFromGUID2(void)
576 {
577 WCHAR str[50];
578 int len;
579
580 /* invalid pointer */
581 SetLastError(0xdeadbeef);
582 len = StringFromGUID2(NULL,str,50);
583 ok(len == 0, "len: %d (expected 0)\n", len);
584 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %x\n", GetLastError());
585
586 /* Test corner cases for buffer size */
587 len = StringFromGUID2(&CLSID_StdFont,str,50);
588 ok(len == 39, "len: %d (expected 39)\n", len);
589 ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n");
590
591 memset(str,0,sizeof str);
592 len = StringFromGUID2(&CLSID_StdFont,str,39);
593 ok(len == 39, "len: %d (expected 39)\n", len);
594 ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n");
595
596 len = StringFromGUID2(&CLSID_StdFont,str,38);
597 ok(len == 0, "len: %d (expected 0)\n", len);
598
599 len = StringFromGUID2(&CLSID_StdFont,str,30);
600 ok(len == 0, "len: %d (expected 0)\n", len);
601 }
602
603 #define test_apt_type(t, q) _test_apt_type(t, q, __LINE__)
604 static void _test_apt_type(APTTYPE expected_type, APTTYPEQUALIFIER expected_qualifier, int line)
605 {
606 APTTYPEQUALIFIER qualifier = ~0u;
607 APTTYPE type = ~0u;
608 HRESULT hr;
609
610 if (!pCoGetApartmentType)
611 return;
612
613 hr = pCoGetApartmentType(&type, &qualifier);
614 ok_(__FILE__, line)(hr == S_OK || hr == CO_E_NOTINITIALIZED, "Unexpected return code: 0x%08x\n", hr);
615 ok_(__FILE__, line)(type == expected_type, "Wrong apartment type %d, expected %d\n", type, expected_type);
616 ok_(__FILE__, line)(qualifier == expected_qualifier, "Wrong apartment qualifier %d, expected %d\n", qualifier,
617 expected_qualifier);
618 }
619
620 static void test_CoCreateInstance(void)
621 {
622 HRESULT hr;
623 IUnknown *pUnk;
624 REFCLSID rclsid = &CLSID_InternetZoneManager;
625
626 pUnk = (IUnknown *)0xdeadbeef;
627 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
628 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
629 ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
630
631 OleInitialize(NULL);
632
633 /* test errors returned for non-registered clsids */
634 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
635 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
636 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pUnk);
637 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc handler should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
638 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_LOCAL_SERVER, &IID_IUnknown, (void **)&pUnk);
639 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered local server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
640 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_REMOTE_SERVER, &IID_IUnknown, (void **)&pUnk);
641 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered remote server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
642
643 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
644 if(hr == REGDB_E_CLASSNOTREG)
645 {
646 skip("IE not installed so can't test CoCreateInstance\n");
647 OleUninitialize();
648 return;
649 }
650
651 ok_ole_success(hr, "CoCreateInstance");
652 if(pUnk) IUnknown_Release(pUnk);
653 OleUninitialize();
654
655 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
656 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
657
658 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE);
659 }
660
661 static void test_CoGetClassObject(void)
662 {
663 HRESULT hr;
664 HANDLE handle;
665 ULONG_PTR cookie;
666 IUnknown *pUnk;
667 REFCLSID rclsid = &CLSID_InternetZoneManager;
668 HKEY hkey;
669 LONG res;
670
671 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
672 ok(hr == CO_E_NOTINITIALIZED, "CoGetClassObject should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
673 ok(pUnk == NULL, "CoGetClassObject should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
674
675 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL);
676 ok(hr == E_INVALIDARG ||
677 broken(hr == CO_E_NOTINITIALIZED), /* win9x */
678 "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr);
679
680 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE);
681
682 if (!pRegOverridePredefKey)
683 {
684 win_skip("RegOverridePredefKey not available\n");
685 return;
686 }
687
688 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
689
690 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
691 if (hr == S_OK)
692 {
693 IUnknown_Release(pUnk);
694
695 res = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
696 KEY_ALL_ACCESS, NULL, &hkey, NULL);
697 ok(!res, "RegCreateKeyEx returned %d\n", res);
698
699 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, hkey);
700 ok(!res, "RegOverridePredefKey returned %d\n", res);
701
702 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
703 ok(hr == S_OK, "CoGetClassObject should have returned S_OK instead of 0x%08x\n", hr);
704
705 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
706 ok(!res, "RegOverridePredefKey returned %d\n", res);
707
708 if (hr == S_OK) IUnknown_Release(pUnk);
709 RegCloseKey(hkey);
710 }
711
712 hr = CoGetClassObject(&CLSID_InProcFreeMarshaler, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
713 ok(hr == S_OK, "got 0x%08x\n", hr);
714 IUnknown_Release(pUnk);
715
716 /* context redefines FreeMarshaler CLSID */
717 if ((handle = activate_context(actctx_manifest, &cookie)))
718 {
719 hr = CoGetClassObject(&CLSID_InProcFreeMarshaler, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
720 ok(hr == S_OK, "got 0x%08x\n", hr);
721 IUnknown_Release(pUnk);
722
723 pDeactivateActCtx(0, cookie);
724 pReleaseActCtx(handle);
725 }
726
727 CoUninitialize();
728 }
729
730 static void test_CoCreateInstanceEx(void)
731 {
732 MULTI_QI qi_res = { &IID_IMoniker };
733 DWORD cookie;
734 HRESULT hr;
735
736 CoInitialize(NULL);
737
738 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
739 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie);
740 ok_ole_success(hr, "CoRegisterClassObject");
741
742 create_instance_iid = IID_NULL;
743 hr = CoCreateInstanceEx(&CLSID_WineOOPTest, NULL, CLSCTX_INPROC_SERVER, NULL, 1, &qi_res);
744 ok(hr == E_NOINTERFACE, "CoCreateInstanceEx failed: %08x\n", hr);
745 ok(IsEqualGUID(&create_instance_iid, qi_res.pIID), "Unexpected CreateInstance iid %s\n",
746 wine_dbgstr_guid(&create_instance_iid));
747
748 hr = CoRevokeClassObject(cookie);
749 ok_ole_success(hr, "CoRevokeClassObject");
750
751 CoUninitialize();
752 }
753
754 static ATOM register_dummy_class(void)
755 {
756 WNDCLASSA wc =
757 {
758 0,
759 DefWindowProcA,
760 0,
761 0,
762 GetModuleHandleA(NULL),
763 NULL,
764 LoadCursorA(NULL, (LPSTR)IDC_ARROW),
765 (HBRUSH)(COLOR_BTNFACE+1),
766 NULL,
767 "WineOleTestClass",
768 };
769
770 return RegisterClassA(&wc);
771 }
772
773 static void test_ole_menu(void)
774 {
775 HWND hwndFrame;
776 HRESULT hr;
777
778 hwndFrame = CreateWindowA((LPCSTR)MAKEINTATOM(register_dummy_class()), "Test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
779 hr = OleSetMenuDescriptor(NULL, hwndFrame, NULL, NULL, NULL);
780 todo_wine ok_ole_success(hr, "OleSetMenuDescriptor");
781
782 DestroyWindow(hwndFrame);
783 }
784
785
786 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
787 {
788 if (ppvObj == NULL) return E_POINTER;
789
790 if (IsEqualGUID(riid, &IID_IUnknown) ||
791 IsEqualGUID(riid, &IID_IClassFactory))
792 {
793 *ppvObj = iface;
794 IMessageFilter_AddRef(iface);
795 return S_OK;
796 }
797
798 return E_NOINTERFACE;
799 }
800
801 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
802 {
803 return 2; /* non-heap object */
804 }
805
806 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
807 {
808 return 1; /* non-heap object */
809 }
810
811 static DWORD WINAPI MessageFilter_HandleInComingCall(
812 IMessageFilter *iface,
813 DWORD dwCallType,
814 HTASK threadIDCaller,
815 DWORD dwTickCount,
816 LPINTERFACEINFO lpInterfaceInfo)
817 {
818 trace("HandleInComingCall\n");
819 return SERVERCALL_ISHANDLED;
820 }
821
822 static DWORD WINAPI MessageFilter_RetryRejectedCall(
823 IMessageFilter *iface,
824 HTASK threadIDCallee,
825 DWORD dwTickCount,
826 DWORD dwRejectType)
827 {
828 trace("RetryRejectedCall\n");
829 return 0;
830 }
831
832 static DWORD WINAPI MessageFilter_MessagePending(
833 IMessageFilter *iface,
834 HTASK threadIDCallee,
835 DWORD dwTickCount,
836 DWORD dwPendingType)
837 {
838 trace("MessagePending\n");
839 todo_wine ok(0, "unexpected call\n");
840 return PENDINGMSG_WAITNOPROCESS;
841 }
842
843 static const IMessageFilterVtbl MessageFilter_Vtbl =
844 {
845 MessageFilter_QueryInterface,
846 MessageFilter_AddRef,
847 MessageFilter_Release,
848 MessageFilter_HandleInComingCall,
849 MessageFilter_RetryRejectedCall,
850 MessageFilter_MessagePending
851 };
852
853 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
854
855 static void test_CoRegisterMessageFilter(void)
856 {
857 HRESULT hr;
858 IMessageFilter *prev_filter;
859
860 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
861 ok(hr == CO_E_NOT_SUPPORTED,
862 "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
863 hr);
864
865 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
866 prev_filter = (IMessageFilter *)0xdeadbeef;
867 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
868 ok(hr == CO_E_NOT_SUPPORTED,
869 "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
870 hr);
871 ok(prev_filter == (IMessageFilter *)0xdeadbeef,
872 "prev_filter should have been set to %p\n", prev_filter);
873 CoUninitialize();
874
875 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
876
877 hr = CoRegisterMessageFilter(NULL, NULL);
878 ok_ole_success(hr, "CoRegisterMessageFilter");
879
880 prev_filter = (IMessageFilter *)0xdeadbeef;
881 hr = CoRegisterMessageFilter(NULL, &prev_filter);
882 ok_ole_success(hr, "CoRegisterMessageFilter");
883 ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
884
885 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
886 ok_ole_success(hr, "CoRegisterMessageFilter");
887 ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
888
889 hr = CoRegisterMessageFilter(NULL, NULL);
890 ok_ole_success(hr, "CoRegisterMessageFilter");
891
892 CoUninitialize();
893 }
894
895 static IUnknown Test_Unknown;
896
897 static HRESULT WINAPI EnumOLEVERB_QueryInterface(IEnumOLEVERB *iface, REFIID riid, void **ppv)
898 {
899 return IUnknown_QueryInterface(&Test_Unknown, riid, ppv);
900 }
901
902 static ULONG WINAPI EnumOLEVERB_AddRef(IEnumOLEVERB *iface)
903 {
904 return 2;
905 }
906
907 static ULONG WINAPI EnumOLEVERB_Release(IEnumOLEVERB *iface)
908 {
909 return 1;
910 }
911
912 static HRESULT WINAPI EnumOLEVERB_Next(IEnumOLEVERB *iface, ULONG celt, OLEVERB *rgelt, ULONG *fetched)
913 {
914 ok(0, "unexpected call\n");
915 return E_NOTIMPL;
916 }
917
918 static HRESULT WINAPI EnumOLEVERB_Skip(IEnumOLEVERB *iface, ULONG celt)
919 {
920 ok(0, "unexpected call\n");
921 return E_NOTIMPL;
922 }
923
924 static HRESULT WINAPI EnumOLEVERB_Reset(IEnumOLEVERB *iface)
925 {
926 ok(0, "unexpected call\n");
927 return E_NOTIMPL;
928 }
929
930 static HRESULT WINAPI EnumOLEVERB_Clone(IEnumOLEVERB *iface, IEnumOLEVERB **ppenum)
931 {
932 ok(0, "unexpected call\n");
933 return E_NOTIMPL;
934 }
935
936 static const IEnumOLEVERBVtbl EnumOLEVERBVtbl = {
937 EnumOLEVERB_QueryInterface,
938 EnumOLEVERB_AddRef,
939 EnumOLEVERB_Release,
940 EnumOLEVERB_Next,
941 EnumOLEVERB_Skip,
942 EnumOLEVERB_Reset,
943 EnumOLEVERB_Clone
944 };
945
946 static IEnumOLEVERB EnumOLEVERB = { &EnumOLEVERBVtbl };
947
948 static HRESULT WINAPI Test_IUnknown_QueryInterface(
949 IUnknown *iface,
950 REFIID riid,
951 LPVOID *ppvObj)
952 {
953 if (ppvObj == NULL) return E_POINTER;
954
955 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IWineTest)) {
956 *ppvObj = iface;
957 }else if(IsEqualIID(riid, &IID_IEnumOLEVERB)) {
958 *ppvObj = &EnumOLEVERB;
959 }else {
960 *ppvObj = NULL;
961 return E_NOINTERFACE;
962 }
963
964 IUnknown_AddRef((IUnknown*)*ppvObj);
965 return S_OK;
966 }
967
968 static ULONG WINAPI Test_IUnknown_AddRef(IUnknown *iface)
969 {
970 return 2; /* non-heap-based object */
971 }
972
973 static ULONG WINAPI Test_IUnknown_Release(IUnknown *iface)
974 {
975 return 1; /* non-heap-based object */
976 }
977
978 static const IUnknownVtbl TestUnknown_Vtbl =
979 {
980 Test_IUnknown_QueryInterface,
981 Test_IUnknown_AddRef,
982 Test_IUnknown_Release,
983 };
984
985 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
986
987 static IPSFactoryBuffer *ps_factory_buffer;
988
989 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(
990 IPSFactoryBuffer * This,
991 /* [in] */ REFIID riid,
992 /* [iid_is][out] */ void **ppvObject)
993 {
994 if (IsEqualIID(riid, &IID_IUnknown) ||
995 IsEqualIID(riid, &IID_IPSFactoryBuffer))
996 {
997 *ppvObject = This;
998 IPSFactoryBuffer_AddRef(This);
999 return S_OK;
1000 }
1001 return E_NOINTERFACE;
1002 }
1003
1004 static ULONG WINAPI PSFactoryBuffer_AddRef(
1005 IPSFactoryBuffer * This)
1006 {
1007 return 2;
1008 }
1009
1010 static ULONG WINAPI PSFactoryBuffer_Release(
1011 IPSFactoryBuffer * This)
1012 {
1013 return 1;
1014 }
1015
1016 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(
1017 IPSFactoryBuffer * This,
1018 /* [in] */ IUnknown *pUnkOuter,
1019 /* [in] */ REFIID riid,
1020 /* [out] */ IRpcProxyBuffer **ppProxy,
1021 /* [out] */ void **ppv)
1022 {
1023 return E_NOTIMPL;
1024 }
1025
1026 static HRESULT WINAPI PSFactoryBuffer_CreateStub(
1027 IPSFactoryBuffer * This,
1028 /* [in] */ REFIID riid,
1029 /* [unique][in] */ IUnknown *pUnkServer,
1030 /* [out] */ IRpcStubBuffer **ppStub)
1031 {
1032 CHECK_EXPECT(CreateStub);
1033
1034 ok(pUnkServer == (IUnknown*)&Test_Unknown, "unexpected pUnkServer %p\n", pUnkServer);
1035 if(!ps_factory_buffer)
1036 return E_NOTIMPL;
1037
1038 return IPSFactoryBuffer_CreateStub(ps_factory_buffer, &IID_IEnumOLEVERB, pUnkServer, ppStub);
1039 }
1040
1041 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
1042 {
1043 PSFactoryBuffer_QueryInterface,
1044 PSFactoryBuffer_AddRef,
1045 PSFactoryBuffer_Release,
1046 PSFactoryBuffer_CreateProxy,
1047 PSFactoryBuffer_CreateStub
1048 };
1049
1050 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
1051
1052 static const CLSID CLSID_WineTestPSFactoryBuffer =
1053 {
1054 0x52011640,
1055 0x8164,
1056 0x4fd0,
1057 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
1058 }; /* 52011640-8164-4fd0-a1a2-5d5a3654d3bd */
1059
1060 static DWORD CALLBACK register_ps_clsid_thread(void *context)
1061 {
1062 HRESULT hr;
1063 CLSID clsid = {0};
1064
1065 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1066
1067 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1068 ok_ole_success(hr, "CoGetPSClsid");
1069 ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
1070 wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
1071
1072 /* test registering a PSClsid in an apartment which is then destroyed */
1073 hr = CoRegisterPSClsid(&IID_TestPS, &clsid);
1074 ok_ole_success(hr, "CoRegisterPSClsid");
1075
1076 CoUninitialize();
1077
1078 return hr;
1079 }
1080
1081 static void test_CoRegisterPSClsid(void)
1082 {
1083 HRESULT hr;
1084 DWORD dwRegistrationKey;
1085 IStream *stream;
1086 CLSID clsid;
1087 HANDLE thread;
1088 DWORD tid;
1089
1090 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
1091 ok(hr == CO_E_NOTINITIALIZED, "CoRegisterPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1092
1093 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1094
1095 hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
1096 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &dwRegistrationKey);
1097 ok_ole_success(hr, "CoRegisterClassObject");
1098
1099 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
1100 ok_ole_success(hr, "CoRegisterPSClsid");
1101
1102 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1103 ok_ole_success(hr, "CoGetPSClsid");
1104 ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
1105 wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
1106
1107 thread = CreateThread(NULL, 0, register_ps_clsid_thread, NULL, 0, &tid);
1108 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1109 ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
1110 CloseHandle(thread);
1111
1112 hr = CoGetPSClsid(&IID_TestPS, &clsid);
1113 ok_ole_success(hr, "CoGetPSClsid");
1114 ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
1115 wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
1116
1117 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1118 ok_ole_success(hr, "CreateStreamOnHGlobal");
1119
1120 SET_EXPECT(CreateStub);
1121 hr = CoMarshalInterface(stream, &IID_IWineTest, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1122 ok(hr == E_NOTIMPL, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1123 CHECK_CALLED(CreateStub);
1124
1125 hr = CoGetPSClsid(&IID_IEnumOLEVERB, &clsid);
1126 ok_ole_success(hr, "CoGetPSClsid");
1127
1128 hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (void **)&ps_factory_buffer);
1129 ok_ole_success(hr, "CoGetClassObject");
1130
1131 hr = CoRegisterPSClsid(&IID_IEnumOLEVERB, &CLSID_WineTestPSFactoryBuffer);
1132 ok_ole_success(hr, "CoRegisterPSClsid");
1133
1134 SET_EXPECT(CreateStub);
1135 hr = CoMarshalInterface(stream, &IID_IEnumOLEVERB, (IUnknown*)&EnumOLEVERB, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1136 ok(hr == S_OK, "CoMarshalInterface should have returned S_OK instead of 0x%08x\n", hr);
1137 CHECK_CALLED(CreateStub);
1138
1139 hr = CoMarshalInterface(stream, &IID_IEnumOLEVERB, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1140 ok(hr == S_OK, "CoMarshalInterface should have returned S_OK instead of 0x%08x\n", hr);
1141
1142 IStream_Release(stream);
1143 IPSFactoryBuffer_Release(ps_factory_buffer);
1144 ps_factory_buffer = NULL;
1145
1146 hr = CoRevokeClassObject(dwRegistrationKey);
1147 ok_ole_success(hr, "CoRevokeClassObject");
1148
1149 CoUninitialize();
1150
1151 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1152
1153 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1154 ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08x\n", hr);
1155
1156 hr = CoGetPSClsid(&IID_TestPS, &clsid);
1157 ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08x\n", hr);
1158
1159 CoUninitialize();
1160
1161 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1162
1163 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
1164 ok_ole_success(hr, "CoRegisterPSClsid");
1165
1166 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1167 ok_ole_success(hr, "CoGetPSClsid");
1168 ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
1169 wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
1170
1171 thread = CreateThread(NULL, 0, register_ps_clsid_thread, NULL, 0, &tid);
1172 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1173 ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
1174 CloseHandle(thread);
1175
1176 hr = CoGetPSClsid(&IID_TestPS, &clsid);
1177 ok_ole_success(hr, "CoGetPSClsid");
1178 ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
1179 wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
1180
1181 CoUninitialize();
1182 }
1183
1184 static void test_CoGetPSClsid(void)
1185 {
1186 ULONG_PTR cookie;
1187 HANDLE handle;
1188 HRESULT hr;
1189 CLSID clsid;
1190 HKEY hkey;
1191 LONG res;
1192 const BOOL is_win64 = (sizeof(void*) != sizeof(int));
1193 BOOL is_wow64 = FALSE;
1194
1195 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1196 ok(hr == CO_E_NOTINITIALIZED,
1197 "CoGetPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n",
1198 hr);
1199
1200 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1201
1202 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1203 ok_ole_success(hr, "CoGetPSClsid");
1204
1205 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1206 ok(hr == REGDB_E_IIDNOTREG,
1207 "CoGetPSClsid for random IID returned 0x%08x instead of REGDB_E_IIDNOTREG\n",
1208 hr);
1209
1210 hr = CoGetPSClsid(&IID_IClassFactory, NULL);
1211 ok(hr == E_INVALIDARG,
1212 "CoGetPSClsid for null clsid returned 0x%08x instead of E_INVALIDARG\n",
1213 hr);
1214
1215 if (!pRegOverridePredefKey)
1216 {
1217 win_skip("RegOverridePredefKey not available\n");
1218 CoUninitialize();
1219 return;
1220 }
1221 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1222 ok_ole_success(hr, "CoGetPSClsid");
1223
1224 res = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
1225 KEY_ALL_ACCESS, NULL, &hkey, NULL);
1226 ok(!res, "RegCreateKeyEx returned %d\n", res);
1227
1228 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, hkey);
1229 ok(!res, "RegOverridePredefKey returned %d\n", res);
1230
1231 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1232 ok_ole_success(hr, "CoGetPSClsid");
1233
1234 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
1235 ok(!res, "RegOverridePredefKey returned %d\n", res);
1236
1237 RegCloseKey(hkey);
1238
1239 /* not registered CLSID */
1240 hr = CoGetPSClsid(&IID_Testiface, &clsid);
1241 ok(hr == REGDB_E_IIDNOTREG, "got 0x%08x\n", hr);
1242
1243 if ((handle = activate_context(actctx_manifest, &cookie)))
1244 {
1245 memset(&clsid, 0, sizeof(clsid));
1246 hr = CoGetPSClsid(&IID_Testiface, &clsid);
1247 ok(hr == S_OK, "got 0x%08x\n", hr);
1248 ok(IsEqualGUID(&clsid, &IID_Testiface), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1249
1250 memset(&clsid, 0, sizeof(clsid));
1251 hr = CoGetPSClsid(&IID_Testiface2, &clsid);
1252 ok(hr == S_OK, "got 0x%08x\n", hr);
1253 ok(IsEqualGUID(&clsid, &IID_Testiface2), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1254
1255 memset(&clsid, 0, sizeof(clsid));
1256 hr = CoGetPSClsid(&IID_Testiface3, &clsid);
1257 ok(hr == S_OK, "got 0x%08x\n", hr);
1258 ok(IsEqualGUID(&clsid, &IID_TestPS), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1259
1260 memset(&clsid, 0xaa, sizeof(clsid));
1261 hr = CoGetPSClsid(&IID_Testiface4, &clsid);
1262 ok(hr == S_OK, "got 0x%08x\n", hr);
1263 ok(IsEqualGUID(&clsid, &GUID_NULL), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1264
1265 /* register same interface and try to get CLSID back */
1266 hr = CoRegisterPSClsid(&IID_Testiface, &IID_Testiface4);
1267 ok(hr == S_OK, "got 0x%08x\n", hr);
1268 memset(&clsid, 0, sizeof(clsid));
1269 hr = CoGetPSClsid(&IID_Testiface, &clsid);
1270 ok(hr == S_OK, "got 0x%08x\n", hr);
1271 ok(IsEqualGUID(&clsid, &IID_Testiface4), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1272
1273 pDeactivateActCtx(0, cookie);
1274 pReleaseActCtx(handle);
1275 }
1276
1277 if (pRegDeleteKeyExA &&
1278 (is_win64 ||
1279 (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
1280 {
1281 static GUID IID_DeadBeef = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
1282 static const char clsidDeadBeef[] = "{deadbeef-dead-beef-dead-beefdeadbeef}";
1283 static const char clsidA[] = "{66666666-8888-7777-6666-555555555555}";
1284 HKEY hkey_iface, hkey_psclsid;
1285 REGSAM opposite = is_win64 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
1286
1287 hr = CoGetPSClsid(&IID_DeadBeef, &clsid);
1288 ok(hr == REGDB_E_IIDNOTREG, "got 0x%08x\n", hr);
1289
1290 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, "Interface",
1291 0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, &hkey_iface, NULL);
1292 ok(!res, "RegCreateKeyEx returned %d\n", res);
1293 res = RegCreateKeyExA(hkey_iface, clsidDeadBeef,
1294 0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, &hkey, NULL);
1295 if (res == ERROR_ACCESS_DENIED)
1296 {
1297 win_skip("Failed to create a key, skipping some of CoGetPSClsid() tests\n");
1298 goto cleanup;
1299 }
1300
1301 ok(!res, "RegCreateKeyEx returned %d\n", res);
1302 res = RegCreateKeyExA(hkey, "ProxyStubClsid32",
1303 0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, &hkey_psclsid, NULL);
1304 ok(!res, "RegCreateKeyEx returned %d\n", res);
1305 res = RegSetValueExA(hkey_psclsid, NULL, 0, REG_SZ, (const BYTE *)clsidA, strlen(clsidA)+1);
1306 ok(!res, "RegSetValueEx returned %d\n", res);
1307 RegCloseKey(hkey_psclsid);
1308
1309 hr = CoGetPSClsid(&IID_DeadBeef, &clsid);
1310 ok_ole_success(hr, "CoGetPSClsid");
1311 ok(IsEqualGUID(&clsid, &IID_TestPS), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1312
1313 res = pRegDeleteKeyExA(hkey, "ProxyStubClsid32", opposite, 0);
1314 ok(!res, "RegDeleteKeyEx returned %d\n", res);
1315 RegCloseKey(hkey);
1316 res = pRegDeleteKeyExA(hkey_iface, clsidDeadBeef, opposite, 0);
1317 ok(!res, "RegDeleteKeyEx returned %d\n", res);
1318
1319 cleanup:
1320 RegCloseKey(hkey_iface);
1321 }
1322
1323 CoUninitialize();
1324 }
1325
1326 /* basic test, mainly for invalid arguments. see marshal.c for more */
1327 static void test_CoUnmarshalInterface(void)
1328 {
1329 IUnknown *pProxy;
1330 IStream *pStream;
1331 HRESULT hr;
1332
1333 hr = CoUnmarshalInterface(NULL, &IID_IUnknown, (void **)&pProxy);
1334 ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1335
1336 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1337 ok_ole_success(hr, "CreateStreamOnHGlobal");
1338
1339 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1340 todo_wine
1341 ok(hr == CO_E_NOTINITIALIZED, "CoUnmarshalInterface should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1342
1343 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1344
1345 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1346 ok(hr == STG_E_READFAULT, "CoUnmarshalInterface should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
1347
1348 CoUninitialize();
1349
1350 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, NULL);
1351 ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1352
1353 IStream_Release(pStream);
1354 }
1355
1356 static void test_CoGetInterfaceAndReleaseStream(void)
1357 {
1358 HRESULT hr;
1359 IUnknown *pUnk;
1360
1361 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1362
1363 hr = CoGetInterfaceAndReleaseStream(NULL, &IID_IUnknown, (void**)&pUnk);
1364 ok(hr == E_INVALIDARG, "hr %08x\n", hr);
1365
1366 CoUninitialize();
1367 }
1368
1369 /* basic test, mainly for invalid arguments. see marshal.c for more */
1370 static void test_CoMarshalInterface(void)
1371 {
1372 IStream *pStream;
1373 HRESULT hr;
1374 static const LARGE_INTEGER llZero;
1375
1376 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1377
1378 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1379 ok_ole_success(hr, "CreateStreamOnHGlobal");
1380
1381 hr = CoMarshalInterface(pStream, &IID_IUnknown, NULL, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1382 ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1383
1384 hr = CoMarshalInterface(NULL, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1385 ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1386
1387 hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1388 ok_ole_success(hr, "CoMarshalInterface");
1389
1390 /* stream not rewound */
1391 hr = CoReleaseMarshalData(pStream);
1392 ok(hr == STG_E_READFAULT, "CoReleaseMarshalData should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
1393
1394 hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1395 ok_ole_success(hr, "IStream_Seek");
1396
1397 hr = CoReleaseMarshalData(pStream);
1398 ok_ole_success(hr, "CoReleaseMarshalData");
1399
1400 IStream_Release(pStream);
1401
1402 CoUninitialize();
1403 }
1404
1405 static void test_CoMarshalInterThreadInterfaceInStream(void)
1406 {
1407 IStream *pStream;
1408 HRESULT hr;
1409 IClassFactory *pProxy;
1410
1411 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1412
1413 cLocks = 0;
1414
1415 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, NULL);
1416 ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1417
1418 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, NULL, &pStream);
1419 ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1420
1421 ok_no_locks();
1422
1423 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, &pStream);
1424 ok_ole_success(hr, "CoMarshalInterThreadInterfaceInStream");
1425
1426 ok_more_than_one_lock();
1427
1428 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1429 ok_ole_success(hr, "CoUnmarshalInterface");
1430
1431 IClassFactory_Release(pProxy);
1432 IStream_Release(pStream);
1433
1434 ok_no_locks();
1435
1436 CoUninitialize();
1437 }
1438
1439 static void test_CoRegisterClassObject(void)
1440 {
1441 ULONG_PTR ctxcookie;
1442 HANDLE handle;
1443 DWORD cookie;
1444 HRESULT hr;
1445 IClassFactory *pcf;
1446
1447 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1448
1449 /* CLSCTX_INPROC_SERVER */
1450 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1451 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1452 ok_ole_success(hr, "CoRegisterClassObject");
1453 hr = CoRevokeClassObject(cookie);
1454 ok_ole_success(hr, "CoRevokeClassObject");
1455
1456 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1457 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1458 ok_ole_success(hr, "CoRegisterClassObject");
1459 hr = CoRevokeClassObject(cookie);
1460 ok_ole_success(hr, "CoRevokeClassObject");
1461
1462 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1463 CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
1464 ok_ole_success(hr, "CoRegisterClassObject");
1465 hr = CoRevokeClassObject(cookie);
1466 ok_ole_success(hr, "CoRevokeClassObject");
1467
1468 /* CLSCTX_LOCAL_SERVER */
1469 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1470 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
1471 ok_ole_success(hr, "CoRegisterClassObject");
1472 hr = CoRevokeClassObject(cookie);
1473 ok_ole_success(hr, "CoRevokeClassObject");
1474
1475 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1476 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1477 ok_ole_success(hr, "CoRegisterClassObject");
1478 hr = CoRevokeClassObject(cookie);
1479 ok_ole_success(hr, "CoRevokeClassObject");
1480
1481 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1482 CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
1483 ok_ole_success(hr, "CoRegisterClassObject");
1484 hr = CoRevokeClassObject(cookie);
1485 ok_ole_success(hr, "CoRevokeClassObject");
1486
1487 /* CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER */
1488 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1489 CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
1490 ok_ole_success(hr, "CoRegisterClassObject");
1491 hr = CoRevokeClassObject(cookie);
1492 ok_ole_success(hr, "CoRevokeClassObject");
1493
1494 /* test whether an object that doesn't support IClassFactory can be
1495 * registered for CLSCTX_LOCAL_SERVER */
1496 hr = CoRegisterClassObject(&CLSID_WineOOPTest, &Test_Unknown,
1497 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
1498 ok_ole_success(hr, "CoRegisterClassObject");
1499 hr = CoRevokeClassObject(cookie);
1500 ok_ole_success(hr, "CoRevokeClassObject");
1501
1502 /* test whether registered class becomes invalid when apartment is destroyed */
1503 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1504 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1505 ok_ole_success(hr, "CoRegisterClassObject");
1506
1507 CoUninitialize();
1508 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1509
1510 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL,
1511 &IID_IClassFactory, (void **)&pcf);
1512 ok(hr == REGDB_E_CLASSNOTREG, "object registered in an apartment shouldn't accessible after it is destroyed\n");
1513
1514 /* crashes with at least win9x DCOM! */
1515 if (0)
1516 CoRevokeClassObject(cookie);
1517
1518 /* test that object is accessible */
1519 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory, CLSCTX_INPROC_SERVER,
1520 REGCLS_MULTIPLEUSE, &cookie);
1521 ok(hr == S_OK, "got 0x%08x\n", hr);
1522
1523 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
1524 ok(hr == S_OK, "got 0x%08x\n", hr);
1525 IClassFactory_Release(pcf);
1526
1527 /* context now contains CLSID_WineOOPTest, test if registered one could still be used */
1528 if ((handle = activate_context(actctx_manifest, &ctxcookie)))
1529 {
1530 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
1531 todo_wine
1532 ok(hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), "got 0x%08x\n", hr);
1533
1534 pDeactivateActCtx(0, ctxcookie);
1535 pReleaseActCtx(handle);
1536 }
1537
1538 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
1539 ok(hr == S_OK, "got 0x%08x\n", hr);
1540 IClassFactory_Release(pcf);
1541
1542 hr = CoRevokeClassObject(cookie);
1543 ok(hr == S_OK, "got 0x%08x\n", hr);
1544
1545 CoUninitialize();
1546 }
1547
1548 static HRESULT get_class_object(CLSCTX clsctx)
1549 {
1550 HRESULT hr;
1551 IClassFactory *pcf;
1552
1553 hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
1554 (void **)&pcf);
1555
1556 if (SUCCEEDED(hr))
1557 IClassFactory_Release(pcf);
1558
1559 return hr;
1560 }
1561
1562 static DWORD CALLBACK get_class_object_thread(LPVOID pv)
1563 {
1564 CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
1565 HRESULT hr;
1566
1567 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1568
1569 hr = get_class_object(clsctx);
1570
1571 CoUninitialize();
1572
1573 return hr;
1574 }
1575
1576 static DWORD CALLBACK get_class_object_proxy_thread(LPVOID pv)
1577 {
1578 CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
1579 HRESULT hr;
1580 IClassFactory *pcf;
1581 IMultiQI *pMQI;
1582
1583 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1584
1585 hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
1586 (void **)&pcf);
1587
1588 if (SUCCEEDED(hr))
1589 {
1590 hr = IClassFactory_QueryInterface(pcf, &IID_IMultiQI, (void **)&pMQI);
1591 if (SUCCEEDED(hr))
1592 IMultiQI_Release(pMQI);
1593 IClassFactory_Release(pcf);
1594 }
1595
1596 CoUninitialize();
1597
1598 return hr;
1599 }
1600
1601 static DWORD CALLBACK register_class_object_thread(LPVOID pv)
1602 {
1603 HRESULT hr;
1604 DWORD cookie;
1605
1606 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1607
1608 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1609 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1610
1611 CoUninitialize();
1612
1613 return hr;
1614 }
1615
1616 static DWORD CALLBACK revoke_class_object_thread(LPVOID pv)
1617 {
1618 DWORD cookie = (DWORD_PTR)pv;
1619 HRESULT hr;
1620
1621 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1622
1623 hr = CoRevokeClassObject(cookie);
1624
1625 CoUninitialize();
1626
1627 return hr;
1628 }
1629
1630 static void test_registered_object_thread_affinity(void)
1631 {
1632 HRESULT hr;
1633 DWORD cookie;
1634 HANDLE thread;
1635 DWORD tid;
1636 DWORD exitcode;
1637
1638 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1639
1640 /* CLSCTX_INPROC_SERVER */
1641
1642 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1643 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1644 ok_ole_success(hr, "CoRegisterClassObject");
1645
1646 thread = CreateThread(NULL, 0, get_class_object_thread, (LPVOID)CLSCTX_INPROC_SERVER, 0, &tid);
1647 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1648 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1649 GetExitCodeThread(thread, &exitcode);
1650 hr = exitcode;
1651 ok(hr == REGDB_E_CLASSNOTREG, "CoGetClassObject on inproc object "
1652 "registered in different thread should return REGDB_E_CLASSNOTREG "
1653 "instead of 0x%08x\n", hr);
1654
1655 hr = get_class_object(CLSCTX_INPROC_SERVER);
1656 ok(hr == S_OK, "CoGetClassObject on inproc object registered in same "
1657 "thread should return S_OK instead of 0x%08x\n", hr);
1658
1659 thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
1660 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1661 ok ( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1662 GetExitCodeThread(thread, &exitcode);
1663 hr = exitcode;
1664 ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different thread should return S_OK instead of 0x%08x\n", hr);
1665
1666 hr = CoRevokeClassObject(cookie);
1667 ok_ole_success(hr, "CoRevokeClassObject");
1668
1669 /* CLSCTX_LOCAL_SERVER */
1670
1671 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1672 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1673 ok_ole_success(hr, "CoRegisterClassObject");
1674
1675 thread = CreateThread(NULL, 0, get_class_object_proxy_thread, (LPVOID)CLSCTX_LOCAL_SERVER, 0, &tid);
1676 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1677 while (MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)
1678 {
1679 MSG msg;
1680 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
1681 {
1682 TranslateMessage(&msg);
1683 DispatchMessageA(&msg);
1684 }
1685 }
1686 GetExitCodeThread(thread, &exitcode);
1687 hr = exitcode;
1688 ok(hr == S_OK, "CoGetClassObject on local server object "
1689 "registered in different thread should return S_OK "
1690 "instead of 0x%08x\n", hr);
1691
1692 hr = get_class_object(CLSCTX_LOCAL_SERVER);
1693 ok(hr == S_OK, "CoGetClassObject on local server object registered in same "
1694 "thread should return S_OK instead of 0x%08x\n", hr);
1695
1696 thread = CreateThread(NULL, 0, revoke_class_object_thread, (LPVOID)(DWORD_PTR)cookie, 0, &tid);
1697 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1698 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1699 GetExitCodeThread(thread, &exitcode);
1700 hr = exitcode;
1701 ok(hr == RPC_E_WRONG_THREAD || broken(hr == S_OK) /* win8 */, "CoRevokeClassObject called from different "
1702 "thread to where registered should return RPC_E_WRONG_THREAD instead of 0x%08x\n", hr);
1703
1704 thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
1705 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1706 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1707 GetExitCodeThread(thread, &exitcode);
1708 hr = exitcode;
1709 ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different "
1710 "thread should return S_OK instead of 0x%08x\n", hr);
1711
1712 hr = CoRevokeClassObject(cookie);
1713 ok_ole_success(hr, "CoRevokeClassObject");
1714
1715 CoUninitialize();
1716 }
1717
1718 static DWORD CALLBACK free_libraries_thread(LPVOID p)
1719 {
1720 CoFreeUnusedLibraries();
1721 return 0;
1722 }
1723
1724 static inline BOOL is_module_loaded(const char *module)
1725 {
1726 return GetModuleHandleA(module) != 0;
1727 }
1728
1729 static void test_CoFreeUnusedLibraries(void)
1730 {
1731 HRESULT hr;
1732 IUnknown *pUnk;
1733 DWORD tid;
1734 HANDLE thread;
1735
1736 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1737
1738 ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1739
1740 hr = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pUnk);
1741 if (hr == REGDB_E_CLASSNOTREG)
1742 {
1743 skip("IE not installed so can't run CoFreeUnusedLibraries test\n");
1744 CoUninitialize();
1745 return;
1746 }
1747 ok_ole_success(hr, "CoCreateInstance");
1748
1749 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1750
1751 ok(pUnk != NULL ||
1752 broken(pUnk == NULL), /* win9x */
1753 "Expected a valid pointer\n");
1754 if (pUnk)
1755 IUnknown_Release(pUnk);
1756
1757 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1758
1759 thread = CreateThread(NULL, 0, free_libraries_thread, NULL, 0, &tid);
1760 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1761 CloseHandle(thread);
1762
1763 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1764
1765 CoFreeUnusedLibraries();
1766
1767 ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1768
1769 CoUninitialize();
1770 }
1771
1772 static void test_CoGetObjectContext(void)
1773 {
1774 HRESULT hr;
1775 ULONG refs;
1776 IComThreadingInfo *pComThreadingInfo, *threadinginfo2;
1777 IContextCallback *pContextCallback;
1778 IObjContext *pObjContext;
1779 APTTYPE apttype;
1780 THDTYPE thdtype;
1781 GUID id, id2;
1782
1783 if (!pCoGetObjectContext)
1784 {
1785 win_skip("CoGetObjectContext not present\n");
1786 return;
1787 }
1788
1789 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1790 ok(hr == CO_E_NOTINITIALIZED, "CoGetObjectContext should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1791 ok(pComThreadingInfo == NULL, "pComThreadingInfo should have been set to NULL\n");
1792
1793 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1794
1795 test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE);
1796
1797 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1798 ok_ole_success(hr, "CoGetObjectContext");
1799
1800 threadinginfo2 = NULL;
1801 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&threadinginfo2);
1802 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1803 ok(pComThreadingInfo == threadinginfo2, "got different instance\n");
1804 IComThreadingInfo_Release(threadinginfo2);
1805
1806 hr = IComThreadingInfo_GetCurrentLogicalThreadId(pComThreadingInfo, NULL);
1807 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1808
1809 id = id2 = GUID_NULL;
1810 hr = IComThreadingInfo_GetCurrentLogicalThreadId(pComThreadingInfo, &id);
1811 ok(hr == S_OK, "got 0x%08x\n", hr);
1812
1813 hr = CoGetCurrentLogicalThreadId(&id2);
1814 ok(IsEqualGUID(&id, &id2), "got %s, expected %s\n", wine_dbgstr_guid(&id), wine_dbgstr_guid(&id2));
1815
1816 hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1817 ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1818 ok(apttype == APTTYPE_MAINSTA, "apartment type should be APTTYPE_MAINSTA instead of %d\n", apttype);
1819
1820 hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1821 ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1822 ok(thdtype == THDTYPE_PROCESSMESSAGES, "thread type should be THDTYPE_PROCESSMESSAGES instead of %d\n", thdtype);
1823
1824 refs = IComThreadingInfo_Release(pComThreadingInfo);
1825 ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1826
1827 hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1828 ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1829
1830 refs = IContextCallback_Release(pContextCallback);
1831 ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1832
1833 CoUninitialize();
1834
1835 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1836
1837 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1838 ok_ole_success(hr, "CoGetObjectContext");
1839
1840 hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1841 ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1842 ok(apttype == APTTYPE_MTA, "apartment type should be APTTYPE_MTA instead of %d\n", apttype);
1843
1844 hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1845 ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1846 ok(thdtype == THDTYPE_BLOCKMESSAGES, "thread type should be THDTYPE_BLOCKMESSAGES instead of %d\n", thdtype);
1847
1848 refs = IComThreadingInfo_Release(pComThreadingInfo);
1849 ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1850
1851 hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1852 ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1853
1854 refs = IContextCallback_Release(pContextCallback);
1855 ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1856
1857 hr = pCoGetObjectContext(&IID_IObjContext, (void **)&pObjContext);
1858 ok_ole_success(hr, "CoGetObjectContext");
1859
1860 refs = IObjContext_Release(pObjContext);
1861 ok(refs == 0, "pObjContext should have 0 refs instead of %d refs\n", refs);
1862
1863 CoUninitialize();
1864 }
1865
1866 typedef struct {
1867 IUnknown IUnknown_iface;
1868 LONG refs;
1869 } Test_CallContext;
1870
1871 static inline Test_CallContext *impl_from_IUnknown(IUnknown *iface)
1872 {
1873 return CONTAINING_RECORD(iface, Test_CallContext, IUnknown_iface);
1874 }
1875
1876 static HRESULT WINAPI Test_CallContext_QueryInterface(
1877 IUnknown *iface,
1878 REFIID riid,
1879 LPVOID *ppvObj)
1880 {
1881 if (ppvObj == NULL) return E_POINTER;
1882
1883 if (IsEqualGUID(riid, &IID_IUnknown))
1884 {
1885 *ppvObj = iface;
1886 IUnknown_AddRef(iface);
1887 return S_OK;
1888 }
1889
1890 *ppvObj = NULL;
1891 return E_NOINTERFACE;
1892 }
1893
1894 static ULONG WINAPI Test_CallContext_AddRef(IUnknown *iface)
1895 {
1896 Test_CallContext *This = impl_from_IUnknown(iface);
1897 return InterlockedIncrement(&This->refs);
1898 }
1899
1900 static ULONG WINAPI Test_CallContext_Release(IUnknown *iface)
1901 {
1902 Test_CallContext *This = impl_from_IUnknown(iface);
1903 ULONG refs = InterlockedDecrement(&This->refs);
1904 if (!refs)
1905 HeapFree(GetProcessHeap(), 0, This);
1906 return refs;
1907 }
1908
1909 static const IUnknownVtbl TestCallContext_Vtbl =
1910 {
1911 Test_CallContext_QueryInterface,
1912 Test_CallContext_AddRef,
1913 Test_CallContext_Release
1914 };
1915
1916 static void test_CoGetCallContext(void)
1917 {
1918 HRESULT hr;
1919 ULONG refs;
1920 IUnknown *pUnk;
1921 Test_CallContext *test_object;
1922
1923 if (!pCoSwitchCallContext)
1924 {
1925 skip("CoSwitchCallContext not present\n");
1926 return;
1927 }
1928
1929 CoInitialize(NULL);
1930
1931 test_object = HeapAlloc(GetProcessHeap(), 0, sizeof(Test_CallContext));
1932 test_object->IUnknown_iface.lpVtbl = &TestCallContext_Vtbl;
1933 test_object->refs = 1;
1934
1935 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1936 ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
1937
1938 pUnk = (IUnknown*)0xdeadbeef;
1939 hr = pCoSwitchCallContext(&test_object->IUnknown_iface, &pUnk);
1940 ok_ole_success(hr, "CoSwitchCallContext");
1941 ok(pUnk == NULL, "expected NULL, got %p\n", pUnk);
1942 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
1943 ok(refs == 2, "Expected refcount 2, got %d\n", refs);
1944 IUnknown_Release(&test_object->IUnknown_iface);
1945
1946 pUnk = (IUnknown*)0xdeadbeef;
1947 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1948 ok_ole_success(hr, "CoGetCallContext");
1949 ok(pUnk == &test_object->IUnknown_iface, "expected %p, got %p\n",
1950 &test_object->IUnknown_iface, pUnk);
1951 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
1952 ok(refs == 3, "Expected refcount 3, got %d\n", refs);
1953 IUnknown_Release(&test_object->IUnknown_iface);
1954 IUnknown_Release(pUnk);
1955
1956 pUnk = (IUnknown*)0xdeadbeef;
1957 hr = pCoSwitchCallContext(NULL, &pUnk);
1958 ok_ole_success(hr, "CoSwitchCallContext");
1959 ok(pUnk == &test_object->IUnknown_iface, "expected %p, got %p\n",
1960 &test_object->IUnknown_iface, pUnk);
1961 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
1962 ok(refs == 2, "Expected refcount 2, got %d\n", refs);
1963 IUnknown_Release(&test_object->IUnknown_iface);
1964
1965 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1966 ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
1967
1968 IUnknown_Release(&test_object->IUnknown_iface);
1969
1970 CoUninitialize();
1971 }
1972
1973 static void test_CoGetContextToken(void)
1974 {
1975 HRESULT hr;
1976 ULONG refs;
1977 ULONG_PTR token, token2;
1978 IObjContext *ctx;
1979
1980 if (!pCoGetContextToken)
1981 {
1982 win_skip("CoGetContextToken not present\n");
1983 return;
1984 }
1985
1986 token = 0xdeadbeef;
1987 hr = pCoGetContextToken(&token);
1988 ok(hr == CO_E_NOTINITIALIZED, "Expected CO_E_NOTINITIALIZED, got 0x%08x\n", hr);
1989 ok(token == 0xdeadbeef, "Expected 0, got 0x%lx\n", token);
1990
1991 test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE);
1992
1993 CoInitialize(NULL);
1994
1995 test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE);
1996
1997 hr = pCoGetContextToken(NULL);
1998 ok(hr == E_POINTER, "Expected E_POINTER, got 0x%08x\n", hr);
1999
2000 token = 0;
2001 hr = pCoGetContextToken(&token);
2002 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
2003 ok(token, "Expected token != 0\n");
2004
2005 token2 = 0;
2006 hr = pCoGetContextToken(&token2);
2007 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
2008 ok(token2 == token, "got different token\n");
2009
2010 refs = IUnknown_AddRef((IUnknown *)token);
2011 ok(refs == 1, "Expected 1, got %u\n", refs);
2012
2013 hr = pCoGetObjectContext(&IID_IObjContext, (void **)&ctx);
2014 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
2015 ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
2016
2017 refs = IObjContext_AddRef(ctx);
2018 ok(refs == 3, "Expected 3, got %u\n", refs);
2019
2020 refs = IObjContext_Release(ctx);
2021 ok(refs == 2, "Expected 2, got %u\n", refs);
2022
2023 refs = IUnknown_Release((IUnknown *)token);
2024 ok(refs == 1, "Expected 1, got %u\n", refs);
2025
2026 /* CoGetContextToken does not add a reference */
2027 token = 0;
2028 hr = pCoGetContextToken(&token);
2029 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
2030 ok(token, "Expected token != 0\n");
2031 ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
2032
2033 refs = IObjContext_AddRef(ctx);
2034 ok(refs == 2, "Expected 1, got %u\n", refs);
2035
2036 refs = IObjContext_Release(ctx);
2037 ok(refs == 1, "Expected 0, got %u\n", refs);
2038
2039 refs = IObjContext_Release(ctx);
2040 ok(refs == 0, "Expected 0, got %u\n", refs);
2041
2042 CoUninitialize();
2043 }
2044
2045 static void test_TreatAsClass(void)
2046 {
2047 HRESULT hr;
2048 CLSID out;
2049 static GUID deadbeef = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
2050 static const char deadbeefA[] = "{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF}";
2051 IInternetProtocol *pIP = NULL;
2052 HKEY clsidkey, deadbeefkey;
2053 LONG lr;
2054
2055 if (!pCoGetTreatAsClass)
2056 {
2057 win_skip("CoGetTreatAsClass not present\n");
2058 return;
2059 }
2060
2061 hr = pCoGetTreatAsClass(&deadbeef,&out);
2062 ok (hr == S_FALSE, "expected S_FALSE got %x\n",hr);
2063 ok (IsEqualGUID(&out,&deadbeef), "expected to get same clsid back\n");
2064
2065 hr = pCoGetTreatAsClass(NULL, &out);
2066 ok(hr == E_INVALIDARG, "expected E_INVALIDARG got %08x\n", hr);
2067 ok(IsEqualGUID(&out, &deadbeef), "expected no change to the clsid\n");
2068
2069 hr = pCoGetTreatAsClass(&deadbeef, NULL);
2070 ok(hr == E_INVALIDARG, "expected E_INVALIDARG got %08x\n", hr);
2071
2072 lr = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &clsidkey);
2073 ok(!lr, "Couldn't open CLSID key, error %d\n", lr);
2074
2075 lr = RegCreateKeyExA(clsidkey, deadbeefA, 0, NULL, 0, KEY_WRITE, NULL, &deadbeefkey, NULL);
2076 if (lr) {
2077 win_skip("CoGetTreatAsClass() tests will be skipped (failed to create a test key, error %d)\n", lr);
2078 RegCloseKey(clsidkey);
2079 return;
2080 }
2081
2082 hr = pCoTreatAsClass(&deadbeef, &deadbeef);
2083 ok(hr == REGDB_E_WRITEREGDB, "CoTreatAsClass gave wrong error: %08x\n", hr);
2084
2085 hr = pCoTreatAsClass(&deadbeef, &CLSID_FileProtocol);
2086 if(hr == REGDB_E_WRITEREGDB){
2087 win_skip("Insufficient privileges to use CoTreatAsClass\n");
2088 goto exit;
2089 }
2090 ok(hr == S_OK, "CoTreatAsClass failed: %08x\n", hr);
2091
2092 hr = pCoGetTreatAsClass(&deadbeef, &out);
2093 ok(hr == S_OK, "CoGetTreatAsClass failed: %08x\n",hr);
2094 ok(IsEqualGUID(&out, &CLSID_FileProtocol), "expected to get substituted clsid\n");
2095
2096 OleInitialize(NULL);
2097
2098 hr = CoCreateInstance(&deadbeef, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pIP);
2099 if(hr == REGDB_E_CLASSNOTREG)
2100 {
2101 win_skip("IE not installed so can't test CoCreateInstance\n");
2102 goto exit;
2103 }
2104
2105 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
2106 if(pIP){
2107 IInternetProtocol_Release(pIP);
2108 pIP = NULL;
2109 }
2110
2111 hr = pCoTreatAsClass(&deadbeef, &CLSID_NULL);
2112 ok(hr == S_OK, "CoTreatAsClass failed: %08x\n", hr);
2113
2114 hr = pCoGetTreatAsClass(&deadbeef, &out);
2115 ok(hr == S_FALSE, "expected S_FALSE got %08x\n", hr);
2116 ok(IsEqualGUID(&out, &deadbeef), "expected to get same clsid back\n");
2117
2118 /* bizarrely, native's CoTreatAsClass takes some time to take effect in CoCreateInstance */
2119 Sleep(200);
2120
2121 hr = CoCreateInstance(&deadbeef, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pIP);
2122 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance gave wrong error: %08x\n", hr);
2123
2124 if(pIP)
2125 IInternetProtocol_Release(pIP);
2126
2127 exit:
2128 OleUninitialize();
2129 RegCloseKey(deadbeefkey);
2130 RegDeleteKeyA(clsidkey, deadbeefA);
2131 RegCloseKey(clsidkey);
2132 }
2133
2134 static void test_CoInitializeEx(void)
2135 {
2136 HRESULT hr;
2137
2138 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2139 ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
2140
2141 /* Calling OleInitialize for the first time should yield S_OK even with
2142 * apartment already initialized by previous CoInitialize(Ex) calls. */
2143 hr = OleInitialize(NULL);
2144 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
2145
2146 /* Subsequent calls to OleInitialize should return S_FALSE */
2147 hr = OleInitialize(NULL);
2148 ok(hr == S_FALSE, "Expected S_FALSE, hr = 0x%08x\n", hr);
2149
2150 /* Cleanup */
2151 CoUninitialize();
2152 OleUninitialize();
2153 OleUninitialize();
2154 }
2155
2156 static void test_OleInitialize_InitCounting(void)
2157 {
2158 HRESULT hr;
2159 IUnknown *pUnk;
2160 REFCLSID rclsid = &CLSID_InternetZoneManager;
2161
2162 /* 1. OleInitialize fails but OleUninitialize is still called: apartment stays initialized */
2163 hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
2164 ok(hr == S_OK, "CoInitializeEx(COINIT_MULTITHREADED) failed with error 0x%08x\n", hr);
2165
2166 hr = OleInitialize(NULL);
2167 ok(hr == RPC_E_CHANGED_MODE, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", RPC_E_CHANGED_MODE, hr);
2168 OleUninitialize();
2169
2170 pUnk = (IUnknown *)0xdeadbeef;
2171 hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
2172 ok(hr == S_OK, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
2173 if (pUnk) IUnknown_Release(pUnk);
2174
2175 CoUninitialize();
2176
2177 /* 2. Extra multiple OleUninitialize: apartment stays initialized until CoUninitialize */
2178 hr = CoInitialize(NULL);
2179 ok(hr == S_OK, "CoInitialize() failed with error 0x%08x\n", hr);
2180
2181 hr = OleInitialize(NULL);
2182 ok(hr == S_OK, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
2183 OleUninitialize();
2184 OleUninitialize();
2185 OleUninitialize();
2186
2187 pUnk = (IUnknown *)0xdeadbeef;
2188 hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
2189 ok(hr == S_OK, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
2190 if (pUnk) IUnknown_Release(pUnk);
2191
2192 CoUninitialize();
2193
2194 pUnk = (IUnknown *)0xdeadbeef;
2195 hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
2196 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", CO_E_NOTINITIALIZED, hr);
2197 if (pUnk) IUnknown_Release(pUnk);
2198
2199 /* 3. CoUninitialize does not formally deinit Ole */
2200 hr = CoInitialize(NULL);
2201 ok(hr == S_OK, "CoInitialize() failed with error 0x%08x\n", hr);
2202
2203 hr = OleInitialize(NULL);
2204 ok(hr == S_OK, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
2205
2206 CoUninitialize();
2207 CoUninitialize();
2208
2209 pUnk = (IUnknown *)0xdeadbeef;
2210 hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
2211 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", CO_E_NOTINITIALIZED, hr);
2212 /* COM is not initialized anymore */
2213 if (pUnk) IUnknown_Release(pUnk);
2214
2215 hr = OleInitialize(NULL);
2216 ok(hr == S_FALSE, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", S_FALSE, hr);
2217 /* ... but native OleInit returns S_FALSE as if Ole is considered initialized */
2218
2219 OleUninitialize();
2220
2221 }
2222
2223 static void test_OleRegGetMiscStatus(void)
2224 {
2225 ULONG_PTR cookie;
2226 HANDLE handle;
2227 DWORD status;
2228 HRESULT hr;
2229
2230 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_ICON, NULL);
2231 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2232
2233 status = 0xdeadbeef;
2234 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_ICON, &status);
2235 ok(hr == REGDB_E_CLASSNOTREG, "got 0x%08x\n", hr);
2236 ok(status == 0, "got 0x%08x\n", status);
2237
2238 status = -1;
2239 hr = OleRegGetMiscStatus(&CLSID_StdFont, DVASPECT_ICON, &status);
2240 ok(hr == S_OK, "got 0x%08x\n", hr);
2241 ok(status == 0, "got 0x%08x\n", status);
2242
2243 if ((handle = activate_context(actctx_manifest, &cookie)))
2244 {
2245 status = 0;
2246 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_ICON, &status);
2247 ok(hr == S_OK, "got 0x%08x\n", hr);
2248 ok(status == OLEMISC_RECOMPOSEONRESIZE, "got 0x%08x\n", status);
2249
2250 /* context data takes precedence over registration info */
2251 status = 0;
2252 hr = OleRegGetMiscStatus(&CLSID_StdFont, DVASPECT_ICON, &status);
2253 ok(hr == S_OK, "got 0x%08x\n", hr);
2254 ok(status == OLEMISC_RECOMPOSEONRESIZE, "got 0x%08x\n", status);
2255
2256 /* there's no such attribute in context */
2257 status = -1;
2258 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_DOCPRINT, &status);
2259 ok(hr == S_OK, "got 0x%08x\n", hr);
2260 ok(status == 0, "got 0x%08x\n", status);
2261
2262 pDeactivateActCtx(0, cookie);
2263 pReleaseActCtx(handle);
2264 }
2265 }
2266
2267 static void test_OleRegGetUserType(void)
2268 {
2269 static const WCHAR stdfont_usertypeW[] = {'S','t','a','n','d','a','r','d',' ','F','o','n','t',0};
2270 static const WCHAR stdfont2_usertypeW[] = {'C','L','S','I','D','_','S','t','d','F','o','n','t',0};
2271 static const WCHAR clsidkeyW[] = {'C','L','S','I','D',0};
2272 static const WCHAR defvalueW[] = {'D','e','f','a','u','l','t',' ','N','a','m','e',0};
2273 static const WCHAR auxvalue0W[] = {'A','u','x',' ','N','a','m','e',' ','0',0};
2274 static const WCHAR auxvalue2W[] = {'A','u','x',' ','N','a','m','e',' ','2',0};
2275 static const WCHAR auxvalue3W[] = {'A','u','x',' ','N','a','m','e',' ','3',0};
2276 static const WCHAR auxvalue4W[] = {'A','u','x',' ','N','a','m','e',' ','4',0};
2277
2278 static const char auxvalues[][16] = {
2279 "Aux Name 0",
2280 "Aux Name 1",
2281 "Aux Name 2",
2282 "Aux Name 3",
2283 "Aux Name 4"
2284 };
2285
2286 HKEY clsidhkey, hkey, auxhkey, classkey;
2287 DWORD form, ret, disposition;
2288 WCHAR clsidW[39];
2289 ULONG_PTR cookie;
2290 HANDLE handle;
2291 HRESULT hr;
2292 WCHAR *str;
2293 int i;
2294
2295 for (form = 0; form <= USERCLASSTYPE_APPNAME+1; form++) {
2296 hr = OleRegGetUserType(&CLSID_Testclass, form, NULL);
2297 ok(hr == E_INVALIDARG, "form %u: got 0x%08x\n", form, hr);
2298
2299 str = (void*)0xdeadbeef;
2300 hr = OleRegGetUserType(&CLSID_Testclass, form, &str);
2301 ok(hr == REGDB_E_CLASSNOTREG, "form %u: got 0x%08x\n", form, hr);
2302 ok(str == NULL, "form %u: got %p\n", form, str);
2303
2304 /* same string returned for StdFont for all form types */
2305 str = NULL;
2306 hr = OleRegGetUserType(&CLSID_StdFont, form, &str);
2307 ok(hr == S_OK, "form %u: got 0x%08x\n", form, hr);
2308 ok(!lstrcmpW(str, stdfont_usertypeW) || !lstrcmpW(str, stdfont2_usertypeW) /* winxp */,
2309 "form %u, got %s\n", form, wine_dbgstr_w(str));
2310 CoTaskMemFree(str);
2311 }
2312
2313 if ((handle = activate_context(actctx_manifest, &cookie)))
2314 {
2315 for (form = 0; form <= USERCLASSTYPE_APPNAME+1; form++) {
2316 str = (void*)0xdeadbeef;
2317 hr = OleRegGetUserType(&CLSID_Testclass, form, &str);
2318 ok(hr == REGDB_E_CLASSNOTREG, "form %u: got 0x%08x\n", form, hr);
2319 ok(str == NULL, "form %u: got %s\n", form, wine_dbgstr_w(str));
2320
2321 /* same string returned for StdFont for all form types */
2322 str = NULL;
2323 hr = OleRegGetUserType(&CLSID_StdFont, form, &str);
2324 ok(hr == S_OK, "form %u: got 0x%08x\n", form, hr);
2325 ok(!lstrcmpW(str, stdfont_usertypeW) || !lstrcmpW(str, stdfont2_usertypeW) /* winxp */,
2326 "form %u, got %s\n", form, wine_dbgstr_w(str));
2327 CoTaskMemFree(str);
2328 }
2329
2330 pDeactivateActCtx(0, cookie);
2331 pReleaseActCtx(handle);
2332 }
2333
2334 /* test using registered CLSID */
2335 StringFromGUID2(&CLSID_non_existent, clsidW, ARRAY_SIZE(clsidW));
2336
2337 ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsidkeyW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &clsidhkey, &disposition);
2338 if (!ret)
2339 {
2340 ret = RegCreateKeyExW(clsidhkey, clsidW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &classkey, NULL);
2341 if (ret)
2342 RegCloseKey(clsidhkey);
2343 }
2344
2345 if (ret == ERROR_ACCESS_DENIED)
2346 {
2347 win_skip("Failed to create test key, skipping some of OleRegGetUserType() tests.\n");
2348 return;
2349 }
2350
2351 ok(!ret, "failed to create a key, error %d\n", ret);
2352
2353 ret = RegSetValueExW(classkey, NULL, 0, REG_SZ, (const BYTE*)defvalueW, sizeof(defvalueW));
2354 ok(!ret, "got error %d\n", ret);
2355
2356 ret = RegCreateKeyExA(classkey, "AuxUserType", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &auxhkey, NULL);
2357 ok(!ret, "got error %d\n", ret);
2358
2359 /* populate AuxUserType */
2360 for (i = 0; i <= 4; i++) {
2361 char name[16];
2362
2363 sprintf(name, "AuxUserType\\%d", i);
2364 ret = RegCreateKeyExA(classkey, name, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2365 ok(!ret, "got error %d\n", ret);
2366
2367 ret = RegSetValueExA(hkey, NULL, 0, REG_SZ, (const BYTE*)auxvalues[i], strlen(auxvalues[i]));
2368 ok(!ret, "got error %d\n", ret);
2369 RegCloseKey(hkey);
2370 }
2371
2372 str = NULL;
2373 hr = OleRegGetUserType(&CLSID_non_existent, 0, &str);
2374 ok(hr == S_OK, "got 0x%08x\n", hr);
2375 ok(!lstrcmpW(str, auxvalue0W), "got %s\n", wine_dbgstr_w(str));
2376 CoTaskMemFree(str);
2377
2378 str = NULL;
2379 hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_FULL, &str);
2380 ok(hr == S_OK, "got 0x%08x\n", hr);
2381 ok(!lstrcmpW(str, defvalueW), "got %s\n", wine_dbgstr_w(str));
2382 CoTaskMemFree(str);
2383
2384 str = NULL;
2385 hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_SHORT, &str);
2386 ok(hr == S_OK, "got 0x%08x\n", hr);
2387 ok(!lstrcmpW(str, auxvalue2W), "got %s\n", wine_dbgstr_w(str));
2388 CoTaskMemFree(str);
2389
2390 str = NULL;
2391 hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME, &str);
2392 ok(hr == S_OK, "got 0x%08x\n", hr);
2393 ok(!lstrcmpW(str, auxvalue3W), "got %s\n", wine_dbgstr_w(str));
2394 CoTaskMemFree(str);
2395
2396 str = NULL;
2397 hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME+1, &str);
2398 ok(hr == S_OK, "got 0x%08x\n", hr);
2399 ok(!lstrcmpW(str, auxvalue4W), "got %s\n", wine_dbgstr_w(str));
2400 CoTaskMemFree(str);
2401
2402 str = NULL;
2403 hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME+2, &str);
2404 ok(hr == S_OK, "got 0x%08x\n", hr);
2405 ok(!lstrcmpW(str, defvalueW), "got %s\n", wine_dbgstr_w(str));
2406 CoTaskMemFree(str);
2407
2408 /* registry cleanup */
2409 for (i = 0; i <= 4; i++)
2410 {
2411 char name[2];
2412 sprintf(name, "%d", i);
2413 RegDeleteKeyA(auxhkey, name);
2414 }
2415 RegCloseKey(auxhkey);
2416 RegDeleteKeyA(classkey, "AuxUserType");
2417 RegCloseKey(classkey);
2418 RegDeleteKeyW(clsidhkey, clsidW);
2419 RegCloseKey(clsidhkey);
2420 if (disposition == REG_CREATED_NEW_KEY)
2421 RegDeleteKeyA(HKEY_CLASSES_ROOT, "CLSID");
2422 }
2423
2424 static void test_CoCreateGuid(void)
2425 {
2426 HRESULT hr;
2427
2428 hr = CoCreateGuid(NULL);
2429 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2430 }
2431
2432 static void CALLBACK apc_test_proc(ULONG_PTR param)
2433 {
2434 /* nothing */
2435 }
2436
2437 static DWORD CALLBACK release_semaphore_thread( LPVOID arg )
2438 {
2439 HANDLE handle = arg;
2440 if (WaitForSingleObject(handle, 200) == WAIT_TIMEOUT)
2441 ReleaseSemaphore(handle, 1, NULL);
2442 return 0;
2443 }
2444
2445 static DWORD CALLBACK send_message_thread(LPVOID arg)
2446 {
2447 HWND hWnd = arg;
2448 Sleep(50);
2449 SendMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2450 return 0;
2451 }
2452
2453 static DWORD CALLBACK send_and_post_user_message_thread(void *arg)
2454 {
2455 HWND hwnd = arg;
2456 Sleep(30);
2457 SendMessageA(hwnd, WM_USER, 0, 0);
2458 PostMessageA(hwnd, WM_USER, 0, 0);
2459 return 0;
2460 }
2461
2462 static DWORD CALLBACK post_message_thread(LPVOID arg)
2463 {
2464 HWND hWnd = arg;
2465 Sleep(50);
2466 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2467 return 0;
2468 }
2469
2470 static const char cls_name[] = "cowait_test_class";
2471
2472 static UINT cowait_msgs[100], cowait_msgs_first, cowait_msgs_last;
2473
2474 static void cowait_msgs_reset(void)
2475 {
2476 cowait_msgs_first = cowait_msgs_last = 0;
2477 }
2478
2479 #define cowait_msgs_expect_empty() _cowait_msgs_expect_empty(__LINE__)
2480 static void _cowait_msgs_expect_empty(unsigned line)
2481 {
2482 while(cowait_msgs_first < cowait_msgs_last) {
2483 ok_(__FILE__,line)(0, "unexpected message %u\n", cowait_msgs[cowait_msgs_first]);
2484 cowait_msgs_first++;
2485 }
2486 cowait_msgs_reset();
2487 }
2488
2489 #define cowait_msgs_expect_notified(a) _cowait_msgs_expect_notified(__LINE__,a)
2490 static void _cowait_msgs_expect_notified(unsigned line, UINT expected_msg)
2491 {
2492 if(cowait_msgs_first == cowait_msgs_last) {
2493 ok_(__FILE__,line)(0, "expected message %u, received none\n", expected_msg);
2494 }else {
2495 ok_(__FILE__,line)(cowait_msgs[cowait_msgs_first] == expected_msg,
2496 "expected message %u, received %u \n",
2497 expected_msg, cowait_msgs[cowait_msgs_first]);
2498 cowait_msgs_first++;
2499 }
2500 }
2501
2502 #define cowait_msgs_expect_queued(a,b) _cowait_msgs_expect_queued(__LINE__,a,b)
2503 static void _cowait_msgs_expect_queued(unsigned line, HWND hwnd, UINT expected_msg)
2504 {
2505 MSG msg;
2506 BOOL success;
2507
2508 success = PeekMessageA(&msg, hwnd, expected_msg, expected_msg, PM_REMOVE);
2509 ok_(__FILE__,line)(success, "PeekMessageA failed: %u\n", GetLastError());
2510 if(success)
2511 ok_(__FILE__,line)(msg.message == expected_msg, "unexpected message %u, expected %u\n",
2512 msg.message, expected_msg);
2513 }
2514
2515 static void flush_messages(void)
2516 {
2517 MSG msg;
2518 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ));
2519 }
2520
2521 static LRESULT CALLBACK cowait_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
2522 {
2523 if(cowait_msgs_last < ARRAY_SIZE(cowait_msgs))
2524 cowait_msgs[cowait_msgs_last++] = msg;
2525 if(msg == WM_DDE_FIRST)
2526 return 6;
2527 return DefWindowProcA(hwnd, msg, wparam, lparam);
2528 }
2529
2530 static DWORD CALLBACK cowait_unmarshal_thread(void *arg)
2531 {
2532 IStream *stream = arg;
2533 IEnumOLEVERB *enum_verb;
2534 LARGE_INTEGER zero;
2535 IUnknown *unk;
2536 HRESULT hr;
2537
2538 CoInitialize(NULL);
2539
2540 zero.QuadPart = 0;
2541 hr = IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
2542 ok(hr == S_OK, "Seek failed: %08x\n", hr);
2543
2544 hr = CoUnmarshalInterface(stream, &IID_IUnknown, (void**)&unk);
2545 ok(hr == S_OK, "CoUnmarshalInterface failed: %08x\n", hr);
2546
2547 hr = IUnknown_QueryInterface(unk, &IID_IEnumOLEVERB, (void**)&enum_verb);
2548 ok(hr == S_OK, "QueryInterface failed: %08x\n", hr);
2549
2550 IEnumOLEVERB_Release(enum_verb);
2551 IUnknown_Release(unk);
2552
2553 CoUninitialize();
2554 return 0;
2555 }
2556
2557 static DWORD CALLBACK test_CoWaitForMultipleHandles_thread(LPVOID arg)
2558 {
2559 HANDLE *handles = arg, event, thread;
2560 IStream *stream;
2561 BOOL success;
2562 DWORD index, tid;
2563 HRESULT hr;
2564 HWND hWnd;
2565 UINT uMSG = 0xc065;
2566 MSG msg;
2567 int ret;
2568
2569 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2570 ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
2571
2572 hWnd = CreateWindowExA(0, cls_name, "Test (thread)", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
2573 ok(hWnd != 0, "CreateWindowExA failed %u\n", GetLastError());
2574
2575 index = 0xdeadbeef;
2576 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2577 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2578 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2579 ok(index==0 || index==0xdeadbeef/* Win 8 */, "expected index 0, got %u\n", index);
2580 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2581 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2582
2583 index = 0xdeadbeef;
2584 PostMessageA(hWnd, WM_USER, 0, 0);
2585 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2586 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2587 ok(index==0 || index==0xdeadbeef/* Win 8 */, "expected index 0, got %u\n", index);
2588 success = PeekMessageA(&msg, hWnd, WM_USER, WM_USER, PM_REMOVE);
2589 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2590
2591 /* Even if CoWaitForMultipleHandles does not pump a message it peeks
2592 * at ALL of them */
2593 index = 0xdeadbeef;
2594 PostMessageA(NULL, uMSG, 0, 0);
2595
2596 hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 2, handles, &index);
2597 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2598 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2599
2600 /* Make sure message was peeked at */
2601 ret = MsgWaitForMultipleObjectsEx(0, NULL, 2, QS_ALLPOSTMESSAGE, MWMO_ALERTABLE);
2602 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
2603
2604 /* But not pumped */
2605 success = PeekMessageA(&msg, NULL, uMSG, uMSG, PM_REMOVE);
2606 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2607
2608 DestroyWindow(hWnd);
2609 CoUninitialize();
2610
2611 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2612 ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
2613
2614 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2615 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
2616
2617 hr = CoMarshalInterface(stream, &IID_IUnknown, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2618 ok(hr == S_OK, "CoMarshalInterface should have returned S_OK instead of 0x%08x\n", hr);
2619
2620 event = CreateEventW(NULL, TRUE, FALSE, NULL);
2621
2622 PostQuitMessage(66);
2623 PostThreadMessageW(GetCurrentThreadId(), WM_QUIT, 0, 0);
2624
2625 hr = CoRegisterMessageFilter(&MessageFilter, NULL);
2626 ok(hr == S_OK, "CoRegisterMessageFilter failed: %08x\n", hr);
2627
2628 thread = CreateThread(NULL, 0, cowait_unmarshal_thread, stream, 0, &tid);
2629 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2630 hr = CoWaitForMultipleHandles(0, 50, 1, &event, &index);
2631 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2632 index = WaitForSingleObject(thread, 200);
2633 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2634 CloseHandle(thread);
2635
2636 hr = CoRegisterMessageFilter(NULL, NULL);
2637 ok(hr == S_OK, "CoRegisterMessageFilter failed: %08x\n", hr);
2638
2639 IStream_Release(stream);
2640
2641 CloseHandle(event);
2642 CoUninitialize();
2643 return 0;
2644 }
2645
2646 static void test_CoWaitForMultipleHandles(void)
2647 {
2648 HANDLE handles[2], thread;
2649 DWORD index, tid;
2650 WNDCLASSEXA wc;
2651 BOOL success;
2652 HRESULT hr;
2653 HWND hWnd;
2654 MSG msg;
2655
2656 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2657 ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
2658
2659 memset(&wc, 0, sizeof(wc));
2660 wc.cbSize = sizeof(wc);
2661 wc.style = CS_VREDRAW | CS_HREDRAW;
2662 wc.hInstance = GetModuleHandleA(0);
2663 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
2664 wc.hbrBackground = NULL;
2665 wc.lpszClassName = cls_name;
2666 wc.lpfnWndProc = cowait_window_proc;
2667 success = RegisterClassExA(&wc) != 0;
2668 ok(success, "RegisterClassExA failed %u\n", GetLastError());
2669
2670 hWnd = CreateWindowExA(0, cls_name, "Test", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
2671 ok(hWnd != 0, "CreateWindowExA failed %u\n", GetLastError());
2672 handles[0] = CreateSemaphoreA(NULL, 1, 1, NULL);
2673 ok(handles[0] != 0, "CreateSemaphoreA failed %u\n", GetLastError());
2674 handles[1] = CreateSemaphoreA(NULL, 1, 1, NULL);
2675 ok(handles[1] != 0, "CreateSemaphoreA failed %u\n", GetLastError());
2676
2677 /* test without flags */
2678
2679 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2680 hr = CoWaitForMultipleHandles(0, 50, 0, handles, NULL);
2681 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
2682 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2683 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2684
2685 index = 0xdeadbeef;
2686 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2687 hr = CoWaitForMultipleHandles(0, 50, 0, NULL, &index);
2688 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
2689 ok(index == 0, "expected index 0, got %u\n", index);
2690 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2691 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2692
2693 index = 0xdeadbeef;
2694 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2695 hr = CoWaitForMultipleHandles(0, 50, 0, handles, &index);
2696 ok(hr == RPC_E_NO_SYNC, "expected RPC_E_NO_SYNC, got 0x%08x\n", hr);
2697 ok(index == 0, "expected index 0, got %u\n", index);
2698 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2699 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2700
2701 index = 0xdeadbeef;
2702 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2703 hr = CoWaitForMultipleHandles(0, 50, 1, handles, &index);
2704 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2705 ok(index == 0, "expected index 0, got %u\n", index);
2706 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2707 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2708
2709 index = 0xdeadbeef;
2710 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2711 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2712 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2713 ok(index == 1, "expected index 1, got %u\n", index);
2714 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2715 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2716
2717 index = 0xdeadbeef;
2718 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2719 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2720 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2721 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2722 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2723 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2724
2725 /* test PostMessageA/SendMessageA from a different thread */
2726
2727 index = 0xdeadbeef;
2728 thread = CreateThread(NULL, 0, post_message_thread, hWnd, 0, &tid);
2729 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2730 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2731 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2732 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2733 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2734 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2735 index = WaitForSingleObject(thread, 200);
2736 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2737 CloseHandle(thread);
2738
2739 index = 0xdeadbeef;
2740 thread = CreateThread(NULL, 0, send_message_thread, hWnd, 0, &tid);
2741 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2742 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2743 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2744 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2745 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2746 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2747 index = WaitForSingleObject(thread, 200);
2748 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2749 CloseHandle(thread);
2750
2751 ReleaseSemaphore(handles[0], 1, NULL);
2752 ReleaseSemaphore(handles[1], 1, NULL);
2753
2754 /* test with COWAIT_WAITALL */
2755
2756 index = 0xdeadbeef;
2757 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2758 hr = CoWaitForMultipleHandles(COWAIT_WAITALL, 50, 2, handles, &index);
2759 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2760 ok(index == 0, "expected index 0, got %u\n", index);
2761 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2762 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2763
2764 index = 0xdeadbeef;
2765 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2766 hr = CoWaitForMultipleHandles(0, 50, 2, handles, &index);
2767 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2768 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2769 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2770 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2771
2772 ReleaseSemaphore(handles[0], 1, NULL);
2773 ReleaseSemaphore(handles[1], 1, NULL);
2774
2775 /* test with COWAIT_ALERTABLE */
2776
2777 index = 0xdeadbeef;
2778 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2779 hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 1, handles, &index);
2780 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2781 ok(index == 0, "expected index 0, got %u\n", index);
2782 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2783 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2784
2785 index = 0xdeadbeef;
2786 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2787 hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 2, handles, &index);
2788 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2789 ok(index == 1, "expected index 1, got %u\n", index);
2790 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2791 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2792
2793 index = 0xdeadbeef;
2794 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2795 hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 2, handles, &index);
2796 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2797 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2798 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2799 ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
2800
2801 index = 0xdeadbeef;
2802 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2803 success = QueueUserAPC(apc_test_proc, GetCurrentThread(), 0);
2804 ok(success, "QueueUserAPC failed %u\n", GetLastError());
2805 hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 2, handles, &index);
2806 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2807 ok(index == WAIT_IO_COMPLETION, "expected index WAIT_IO_COMPLETION, got %u\n", index);
2808 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2809 ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
2810
2811 /* test with COWAIT_INPUTAVAILABLE (semaphores are still locked) */
2812
2813 index = 0xdeadbeef;
2814 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2815 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_NOREMOVE);
2816 ok(success, "PeekMessageA returned FALSE\n");
2817 hr = CoWaitForMultipleHandles(0, 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 = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_NOREMOVE);
2826 ok(success, "PeekMessageA returned FALSE\n");
2827 thread = CreateThread(NULL, 0, release_semaphore_thread, handles[1], 0, &tid);
2828 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2829 hr = CoWaitForMultipleHandles(COWAIT_INPUTAVAILABLE, 50, 2, handles, &index);
2830 ok(hr == RPC_S_CALLPENDING || broken(hr == E_INVALIDARG) || broken(hr == S_OK) /* Win 8 */,
2831 "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2832 if (hr != S_OK) ReleaseSemaphore(handles[1], 1, NULL);
2833 ok(index == 0 || broken(index == 1) /* Win 8 */, "expected index 0, got %u\n", index);
2834 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2835 ok(!success || broken(success && hr == E_INVALIDARG),
2836 "CoWaitForMultipleHandles didn't pump any messages\n");
2837 index = WaitForSingleObject(thread, 200);
2838 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2839 CloseHandle(thread);
2840
2841 cowait_msgs_reset();
2842 PostMessageA(hWnd, 0, 0, 0);
2843 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2844 PostMessageA(hWnd, WM_USER+1, 0, 0);
2845 PostMessageA(hWnd, WM_DDE_FIRST+1, 0, 0);
2846 thread = CreateThread(NULL, 0, send_and_post_user_message_thread, hWnd, 0, &tid);
2847 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2848
2849 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2850 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2851
2852 cowait_msgs_expect_notified(WM_DDE_FIRST);
2853 cowait_msgs_expect_notified(WM_DDE_FIRST+1);
2854 cowait_msgs_expect_notified(WM_USER);
2855 cowait_msgs_expect_empty();
2856 cowait_msgs_expect_queued(hWnd, WM_USER);
2857 cowait_msgs_expect_queued(hWnd, WM_USER+1);
2858 flush_messages();
2859
2860 index = WaitForSingleObject(thread, 200);
2861 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2862 CloseHandle(thread);
2863
2864 /* test behaviour of WM_QUIT (semaphores are still locked) */
2865
2866 PostMessageA(hWnd, WM_QUIT, 40, 0);
2867 memset(&msg, 0, sizeof(msg));
2868 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2869 ok(success, "PeekMessageA failed, error %u\n", GetLastError());
2870 ok(msg.message == WM_QUIT, "expected msg.message = WM_QUIT, got %u\n", msg.message);
2871 ok(msg.wParam == 40, "expected msg.wParam = 40, got %lu\n", msg.wParam);
2872 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2873 ok(!success, "PeekMessageA succeeded\n");
2874
2875 cowait_msgs_reset();
2876 PostMessageA(hWnd, WM_QUIT, 40, 0);
2877 PostMessageA(hWnd, 0, 0, 0);
2878 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2879 PostMessageA(hWnd, WM_USER+1, 0, 0);
2880 PostMessageA(hWnd, WM_DDE_FIRST+1, 0, 0);
2881 thread = CreateThread(NULL, 0, send_and_post_user_message_thread, hWnd, 0, &tid);
2882 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2883
2884 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2885 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2886
2887 cowait_msgs_expect_notified(WM_DDE_FIRST);
2888 cowait_msgs_expect_notified(WM_DDE_FIRST+1);
2889 cowait_msgs_expect_notified(WM_USER);
2890 cowait_msgs_expect_empty();
2891 cowait_msgs_expect_queued(hWnd, WM_USER);
2892 flush_messages();
2893
2894 index = WaitForSingleObject(thread, 200);
2895 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2896 CloseHandle(thread);
2897
2898 index = 0xdeadbeef;
2899 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2900 PostMessageA(hWnd, WM_QUIT, 41, 0);
2901 thread = CreateThread(NULL, 0, post_message_thread, hWnd, 0, &tid);
2902 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2903 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2904 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2905 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2906 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2907 todo_wine
2908 ok(success || broken(!success) /* Win 2000/XP/8 */, "PeekMessageA failed, error %u\n", GetLastError());
2909 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2910 ok(!success, "PeekMessageA succeeded\n");
2911 memset(&msg, 0, sizeof(msg));
2912 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2913 todo_wine
2914 ok(!success || broken(success) /* Win 2000/XP/8 */, "PeekMessageA succeeded\n");
2915 if (success)
2916 {
2917 ok(msg.message == WM_QUIT, "expected msg.message = WM_QUIT, got %u\n", msg.message);
2918 ok(msg.wParam == 41, "expected msg.wParam = 41, got %lu\n", msg.wParam);
2919 }
2920 index = WaitForSingleObject(thread, 200);
2921 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2922 CloseHandle(thread);
2923
2924 index = 0xdeadbeef;
2925 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2926 PostMessageA(hWnd, WM_QUIT, 42, 0);
2927 thread = CreateThread(NULL, 0, send_message_thread, hWnd, 0, &tid);
2928 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2929 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2930 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2931 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2932 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2933 ok(!success, "CoWaitForMultipleHandles didn't pump all WM_DDE_FIRST messages\n");
2934 memset(&msg, 0, sizeof(msg));
2935 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2936 ok(success, "PeekMessageA failed, error %u\n", GetLastError());
2937 ok(msg.message == WM_QUIT, "expected msg.message = WM_QUIT, got %u\n", msg.message);
2938 ok(msg.wParam == 42, "expected msg.wParam = 42, got %lu\n", msg.wParam);
2939 index = WaitForSingleObject(thread, 200);
2940 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2941 CloseHandle(thread);
2942
2943 PostQuitMessage(43);
2944 memset(&msg, 0, sizeof(msg));
2945 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2946 ok(success || broken(!success) /* Win 8 */, "PeekMessageA failed, error %u\n", GetLastError());
2947 if (!success)
2948 win_skip("PostQuitMessage didn't queue a WM_QUIT message, skipping tests\n");
2949 else
2950 {
2951 ok(msg.message == WM_QUIT, "expected msg.message = WM_QUIT, got %u\n", msg.message);
2952 ok(msg.wParam == 43, "expected msg.wParam = 43, got %lu\n", msg.wParam);
2953 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2954 ok(!success, "PeekMessageA succeeded\n");
2955
2956 index = 0xdeadbeef;
2957 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2958 PostQuitMessage(44);
2959 thread = CreateThread(NULL, 0, post_message_thread, hWnd, 0, &tid);
2960 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2961 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2962 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2963 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2964 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2965 ok(success, "PeekMessageA failed, error %u\n", GetLastError());
2966 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2967 ok(!success, "PeekMessageA succeeded\n");
2968 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2969 ok(!success, "CoWaitForMultipleHandles didn't remove WM_QUIT messages\n");
2970 index = WaitForSingleObject(thread, 200);
2971 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2972 CloseHandle(thread);
2973
2974 index = 0xdeadbeef;
2975 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
2976 PostQuitMessage(45);
2977 thread = CreateThread(NULL, 0, send_message_thread, hWnd, 0, &tid);
2978 ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError());
2979 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
2980 ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr);
2981 ok(index == 0 || broken(index == 0xdeadbeef) /* Win 8 */, "expected index 0, got %u\n", index);
2982 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2983 ok(success, "PeekMessageA failed, error %u\n", GetLastError());
2984 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
2985 ok(!success, "PeekMessageA succeeded\n");
2986 success = PeekMessageA(&msg, hWnd, WM_QUIT, WM_QUIT, PM_REMOVE);
2987 ok(!success, "CoWaitForMultipleHandles didn't remove WM_QUIT messages\n");
2988 index = WaitForSingleObject(thread, 200);
2989 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2990 CloseHandle(thread);
2991 }
2992
2993 /* test message pumping when CoWaitForMultipleHandles is called from non main apartment thread */
2994 thread = CreateThread(NULL, 0, test_CoWaitForMultipleHandles_thread, handles, 0, &tid);
2995 index = WaitForSingleObject(thread, 500);
2996 ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2997 CloseHandle(thread);
2998
2999 CoUninitialize();
3000
3001 /* If COM was not initialized, messages are neither pumped nor peeked at */
3002 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
3003 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
3004 ok(hr == RPC_S_CALLPENDING, "got %#x\n", hr);
3005 success = MsgWaitForMultipleObjectsEx(0, NULL, 2, QS_ALLPOSTMESSAGE, MWMO_ALERTABLE);
3006 ok(success == 0, "MsgWaitForMultipleObjects returned %x\n", success);
3007 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
3008 ok(success, "PeekMessage failed: %u\n", GetLastError());
3009
3010 /* same in an MTA */
3011 CoInitializeEx(NULL, COINIT_MULTITHREADED);
3012
3013 PostMessageA(hWnd, WM_DDE_FIRST, 0, 0);
3014 hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index);
3015 ok(hr == RPC_S_CALLPENDING, "got %#x\n", hr);
3016 success = MsgWaitForMultipleObjectsEx(0, NULL, 2, QS_ALLPOSTMESSAGE, MWMO_ALERTABLE);
3017 ok(success == 0, "MsgWaitForMultipleObjects returned %x\n", success);
3018 success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE);
3019 ok(success, "PeekMessage failed: %u\n", GetLastError());
3020
3021 CoUninitialize();
3022
3023 CloseHandle(handles[0]);
3024 CloseHandle(handles[1]);
3025 DestroyWindow(hWnd);
3026
3027 success = UnregisterClassA(cls_name, GetModuleHandleA(0));
3028 ok(success, "UnregisterClass failed %u\n", GetLastError());
3029 }
3030
3031 static void test_CoGetMalloc(void)
3032 {
3033 IMalloc *imalloc;
3034 HRESULT hr;
3035
3036 if (0) /* crashes on native */
3037 hr = CoGetMalloc(0, NULL);
3038
3039 imalloc = (void*)0xdeadbeef;
3040 hr = CoGetMalloc(0, &imalloc);
3041 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3042 ok(imalloc == NULL, "got %p\n", imalloc);
3043
3044 imalloc = (void*)0xdeadbeef;
3045 hr = CoGetMalloc(MEMCTX_SHARED, &imalloc);
3046 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3047 ok(imalloc == NULL, "got %p\n", imalloc);
3048
3049 imalloc = (void*)0xdeadbeef;
3050 hr = CoGetMalloc(MEMCTX_MACSYSTEM, &imalloc);
3051 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3052 ok(imalloc == NULL, "got %p\n", imalloc);
3053
3054 imalloc = (void*)0xdeadbeef;
3055 hr = CoGetMalloc(MEMCTX_UNKNOWN, &imalloc);
3056 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3057 ok(imalloc == NULL, "got %p\n", imalloc);
3058
3059 imalloc = (void*)0xdeadbeef;
3060 hr = CoGetMalloc(MEMCTX_SAME, &imalloc);
3061 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3062 ok(imalloc == NULL, "got %p\n", imalloc);
3063
3064 imalloc = NULL;
3065 hr = CoGetMalloc(MEMCTX_TASK, &imalloc);
3066 ok(hr == S_OK, "got 0x%08x\n", hr);
3067 ok(imalloc != NULL, "got %p\n", imalloc);
3068 IMalloc_Release(imalloc);
3069 }
3070
3071 static void test_CoGetApartmentType(void)
3072 {
3073 APTTYPEQUALIFIER qualifier;
3074 APTTYPE type;
3075 HRESULT hr;
3076
3077 if (!pCoGetApartmentType)
3078 {
3079 win_skip("CoGetApartmentType not present\n");
3080 return;
3081 }
3082
3083 hr = pCoGetApartmentType(NULL, NULL);
3084 ok(hr == E_INVALIDARG, "CoGetApartmentType succeeded, error: 0x%08x\n", hr);
3085
3086 type = 0xdeadbeef;
3087 hr = pCoGetApartmentType(&type, NULL);
3088 ok(hr == E_INVALIDARG, "CoGetApartmentType succeeded, error: 0x%08x\n", hr);
3089 ok(type == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", type);
3090
3091 qualifier = 0xdeadbeef;
3092 hr = pCoGetApartmentType(NULL, &qualifier);
3093 ok(hr == E_INVALIDARG, "CoGetApartmentType succeeded, error: 0x%08x\n", hr);
3094 ok(qualifier == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", qualifier);
3095
3096 type = 0xdeadbeef;
3097 qualifier = 0xdeadbeef;
3098 hr = pCoGetApartmentType(&type, &qualifier);
3099 ok(hr == CO_E_NOTINITIALIZED, "CoGetApartmentType succeeded, error: 0x%08x\n", hr);
3100 ok(type == APTTYPE_CURRENT, "Expected APTTYPE_CURRENT, got %u\n", type);
3101 ok(qualifier == APTTYPEQUALIFIER_NONE, "Expected APTTYPEQUALIFIER_NONE, got %u\n", qualifier);
3102
3103 type = 0xdeadbeef;
3104 qualifier = 0xdeadbeef;
3105 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
3106 ok(hr == S_OK, "CoInitializeEx failed, error: 0x%08x\n", hr);
3107 hr = pCoGetApartmentType(&type, &qualifier);
3108 ok(hr == S_OK, "CoGetApartmentType failed, error: 0x%08x\n", hr);
3109 ok(type == APTTYPE_MAINSTA, "Expected APTTYPE_MAINSTA, got %u\n", type);
3110 ok(qualifier == APTTYPEQUALIFIER_NONE, "Expected APTTYPEQUALIFIER_NONE, got %u\n", qualifier);
3111 CoUninitialize();
3112
3113 type = 0xdeadbeef;
3114 qualifier = 0xdeadbeef;
3115 hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
3116 ok(hr == S_OK, "CoInitializeEx failed, error: 0x%08x\n", hr);
3117 hr = pCoGetApartmentType(&type, &qualifier);
3118 ok(hr == S_OK, "CoGetApartmentType failed, error: 0x%08x\n", hr);
3119 ok(type == APTTYPE_MTA, "Expected APTTYPE_MTA, got %u\n", type);
3120 ok(qualifier == APTTYPEQUALIFIER_NONE, "Expected APTTYPEQUALIFIER_NONE, got %u\n", qualifier);
3121 CoUninitialize();
3122 }
3123
3124 static HRESULT WINAPI testspy_QI(IMallocSpy *iface, REFIID riid, void **obj)
3125 {
3126 if (IsEqualIID(riid, &IID_IMallocSpy) || IsEqualIID(riid, &IID_IUnknown))
3127 {
3128 *obj = iface;
3129 IMallocSpy_AddRef(iface);
3130 return S_OK;
3131 }
3132
3133 return E_NOINTERFACE;
3134 }
3135
3136 static ULONG WINAPI testspy_AddRef(IMallocSpy *iface)
3137 {
3138 return 2;
3139 }
3140
3141 static ULONG WINAPI testspy_Release(IMallocSpy *iface)
3142 {
3143 return 1;
3144 }
3145
3146 static SIZE_T WINAPI testspy_PreAlloc(IMallocSpy *iface, SIZE_T cb)
3147 {
3148 ok(0, "unexpected call\n");
3149 return 0;
3150 }
3151
3152 static void* WINAPI testspy_PostAlloc(IMallocSpy *iface, void *ptr)
3153 {
3154 ok(0, "unexpected call\n");
3155 return NULL;
3156 }
3157
3158 static void* WINAPI testspy_PreFree(IMallocSpy *iface, void *ptr, BOOL spyed)
3159 {
3160 ok(0, "unexpected call\n");
3161 return NULL;
3162 }
3163
3164 static void WINAPI testspy_PostFree(IMallocSpy *iface, BOOL spyed)
3165 {
3166 ok(0, "unexpected call\n");
3167 }
3168
3169 static SIZE_T WINAPI testspy_PreRealloc(IMallocSpy *iface, void *ptr, SIZE_T cb, void **newptr, BOOL spyed)
3170 {
3171 ok(0, "unexpected call\n");
3172 return 0;
3173 }
3174
3175 static void* WINAPI testspy_PostRealloc(IMallocSpy *iface, void *ptr, BOOL spyed)
3176 {
3177 ok(0, "unexpected call\n");
3178 return NULL;
3179 }
3180
3181 static void* WINAPI testspy_PreGetSize(IMallocSpy *iface, void *ptr, BOOL spyed)
3182 {
3183 ok(0, "unexpected call\n");
3184 return NULL;
3185 }
3186
3187 static SIZE_T WINAPI testspy_PostGetSize(IMallocSpy *iface, SIZE_T actual, BOOL spyed)
3188 {
3189 ok(0, "unexpected call\n");
3190 return 0;
3191 }
3192
3193 static void* WINAPI testspy_PreDidAlloc(IMallocSpy *iface, void *ptr, BOOL spyed)
3194 {
3195 ok(0, "unexpected call\n");
3196 return NULL;
3197 }
3198
3199 static int WINAPI testspy_PostDidAlloc(IMallocSpy *iface, void *ptr, BOOL spyed, int actual)
3200 {
3201 ok(0, "unexpected call\n");
3202 return 0;
3203 }
3204
3205 static void WINAPI testspy_PreHeapMinimize(IMallocSpy *iface)
3206 {
3207 ok(0, "unexpected call\n");
3208 }
3209
3210 static void WINAPI testspy_PostHeapMinimize(IMallocSpy *iface)
3211 {
3212 ok(0, "unexpected call\n");
3213 }
3214
3215 static const IMallocSpyVtbl testspyvtbl =
3216 {
3217 testspy_QI,
3218 testspy_AddRef,
3219 testspy_Release,
3220 testspy_PreAlloc,
3221 testspy_PostAlloc,
3222 testspy_PreFree,
3223 testspy_PostFree,
3224 testspy_PreRealloc,
3225 testspy_PostRealloc,
3226 testspy_PreGetSize,
3227 testspy_PostGetSize,
3228 testspy_PreDidAlloc,
3229 testspy_PostDidAlloc,
3230 testspy_PreHeapMinimize,
3231 testspy_PostHeapMinimize
3232 };
3233
3234 static IMallocSpy testspy = { &testspyvtbl };
3235
3236 static void test_IMallocSpy(void)
3237 {
3238 IMalloc *imalloc;
3239 HRESULT hr;
3240
3241 hr = CoRegisterMallocSpy(NULL);
3242 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3243
3244 hr = CoRevokeMallocSpy();
3245 ok(hr == CO_E_OBJNOTREG, "got 0x%08x\n", hr);
3246
3247 hr = CoRegisterMallocSpy(&testspy);
3248 ok(hr == S_OK, "got 0x%08x\n", hr);
3249
3250 hr = CoRegisterMallocSpy(NULL);
3251 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3252
3253 hr = CoRegisterMallocSpy(&testspy);
3254 ok(hr == CO_E_OBJISREG, "got 0x%08x\n", hr);
3255
3256 imalloc = NULL;
3257 hr = CoGetMalloc(MEMCTX_TASK, &imalloc);
3258 ok(hr == S_OK, "got 0x%08x\n", hr);
3259 ok(imalloc != NULL, "got %p\n", imalloc);
3260
3261 IMalloc_Free(imalloc, NULL);
3262
3263 IMalloc_Release(imalloc);
3264
3265 hr = CoRevokeMallocSpy();
3266 ok(hr == S_OK, "got 0x%08x\n", hr);
3267
3268 hr = CoRevokeMallocSpy();
3269 ok(hr == CO_E_OBJNOTREG, "got 0x%08x\n", hr);
3270 }
3271
3272 static void test_CoGetCurrentLogicalThreadId(void)
3273 {
3274 HRESULT hr;
3275 GUID id;
3276
3277 hr = CoGetCurrentLogicalThreadId(NULL);
3278 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3279
3280 id = GUID_NULL;
3281 hr = CoGetCurrentLogicalThreadId(&id);
3282 ok(hr == S_OK, "got 0x%08x\n", hr);
3283 ok(!IsEqualGUID(&id, &GUID_NULL), "got null id\n");
3284 }
3285
3286 static HRESULT WINAPI testinitialize_QI(IInitializeSpy *iface, REFIID riid, void **obj)
3287 {
3288 if (IsEqualIID(riid, &IID_IInitializeSpy) || IsEqualIID(riid, &IID_IUnknown))
3289 {
3290 *obj = iface;
3291 IInitializeSpy_AddRef(iface);
3292 return S_OK;
3293 }
3294
3295 *obj = NULL;
3296 return E_NOINTERFACE;
3297 }
3298
3299 static ULONG WINAPI testinitialize_AddRef(IInitializeSpy *iface)
3300 {
3301 return 2;
3302 }
3303
3304 static ULONG WINAPI testinitialize_Release(IInitializeSpy *iface)
3305 {
3306 return 1;
3307 }
3308
3309 static HRESULT WINAPI testinitialize_PreInitialize(IInitializeSpy *iface, DWORD coinit, DWORD aptrefs)
3310 {
3311 ok(0, "unexpected call\n");
3312 return E_NOTIMPL;
3313 }
3314
3315 static HRESULT WINAPI testinitialize_PostInitialize(IInitializeSpy *iface, HRESULT hr, DWORD coinit, DWORD aptrefs)
3316 {
3317 ok(0, "unexpected call\n");
3318 return E_NOTIMPL;
3319 }
3320
3321 static HRESULT WINAPI testinitialize_PreUninitialize(IInitializeSpy *iface, DWORD aptrefs)
3322 {
3323 ok(0, "unexpected call\n");
3324 return E_NOTIMPL;
3325 }
3326
3327 static HRESULT WINAPI testinitialize_PostUninitialize(IInitializeSpy *iface, DWORD aptrefs)
3328 {
3329 ok(0, "unexpected call\n");
3330 return E_NOTIMPL;
3331 }
3332
3333 static const IInitializeSpyVtbl testinitializevtbl =
3334 {
3335 testinitialize_QI,
3336 testinitialize_AddRef,
3337 testinitialize_Release,
3338 testinitialize_PreInitialize,
3339 testinitialize_PostInitialize,
3340 testinitialize_PreUninitialize,
3341 testinitialize_PostUninitialize
3342 };
3343
3344 static IInitializeSpy testinitialize = { &testinitializevtbl };
3345
3346 static void test_IInitializeSpy(void)
3347 {
3348 ULARGE_INTEGER cookie, cookie1, cookie2;
3349 HRESULT hr;
3350
3351 hr = CoRegisterInitializeSpy(NULL, NULL);
3352 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3353
3354 cookie.QuadPart = 1;
3355 hr = CoRegisterInitializeSpy(NULL, &cookie);
3356 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3357 ok(cookie.QuadPart == 1, "got wrong cookie\n");
3358
3359 hr = CoRegisterInitializeSpy(&testinitialize, NULL);
3360 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3361
3362 cookie.HighPart = 0;
3363 cookie.LowPart = 1;
3364 hr = CoRegisterInitializeSpy(&testinitialize, &cookie);
3365 ok(hr == S_OK, "got 0x%08x\n", hr);
3366 todo_wine {
3367 ok(cookie.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie.HighPart,
3368 GetCurrentThreadId());
3369 ok(cookie.LowPart == 0, "got wrong low part 0x%x\n", cookie.LowPart);
3370 }
3371 /* register same instance one more time */
3372 cookie1.HighPart = 0;
3373 cookie1.LowPart = 0;
3374 hr = CoRegisterInitializeSpy(&testinitialize, &cookie1);
3375 todo_wine {
3376 ok(hr == S_OK, "got 0x%08x\n", hr);
3377 ok(cookie1.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie1.HighPart,
3378 GetCurrentThreadId());
3379 ok(cookie1.LowPart == 1, "got wrong low part 0x%x\n", cookie1.LowPart);
3380 }
3381 cookie2.HighPart = 0;
3382 cookie2.LowPart = 0;
3383 hr = CoRegisterInitializeSpy(&testinitialize, &cookie2);
3384 todo_wine {
3385 ok(hr == S_OK, "got 0x%08x\n", hr);
3386 ok(cookie2.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie2.HighPart,
3387 GetCurrentThreadId());
3388 ok(cookie2.LowPart == 2, "got wrong low part 0x%x\n", cookie2.LowPart);
3389 }
3390 hr = CoRevokeInitializeSpy(cookie1);
3391 todo_wine
3392 ok(hr == S_OK, "got 0x%08x\n", hr);
3393
3394 hr = CoRevokeInitializeSpy(cookie1);
3395 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3396
3397 cookie1.HighPart = 0;
3398 cookie1.LowPart = 0;
3399 hr = CoRegisterInitializeSpy(&testinitialize, &cookie1);
3400 todo_wine {
3401 ok(hr == S_OK, "got 0x%08x\n", hr);
3402 ok(cookie1.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie1.HighPart,
3403 GetCurrentThreadId());
3404 ok(cookie1.LowPart == 1, "got wrong low part 0x%x\n", cookie1.LowPart);
3405 }
3406 hr = CoRevokeInitializeSpy(cookie);
3407 ok(hr == S_OK, "got 0x%08x\n", hr);
3408
3409 hr = CoRevokeInitializeSpy(cookie1);
3410 todo_wine
3411 ok(hr == S_OK, "got 0x%08x\n", hr);
3412
3413 hr = CoRevokeInitializeSpy(cookie2);
3414 todo_wine
3415 ok(hr == S_OK, "got 0x%08x\n", hr);
3416 }
3417
3418 static HRESULT g_persistfile_qi_ret;
3419 static HRESULT g_persistfile_load_ret;
3420 static HRESULT WINAPI testinstance_QI(IPersistFile *iface, REFIID riid, void **obj)
3421 {
3422 if (IsEqualIID(riid, &IID_IUnknown)) {
3423 *obj = iface;
3424 IUnknown_AddRef(iface);
3425 return S_OK;
3426 }
3427
3428 if (IsEqualIID(riid, &IID_IPersistFile)) {
3429 if (SUCCEEDED(g_persistfile_qi_ret)) {
3430 *obj = iface;
3431 IUnknown_AddRef(iface);
3432 }
3433 else
3434 *obj = NULL;
3435 return g_persistfile_qi_ret;
3436 }
3437
3438 ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid));
3439 *obj = NULL;
3440 return E_NOINTERFACE;
3441 }
3442
3443 static ULONG WINAPI testinstance_AddRef(IPersistFile *iface)
3444 {
3445 return 2;
3446 }
3447
3448 static ULONG WINAPI testinstance_Release(IPersistFile *iface)
3449 {
3450 return 1;
3451 }
3452
3453 static HRESULT WINAPI testinstance_GetClassID(IPersistFile *iface, CLSID *clsid)
3454 {
3455 ok(0, "unexpected call\n");
3456 return E_NOTIMPL;
3457 }
3458
3459 static HRESULT WINAPI testinstance_IsDirty(IPersistFile *iface)
3460 {
3461 ok(0, "unexpected call\n");
3462 return E_NOTIMPL;
3463 }
3464
3465 static HRESULT WINAPI testinstance_Load(IPersistFile *iface, LPCOLESTR filename, DWORD mode)
3466 {
3467 return g_persistfile_load_ret;
3468 }
3469
3470 static HRESULT WINAPI testinstance_Save(IPersistFile *iface, LPCOLESTR filename, BOOL remember)
3471 {
3472 return E_NOTIMPL;
3473 }
3474
3475 static HRESULT WINAPI testinstance_SaveCompleted(IPersistFile *iface, LPCOLESTR filename)
3476 {
3477 ok(0, "unexpected call\n");
3478 return E_NOTIMPL;
3479 }
3480
3481 static HRESULT WINAPI testinstance_GetCurFile(IPersistFile *iface, LPOLESTR *filename)
3482 {
3483 ok(0, "unexpected call\n");
3484 return E_NOTIMPL;
3485 }
3486
3487 static const IPersistFileVtbl testpersistfilevtbl = {
3488 testinstance_QI,
3489 testinstance_AddRef,
3490 testinstance_Release,
3491 testinstance_GetClassID,
3492 testinstance_IsDirty,
3493 testinstance_Load,
3494 testinstance_Save,
3495 testinstance_SaveCompleted,
3496 testinstance_GetCurFile
3497 };
3498
3499 static IPersistFile testpersistfile = { &testpersistfilevtbl };
3500
3501 static HRESULT WINAPI getinstance_cf_QI(IClassFactory *iface, REFIID riid, void **obj)
3502 {
3503 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) {
3504 *obj = iface;
3505 IClassFactory_AddRef(iface);
3506 return S_OK;
3507 }
3508
3509 *obj = NULL;
3510 return E_NOINTERFACE;
3511 }
3512
3513 static ULONG WINAPI getinstance_cf_AddRef(IClassFactory *iface)
3514 {
3515 return 2;
3516 }
3517
3518 static ULONG WINAPI getinstance_cf_Release(IClassFactory *iface)
3519 {
3520 return 1;
3521 }
3522
3523 static HRESULT WINAPI getinstance_cf_CreateInstance(IClassFactory *iface, IUnknown *outer,
3524 REFIID riid, void **obj)
3525 {
3526 if (IsEqualIID(riid, &IID_IUnknown)) {
3527 *obj = &testpersistfile;
3528 return S_OK;
3529 }
3530
3531 ok(0, "unexpected call, riid %s\n", wine_dbgstr_guid(riid));
3532 *obj = NULL;
3533 return E_NOTIMPL;
3534 }
3535
3536 static HRESULT WINAPI getinstance_cf_LockServer(IClassFactory *iface, BOOL lock)
3537 {
3538 ok(0, "unexpected call\n");
3539 return E_NOTIMPL;
3540 }
3541
3542 static const IClassFactoryVtbl getinstance_cf_vtbl = {
3543 getinstance_cf_QI,
3544 getinstance_cf_AddRef,
3545 getinstance_cf_Release,
3546 getinstance_cf_CreateInstance,
3547 getinstance_cf_LockServer
3548 };
3549
3550 static IClassFactory getinstance_cf = { &getinstance_cf_vtbl };
3551
3552 static void test_CoGetInstanceFromFile(void)
3553 {
3554 static const WCHAR filenameW[] = {'d','u','m','m','y','p','a','t','h',0};
3555 CLSID *clsid = (CLSID*)&CLSID_testclsid;
3556 MULTI_QI mqi[2];
3557 DWORD cookie;
3558 HRESULT hr;
3559
3560 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
3561 ok(hr == S_OK, "got 0x%08x\n", hr);
3562
3563 /* CLSID is not specified, file does not exist */
3564 mqi[0].pIID = &IID_IUnknown;
3565 mqi[0].pItf = NULL;
3566 mqi[0].hr = E_NOTIMPL;
3567 hr = CoGetInstanceFromFile(NULL, NULL, NULL, CLSCTX_INPROC_SERVER, STGM_READ, (OLECHAR*)filenameW, 1, mqi);
3568 todo_wine
3569 ok(hr == MK_E_CANTOPENFILE, "got 0x%08x\n", hr);
3570 ok(mqi[0].pItf == NULL, "got %p\n", mqi[0].pItf);
3571 ok(mqi[0].hr == E_NOINTERFACE, "got 0x%08x\n", mqi[0].hr);
3572
3573 /* class is not available */
3574 mqi[0].pIID = &IID_IUnknown;
3575 mqi[0].pItf = NULL;
3576 mqi[0].hr = E_NOTIMPL;
3577 hr = CoGetInstanceFromFile(NULL, clsid, NULL, CLSCTX_INPROC_SERVER, STGM_READ, (OLECHAR*)filenameW, 1, mqi);
3578 ok(hr == REGDB_E_CLASSNOTREG, "got 0x%08x\n", hr);
3579 ok(mqi[0].pItf == NULL, "got %p\n", mqi[0].pItf);
3580 ok(mqi[0].hr == REGDB_E_CLASSNOTREG, "got 0x%08x\n", mqi[0].hr);
3581
3582 hr = CoRegisterClassObject(clsid, (IUnknown*)&getinstance_cf, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE,
3583 &cookie);
3584 ok(hr == S_OK, "got 0x%08x\n", hr);
3585
3586 mqi[0].pIID = &IID_IUnknown;
3587 mqi[0].pItf = (void*)0xdeadbeef;
3588 mqi[0].hr = S_OK;
3589 hr = CoGetInstanceFromFile(NULL, clsid, NULL, CLSCTX_INPROC_SERVER, STGM_READ, (OLECHAR*)filenameW, 1, mqi);
3590 todo_wine {
3591 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3592 ok(mqi[0].pItf == (void*)0xdeadbeef, "got %p\n", mqi[0].pItf);
3593 }
3594 ok(mqi[0].hr == S_OK, "got 0x%08x\n", mqi[0].hr);
3595
3596 mqi[0].pIID = &IID_IUnknown;
3597 mqi[0].pItf = (void*)0xdeadbeef;
3598 mqi[0].hr = E_NOTIMPL;
3599 hr = CoGetInstanceFromFile(NULL, clsid, NULL, CLSCTX_INPROC_SERVER, STGM_READ, (OLECHAR*)filenameW, 1, mqi);
3600 todo_wine {
3601 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3602 ok(mqi[0].pItf == (void*)0xdeadbeef, "got %p\n", mqi[0].pItf);
3603 ok(mqi[0].hr == E_NOTIMPL, "got 0x%08x\n", mqi[0].hr);
3604 }
3605 mqi[0].pIID = &IID_IUnknown;
3606 mqi[0].pItf = NULL;
3607 mqi[0].hr = E_NOTIMPL;
3608 hr = CoGetInstanceFromFile(NULL, clsid, NULL, CLSCTX_INPROC_SERVER, STGM_READ, (OLECHAR*)filenameW, 1, mqi);
3609 ok(hr == S_OK, "got 0x%08x\n", hr);
3610 ok(mqi[0].pItf != NULL, "got %p\n", mqi[0].pItf);
3611 ok(mqi[0].hr == S_OK, "got 0x%08x\n", mqi[0].hr);
3612
3613 mqi[0].pIID = &IID_IUnknown;
3614 mqi[0].pItf = NULL;
3615 mqi[0].hr = S_OK;
3616 hr = CoGetInstanceFromFile(NULL, clsid, NULL, CLSCTX_INPROC_SERVER, STGM_READ, (OLECHAR*)filenameW, 1, mqi);
3617 ok(hr == S_OK, "got 0x%08x\n", hr);
3618 ok(mqi[0].pItf != NULL, "got %p\n", mqi[0].pItf);
3619 ok(mqi[0].hr == S_OK, "got 0x%08x\n", mqi[0].hr);
3620
3621 mqi[0].pIID = &IID_IUnknown;
3622 mqi[0].pItf = NULL;
3623 mqi[0].hr = S_OK;
3624 g_persistfile_qi_ret = S_FALSE;
3625 hr = CoGetInstanceFromFile(NULL, clsid, NULL, CLSCTX_INPROC_SERVER, STGM_READ, (OLECHAR*)filenameW, 1, mqi);
3626 ok(hr == S_OK, "got 0x%08x\n", hr);
3627 ok(mqi[0].pItf != NULL, "got %p\n", mqi[0].pItf);
3628 ok(mqi[0].hr == S_OK, "got 0x%08x\n", mqi[0].hr);
3629 g_persistfile_qi_ret = S_OK;
3630
3631 mqi[0].pIID = &IID_IUnknown;
3632 mqi[0].pItf = NULL;
3633 mqi[0].hr = S_OK;
3634 mqi[1].pIID = &IID_IUnknown;
3635 mqi[1].pItf = NULL;
3636 mqi[1].hr = S_OK;
3637 g_persistfile_qi_ret = 0x8000efef;
3638 hr = CoGetInstanceFromFile(NULL, clsid, NULL, CLSCTX_INPROC_SERVER, STGM_READ, (OLECHAR*)filenameW, 2, mqi);
3639 ok(hr == 0x8000efef, "got 0x%08x\n", hr);
3640 ok(mqi[0].pItf == NULL, "got %p\n", mqi[0].pItf);
3641 ok(mqi[0].hr == 0x8000efef, "got 0x%08x\n", mqi[0].hr);
3642 ok(mqi[1].pItf == NULL, "got %p\n", mqi[1].pItf);
3643 ok(mqi[1].hr == 0x8000efef, "got 0x%08x\n", mqi[1].hr);
3644 g_persistfile_qi_ret = S_OK;
3645
3646 mqi[0].pIID = &IID_IUnknown;
3647 mqi[0].pItf = NULL;
3648 mqi[0].hr = S_OK;
3649 mqi[1].pIID = &IID_IUnknown;
3650 mqi[1].pItf = NULL;
3651 mqi[1].hr = S_OK;
3652 g_persistfile_load_ret = 0x8000fefe;
3653 hr = CoGetInstanceFromFile(NULL, clsid, NULL, CLSCTX_INPROC_SERVER, STGM_READ, (OLECHAR*)filenameW, 2, mqi);
3654 ok(hr == 0x8000fefe, "got 0x%08x\n", hr);
3655 ok(mqi[0].pItf == NULL, "got %p\n", mqi[0].pItf);
3656 ok(mqi[0].hr == 0x8000fefe, "got 0x%08x\n", mqi[0].hr);
3657 ok(mqi[1].pItf == NULL, "got %p\n", mqi[1].pItf);
3658 ok(mqi[1].hr == 0x8000fefe, "got 0x%08x\n", mqi[1].hr);
3659 g_persistfile_load_ret = S_OK;
3660
3661 hr = CoRevokeClassObject(cookie);
3662 ok(hr == S_OK, "got 0x%08x\n", hr);
3663
3664 CoUninitialize();
3665 }
3666
3667 static void test_GlobalOptions(void)
3668 {
3669 IGlobalOptions *global_options;
3670 HRESULT hres;
3671
3672 CoInitialize(NULL);
3673
3674 hres = CoCreateInstance(&CLSID_GlobalOptions, NULL, CLSCTX_INPROC_SERVER,
3675 &IID_IGlobalOptions, (void**)&global_options);
3676 ok(hres == S_OK || broken(hres == E_NOINTERFACE), "CoCreateInstance(CLSID_GlobalOptions) failed: %08x\n", hres);
3677 if(FAILED(hres))
3678 {
3679 win_skip("CLSID_GlobalOptions not available\n");
3680 CoUninitialize();
3681 return;
3682 }
3683
3684 IGlobalOptions_Release(global_options);
3685
3686 hres = CoCreateInstance(&CLSID_GlobalOptions, (IUnknown*)0xdeadbeef, CLSCTX_INPROC_SERVER,
3687 &IID_IGlobalOptions, (void**)&global_options);
3688 ok(hres == E_INVALIDARG, "CoCreateInstance(CLSID_GlobalOptions) failed: %08x\n", hres);
3689
3690 CoUninitialize();
3691 }
3692
3693 static void init_funcs(void)
3694 {
3695 HMODULE hOle32 = GetModuleHandleA("ole32");
3696 HMODULE hAdvapi32 = GetModuleHandleA("advapi32");
3697 HMODULE hkernel32 = GetModuleHandleA("kernel32");
3698
3699 pCoGetObjectContext = (void*)GetProcAddress(hOle32, "CoGetObjectContext");
3700 pCoSwitchCallContext = (void*)GetProcAddress(hOle32, "CoSwitchCallContext");
3701 pCoGetTreatAsClass = (void*)GetProcAddress(hOle32,"CoGetTreatAsClass");
3702 pCoTreatAsClass = (void*)GetProcAddress(hOle32,"CoTreatAsClass");
3703 pCoGetContextToken = (void*)GetProcAddress(hOle32, "CoGetContextToken");
3704 pCoGetApartmentType = (void*)GetProcAddress(hOle32, "CoGetApartmentType");
3705 pRegDeleteKeyExA = (void*)GetProcAddress(hAdvapi32, "RegDeleteKeyExA");
3706 pRegOverridePredefKey = (void*)GetProcAddress(hAdvapi32, "RegOverridePredefKey");
3707 pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx");
3708
3709 pActivateActCtx = (void*)GetProcAddress(hkernel32, "ActivateActCtx");
3710 pCreateActCtxW = (void*)GetProcAddress(hkernel32, "CreateActCtxW");
3711 pDeactivateActCtx = (void*)GetProcAddress(hkernel32, "DeactivateActCtx");
3712 pIsWow64Process = (void*)GetProcAddress(hkernel32, "IsWow64Process");
3713 pReleaseActCtx = (void*)GetProcAddress(hkernel32, "ReleaseActCtx");
3714 }
3715
3716 static DWORD CALLBACK implicit_mta_proc(void *param)
3717 {
3718 IComThreadingInfo *threading_info;
3719 ULONG_PTR token;
3720 IUnknown *unk;
3721 DWORD cookie;
3722 CLSID clsid;
3723 HRESULT hr;
3724
3725 test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA);
3726
3727 hr = CoCreateInstance(&CLSID_InternetZoneManager, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk);
3728 ok_ole_success(hr, "CoCreateInstance");
3729 IUnknown_Release(unk);
3730
3731 hr = CoGetClassObject(&CLSID_InternetZoneManager, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&unk);
3732 ok_ole_success(hr, "CoGetClassObject");
3733 IUnknown_Release(unk);
3734
3735 hr = CoGetObjectContext(&IID_IComThreadingInfo, (void **)&threading_info);
3736 ok_ole_success(hr, "CoGetObjectContext");
3737 IComThreadingInfo_Release(threading_info);
3738
3739 hr = CoGetContextToken(&token);
3740 ok_ole_success(hr, "CoGetContextToken");
3741
3742 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
3743 ok_ole_success(hr, "CoRegisterPSClsid");
3744
3745 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
3746 ok_ole_success(hr, "CoGetPSClsid");
3747
3748 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
3749 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
3750 ok_ole_success(hr, "CoRegisterClassObject");
3751
3752 hr = CoRevokeClassObject(cookie);
3753 ok_ole_success(hr, "CoRevokeClassObject");
3754
3755 hr = CoRegisterMessageFilter(NULL, NULL);
3756 ok(hr == CO_E_NOT_SUPPORTED, "got %#x\n", hr);
3757
3758 hr = CoLockObjectExternal((IUnknown *)&Test_Unknown, TRUE, TRUE);
3759 ok_ole_success(hr, "CoLockObjectExternal");
3760
3761 hr = CoDisconnectObject((IUnknown *)&Test_Unknown, 0);
3762 ok_ole_success(hr, "CoDisconnectObject");
3763
3764 return 0;
3765 }
3766
3767 /* Some COM functions (perhaps even all of them?) can make use of an "implicit"
3768 * multi-threaded apartment created by another thread in the same process. */
3769 static void test_implicit_mta(void)
3770 {
3771 HANDLE thread;
3772
3773 CoInitializeEx(NULL, COINIT_MULTITHREADED);
3774
3775 thread = CreateThread(NULL, 0, implicit_mta_proc, NULL, 0, NULL);
3776 ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
3777
3778 CoUninitialize();
3779 }
3780
3781 START_TEST(compobj)
3782 {
3783 init_funcs();
3784
3785 if (!pCoInitializeEx)
3786 {
3787 trace("You need DCOM95 installed to run this test\n");
3788 return;
3789 }
3790
3791 if (!pCreateActCtxW)
3792 win_skip("Activation contexts are not supported, some tests will be skipped.\n");
3793
3794 test_ProgIDFromCLSID();
3795 test_CLSIDFromProgID();
3796 test_CLSIDFromString();
3797 test_IIDFromString();
3798 test_StringFromGUID2();
3799 test_CoCreateInstance();
3800 test_ole_menu();
3801 test_CoGetClassObject();
3802 test_CoCreateInstanceEx();
3803 test_CoRegisterMessageFilter();
3804 test_CoRegisterPSClsid();
3805 test_CoGetPSClsid();
3806 test_CoUnmarshalInterface();
3807 test_CoGetInterfaceAndReleaseStream();
3808 test_CoMarshalInterface();
3809 test_CoMarshalInterThreadInterfaceInStream();
3810 test_CoRegisterClassObject();
3811 test_registered_object_thread_affinity();
3812 test_CoFreeUnusedLibraries();
3813 test_CoGetObjectContext();
3814 test_CoGetCallContext();
3815 test_CoGetContextToken();
3816 test_TreatAsClass();
3817 test_CoInitializeEx();
3818 test_OleInitialize_InitCounting();
3819 test_OleRegGetMiscStatus();
3820 test_CoCreateGuid();
3821 test_CoWaitForMultipleHandles();
3822 test_CoGetMalloc();
3823 test_OleRegGetUserType();
3824 test_CoGetApartmentType();
3825 test_IMallocSpy();
3826 test_CoGetCurrentLogicalThreadId();
3827 test_IInitializeSpy();
3828 test_CoGetInstanceFromFile();
3829 test_GlobalOptions();
3830 test_implicit_mta();
3831 }