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