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