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