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