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