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