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