[OLE32_WINETEST]
[reactos.git] / rostests / winetests / ole32 / compobj.c
1 /*
2 * Component Object Tests
3 *
4 * Copyright 2005 Robert Shearman
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #define WIN32_NO_STATUS
22 #define _INC_WINDOWS
23 #define COM_NO_WINDOWS_H
24
25 #define COBJMACROS
26 #define CONST_VTABLE
27
28 #include <stdarg.h>
29 #include <stdio.h>
30
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winnls.h>
34 #include <winreg.h>
35 #define USE_COM_CONTEXT_DEF
36 #include <initguid.h>
37 //#include "objbase.h"
38 //#include "shlguid.h"
39 #include <ole2.h>
40 #include <urlmon.h> /* for CLSID_FileProtocol */
41
42 #include <ctxtcall.h>
43
44 #include <wine/test.h>
45
46 extern const IID GUID_NULL;
47
48 /* functions that are not present on all versions of Windows */
49 static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
50 static HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv);
51 static HRESULT (WINAPI * pCoSwitchCallContext)(IUnknown *pObject, IUnknown **ppOldObject);
52 static HRESULT (WINAPI * pCoGetTreatAsClass)(REFCLSID clsidOld, LPCLSID pClsidNew);
53 static HRESULT (WINAPI * pCoTreatAsClass)(REFCLSID clsidOld, REFCLSID pClsidNew);
54 static HRESULT (WINAPI * pCoGetContextToken)(ULONG_PTR *token);
55 static LONG (WINAPI * pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
56 static LONG (WINAPI * pRegOverridePredefKey)(HKEY key, HKEY override);
57
58 static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
59 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
60 static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
61 static BOOL (WINAPI *pIsWow64Process)(HANDLE, LPBOOL);
62 static void (WINAPI *pReleaseActCtx)(HANDLE);
63
64 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
65 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
66 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
67
68 static const CLSID CLSID_non_existent = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
69 static const CLSID CLSID_StdFont = { 0x0be35203, 0x8f91, 0x11ce, { 0x9d, 0xe3, 0x00, 0xaa, 0x00, 0x4b, 0xb8, 0x51 } };
70 static const GUID IID_Testiface = { 0x22222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
71 static const GUID IID_Testiface2 = { 0x32222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
72 static const GUID IID_Testiface3 = { 0x42222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
73 static const GUID IID_Testiface4 = { 0x52222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
74 static const GUID IID_Testiface5 = { 0x62222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
75 static const GUID IID_Testiface6 = { 0x72222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
76 static const GUID IID_TestPS = { 0x66666666, 0x8888, 0x7777, { 0x66, 0x66, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 } };
77
78 DEFINE_GUID(CLSID_InProcFreeMarshaler, 0x0000033a,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
79
80 static const WCHAR stdfont[] = {'S','t','d','F','o','n','t',0};
81 static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
82 static const WCHAR wszCLSID_StdFont[] =
83 {
84 '{','0','b','e','3','5','2','0','3','-','8','f','9','1','-','1','1','c','e','-',
85 '9','d','e','3','-','0','0','a','a','0','0','4','b','b','8','5','1','}',0
86 };
87 static const WCHAR progidW[] = {'P','r','o','g','I','d','.','P','r','o','g','I','d',0};
88 static const WCHAR cf_brokenW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
89 'c','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}','a',0};
90
91 DEFINE_GUID(IID_IWineTest, 0x5201163f, 0x8164, 0x4fd0, 0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd);
92 DEFINE_GUID(CLSID_WineOOPTest, 0x5201163f, 0x8164, 0x4fd0, 0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd);
93
94 static LONG cLocks;
95
96 static void LockModule(void)
97 {
98 InterlockedIncrement(&cLocks);
99 }
100
101 static void UnlockModule(void)
102 {
103 InterlockedDecrement(&cLocks);
104 }
105
106 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
107 LPCLASSFACTORY iface,
108 REFIID riid,
109 LPVOID *ppvObj)
110 {
111 if (ppvObj == NULL) return E_POINTER;
112
113 if (IsEqualGUID(riid, &IID_IUnknown) ||
114 IsEqualGUID(riid, &IID_IClassFactory))
115 {
116 *ppvObj = iface;
117 IClassFactory_AddRef(iface);
118 return S_OK;
119 }
120
121 *ppvObj = NULL;
122 return E_NOINTERFACE;
123 }
124
125 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
126 {
127 LockModule();
128 return 2; /* non-heap-based object */
129 }
130
131 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
132 {
133 UnlockModule();
134 return 1; /* non-heap-based object */
135 }
136
137 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
138 LPCLASSFACTORY iface,
139 IUnknown *pUnkOuter,
140 REFIID riid,
141 LPVOID *ppvObj)
142 {
143 *ppvObj = NULL;
144 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
145 return E_NOINTERFACE;
146 }
147
148 static HRESULT WINAPI Test_IClassFactory_LockServer(
149 LPCLASSFACTORY iface,
150 BOOL fLock)
151 {
152 return S_OK;
153 }
154
155 static const IClassFactoryVtbl TestClassFactory_Vtbl =
156 {
157 Test_IClassFactory_QueryInterface,
158 Test_IClassFactory_AddRef,
159 Test_IClassFactory_Release,
160 Test_IClassFactory_CreateInstance,
161 Test_IClassFactory_LockServer
162 };
163
164 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
165
166 static WCHAR manifest_path[MAX_PATH];
167
168 static BOOL create_manifest_file(const char *filename, const char *manifest)
169 {
170 int manifest_len;
171 DWORD size;
172 HANDLE file;
173 WCHAR path[MAX_PATH];
174
175 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
176 GetFullPathNameW(path, sizeof(manifest_path)/sizeof(WCHAR), manifest_path, NULL);
177
178 manifest_len = strlen(manifest);
179 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
180 FILE_ATTRIBUTE_NORMAL, NULL);
181 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
182 if(file == INVALID_HANDLE_VALUE)
183 return FALSE;
184 WriteFile(file, manifest, manifest_len, &size, NULL);
185 CloseHandle(file);
186
187 return TRUE;
188 }
189
190 static HANDLE activate_context(const char *manifest, ULONG_PTR *cookie)
191 {
192 WCHAR path[MAX_PATH];
193 ACTCTXW actctx;
194 HANDLE handle;
195 BOOL ret;
196
197 if (!pCreateActCtxW) return NULL;
198
199 create_manifest_file("file.manifest", manifest);
200
201 MultiByteToWideChar( CP_ACP, 0, "file.manifest", -1, path, MAX_PATH );
202 memset(&actctx, 0, sizeof(ACTCTXW));
203 actctx.cbSize = sizeof(ACTCTXW);
204 actctx.lpSource = path;
205
206 handle = pCreateActCtxW(&actctx);
207 ok(handle != INVALID_HANDLE_VALUE || broken(handle == INVALID_HANDLE_VALUE) /* some old XP/2k3 versions */,
208 "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
209 if (handle == INVALID_HANDLE_VALUE)
210 {
211 win_skip("activation context generation failed, some tests will be skipped\n");
212 handle = NULL;
213 }
214
215 ok(actctx.cbSize == sizeof(ACTCTXW), "actctx.cbSize=%d\n", actctx.cbSize);
216 ok(actctx.dwFlags == 0, "actctx.dwFlags=%d\n", actctx.dwFlags);
217 ok(actctx.lpSource == path, "actctx.lpSource=%p\n", actctx.lpSource);
218 ok(actctx.wProcessorArchitecture == 0, "actctx.wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
219 ok(actctx.wLangId == 0, "actctx.wLangId=%d\n", actctx.wLangId);
220 ok(actctx.lpAssemblyDirectory == NULL, "actctx.lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
221 ok(actctx.lpResourceName == NULL, "actctx.lpResourceName=%p\n", actctx.lpResourceName);
222 ok(actctx.lpApplicationName == NULL, "actctx.lpApplicationName=%p\n", actctx.lpApplicationName);
223 ok(actctx.hModule == NULL, "actctx.hModule=%p\n", actctx.hModule);
224
225 DeleteFileA("file.manifest");
226
227 if (handle)
228 {
229 ret = pActivateActCtx(handle, cookie);
230 ok(ret, "ActivateActCtx failed: %u\n", GetLastError());
231 }
232
233 return handle;
234 }
235
236 static const char actctx_manifest[] =
237 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
238 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\""
239 " publicKeyToken=\"6595b6414666f1df\" />"
240 "<file name=\"testlib.dll\">"
241 " <comClass"
242 " clsid=\"{0000033a-0000-0000-c000-000000000046}\""
243 " progid=\"FTMarshal\""
244 " />"
245 " <comClass"
246 " clsid=\"{5201163f-8164-4fd0-a1a2-5d5a3654d3bd}\""
247 " progid=\"WineOOPTest\""
248 " />"
249 " <comClass description=\"Test com class\""
250 " clsid=\"{12345678-1234-1234-1234-56789abcdef0}\""
251 " progid=\"ProgId.ProgId\""
252 " miscStatusIcon=\"recomposeonresize\""
253 " />"
254 " <comClass clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb851}\""
255 " progid=\"CustomFont\""
256 " miscStatusIcon=\"recomposeonresize\""
257 " miscStatusContent=\"insideout\""
258 " />"
259 " <comClass clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb852}\""
260 " progid=\"StdFont\""
261 " />"
262 " <comClass clsid=\"{62222222-1234-1234-1234-56789abcdef0}\" >"
263 " <progid>ProgId.ProgId.1</progid>"
264 " </comClass>"
265 " <comInterfaceProxyStub "
266 " name=\"Iifaceps\""
267 " iid=\"{22222222-1234-1234-1234-56789abcdef0}\""
268 " proxyStubClsid32=\"{66666666-8888-7777-6666-555555555555}\""
269 " />"
270 "</file>"
271 " <comInterfaceExternalProxyStub "
272 " name=\"Iifaceps2\""
273 " iid=\"{32222222-1234-1234-1234-56789abcdef0}\""
274 " />"
275 " <comInterfaceExternalProxyStub "
276 " name=\"Iifaceps3\""
277 " iid=\"{42222222-1234-1234-1234-56789abcdef0}\""
278 " proxyStubClsid32=\"{66666666-8888-7777-6666-555555555555}\""
279 " />"
280 " <comInterfaceExternalProxyStub "
281 " name=\"Iifaceps4\""
282 " iid=\"{52222222-1234-1234-1234-56789abcdef0}\""
283 " proxyStubClsid32=\"{00000000-0000-0000-0000-000000000000}\""
284 " />"
285 " <clrClass "
286 " clsid=\"{72222222-1234-1234-1234-56789abcdef0}\""
287 " name=\"clrclass\""
288 " >"
289 " <progid>clrprogid.1</progid>"
290 " </clrClass>"
291 "</assembly>";
292
293 DEFINE_GUID(CLSID_Testclass, 0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0);
294
295 static void test_ProgIDFromCLSID(void)
296 {
297 ULONG_PTR cookie = 0;
298 LPWSTR progid;
299 HANDLE handle;
300 HRESULT hr;
301
302 hr = ProgIDFromCLSID(&CLSID_StdFont, &progid);
303 ok(hr == S_OK, "ProgIDFromCLSID failed with error 0x%08x\n", hr);
304 if (hr == S_OK)
305 {
306 ok(!lstrcmpiW(progid, stdfont), "Didn't get expected prog ID\n");
307 CoTaskMemFree(progid);
308 }
309
310 progid = (LPWSTR)0xdeadbeef;
311 hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
312 ok(hr == REGDB_E_CLASSNOTREG, "ProgIDFromCLSID returned %08x\n", hr);
313 ok(progid == NULL, "ProgIDFromCLSID returns with progid %p\n", progid);
314
315 hr = ProgIDFromCLSID(&CLSID_StdFont, NULL);
316 ok(hr == E_INVALIDARG, "ProgIDFromCLSID should return E_INVALIDARG instead of 0x%08x\n", hr);
317
318 if ((handle = activate_context(actctx_manifest, &cookie)))
319 {
320 static const WCHAR customfontW[] = {'C','u','s','t','o','m','F','o','n','t',0};
321
322 hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
323 ok(hr == S_OK, "got 0x%08x\n", hr);
324 ok(!lstrcmpiW(progid, progidW), "got %s\n", wine_dbgstr_w(progid));
325 CoTaskMemFree(progid);
326
327 /* try something registered and redirected */
328 progid = NULL;
329 hr = ProgIDFromCLSID(&CLSID_StdFont, &progid);
330 ok(hr == S_OK, "got 0x%08x\n", hr);
331 ok(!lstrcmpiW(progid, customfontW), "got wrong progid %s\n", wine_dbgstr_w(progid));
332 CoTaskMemFree(progid);
333
334 /* classes without default progid, progid list is not used */
335 hr = ProgIDFromCLSID(&IID_Testiface5, &progid);
336 ok(hr == REGDB_E_CLASSNOTREG, "got 0x%08x\n", hr);
337
338 hr = ProgIDFromCLSID(&IID_Testiface6, &progid);
339 ok(hr == REGDB_E_CLASSNOTREG, "got 0x%08x\n", hr);
340
341 pDeactivateActCtx(0, cookie);
342 pReleaseActCtx(handle);
343 }
344 }
345
346 static void test_CLSIDFromProgID(void)
347 {
348 ULONG_PTR cookie = 0;
349 HANDLE handle;
350 CLSID clsid;
351 HRESULT hr = CLSIDFromProgID(stdfont, &clsid);
352 ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08x\n", hr);
353 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
354
355 hr = CLSIDFromString(stdfont, &clsid);
356 ok_ole_success(hr, "CLSIDFromString");
357 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
358
359 /* test some failure cases */
360
361 hr = CLSIDFromProgID(wszNonExistent, NULL);
362 ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
363
364 hr = CLSIDFromProgID(NULL, &clsid);
365 ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
366
367 memset(&clsid, 0xcc, sizeof(clsid));
368 hr = CLSIDFromProgID(wszNonExistent, &clsid);
369 ok(hr == CO_E_CLASSSTRING, "CLSIDFromProgID on nonexistent ProgID should have returned CO_E_CLASSSTRING instead of 0x%08x\n", hr);
370 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "CLSIDFromProgID should have set clsid to all-zeros on failure\n");
371
372 /* fails without proper context */
373 memset(&clsid, 0xcc, sizeof(clsid));
374 hr = CLSIDFromProgID(progidW, &clsid);
375 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
376 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "wrong clsid\n");
377
378 if ((handle = activate_context(actctx_manifest, &cookie)))
379 {
380 GUID clsid1;
381
382 memset(&clsid, 0xcc, sizeof(clsid));
383 hr = CLSIDFromProgID(wszNonExistent, &clsid);
384 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
385 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "should have zero CLSID on failure\n");
386
387 /* CLSIDFromString() doesn't check activation context */
388 hr = CLSIDFromString(progidW, &clsid);
389 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
390
391 clsid = CLSID_NULL;
392 hr = CLSIDFromProgID(progidW, &clsid);
393 /* it returns generated CLSID here */
394 ok(!IsEqualCLSID(&clsid, &CLSID_non_existent) && !IsEqualCLSID(&clsid, &CLSID_NULL),
395 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
396
397 /* duplicate progid present in context - returns generated guid here too */
398 clsid = CLSID_NULL;
399 hr = CLSIDFromProgID(stdfont, &clsid);
400 ok(hr == S_OK, "got 0x%08x\n", hr);
401 clsid1 = CLSID_StdFont;
402 /* that's where it differs from StdFont */
403 clsid1.Data4[7] = 0x52;
404 ok(!IsEqualCLSID(&clsid, &CLSID_StdFont) && !IsEqualCLSID(&clsid, &CLSID_NULL) && !IsEqualCLSID(&clsid, &clsid1),
405 "got %s\n", wine_dbgstr_guid(&clsid));
406
407 pDeactivateActCtx(0, cookie);
408 pReleaseActCtx(handle);
409 }
410 }
411
412 static void test_CLSIDFromString(void)
413 {
414 CLSID clsid;
415 WCHAR wszCLSID_Broken[50];
416 UINT i;
417
418 HRESULT hr = CLSIDFromString(wszCLSID_StdFont, &clsid);
419 ok_ole_success(hr, "CLSIDFromString");
420 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
421
422 memset(&clsid, 0xab, sizeof(clsid));
423 hr = CLSIDFromString(NULL, &clsid);
424 ok(hr == S_OK, "got 0x%08x\n", hr);
425 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
426
427 /* string is longer, but starts with a valid CLSID */
428 memset(&clsid, 0, sizeof(clsid));
429 hr = CLSIDFromString(cf_brokenW, &clsid);
430 ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
431 ok(IsEqualCLSID(&clsid, &IID_IClassFactory), "got %s\n", wine_dbgstr_guid(&clsid));
432
433 lstrcpyW(wszCLSID_Broken, wszCLSID_StdFont);
434 for(i = lstrlenW(wszCLSID_StdFont); i < 49; i++)
435 wszCLSID_Broken[i] = 'A';
436 wszCLSID_Broken[i] = '\0';
437
438 memset(&clsid, 0, sizeof(CLSID));
439 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
440 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
441 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
442
443 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)-1] = 'A';
444 memset(&clsid, 0, sizeof(CLSID));
445 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
446 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
447 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
448
449 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)] = '\0';
450 memset(&clsid, 0, sizeof(CLSID));
451 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
452 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
453 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
454
455 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)-1] = '\0';
456 memset(&clsid, 0, sizeof(CLSID));
457 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
458 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
459 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
460
461 memset(&clsid, 0xcc, sizeof(CLSID));
462 hr = CLSIDFromString(wszCLSID_Broken+1, &clsid);
463 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
464 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
465
466 wszCLSID_Broken[9] = '*';
467 memset(&clsid, 0xcc, sizeof(CLSID));
468 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
469 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
470 ok(clsid.Data1 == CLSID_StdFont.Data1, "Got %08x\n", clsid.Data1);
471 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
472
473 wszCLSID_Broken[3] = '*';
474 memset(&clsid, 0xcc, sizeof(CLSID));
475 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
476 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
477 ok(clsid.Data1 == 0xb, "Got %08x\n", clsid.Data1);
478 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
479
480 wszCLSID_Broken[3] = '\0';
481 memset(&clsid, 0xcc, sizeof(CLSID));
482 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
483 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
484 ok(clsid.Data1 == 0xb, "Got %08x\n", clsid.Data1);
485 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
486 }
487
488 static void test_IIDFromString(void)
489 {
490 static const WCHAR cfW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
491 'c','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
492 static const WCHAR brokenW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
493 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
494 static const WCHAR broken2W[] = {'{','0','0','0','0','0','0','0','1','=','0','0','0','0','-','0','0','0','0','-',
495 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
496 static const WCHAR broken3W[] = {'b','r','o','k','e','n','0','0','1','=','0','0','0','0','-','0','0','0','0','-',
497 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
498 HRESULT hr;
499 IID iid;
500
501 hr = IIDFromString(wszCLSID_StdFont, &iid);
502 ok(hr == S_OK, "got 0x%08x\n", hr);
503 ok(IsEqualIID(&iid, &CLSID_StdFont), "got iid %s\n", wine_dbgstr_guid(&iid));
504
505 memset(&iid, 0xab, sizeof(iid));
506 hr = IIDFromString(NULL, &iid);
507 ok(hr == S_OK, "got 0x%08x\n", hr);
508 ok(IsEqualIID(&iid, &CLSID_NULL), "got iid %s\n", wine_dbgstr_guid(&iid));
509
510 hr = IIDFromString(cfW, &iid);
511 ok(hr == S_OK, "got 0x%08x\n", hr);
512 ok(IsEqualIID(&iid, &IID_IClassFactory), "got iid %s\n", wine_dbgstr_guid(&iid));
513
514 /* string starts with a valid IID but is longer */
515 memset(&iid, 0xab, sizeof(iid));
516 hr = IIDFromString(cf_brokenW, &iid);
517 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
518 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
519
520 /* invalid IID in a valid format */
521 memset(&iid, 0xab, sizeof(iid));
522 hr = IIDFromString(brokenW, &iid);
523 ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
524 ok(iid.Data1 == 0x00000001, "Got %08x\n", iid.Data1);
525
526 memset(&iid, 0xab, sizeof(iid));
527 hr = IIDFromString(broken2W, &iid);
528 ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
529 ok(iid.Data1 == 0x00000001, "Got %08x\n", iid.Data1);
530
531 /* format is broken, but string length is okay */
532 memset(&iid, 0xab, sizeof(iid));
533 hr = IIDFromString(broken3W, &iid);
534 ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
535 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
536
537 /* invalid string */
538 memset(&iid, 0xab, sizeof(iid));
539 hr = IIDFromString(wszNonExistent, &iid);
540 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
541 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
542
543 /* valid ProgID */
544 memset(&iid, 0xab, sizeof(iid));
545 hr = IIDFromString(stdfont, &iid);
546 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
547 ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
548 }
549
550 static void test_StringFromGUID2(void)
551 {
552 WCHAR str[50];
553 int len;
554
555 /* invalid pointer */
556 SetLastError(0xdeadbeef);
557 len = StringFromGUID2(NULL,str,50);
558 ok(len == 0, "len: %d (expected 0)\n", len);
559 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %x\n", GetLastError());
560
561 /* Test corner cases for buffer size */
562 len = StringFromGUID2(&CLSID_StdFont,str,50);
563 ok(len == 39, "len: %d (expected 39)\n", len);
564 ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n");
565
566 memset(str,0,sizeof str);
567 len = StringFromGUID2(&CLSID_StdFont,str,39);
568 ok(len == 39, "len: %d (expected 39)\n", len);
569 ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n");
570
571 len = StringFromGUID2(&CLSID_StdFont,str,38);
572 ok(len == 0, "len: %d (expected 0)\n", len);
573
574 len = StringFromGUID2(&CLSID_StdFont,str,30);
575 ok(len == 0, "len: %d (expected 0)\n", len);
576 }
577
578 struct info
579 {
580 HANDLE wait, stop;
581 };
582
583 static DWORD CALLBACK ole_initialize_thread(LPVOID pv)
584 {
585 HRESULT hr;
586 struct info *info = pv;
587
588 hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
589
590 SetEvent(info->wait);
591 WaitForSingleObject(info->stop, 10000);
592
593 CoUninitialize();
594 return hr;
595 }
596
597 static void test_CoCreateInstance(void)
598 {
599 HRESULT hr;
600 HANDLE thread;
601 DWORD tid, exitcode;
602 IUnknown *pUnk;
603 struct info info;
604 REFCLSID rclsid = &CLSID_InternetZoneManager;
605
606 pUnk = (IUnknown *)0xdeadbeef;
607 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
608 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
609 ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
610
611 OleInitialize(NULL);
612
613 /* test errors returned for non-registered clsids */
614 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
615 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
616 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pUnk);
617 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc handler should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
618 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_LOCAL_SERVER, &IID_IUnknown, (void **)&pUnk);
619 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered local server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
620 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_REMOTE_SERVER, &IID_IUnknown, (void **)&pUnk);
621 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered remote server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
622
623 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
624 if(hr == REGDB_E_CLASSNOTREG)
625 {
626 skip("IE not installed so can't test CoCreateInstance\n");
627 OleUninitialize();
628 return;
629 }
630
631 ok_ole_success(hr, "CoCreateInstance");
632 if(pUnk) IUnknown_Release(pUnk);
633 OleUninitialize();
634
635 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
636 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
637
638 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
639 thread has already done so */
640
641 info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
642 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
643
644 info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
645 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
646
647 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
648 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
649
650 ok( !WaitForSingleObject(info.wait, 10000 ), "wait timed out\n" );
651
652 pUnk = (IUnknown *)0xdeadbeef;
653 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
654 ok(hr == S_OK, "CoCreateInstance should have returned S_OK instead of 0x%08x\n", hr);
655 if (pUnk) IUnknown_Release(pUnk);
656
657 SetEvent(info.stop);
658 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
659
660 GetExitCodeThread(thread, &exitcode);
661 hr = exitcode;
662 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
663
664 CloseHandle(thread);
665 CloseHandle(info.wait);
666 CloseHandle(info.stop);
667 }
668
669 static void test_CoGetClassObject(void)
670 {
671 HRESULT hr;
672 HANDLE thread, handle;
673 DWORD tid, exitcode;
674 ULONG_PTR cookie;
675 IUnknown *pUnk;
676 struct info info;
677 REFCLSID rclsid = &CLSID_InternetZoneManager;
678 HKEY hkey;
679 LONG res;
680
681 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
682 ok(hr == CO_E_NOTINITIALIZED, "CoGetClassObject should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
683 ok(pUnk == NULL, "CoGetClassObject should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
684
685 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL);
686 ok(hr == E_INVALIDARG ||
687 broken(hr == CO_E_NOTINITIALIZED), /* win9x */
688 "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr);
689
690 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
691 thread has already done so */
692
693 info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
694 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
695
696 info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
697 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
698
699 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
700 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
701
702 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
703
704 pUnk = (IUnknown *)0xdeadbeef;
705 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
706 if(hr == REGDB_E_CLASSNOTREG)
707 skip("IE not installed so can't test CoGetClassObject\n");
708 else
709 {
710 ok(hr == S_OK, "CoGetClassObject should have returned S_OK instead of 0x%08x\n", hr);
711 if (pUnk) IUnknown_Release(pUnk);
712 }
713
714 SetEvent(info.stop);
715 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
716
717 GetExitCodeThread(thread, &exitcode);
718 hr = exitcode;
719 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
720
721 CloseHandle(thread);
722 CloseHandle(info.wait);
723 CloseHandle(info.stop);
724
725 if (!pRegOverridePredefKey)
726 {
727 win_skip("RegOverridePredefKey not available\n");
728 return;
729 }
730
731 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
732
733 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
734 if (hr == S_OK)
735 {
736 IUnknown_Release(pUnk);
737
738 res = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
739 KEY_ALL_ACCESS, NULL, &hkey, NULL);
740 ok(!res, "RegCreateKeyEx returned %d\n", res);
741
742 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, hkey);
743 ok(!res, "RegOverridePredefKey returned %d\n", res);
744
745 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
746 ok(hr == S_OK, "CoGetClassObject should have returned S_OK instead of 0x%08x\n", hr);
747
748 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
749 ok(!res, "RegOverridePredefKey returned %d\n", res);
750
751 if (hr == S_OK) IUnknown_Release(pUnk);
752 RegCloseKey(hkey);
753 }
754
755 hr = CoGetClassObject(&CLSID_InProcFreeMarshaler, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
756 ok(hr == S_OK, "got 0x%08x\n", hr);
757 IUnknown_Release(pUnk);
758
759 /* context redefines FreeMarshaler CLSID */
760 if ((handle = activate_context(actctx_manifest, &cookie)))
761 {
762 hr = CoGetClassObject(&CLSID_InProcFreeMarshaler, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
763 ok(hr == S_OK, "got 0x%08x\n", hr);
764 IUnknown_Release(pUnk);
765
766 pDeactivateActCtx(0, cookie);
767 pReleaseActCtx(handle);
768 }
769
770 CoUninitialize();
771 }
772
773 static ATOM register_dummy_class(void)
774 {
775 WNDCLASSA wc =
776 {
777 0,
778 DefWindowProcA,
779 0,
780 0,
781 GetModuleHandleA(NULL),
782 NULL,
783 LoadCursorA(NULL, (LPSTR)IDC_ARROW),
784 (HBRUSH)(COLOR_BTNFACE+1),
785 NULL,
786 "WineOleTestClass",
787 };
788
789 return RegisterClassA(&wc);
790 }
791
792 static void test_ole_menu(void)
793 {
794 HWND hwndFrame;
795 HRESULT hr;
796
797 hwndFrame = CreateWindowA((LPCSTR)MAKEINTATOM(register_dummy_class()), "Test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
798 hr = OleSetMenuDescriptor(NULL, hwndFrame, NULL, NULL, NULL);
799 todo_wine ok_ole_success(hr, "OleSetMenuDescriptor");
800
801 DestroyWindow(hwndFrame);
802 }
803
804
805 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
806 {
807 if (ppvObj == NULL) return E_POINTER;
808
809 if (IsEqualGUID(riid, &IID_IUnknown) ||
810 IsEqualGUID(riid, &IID_IClassFactory))
811 {
812 *ppvObj = iface;
813 IMessageFilter_AddRef(iface);
814 return S_OK;
815 }
816
817 return E_NOINTERFACE;
818 }
819
820 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
821 {
822 return 2; /* non-heap object */
823 }
824
825 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
826 {
827 return 1; /* non-heap object */
828 }
829
830 static DWORD WINAPI MessageFilter_HandleInComingCall(
831 IMessageFilter *iface,
832 DWORD dwCallType,
833 HTASK threadIDCaller,
834 DWORD dwTickCount,
835 LPINTERFACEINFO lpInterfaceInfo)
836 {
837 trace("HandleInComingCall\n");
838 return SERVERCALL_ISHANDLED;
839 }
840
841 static DWORD WINAPI MessageFilter_RetryRejectedCall(
842 IMessageFilter *iface,
843 HTASK threadIDCallee,
844 DWORD dwTickCount,
845 DWORD dwRejectType)
846 {
847 trace("RetryRejectedCall\n");
848 return 0;
849 }
850
851 static DWORD WINAPI MessageFilter_MessagePending(
852 IMessageFilter *iface,
853 HTASK threadIDCallee,
854 DWORD dwTickCount,
855 DWORD dwPendingType)
856 {
857 trace("MessagePending\n");
858 return PENDINGMSG_WAITNOPROCESS;
859 }
860
861 static const IMessageFilterVtbl MessageFilter_Vtbl =
862 {
863 MessageFilter_QueryInterface,
864 MessageFilter_AddRef,
865 MessageFilter_Release,
866 MessageFilter_HandleInComingCall,
867 MessageFilter_RetryRejectedCall,
868 MessageFilter_MessagePending
869 };
870
871 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
872
873 static void test_CoRegisterMessageFilter(void)
874 {
875 HRESULT hr;
876 IMessageFilter *prev_filter;
877
878 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
879 ok(hr == CO_E_NOT_SUPPORTED,
880 "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
881 hr);
882
883 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
884 prev_filter = (IMessageFilter *)0xdeadbeef;
885 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
886 ok(hr == CO_E_NOT_SUPPORTED,
887 "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
888 hr);
889 ok(prev_filter == (IMessageFilter *)0xdeadbeef,
890 "prev_filter should have been set to %p\n", prev_filter);
891 CoUninitialize();
892
893 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
894
895 hr = CoRegisterMessageFilter(NULL, NULL);
896 ok_ole_success(hr, "CoRegisterMessageFilter");
897
898 prev_filter = (IMessageFilter *)0xdeadbeef;
899 hr = CoRegisterMessageFilter(NULL, &prev_filter);
900 ok_ole_success(hr, "CoRegisterMessageFilter");
901 ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
902
903 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
904 ok_ole_success(hr, "CoRegisterMessageFilter");
905 ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
906
907 hr = CoRegisterMessageFilter(NULL, NULL);
908 ok_ole_success(hr, "CoRegisterMessageFilter");
909
910 CoUninitialize();
911 }
912
913 static HRESULT WINAPI Test_IUnknown_QueryInterface(
914 IUnknown *iface,
915 REFIID riid,
916 LPVOID *ppvObj)
917 {
918 if (ppvObj == NULL) return E_POINTER;
919
920 if (IsEqualIID(riid, &IID_IUnknown) ||
921 IsEqualIID(riid, &IID_IWineTest))
922 {
923 *ppvObj = iface;
924 IUnknown_AddRef(iface);
925 return S_OK;
926 }
927
928 *ppvObj = NULL;
929 return E_NOINTERFACE;
930 }
931
932 static ULONG WINAPI Test_IUnknown_AddRef(IUnknown *iface)
933 {
934 return 2; /* non-heap-based object */
935 }
936
937 static ULONG WINAPI Test_IUnknown_Release(IUnknown *iface)
938 {
939 return 1; /* non-heap-based object */
940 }
941
942 static const IUnknownVtbl TestUnknown_Vtbl =
943 {
944 Test_IUnknown_QueryInterface,
945 Test_IUnknown_AddRef,
946 Test_IUnknown_Release,
947 };
948
949 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
950
951 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(
952 IPSFactoryBuffer * This,
953 /* [in] */ REFIID riid,
954 /* [iid_is][out] */ void **ppvObject)
955 {
956 if (IsEqualIID(riid, &IID_IUnknown) ||
957 IsEqualIID(riid, &IID_IPSFactoryBuffer))
958 {
959 *ppvObject = This;
960 IPSFactoryBuffer_AddRef(This);
961 return S_OK;
962 }
963 return E_NOINTERFACE;
964 }
965
966 static ULONG WINAPI PSFactoryBuffer_AddRef(
967 IPSFactoryBuffer * This)
968 {
969 return 2;
970 }
971
972 static ULONG WINAPI PSFactoryBuffer_Release(
973 IPSFactoryBuffer * This)
974 {
975 return 1;
976 }
977
978 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(
979 IPSFactoryBuffer * This,
980 /* [in] */ IUnknown *pUnkOuter,
981 /* [in] */ REFIID riid,
982 /* [out] */ IRpcProxyBuffer **ppProxy,
983 /* [out] */ void **ppv)
984 {
985 return E_NOTIMPL;
986 }
987
988 static HRESULT WINAPI PSFactoryBuffer_CreateStub(
989 IPSFactoryBuffer * This,
990 /* [in] */ REFIID riid,
991 /* [unique][in] */ IUnknown *pUnkServer,
992 /* [out] */ IRpcStubBuffer **ppStub)
993 {
994 return E_NOTIMPL;
995 }
996
997 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
998 {
999 PSFactoryBuffer_QueryInterface,
1000 PSFactoryBuffer_AddRef,
1001 PSFactoryBuffer_Release,
1002 PSFactoryBuffer_CreateProxy,
1003 PSFactoryBuffer_CreateStub
1004 };
1005
1006 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
1007
1008 static const CLSID CLSID_WineTestPSFactoryBuffer =
1009 {
1010 0x52011640,
1011 0x8164,
1012 0x4fd0,
1013 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
1014 }; /* 52011640-8164-4fd0-a1a2-5d5a3654d3bd */
1015
1016 static void test_CoRegisterPSClsid(void)
1017 {
1018 HRESULT hr;
1019 DWORD dwRegistrationKey;
1020 IStream *stream;
1021 CLSID clsid;
1022
1023 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
1024 ok(hr == CO_E_NOTINITIALIZED, "CoRegisterPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1025
1026 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1027
1028 hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
1029 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &dwRegistrationKey);
1030 ok_ole_success(hr, "CoRegisterClassObject");
1031
1032 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
1033 ok_ole_success(hr, "CoRegisterPSClsid");
1034
1035 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1036 ok_ole_success(hr, "CreateStreamOnHGlobal");
1037
1038 hr = CoMarshalInterface(stream, &IID_IWineTest, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1039 ok(hr == E_NOTIMPL, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1040 IStream_Release(stream);
1041
1042 hr = CoRevokeClassObject(dwRegistrationKey);
1043 ok_ole_success(hr, "CoRevokeClassObject");
1044
1045 CoUninitialize();
1046
1047 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1048
1049 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1050 ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08x\n", hr);
1051
1052 CoUninitialize();
1053 }
1054
1055 static void test_CoGetPSClsid(void)
1056 {
1057 ULONG_PTR cookie;
1058 HANDLE handle;
1059 HRESULT hr;
1060 CLSID clsid;
1061 HKEY hkey;
1062 LONG res;
1063 const BOOL is_win64 = (sizeof(void*) != sizeof(int));
1064 BOOL is_wow64 = FALSE;
1065
1066 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1067 ok(hr == CO_E_NOTINITIALIZED,
1068 "CoGetPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n",
1069 hr);
1070
1071 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1072
1073 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1074 ok_ole_success(hr, "CoGetPSClsid");
1075
1076 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
1077 ok(hr == REGDB_E_IIDNOTREG,
1078 "CoGetPSClsid for random IID returned 0x%08x instead of REGDB_E_IIDNOTREG\n",
1079 hr);
1080
1081 hr = CoGetPSClsid(&IID_IClassFactory, NULL);
1082 ok(hr == E_INVALIDARG,
1083 "CoGetPSClsid for null clsid returned 0x%08x instead of E_INVALIDARG\n",
1084 hr);
1085
1086 if (!pRegOverridePredefKey)
1087 {
1088 win_skip("RegOverridePredefKey not available\n");
1089 CoUninitialize();
1090 return;
1091 }
1092 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1093 ok_ole_success(hr, "CoGetPSClsid");
1094
1095 res = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
1096 KEY_ALL_ACCESS, NULL, &hkey, NULL);
1097 ok(!res, "RegCreateKeyEx returned %d\n", res);
1098
1099 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, hkey);
1100 ok(!res, "RegOverridePredefKey returned %d\n", res);
1101
1102 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
1103 ok_ole_success(hr, "CoGetPSClsid");
1104
1105 res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
1106 ok(!res, "RegOverridePredefKey returned %d\n", res);
1107
1108 RegCloseKey(hkey);
1109
1110 /* not registered CLSID */
1111 hr = CoGetPSClsid(&IID_Testiface, &clsid);
1112 ok(hr == REGDB_E_IIDNOTREG, "got 0x%08x\n", hr);
1113
1114 if ((handle = activate_context(actctx_manifest, &cookie)))
1115 {
1116 memset(&clsid, 0, sizeof(clsid));
1117 hr = CoGetPSClsid(&IID_Testiface, &clsid);
1118 ok(hr == S_OK, "got 0x%08x\n", hr);
1119 ok(IsEqualGUID(&clsid, &IID_Testiface), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1120
1121 memset(&clsid, 0, sizeof(clsid));
1122 hr = CoGetPSClsid(&IID_Testiface2, &clsid);
1123 ok(hr == S_OK, "got 0x%08x\n", hr);
1124 ok(IsEqualGUID(&clsid, &IID_Testiface2), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1125
1126 memset(&clsid, 0, sizeof(clsid));
1127 hr = CoGetPSClsid(&IID_Testiface3, &clsid);
1128 ok(hr == S_OK, "got 0x%08x\n", hr);
1129 ok(IsEqualGUID(&clsid, &IID_TestPS), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1130
1131 memset(&clsid, 0xaa, sizeof(clsid));
1132 hr = CoGetPSClsid(&IID_Testiface4, &clsid);
1133 ok(hr == S_OK, "got 0x%08x\n", hr);
1134 ok(IsEqualGUID(&clsid, &GUID_NULL), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1135
1136 /* register same interface and try to get CLSID back */
1137 hr = CoRegisterPSClsid(&IID_Testiface, &IID_Testiface4);
1138 ok(hr == S_OK, "got 0x%08x\n", hr);
1139 memset(&clsid, 0, sizeof(clsid));
1140 hr = CoGetPSClsid(&IID_Testiface, &clsid);
1141 ok(hr == S_OK, "got 0x%08x\n", hr);
1142 ok(IsEqualGUID(&clsid, &IID_Testiface4), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1143
1144 pDeactivateActCtx(0, cookie);
1145 pReleaseActCtx(handle);
1146 }
1147
1148 if (pRegDeleteKeyExA &&
1149 (is_win64 ||
1150 (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
1151 {
1152 static GUID IID_DeadBeef = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
1153 static const char clsidDeadBeef[] = "{deadbeef-dead-beef-dead-beefdeadbeef}";
1154 static const char clsidA[] = "{66666666-8888-7777-6666-555555555555}";
1155 HKEY hkey_iface, hkey_psclsid;
1156 REGSAM opposite = is_win64 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
1157
1158 hr = CoGetPSClsid(&IID_DeadBeef, &clsid);
1159 ok(hr == REGDB_E_IIDNOTREG, "got 0x%08x\n", hr);
1160
1161 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, "Interface",
1162 0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, &hkey_iface, NULL);
1163 ok(!res, "RegCreateKeyEx returned %d\n", res);
1164 res = RegCreateKeyExA(hkey_iface, clsidDeadBeef,
1165 0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, &hkey, NULL);
1166 ok(!res, "RegCreateKeyEx returned %d\n", res);
1167 res = RegCreateKeyExA(hkey, "ProxyStubClsid32",
1168 0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, &hkey_psclsid, NULL);
1169 res = RegSetValueExA(hkey_psclsid, NULL, 0, REG_SZ, (const BYTE *)clsidA, strlen(clsidA)+1);
1170 ok(!res, "RegSetValueEx returned %d\n", res);
1171 RegCloseKey(hkey_psclsid);
1172
1173 hr = CoGetPSClsid(&IID_DeadBeef, &clsid);
1174 ok_ole_success(hr, "CoGetPSClsid");
1175 ok(IsEqualGUID(&clsid, &IID_TestPS), "got clsid %s\n", wine_dbgstr_guid(&clsid));
1176
1177 res = pRegDeleteKeyExA(hkey, "ProxyStubClsid32", opposite, 0);
1178 ok(!res, "RegDeleteKeyEx returned %d\n", res);
1179 RegCloseKey(hkey);
1180 res = pRegDeleteKeyExA(hkey_iface, clsidDeadBeef, opposite, 0);
1181 ok(!res, "RegDeleteKeyEx returned %d\n", res);
1182 RegCloseKey(hkey_iface);
1183 }
1184
1185 CoUninitialize();
1186 }
1187
1188 /* basic test, mainly for invalid arguments. see marshal.c for more */
1189 static void test_CoUnmarshalInterface(void)
1190 {
1191 IUnknown *pProxy;
1192 IStream *pStream;
1193 HRESULT hr;
1194
1195 hr = CoUnmarshalInterface(NULL, &IID_IUnknown, (void **)&pProxy);
1196 ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1197
1198 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1199 ok_ole_success(hr, "CreateStreamOnHGlobal");
1200
1201 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1202 todo_wine
1203 ok(hr == CO_E_NOTINITIALIZED, "CoUnmarshalInterface should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1204
1205 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1206
1207 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1208 ok(hr == STG_E_READFAULT, "CoUnmarshalInterface should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
1209
1210 CoUninitialize();
1211
1212 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, NULL);
1213 ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1214
1215 IStream_Release(pStream);
1216 }
1217
1218 static void test_CoGetInterfaceAndReleaseStream(void)
1219 {
1220 HRESULT hr;
1221 IUnknown *pUnk;
1222
1223 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1224
1225 hr = CoGetInterfaceAndReleaseStream(NULL, &IID_IUnknown, (void**)&pUnk);
1226 ok(hr == E_INVALIDARG, "hr %08x\n", hr);
1227
1228 CoUninitialize();
1229 }
1230
1231 /* basic test, mainly for invalid arguments. see marshal.c for more */
1232 static void test_CoMarshalInterface(void)
1233 {
1234 IStream *pStream;
1235 HRESULT hr;
1236 static const LARGE_INTEGER llZero;
1237
1238 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1239
1240 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1241 ok_ole_success(hr, "CreateStreamOnHGlobal");
1242
1243 hr = CoMarshalInterface(pStream, &IID_IUnknown, NULL, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1244 ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1245
1246 hr = CoMarshalInterface(NULL, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1247 ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1248
1249 hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1250 ok_ole_success(hr, "CoMarshalInterface");
1251
1252 /* stream not rewound */
1253 hr = CoReleaseMarshalData(pStream);
1254 ok(hr == STG_E_READFAULT, "CoReleaseMarshalData should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
1255
1256 hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1257 ok_ole_success(hr, "IStream_Seek");
1258
1259 hr = CoReleaseMarshalData(pStream);
1260 ok_ole_success(hr, "CoReleaseMarshalData");
1261
1262 IStream_Release(pStream);
1263
1264 CoUninitialize();
1265 }
1266
1267 static void test_CoMarshalInterThreadInterfaceInStream(void)
1268 {
1269 IStream *pStream;
1270 HRESULT hr;
1271 IClassFactory *pProxy;
1272
1273 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1274
1275 cLocks = 0;
1276
1277 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, NULL);
1278 ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1279
1280 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, NULL, &pStream);
1281 ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1282
1283 ok_no_locks();
1284
1285 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, &pStream);
1286 ok_ole_success(hr, "CoMarshalInterThreadInterfaceInStream");
1287
1288 ok_more_than_one_lock();
1289
1290 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1291 ok_ole_success(hr, "CoUnmarshalInterface");
1292
1293 IClassFactory_Release(pProxy);
1294 IStream_Release(pStream);
1295
1296 ok_no_locks();
1297
1298 CoUninitialize();
1299 }
1300
1301 static void test_CoRegisterClassObject(void)
1302 {
1303 ULONG_PTR ctxcookie;
1304 HANDLE handle;
1305 DWORD cookie;
1306 HRESULT hr;
1307 IClassFactory *pcf;
1308
1309 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1310
1311 /* CLSCTX_INPROC_SERVER */
1312 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1313 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1314 ok_ole_success(hr, "CoRegisterClassObject");
1315 hr = CoRevokeClassObject(cookie);
1316 ok_ole_success(hr, "CoRevokeClassObject");
1317
1318 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1319 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1320 ok_ole_success(hr, "CoRegisterClassObject");
1321 hr = CoRevokeClassObject(cookie);
1322 ok_ole_success(hr, "CoRevokeClassObject");
1323
1324 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1325 CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
1326 ok_ole_success(hr, "CoRegisterClassObject");
1327 hr = CoRevokeClassObject(cookie);
1328 ok_ole_success(hr, "CoRevokeClassObject");
1329
1330 /* CLSCTX_LOCAL_SERVER */
1331 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1332 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
1333 ok_ole_success(hr, "CoRegisterClassObject");
1334 hr = CoRevokeClassObject(cookie);
1335 ok_ole_success(hr, "CoRevokeClassObject");
1336
1337 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1338 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1339 ok_ole_success(hr, "CoRegisterClassObject");
1340 hr = CoRevokeClassObject(cookie);
1341 ok_ole_success(hr, "CoRevokeClassObject");
1342
1343 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1344 CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
1345 ok_ole_success(hr, "CoRegisterClassObject");
1346 hr = CoRevokeClassObject(cookie);
1347 ok_ole_success(hr, "CoRevokeClassObject");
1348
1349 /* CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER */
1350 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1351 CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
1352 ok_ole_success(hr, "CoRegisterClassObject");
1353 hr = CoRevokeClassObject(cookie);
1354 ok_ole_success(hr, "CoRevokeClassObject");
1355
1356 /* test whether an object that doesn't support IClassFactory can be
1357 * registered for CLSCTX_LOCAL_SERVER */
1358 hr = CoRegisterClassObject(&CLSID_WineOOPTest, &Test_Unknown,
1359 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
1360 ok_ole_success(hr, "CoRegisterClassObject");
1361 hr = CoRevokeClassObject(cookie);
1362 ok_ole_success(hr, "CoRevokeClassObject");
1363
1364 /* test whether registered class becomes invalid when apartment is destroyed */
1365 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1366 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1367 ok_ole_success(hr, "CoRegisterClassObject");
1368
1369 CoUninitialize();
1370 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1371
1372 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL,
1373 &IID_IClassFactory, (void **)&pcf);
1374 ok(hr == REGDB_E_CLASSNOTREG, "object registered in an apartment shouldn't accessible after it is destroyed\n");
1375
1376 /* crashes with at least win9x DCOM! */
1377 if (0)
1378 CoRevokeClassObject(cookie);
1379
1380 /* test that object is accessible */
1381 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory, CLSCTX_INPROC_SERVER,
1382 REGCLS_MULTIPLEUSE, &cookie);
1383 ok(hr == S_OK, "got 0x%08x\n", hr);
1384
1385 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
1386 ok(hr == S_OK, "got 0x%08x\n", hr);
1387 IClassFactory_Release(pcf);
1388
1389 /* context now contains CLSID_WineOOPTest, test if registered one could still be used */
1390 if ((handle = activate_context(actctx_manifest, &ctxcookie)))
1391 {
1392 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
1393 todo_wine
1394 ok(hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), "got 0x%08x\n", hr);
1395
1396 pDeactivateActCtx(0, ctxcookie);
1397 pReleaseActCtx(handle);
1398 }
1399
1400 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
1401 ok(hr == S_OK, "got 0x%08x\n", hr);
1402 IClassFactory_Release(pcf);
1403
1404 hr = CoRevokeClassObject(cookie);
1405 ok(hr == S_OK, "got 0x%08x\n", hr);
1406
1407 CoUninitialize();
1408 }
1409
1410 static HRESULT get_class_object(CLSCTX clsctx)
1411 {
1412 HRESULT hr;
1413 IClassFactory *pcf;
1414
1415 hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
1416 (void **)&pcf);
1417
1418 if (SUCCEEDED(hr))
1419 IClassFactory_Release(pcf);
1420
1421 return hr;
1422 }
1423
1424 static DWORD CALLBACK get_class_object_thread(LPVOID pv)
1425 {
1426 CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
1427 HRESULT hr;
1428
1429 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1430
1431 hr = get_class_object(clsctx);
1432
1433 CoUninitialize();
1434
1435 return hr;
1436 }
1437
1438 static DWORD CALLBACK get_class_object_proxy_thread(LPVOID pv)
1439 {
1440 CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
1441 HRESULT hr;
1442 IClassFactory *pcf;
1443 IMultiQI *pMQI;
1444
1445 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1446
1447 hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
1448 (void **)&pcf);
1449
1450 if (SUCCEEDED(hr))
1451 {
1452 hr = IClassFactory_QueryInterface(pcf, &IID_IMultiQI, (void **)&pMQI);
1453 if (SUCCEEDED(hr))
1454 IMultiQI_Release(pMQI);
1455 IClassFactory_Release(pcf);
1456 }
1457
1458 CoUninitialize();
1459
1460 return hr;
1461 }
1462
1463 static DWORD CALLBACK register_class_object_thread(LPVOID pv)
1464 {
1465 HRESULT hr;
1466 DWORD cookie;
1467
1468 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1469
1470 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1471 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1472
1473 CoUninitialize();
1474
1475 return hr;
1476 }
1477
1478 static DWORD CALLBACK revoke_class_object_thread(LPVOID pv)
1479 {
1480 DWORD cookie = (DWORD_PTR)pv;
1481 HRESULT hr;
1482
1483 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1484
1485 hr = CoRevokeClassObject(cookie);
1486
1487 CoUninitialize();
1488
1489 return hr;
1490 }
1491
1492 static void test_registered_object_thread_affinity(void)
1493 {
1494 HRESULT hr;
1495 DWORD cookie;
1496 HANDLE thread;
1497 DWORD tid;
1498 DWORD exitcode;
1499
1500 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1501
1502 /* CLSCTX_INPROC_SERVER */
1503
1504 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1505 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1506 ok_ole_success(hr, "CoRegisterClassObject");
1507
1508 thread = CreateThread(NULL, 0, get_class_object_thread, (LPVOID)CLSCTX_INPROC_SERVER, 0, &tid);
1509 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1510 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1511 GetExitCodeThread(thread, &exitcode);
1512 hr = exitcode;
1513 ok(hr == REGDB_E_CLASSNOTREG, "CoGetClassObject on inproc object "
1514 "registered in different thread should return REGDB_E_CLASSNOTREG "
1515 "instead of 0x%08x\n", hr);
1516
1517 hr = get_class_object(CLSCTX_INPROC_SERVER);
1518 ok(hr == S_OK, "CoGetClassObject on inproc object registered in same "
1519 "thread should return S_OK instead of 0x%08x\n", hr);
1520
1521 thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
1522 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1523 ok ( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1524 GetExitCodeThread(thread, &exitcode);
1525 hr = exitcode;
1526 ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different thread should return S_OK instead of 0x%08x\n", hr);
1527
1528 hr = CoRevokeClassObject(cookie);
1529 ok_ole_success(hr, "CoRevokeClassObject");
1530
1531 /* CLSCTX_LOCAL_SERVER */
1532
1533 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1534 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1535 ok_ole_success(hr, "CoRegisterClassObject");
1536
1537 thread = CreateThread(NULL, 0, get_class_object_proxy_thread, (LPVOID)CLSCTX_LOCAL_SERVER, 0, &tid);
1538 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1539 while (MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)
1540 {
1541 MSG msg;
1542 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
1543 {
1544 TranslateMessage(&msg);
1545 DispatchMessageA(&msg);
1546 }
1547 }
1548 GetExitCodeThread(thread, &exitcode);
1549 hr = exitcode;
1550 ok(hr == S_OK, "CoGetClassObject on local server object "
1551 "registered in different thread should return S_OK "
1552 "instead of 0x%08x\n", hr);
1553
1554 hr = get_class_object(CLSCTX_LOCAL_SERVER);
1555 ok(hr == S_OK, "CoGetClassObject on local server object registered in same "
1556 "thread should return S_OK instead of 0x%08x\n", hr);
1557
1558 thread = CreateThread(NULL, 0, revoke_class_object_thread, (LPVOID)(DWORD_PTR)cookie, 0, &tid);
1559 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1560 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1561 GetExitCodeThread(thread, &exitcode);
1562 hr = exitcode;
1563 ok(hr == RPC_E_WRONG_THREAD, "CoRevokeClassObject called from different "
1564 "thread to where registered should return RPC_E_WRONG_THREAD instead of 0x%08x\n", hr);
1565
1566 thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
1567 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1568 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1569 GetExitCodeThread(thread, &exitcode);
1570 hr = exitcode;
1571 ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different "
1572 "thread should return S_OK instead of 0x%08x\n", hr);
1573
1574 hr = CoRevokeClassObject(cookie);
1575 ok_ole_success(hr, "CoRevokeClassObject");
1576
1577 CoUninitialize();
1578 }
1579
1580 static DWORD CALLBACK free_libraries_thread(LPVOID p)
1581 {
1582 CoFreeUnusedLibraries();
1583 return 0;
1584 }
1585
1586 static inline BOOL is_module_loaded(const char *module)
1587 {
1588 return GetModuleHandleA(module) != 0;
1589 }
1590
1591 static void test_CoFreeUnusedLibraries(void)
1592 {
1593 HRESULT hr;
1594 IUnknown *pUnk;
1595 DWORD tid;
1596 HANDLE thread;
1597
1598 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1599
1600 ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1601
1602 hr = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pUnk);
1603 if (hr == REGDB_E_CLASSNOTREG)
1604 {
1605 skip("IE not installed so can't run CoFreeUnusedLibraries test\n");
1606 CoUninitialize();
1607 return;
1608 }
1609 ok_ole_success(hr, "CoCreateInstance");
1610
1611 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1612
1613 ok(pUnk != NULL ||
1614 broken(pUnk == NULL), /* win9x */
1615 "Expected a valid pointer\n");
1616 if (pUnk)
1617 IUnknown_Release(pUnk);
1618
1619 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1620
1621 thread = CreateThread(NULL, 0, free_libraries_thread, NULL, 0, &tid);
1622 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1623 CloseHandle(thread);
1624
1625 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1626
1627 CoFreeUnusedLibraries();
1628
1629 ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1630
1631 CoUninitialize();
1632 }
1633
1634 static void test_CoGetObjectContext(void)
1635 {
1636 HRESULT hr;
1637 ULONG refs;
1638 IComThreadingInfo *pComThreadingInfo;
1639 IContextCallback *pContextCallback;
1640 IObjContext *pObjContext;
1641 APTTYPE apttype;
1642 THDTYPE thdtype;
1643 struct info info;
1644 HANDLE thread;
1645 DWORD tid, exitcode;
1646
1647 if (!pCoGetObjectContext)
1648 {
1649 skip("CoGetObjectContext not present\n");
1650 return;
1651 }
1652
1653 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1654 ok(hr == CO_E_NOTINITIALIZED, "CoGetObjectContext should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1655 ok(pComThreadingInfo == NULL, "pComThreadingInfo should have been set to NULL\n");
1656
1657 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
1658 thread has already done so */
1659
1660 info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
1661 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
1662
1663 info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
1664 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
1665
1666 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
1667 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1668
1669 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
1670
1671 pComThreadingInfo = NULL;
1672 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1673 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1674 IComThreadingInfo_Release(pComThreadingInfo);
1675
1676 SetEvent(info.stop);
1677 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1678
1679 GetExitCodeThread(thread, &exitcode);
1680 hr = exitcode;
1681 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
1682
1683 CloseHandle(thread);
1684 CloseHandle(info.wait);
1685 CloseHandle(info.stop);
1686
1687 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1688
1689 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1690 ok_ole_success(hr, "CoGetObjectContext");
1691
1692 hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1693 ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1694 ok(apttype == APTTYPE_MAINSTA, "apartment type should be APTTYPE_MAINSTA instead of %d\n", apttype);
1695
1696 hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1697 ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1698 ok(thdtype == THDTYPE_PROCESSMESSAGES, "thread type should be THDTYPE_PROCESSMESSAGES instead of %d\n", thdtype);
1699
1700 refs = IComThreadingInfo_Release(pComThreadingInfo);
1701 ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1702
1703 hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1704 ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1705
1706 if (hr == S_OK)
1707 {
1708 refs = IContextCallback_Release(pContextCallback);
1709 ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1710 }
1711
1712 CoUninitialize();
1713
1714 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1715
1716 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1717 ok_ole_success(hr, "CoGetObjectContext");
1718
1719 hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1720 ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1721 ok(apttype == APTTYPE_MTA, "apartment type should be APTTYPE_MTA instead of %d\n", apttype);
1722
1723 hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1724 ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1725 ok(thdtype == THDTYPE_BLOCKMESSAGES, "thread type should be THDTYPE_BLOCKMESSAGES instead of %d\n", thdtype);
1726
1727 refs = IComThreadingInfo_Release(pComThreadingInfo);
1728 ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1729
1730 hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1731 ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1732
1733 if (hr == S_OK)
1734 {
1735 refs = IContextCallback_Release(pContextCallback);
1736 ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1737 }
1738
1739 hr = pCoGetObjectContext(&IID_IObjContext, (void **)&pObjContext);
1740 ok_ole_success(hr, "CoGetObjectContext");
1741
1742 refs = IObjContext_Release(pObjContext);
1743 ok(refs == 0, "pObjContext should have 0 refs instead of %d refs\n", refs);
1744
1745 CoUninitialize();
1746 }
1747
1748 typedef struct {
1749 IUnknown IUnknown_iface;
1750 LONG refs;
1751 } Test_CallContext;
1752
1753 static inline Test_CallContext *impl_from_IUnknown(IUnknown *iface)
1754 {
1755 return CONTAINING_RECORD(iface, Test_CallContext, IUnknown_iface);
1756 }
1757
1758 static HRESULT WINAPI Test_CallContext_QueryInterface(
1759 IUnknown *iface,
1760 REFIID riid,
1761 LPVOID *ppvObj)
1762 {
1763 if (ppvObj == NULL) return E_POINTER;
1764
1765 if (IsEqualGUID(riid, &IID_IUnknown))
1766 {
1767 *ppvObj = iface;
1768 IUnknown_AddRef(iface);
1769 return S_OK;
1770 }
1771
1772 *ppvObj = NULL;
1773 return E_NOINTERFACE;
1774 }
1775
1776 static ULONG WINAPI Test_CallContext_AddRef(IUnknown *iface)
1777 {
1778 Test_CallContext *This = impl_from_IUnknown(iface);
1779 return InterlockedIncrement(&This->refs);
1780 }
1781
1782 static ULONG WINAPI Test_CallContext_Release(IUnknown *iface)
1783 {
1784 Test_CallContext *This = impl_from_IUnknown(iface);
1785 ULONG refs = InterlockedDecrement(&This->refs);
1786 if (!refs)
1787 HeapFree(GetProcessHeap(), 0, This);
1788 return refs;
1789 }
1790
1791 static const IUnknownVtbl TestCallContext_Vtbl =
1792 {
1793 Test_CallContext_QueryInterface,
1794 Test_CallContext_AddRef,
1795 Test_CallContext_Release
1796 };
1797
1798 static void test_CoGetCallContext(void)
1799 {
1800 HRESULT hr;
1801 ULONG refs;
1802 IUnknown *pUnk;
1803 Test_CallContext *test_object;
1804
1805 if (!pCoSwitchCallContext)
1806 {
1807 skip("CoSwitchCallContext not present\n");
1808 return;
1809 }
1810
1811 CoInitialize(NULL);
1812
1813 test_object = HeapAlloc(GetProcessHeap(), 0, sizeof(Test_CallContext));
1814 test_object->IUnknown_iface.lpVtbl = &TestCallContext_Vtbl;
1815 test_object->refs = 1;
1816
1817 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1818 ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
1819
1820 pUnk = (IUnknown*)0xdeadbeef;
1821 hr = pCoSwitchCallContext(&test_object->IUnknown_iface, &pUnk);
1822 ok_ole_success(hr, "CoSwitchCallContext");
1823 ok(pUnk == NULL, "expected NULL, got %p\n", pUnk);
1824 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
1825 ok(refs == 2, "Expected refcount 2, got %d\n", refs);
1826 IUnknown_Release(&test_object->IUnknown_iface);
1827
1828 pUnk = (IUnknown*)0xdeadbeef;
1829 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1830 ok_ole_success(hr, "CoGetCallContext");
1831 ok(pUnk == &test_object->IUnknown_iface, "expected %p, got %p\n",
1832 &test_object->IUnknown_iface, pUnk);
1833 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
1834 ok(refs == 3, "Expected refcount 3, got %d\n", refs);
1835 IUnknown_Release(&test_object->IUnknown_iface);
1836 IUnknown_Release(pUnk);
1837
1838 pUnk = (IUnknown*)0xdeadbeef;
1839 hr = pCoSwitchCallContext(NULL, &pUnk);
1840 ok_ole_success(hr, "CoSwitchCallContext");
1841 ok(pUnk == &test_object->IUnknown_iface, "expected %p, got %p\n",
1842 &test_object->IUnknown_iface, pUnk);
1843 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
1844 ok(refs == 2, "Expected refcount 2, got %d\n", refs);
1845 IUnknown_Release(&test_object->IUnknown_iface);
1846
1847 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1848 ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
1849
1850 IUnknown_Release(&test_object->IUnknown_iface);
1851
1852 CoUninitialize();
1853 }
1854
1855 static void test_CoGetContextToken(void)
1856 {
1857 HRESULT hr;
1858 ULONG refs;
1859 ULONG_PTR token;
1860 IObjContext *ctx;
1861 struct info info;
1862 HANDLE thread;
1863 DWORD tid, exitcode;
1864
1865 if (!pCoGetContextToken)
1866 {
1867 win_skip("CoGetContextToken not present\n");
1868 return;
1869 }
1870
1871 token = 0xdeadbeef;
1872 hr = pCoGetContextToken(&token);
1873 ok(hr == CO_E_NOTINITIALIZED, "Expected CO_E_NOTINITIALIZED, got 0x%08x\n", hr);
1874 ok(token == 0xdeadbeef, "Expected 0, got 0x%lx\n", token);
1875
1876 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
1877 thread has already done so */
1878
1879 info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
1880 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
1881
1882 info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
1883 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
1884
1885 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
1886 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1887
1888 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
1889
1890 token = 0;
1891 hr = pCoGetContextToken(&token);
1892 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1893
1894 SetEvent(info.stop);
1895 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1896
1897 GetExitCodeThread(thread, &exitcode);
1898 hr = exitcode;
1899 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
1900
1901 CloseHandle(thread);
1902 CloseHandle(info.wait);
1903 CloseHandle(info.stop);
1904
1905 CoInitialize(NULL);
1906
1907 hr = pCoGetContextToken(NULL);
1908 ok(hr == E_POINTER, "Expected E_POINTER, got 0x%08x\n", hr);
1909
1910 token = 0;
1911 hr = pCoGetContextToken(&token);
1912 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1913 ok(token, "Expected token != 0\n");
1914
1915 refs = IUnknown_AddRef((IUnknown *)token);
1916 todo_wine ok(refs == 1, "Expected 1, got %u\n", refs);
1917
1918 hr = pCoGetObjectContext(&IID_IObjContext, (void **)&ctx);
1919 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1920 todo_wine ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
1921
1922 refs = IUnknown_AddRef((IUnknown *)ctx);
1923 todo_wine ok(refs == 3, "Expected 3, got %u\n", refs);
1924
1925 refs = IUnknown_Release((IUnknown *)ctx);
1926 todo_wine ok(refs == 2, "Expected 2, got %u\n", refs);
1927
1928 refs = IUnknown_Release((IUnknown *)token);
1929 ok(refs == 1, "Expected 1, got %u\n", refs);
1930
1931 /* CoGetContextToken does not add a reference */
1932 token = 0;
1933 hr = pCoGetContextToken(&token);
1934 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1935 ok(token, "Expected token != 0\n");
1936 todo_wine ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
1937
1938 refs = IUnknown_AddRef((IUnknown *)ctx);
1939 ok(refs == 2, "Expected 1, got %u\n", refs);
1940
1941 refs = IUnknown_Release((IUnknown *)ctx);
1942 ok(refs == 1, "Expected 0, got %u\n", refs);
1943
1944 refs = IUnknown_Release((IUnknown *)ctx);
1945 ok(refs == 0, "Expected 0, got %u\n", refs);
1946
1947 CoUninitialize();
1948 }
1949
1950 static void test_TreatAsClass(void)
1951 {
1952 HRESULT hr;
1953 CLSID out;
1954 static GUID deadbeef = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
1955 static const char deadbeefA[] = "{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF}";
1956 IInternetProtocol *pIP = NULL;
1957 HKEY clsidkey, deadbeefkey;
1958 LONG lr;
1959
1960 if (!pCoGetTreatAsClass)
1961 {
1962 win_skip("CoGetTreatAsClass not present\n");
1963 return;
1964 }
1965 hr = pCoGetTreatAsClass(&deadbeef,&out);
1966 ok (hr == S_FALSE, "expected S_FALSE got %x\n",hr);
1967 ok (IsEqualGUID(&out,&deadbeef), "expected to get same clsid back\n");
1968
1969 lr = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &clsidkey);
1970 ok(lr == ERROR_SUCCESS, "Couldn't open CLSID key\n");
1971
1972 lr = RegCreateKeyExA(clsidkey, deadbeefA, 0, NULL, 0, KEY_WRITE, NULL, &deadbeefkey, NULL);
1973 ok(lr == ERROR_SUCCESS, "Couldn't create class key\n");
1974
1975 hr = pCoTreatAsClass(&deadbeef, &deadbeef);
1976 ok(hr == REGDB_E_WRITEREGDB, "CoTreatAsClass gave wrong error: %08x\n", hr);
1977
1978 hr = pCoTreatAsClass(&deadbeef, &CLSID_FileProtocol);
1979 if(hr == REGDB_E_WRITEREGDB){
1980 win_skip("Insufficient privileges to use CoTreatAsClass\n");
1981 goto exit;
1982 }
1983 ok(hr == S_OK, "CoTreatAsClass failed: %08x\n", hr);
1984
1985 hr = pCoGetTreatAsClass(&deadbeef, &out);
1986 ok(hr == S_OK, "CoGetTreatAsClass failed: %08x\n",hr);
1987 ok(IsEqualGUID(&out, &CLSID_FileProtocol), "expected to get substituted clsid\n");
1988
1989 OleInitialize(NULL);
1990
1991 hr = CoCreateInstance(&deadbeef, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pIP);
1992 if(hr == REGDB_E_CLASSNOTREG)
1993 {
1994 win_skip("IE not installed so can't test CoCreateInstance\n");
1995 goto exit;
1996 }
1997
1998 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
1999 if(pIP){
2000 IInternetProtocol_Release(pIP);
2001 pIP = NULL;
2002 }
2003
2004 hr = pCoTreatAsClass(&deadbeef, &CLSID_NULL);
2005 ok(hr == S_OK, "CoTreatAsClass failed: %08x\n", hr);
2006
2007 hr = pCoGetTreatAsClass(&deadbeef, &out);
2008 ok(hr == S_FALSE, "expected S_FALSE got %08x\n", hr);
2009 ok(IsEqualGUID(&out, &deadbeef), "expected to get same clsid back\n");
2010
2011 /* bizarrely, native's CoTreatAsClass takes some time to take effect in CoCreateInstance */
2012 Sleep(200);
2013
2014 hr = CoCreateInstance(&deadbeef, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pIP);
2015 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance gave wrong error: %08x\n", hr);
2016
2017 if(pIP)
2018 IInternetProtocol_Release(pIP);
2019
2020 exit:
2021 OleUninitialize();
2022 RegCloseKey(deadbeefkey);
2023 RegDeleteKeyA(clsidkey, deadbeefA);
2024 RegCloseKey(clsidkey);
2025 }
2026
2027 static void test_CoInitializeEx(void)
2028 {
2029 HRESULT hr;
2030
2031 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2032 ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
2033
2034 /* Calling OleInitialize for the first time should yield S_OK even with
2035 * apartment already initialized by previous CoInitialize(Ex) calls. */
2036 hr = OleInitialize(NULL);
2037 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
2038
2039 /* Subsequent calls to OleInitialize should return S_FALSE */
2040 hr = OleInitialize(NULL);
2041 ok(hr == S_FALSE, "Expected S_FALSE, hr = 0x%08x\n", hr);
2042
2043 /* Cleanup */
2044 CoUninitialize();
2045 OleUninitialize();
2046 }
2047
2048 static void test_OleRegGetMiscStatus(void)
2049 {
2050 ULONG_PTR cookie;
2051 HANDLE handle;
2052 DWORD status;
2053 HRESULT hr;
2054
2055 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_ICON, NULL);
2056 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2057
2058 status = 0xdeadbeef;
2059 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_ICON, &status);
2060 ok(hr == REGDB_E_CLASSNOTREG, "got 0x%08x\n", hr);
2061 ok(status == 0, "got 0x%08x\n", status);
2062
2063 status = -1;
2064 hr = OleRegGetMiscStatus(&CLSID_StdFont, DVASPECT_ICON, &status);
2065 ok(hr == S_OK, "got 0x%08x\n", hr);
2066 ok(status == 0, "got 0x%08x\n", status);
2067
2068 if ((handle = activate_context(actctx_manifest, &cookie)))
2069 {
2070 status = 0;
2071 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_ICON, &status);
2072 ok(hr == S_OK, "got 0x%08x\n", hr);
2073 ok(status == OLEMISC_RECOMPOSEONRESIZE, "got 0x%08x\n", status);
2074
2075 /* context data takes precedence over registration info */
2076 status = 0;
2077 hr = OleRegGetMiscStatus(&CLSID_StdFont, DVASPECT_ICON, &status);
2078 ok(hr == S_OK, "got 0x%08x\n", hr);
2079 ok(status == OLEMISC_RECOMPOSEONRESIZE, "got 0x%08x\n", status);
2080
2081 /* there's no such attribute in context */
2082 status = -1;
2083 hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_DOCPRINT, &status);
2084 ok(hr == S_OK, "got 0x%08x\n", hr);
2085 ok(status == 0, "got 0x%08x\n", status);
2086
2087 pDeactivateActCtx(0, cookie);
2088 pReleaseActCtx(handle);
2089 }
2090 }
2091
2092 static void test_CoCreateGuid(void)
2093 {
2094 HRESULT hr;
2095
2096 hr = CoCreateGuid(NULL);
2097 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2098 }
2099
2100 static void init_funcs(void)
2101 {
2102 HMODULE hOle32 = GetModuleHandleA("ole32");
2103 HMODULE hAdvapi32 = GetModuleHandleA("advapi32");
2104 HMODULE hkernel32 = GetModuleHandleA("kernel32");
2105
2106 pCoGetObjectContext = (void*)GetProcAddress(hOle32, "CoGetObjectContext");
2107 pCoSwitchCallContext = (void*)GetProcAddress(hOle32, "CoSwitchCallContext");
2108 pCoGetTreatAsClass = (void*)GetProcAddress(hOle32,"CoGetTreatAsClass");
2109 pCoTreatAsClass = (void*)GetProcAddress(hOle32,"CoTreatAsClass");
2110 pCoGetContextToken = (void*)GetProcAddress(hOle32, "CoGetContextToken");
2111 pRegDeleteKeyExA = (void*)GetProcAddress(hAdvapi32, "RegDeleteKeyExA");
2112 pRegOverridePredefKey = (void*)GetProcAddress(hAdvapi32, "RegOverridePredefKey");
2113 pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx");
2114
2115 pActivateActCtx = (void*)GetProcAddress(hkernel32, "ActivateActCtx");
2116 pCreateActCtxW = (void*)GetProcAddress(hkernel32, "CreateActCtxW");
2117 pDeactivateActCtx = (void*)GetProcAddress(hkernel32, "DeactivateActCtx");
2118 pIsWow64Process = (void*)GetProcAddress(hkernel32, "IsWow64Process");
2119 pReleaseActCtx = (void*)GetProcAddress(hkernel32, "ReleaseActCtx");
2120 }
2121
2122 START_TEST(compobj)
2123 {
2124 init_funcs();
2125
2126 if (!pCoInitializeEx)
2127 {
2128 trace("You need DCOM95 installed to run this test\n");
2129 return;
2130 }
2131
2132 if (!pCreateActCtxW)
2133 win_skip("Activation contexts are not supported, some tests will be skipped.\n");
2134
2135 test_ProgIDFromCLSID();
2136 test_CLSIDFromProgID();
2137 test_CLSIDFromString();
2138 test_IIDFromString();
2139 test_StringFromGUID2();
2140 test_CoCreateInstance();
2141 test_ole_menu();
2142 test_CoGetClassObject();
2143 test_CoRegisterMessageFilter();
2144 test_CoRegisterPSClsid();
2145 test_CoGetPSClsid();
2146 test_CoUnmarshalInterface();
2147 test_CoGetInterfaceAndReleaseStream();
2148 test_CoMarshalInterface();
2149 test_CoMarshalInterThreadInterfaceInStream();
2150 test_CoRegisterClassObject();
2151 test_registered_object_thread_affinity();
2152 test_CoFreeUnusedLibraries();
2153 test_CoGetObjectContext();
2154 test_CoGetCallContext();
2155 test_CoGetContextToken();
2156 test_TreatAsClass();
2157 test_CoInitializeEx();
2158 test_OleRegGetMiscStatus();
2159 test_CoCreateGuid();
2160 }