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