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