jscript: Removed unused do_*_tag_format arguments.
[wine/multimedia.git] / dlls / ole32 / tests / compobj.c
blobb76c9d2887b55e3637a33bd129fcd54d2d39c9e9
1 /*
2 * Component Object Tests
4 * Copyright 2005 Robert Shearman
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.
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.
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
21 #define COBJMACROS
22 #define CONST_VTABLE
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #define USE_COM_CONTEXT_DEF
29 #include "initguid.h"
30 #include "objbase.h"
31 #include "shlguid.h"
32 #include "urlmon.h" /* for CLSID_FileProtocol */
34 #include "ctxtcall.h"
36 #include "wine/test.h"
38 /* functions that are not present on all versions of Windows */
39 static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
40 static HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv);
41 static HRESULT (WINAPI * pCoSwitchCallContext)(IUnknown *pObject, IUnknown **ppOldObject);
42 static HRESULT (WINAPI * pCoGetTreatAsClass)(REFCLSID clsidOld, LPCLSID pClsidNew);
43 static HRESULT (WINAPI * pCoGetContextToken)(ULONG_PTR *token);
45 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
46 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
47 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
49 static const CLSID CLSID_non_existent = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
50 static const CLSID CLSID_StdFont = { 0x0be35203, 0x8f91, 0x11ce, { 0x9d, 0xe3, 0x00, 0xaa, 0x00, 0x4b, 0xb8, 0x51 } };
51 static WCHAR stdfont[] = {'S','t','d','F','o','n','t',0};
52 static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
53 static WCHAR wszCLSID_StdFont[] =
55 '{','0','b','e','3','5','2','0','3','-','8','f','9','1','-','1','1','c','e','-',
56 '9','d','e','3','-','0','0','a','a','0','0','4','b','b','8','5','1','}',0
59 static const IID IID_IWineTest =
61 0x5201163f,
62 0x8164,
63 0x4fd0,
64 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
65 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
66 static const CLSID CLSID_WineOOPTest = {
67 0x5201163f,
68 0x8164,
69 0x4fd0,
70 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
71 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
73 static LONG cLocks;
75 static void LockModule(void)
77 InterlockedIncrement(&cLocks);
80 static void UnlockModule(void)
82 InterlockedDecrement(&cLocks);
85 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
86 LPCLASSFACTORY iface,
87 REFIID riid,
88 LPVOID *ppvObj)
90 if (ppvObj == NULL) return E_POINTER;
92 if (IsEqualGUID(riid, &IID_IUnknown) ||
93 IsEqualGUID(riid, &IID_IClassFactory))
95 *ppvObj = iface;
96 IClassFactory_AddRef(iface);
97 return S_OK;
100 *ppvObj = NULL;
101 return E_NOINTERFACE;
104 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
106 LockModule();
107 return 2; /* non-heap-based object */
110 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
112 UnlockModule();
113 return 1; /* non-heap-based object */
116 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
117 LPCLASSFACTORY iface,
118 IUnknown *pUnkOuter,
119 REFIID riid,
120 LPVOID *ppvObj)
122 *ppvObj = NULL;
123 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
124 return E_NOINTERFACE;
127 static HRESULT WINAPI Test_IClassFactory_LockServer(
128 LPCLASSFACTORY iface,
129 BOOL fLock)
131 return S_OK;
134 static const IClassFactoryVtbl TestClassFactory_Vtbl =
136 Test_IClassFactory_QueryInterface,
137 Test_IClassFactory_AddRef,
138 Test_IClassFactory_Release,
139 Test_IClassFactory_CreateInstance,
140 Test_IClassFactory_LockServer
143 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
145 static void test_ProgIDFromCLSID(void)
147 LPWSTR progid;
148 HRESULT hr = ProgIDFromCLSID(&CLSID_StdFont, &progid);
149 ok(hr == S_OK, "ProgIDFromCLSID failed with error 0x%08x\n", hr);
150 if (hr == S_OK)
152 ok(!lstrcmpiW(progid, stdfont), "Didn't get expected prog ID\n");
153 CoTaskMemFree(progid);
156 progid = (LPWSTR)0xdeadbeef;
157 hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
158 ok(hr == REGDB_E_CLASSNOTREG, "ProgIDFromCLSID returned %08x\n", hr);
159 ok(progid == NULL, "ProgIDFromCLSID returns with progid %p\n", progid);
161 hr = ProgIDFromCLSID(&CLSID_StdFont, NULL);
162 ok(hr == E_INVALIDARG, "ProgIDFromCLSID should return E_INVALIDARG instead of 0x%08x\n", hr);
165 static void test_CLSIDFromProgID(void)
167 CLSID clsid;
168 HRESULT hr = CLSIDFromProgID(stdfont, &clsid);
169 ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08x\n", hr);
170 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
172 hr = CLSIDFromString(stdfont, &clsid);
173 ok_ole_success(hr, "CLSIDFromString");
174 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
176 /* test some failure cases */
178 hr = CLSIDFromProgID(wszNonExistent, NULL);
179 ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
181 hr = CLSIDFromProgID(NULL, &clsid);
182 ok(hr == E_INVALIDARG, "CLSIDFromProgID should have returned E_INVALIDARG instead of 0x%08x\n", hr);
184 memset(&clsid, 0xcc, sizeof(clsid));
185 hr = CLSIDFromProgID(wszNonExistent, &clsid);
186 ok(hr == CO_E_CLASSSTRING, "CLSIDFromProgID on nonexistent ProgID should have returned CO_E_CLASSSTRING instead of 0x%08x\n", hr);
187 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "CLSIDFromProgID should have set clsid to all-zeros on failure\n");
190 static void test_CLSIDFromString(void)
192 CLSID clsid;
193 WCHAR wszCLSID_Broken[50];
194 UINT i;
196 HRESULT hr = CLSIDFromString(wszCLSID_StdFont, &clsid);
197 ok_ole_success(hr, "CLSIDFromString");
198 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
200 hr = CLSIDFromString(NULL, &clsid);
201 ok_ole_success(hr, "CLSIDFromString");
202 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
204 lstrcpyW(wszCLSID_Broken, wszCLSID_StdFont);
205 for(i = lstrlenW(wszCLSID_StdFont); i < 49; i++)
206 wszCLSID_Broken[i] = 'A';
207 wszCLSID_Broken[i] = '\0';
209 memset(&clsid, 0, sizeof(CLSID));
210 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
211 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
212 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
214 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)-1] = 'A';
215 memset(&clsid, 0, sizeof(CLSID));
216 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
217 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
218 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
220 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)] = '\0';
221 memset(&clsid, 0, sizeof(CLSID));
222 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
223 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
224 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
226 wszCLSID_Broken[lstrlenW(wszCLSID_StdFont)-1] = '\0';
227 memset(&clsid, 0, sizeof(CLSID));
228 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
229 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
230 ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
232 memset(&clsid, 0xcc, sizeof(CLSID));
233 hr = CLSIDFromString(wszCLSID_Broken+1, &clsid);
234 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
235 ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
237 wszCLSID_Broken[9] = '*';
238 memset(&clsid, 0xcc, sizeof(CLSID));
239 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
240 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
241 ok(clsid.Data1 == CLSID_StdFont.Data1, "Got %08x\n", clsid.Data1);
242 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
244 wszCLSID_Broken[3] = '*';
245 memset(&clsid, 0xcc, sizeof(CLSID));
246 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
247 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
248 ok(clsid.Data1 == 0xb, "Got %08x\n", clsid.Data1);
249 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
251 wszCLSID_Broken[3] = '\0';
252 memset(&clsid, 0xcc, sizeof(CLSID));
253 hr = CLSIDFromString(wszCLSID_Broken, &clsid);
254 ok(hr == CO_E_CLASSSTRING, "Got %08x\n", hr);
255 ok(clsid.Data1 == 0xb, "Got %08x\n", clsid.Data1);
256 ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
259 static void test_StringFromGUID2(void)
261 WCHAR str[50];
262 int len;
264 /* invalid pointer */
265 SetLastError(0xdeadbeef);
266 len = StringFromGUID2(NULL,str,50);
267 ok(len == 0, "len: %d (expected 0)\n", len);
268 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %x\n", GetLastError());
270 /* Test corner cases for buffer size */
271 len = StringFromGUID2(&CLSID_StdFont,str,50);
272 ok(len == 39, "len: %d (expected 39)\n", len);
273 ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n");
275 memset(str,0,sizeof str);
276 len = StringFromGUID2(&CLSID_StdFont,str,39);
277 ok(len == 39, "len: %d (expected 39)\n", len);
278 ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n");
280 len = StringFromGUID2(&CLSID_StdFont,str,38);
281 ok(len == 0, "len: %d (expected 0)\n", len);
283 len = StringFromGUID2(&CLSID_StdFont,str,30);
284 ok(len == 0, "len: %d (expected 0)\n", len);
287 struct info
289 HANDLE wait, stop;
292 static DWORD CALLBACK ole_initialize_thread(LPVOID pv)
294 HRESULT hr;
295 struct info *info = pv;
297 hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
299 SetEvent(info->wait);
300 WaitForSingleObject(info->stop, 10000);
302 CoUninitialize();
303 return hr;
306 static void test_CoCreateInstance(void)
308 HRESULT hr;
309 HANDLE thread;
310 DWORD tid, exitcode;
311 IUnknown *pUnk;
312 struct info info;
313 REFCLSID rclsid = &CLSID_InternetZoneManager;
315 pUnk = (IUnknown *)0xdeadbeef;
316 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
317 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
318 ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
320 OleInitialize(NULL);
322 /* test errors returned for non-registered clsids */
323 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
324 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
325 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pUnk);
326 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc handler should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
327 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_LOCAL_SERVER, &IID_IUnknown, (void **)&pUnk);
328 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered local server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
329 hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_REMOTE_SERVER, &IID_IUnknown, (void **)&pUnk);
330 ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered remote server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
332 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
333 if(hr == REGDB_E_CLASSNOTREG)
335 skip("IE not installed so can't test CoCreateInstance\n");
336 OleUninitialize();
337 return;
340 ok_ole_success(hr, "CoCreateInstance");
341 if(pUnk) IUnknown_Release(pUnk);
342 OleUninitialize();
344 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
345 ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
347 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
348 thread has already done so */
350 info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
351 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
353 info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
354 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
356 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
357 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
359 ok( !WaitForSingleObject(info.wait, 10000 ), "wait timed out\n" );
361 pUnk = (IUnknown *)0xdeadbeef;
362 hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
363 ok(hr == S_OK, "CoCreateInstance should have returned S_OK instead of 0x%08x\n", hr);
364 if (pUnk) IUnknown_Release(pUnk);
366 SetEvent(info.stop);
367 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
369 GetExitCodeThread(thread, &exitcode);
370 hr = exitcode;
371 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
373 CloseHandle(thread);
374 CloseHandle(info.wait);
375 CloseHandle(info.stop);
378 static void test_CoGetClassObject(void)
380 HRESULT hr;
381 HANDLE thread;
382 DWORD tid, exitcode;
383 IUnknown *pUnk;
384 struct info info;
385 REFCLSID rclsid = &CLSID_InternetZoneManager;
387 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
388 ok(hr == CO_E_NOTINITIALIZED, "CoGetClassObject should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
389 ok(pUnk == NULL, "CoGetClassObject should have changed the passed in pointer to NULL, instead of %p\n", pUnk);
391 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL);
392 ok(hr == E_INVALIDARG ||
393 broken(hr == CO_E_NOTINITIALIZED), /* win9x */
394 "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr);
396 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
397 thread has already done so */
399 info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
400 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
402 info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
403 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
405 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
406 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
408 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
410 pUnk = (IUnknown *)0xdeadbeef;
411 hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
412 if(hr == REGDB_E_CLASSNOTREG)
413 skip("IE not installed so can't test CoGetClassObject\n");
414 else
416 ok(hr == S_OK, "CoGetClassObject should have returned S_OK instead of 0x%08x\n", hr);
417 if (pUnk) IUnknown_Release(pUnk);
420 SetEvent(info.stop);
421 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
423 GetExitCodeThread(thread, &exitcode);
424 hr = exitcode;
425 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
427 CloseHandle(thread);
428 CloseHandle(info.wait);
429 CloseHandle(info.stop);
432 static ATOM register_dummy_class(void)
434 WNDCLASS wc =
437 DefWindowProc,
440 GetModuleHandle(NULL),
441 NULL,
442 LoadCursor(NULL, IDC_ARROW),
443 (HBRUSH)(COLOR_BTNFACE+1),
444 NULL,
445 TEXT("WineOleTestClass"),
448 return RegisterClass(&wc);
451 static void test_ole_menu(void)
453 HWND hwndFrame;
454 HRESULT hr;
456 hwndFrame = CreateWindow(MAKEINTATOM(register_dummy_class()), "Test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
457 hr = OleSetMenuDescriptor(NULL, hwndFrame, NULL, NULL, NULL);
458 todo_wine ok_ole_success(hr, "OleSetMenuDescriptor");
460 DestroyWindow(hwndFrame);
464 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
466 if (ppvObj == NULL) return E_POINTER;
468 if (IsEqualGUID(riid, &IID_IUnknown) ||
469 IsEqualGUID(riid, &IID_IClassFactory))
471 *ppvObj = iface;
472 IMessageFilter_AddRef(iface);
473 return S_OK;
476 return E_NOINTERFACE;
479 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
481 return 2; /* non-heap object */
484 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
486 return 1; /* non-heap object */
489 static DWORD WINAPI MessageFilter_HandleInComingCall(
490 IMessageFilter *iface,
491 DWORD dwCallType,
492 HTASK threadIDCaller,
493 DWORD dwTickCount,
494 LPINTERFACEINFO lpInterfaceInfo)
496 trace("HandleInComingCall\n");
497 return SERVERCALL_ISHANDLED;
500 static DWORD WINAPI MessageFilter_RetryRejectedCall(
501 IMessageFilter *iface,
502 HTASK threadIDCallee,
503 DWORD dwTickCount,
504 DWORD dwRejectType)
506 trace("RetryRejectedCall\n");
507 return 0;
510 static DWORD WINAPI MessageFilter_MessagePending(
511 IMessageFilter *iface,
512 HTASK threadIDCallee,
513 DWORD dwTickCount,
514 DWORD dwPendingType)
516 trace("MessagePending\n");
517 return PENDINGMSG_WAITNOPROCESS;
520 static const IMessageFilterVtbl MessageFilter_Vtbl =
522 MessageFilter_QueryInterface,
523 MessageFilter_AddRef,
524 MessageFilter_Release,
525 MessageFilter_HandleInComingCall,
526 MessageFilter_RetryRejectedCall,
527 MessageFilter_MessagePending
530 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
532 static void test_CoRegisterMessageFilter(void)
534 HRESULT hr;
535 IMessageFilter *prev_filter;
537 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
538 ok(hr == CO_E_NOT_SUPPORTED,
539 "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
540 hr);
542 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
543 prev_filter = (IMessageFilter *)0xdeadbeef;
544 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
545 ok(hr == CO_E_NOT_SUPPORTED,
546 "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08x\n",
547 hr);
548 ok(prev_filter == (IMessageFilter *)0xdeadbeef,
549 "prev_filter should have been set to %p\n", prev_filter);
550 CoUninitialize();
552 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
554 hr = CoRegisterMessageFilter(NULL, NULL);
555 ok_ole_success(hr, "CoRegisterMessageFilter");
557 prev_filter = (IMessageFilter *)0xdeadbeef;
558 hr = CoRegisterMessageFilter(NULL, &prev_filter);
559 ok_ole_success(hr, "CoRegisterMessageFilter");
560 ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
562 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
563 ok_ole_success(hr, "CoRegisterMessageFilter");
564 ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter);
566 hr = CoRegisterMessageFilter(NULL, NULL);
567 ok_ole_success(hr, "CoRegisterMessageFilter");
569 CoUninitialize();
572 static HRESULT WINAPI Test_IUnknown_QueryInterface(
573 IUnknown *iface,
574 REFIID riid,
575 LPVOID *ppvObj)
577 if (ppvObj == NULL) return E_POINTER;
579 if (IsEqualIID(riid, &IID_IUnknown) ||
580 IsEqualIID(riid, &IID_IWineTest))
582 *ppvObj = iface;
583 IUnknown_AddRef(iface);
584 return S_OK;
587 *ppvObj = NULL;
588 return E_NOINTERFACE;
591 static ULONG WINAPI Test_IUnknown_AddRef(IUnknown *iface)
593 return 2; /* non-heap-based object */
596 static ULONG WINAPI Test_IUnknown_Release(IUnknown *iface)
598 return 1; /* non-heap-based object */
601 static const IUnknownVtbl TestUnknown_Vtbl =
603 Test_IUnknown_QueryInterface,
604 Test_IUnknown_AddRef,
605 Test_IUnknown_Release,
608 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
610 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(
611 IPSFactoryBuffer * This,
612 /* [in] */ REFIID riid,
613 /* [iid_is][out] */ void **ppvObject)
615 if (IsEqualIID(riid, &IID_IUnknown) ||
616 IsEqualIID(riid, &IID_IPSFactoryBuffer))
618 *ppvObject = This;
619 IPSFactoryBuffer_AddRef(This);
620 return S_OK;
622 return E_NOINTERFACE;
625 static ULONG WINAPI PSFactoryBuffer_AddRef(
626 IPSFactoryBuffer * This)
628 return 2;
631 static ULONG WINAPI PSFactoryBuffer_Release(
632 IPSFactoryBuffer * This)
634 return 1;
637 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(
638 IPSFactoryBuffer * This,
639 /* [in] */ IUnknown *pUnkOuter,
640 /* [in] */ REFIID riid,
641 /* [out] */ IRpcProxyBuffer **ppProxy,
642 /* [out] */ void **ppv)
644 return E_NOTIMPL;
647 static HRESULT WINAPI PSFactoryBuffer_CreateStub(
648 IPSFactoryBuffer * This,
649 /* [in] */ REFIID riid,
650 /* [unique][in] */ IUnknown *pUnkServer,
651 /* [out] */ IRpcStubBuffer **ppStub)
653 return E_NOTIMPL;
656 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
658 PSFactoryBuffer_QueryInterface,
659 PSFactoryBuffer_AddRef,
660 PSFactoryBuffer_Release,
661 PSFactoryBuffer_CreateProxy,
662 PSFactoryBuffer_CreateStub
665 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
667 static const CLSID CLSID_WineTestPSFactoryBuffer =
669 0x52011640,
670 0x8164,
671 0x4fd0,
672 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
673 }; /* 52011640-8164-4fd0-a1a2-5d5a3654d3bd */
675 static void test_CoRegisterPSClsid(void)
677 HRESULT hr;
678 DWORD dwRegistrationKey;
679 IStream *stream;
680 CLSID clsid;
682 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
683 ok(hr == CO_E_NOTINITIALIZED, "CoRegisterPSClsid should have returened CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
685 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
687 hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
688 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &dwRegistrationKey);
689 ok_ole_success(hr, "CoRegisterClassObject");
691 hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
692 ok_ole_success(hr, "CoRegisterPSClsid");
694 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
695 ok_ole_success(hr, "CreateStreamOnHGlobal");
697 hr = CoMarshalInterface(stream, &IID_IWineTest, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
698 ok(hr == E_NOTIMPL, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr);
699 IStream_Release(stream);
701 hr = CoRevokeClassObject(dwRegistrationKey);
702 ok_ole_success(hr, "CoRevokeClassObject");
704 CoUninitialize();
706 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
708 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
709 ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08x\n", hr);
711 CoUninitialize();
714 static void test_CoGetPSClsid(void)
716 HRESULT hr;
717 CLSID clsid;
719 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
720 ok(hr == CO_E_NOTINITIALIZED,
721 "CoGetPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n",
722 hr);
724 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
726 hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
727 ok_ole_success(hr, "CoGetPSClsid");
729 hr = CoGetPSClsid(&IID_IWineTest, &clsid);
730 ok(hr == REGDB_E_IIDNOTREG,
731 "CoGetPSClsid for random IID returned 0x%08x instead of REGDB_E_IIDNOTREG\n",
732 hr);
734 hr = CoGetPSClsid(&IID_IClassFactory, NULL);
735 ok(hr == E_INVALIDARG,
736 "CoGetPSClsid for null clsid returned 0x%08x instead of E_INVALIDARG\n",
737 hr);
739 CoUninitialize();
742 /* basic test, mainly for invalid arguments. see marshal.c for more */
743 static void test_CoUnmarshalInterface(void)
745 IUnknown *pProxy;
746 IStream *pStream;
747 HRESULT hr;
749 hr = CoUnmarshalInterface(NULL, &IID_IUnknown, (void **)&pProxy);
750 ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
752 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
753 ok_ole_success(hr, "CreateStreamOnHGlobal");
755 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
756 todo_wine
757 ok(hr == CO_E_NOTINITIALIZED, "CoUnmarshalInterface should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
759 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
761 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
762 ok(hr == STG_E_READFAULT, "CoUnmarshalInterface should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
764 CoUninitialize();
766 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, NULL);
767 ok(hr == E_INVALIDARG, "CoUnmarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
769 IStream_Release(pStream);
772 static void test_CoGetInterfaceAndReleaseStream(void)
774 HRESULT hr;
775 IUnknown *pUnk;
777 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
779 hr = CoGetInterfaceAndReleaseStream(NULL, &IID_IUnknown, (void**)&pUnk);
780 ok(hr == E_INVALIDARG, "hr %08x\n", hr);
782 CoUninitialize();
785 /* basic test, mainly for invalid arguments. see marshal.c for more */
786 static void test_CoMarshalInterface(void)
788 IStream *pStream;
789 HRESULT hr;
790 static const LARGE_INTEGER llZero;
792 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
794 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
795 ok_ole_success(hr, "CreateStreamOnHGlobal");
797 hr = CoMarshalInterface(pStream, &IID_IUnknown, NULL, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
798 ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
800 hr = CoMarshalInterface(NULL, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
801 ok(hr == E_INVALIDARG, "CoMarshalInterface should have returned E_INVALIDARG instead of 0x%08x\n", hr);
803 hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
804 ok_ole_success(hr, "CoMarshalInterface");
806 /* stream not rewound */
807 hr = CoReleaseMarshalData(pStream);
808 ok(hr == STG_E_READFAULT, "CoReleaseMarshalData should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
810 hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
811 ok_ole_success(hr, "IStream_Seek");
813 hr = CoReleaseMarshalData(pStream);
814 ok_ole_success(hr, "CoReleaseMarshalData");
816 IStream_Release(pStream);
818 CoUninitialize();
821 static void test_CoMarshalInterThreadInterfaceInStream(void)
823 IStream *pStream;
824 HRESULT hr;
825 IClassFactory *pProxy;
827 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
829 cLocks = 0;
831 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, NULL);
832 ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
834 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, NULL, &pStream);
835 ok(hr == E_INVALIDARG, "CoMarshalInterThreadInterfaceInStream should have returned E_INVALIDARG instead of 0x%08x\n", hr);
837 ok_no_locks();
839 hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, (IUnknown *)&Test_ClassFactory, &pStream);
840 ok_ole_success(hr, "CoMarshalInterThreadInterfaceInStream");
842 ok_more_than_one_lock();
844 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
845 ok_ole_success(hr, "CoUnmarshalInterface");
847 IClassFactory_Release(pProxy);
848 IStream_Release(pStream);
850 ok_no_locks();
852 CoUninitialize();
855 static void test_CoRegisterClassObject(void)
857 DWORD cookie;
858 HRESULT hr;
859 IClassFactory *pcf;
861 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
863 /* CLSCTX_INPROC_SERVER */
864 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
865 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
866 ok_ole_success(hr, "CoRegisterClassObject");
867 hr = CoRevokeClassObject(cookie);
868 ok_ole_success(hr, "CoRevokeClassObject");
870 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
871 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie);
872 ok_ole_success(hr, "CoRegisterClassObject");
873 hr = CoRevokeClassObject(cookie);
874 ok_ole_success(hr, "CoRevokeClassObject");
876 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
877 CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
878 ok_ole_success(hr, "CoRegisterClassObject");
879 hr = CoRevokeClassObject(cookie);
880 ok_ole_success(hr, "CoRevokeClassObject");
882 /* CLSCTX_LOCAL_SERVER */
883 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
884 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
885 ok_ole_success(hr, "CoRegisterClassObject");
886 hr = CoRevokeClassObject(cookie);
887 ok_ole_success(hr, "CoRevokeClassObject");
889 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
890 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
891 ok_ole_success(hr, "CoRegisterClassObject");
892 hr = CoRevokeClassObject(cookie);
893 ok_ole_success(hr, "CoRevokeClassObject");
895 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
896 CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE, &cookie);
897 ok_ole_success(hr, "CoRegisterClassObject");
898 hr = CoRevokeClassObject(cookie);
899 ok_ole_success(hr, "CoRevokeClassObject");
901 /* CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER */
902 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
903 CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
904 ok_ole_success(hr, "CoRegisterClassObject");
905 hr = CoRevokeClassObject(cookie);
906 ok_ole_success(hr, "CoRevokeClassObject");
908 /* test whether an object that doesn't support IClassFactory can be
909 * registered for CLSCTX_LOCAL_SERVER */
910 hr = CoRegisterClassObject(&CLSID_WineOOPTest, &Test_Unknown,
911 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
912 ok_ole_success(hr, "CoRegisterClassObject");
913 hr = CoRevokeClassObject(cookie);
914 ok_ole_success(hr, "CoRevokeClassObject");
916 /* test whether registered class becomes invalid when apartment is destroyed */
917 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
918 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
919 ok_ole_success(hr, "CoRegisterClassObject");
921 CoUninitialize();
922 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
924 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL,
925 &IID_IClassFactory, (void **)&pcf);
926 ok(hr == REGDB_E_CLASSNOTREG, "object registered in an apartment shouldn't accessible after it is destroyed\n");
928 /* crashes with at least win9x DCOM! */
929 if (0)
930 CoRevokeClassObject(cookie);
932 CoUninitialize();
935 static HRESULT get_class_object(CLSCTX clsctx)
937 HRESULT hr;
938 IClassFactory *pcf;
940 hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
941 (void **)&pcf);
943 if (SUCCEEDED(hr))
944 IClassFactory_Release(pcf);
946 return hr;
949 static DWORD CALLBACK get_class_object_thread(LPVOID pv)
951 CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
952 HRESULT hr;
954 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
956 hr = get_class_object(clsctx);
958 CoUninitialize();
960 return hr;
963 static DWORD CALLBACK get_class_object_proxy_thread(LPVOID pv)
965 CLSCTX clsctx = (CLSCTX)(DWORD_PTR)pv;
966 HRESULT hr;
967 IClassFactory *pcf;
968 IMultiQI *pMQI;
970 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
972 hr = CoGetClassObject(&CLSID_WineOOPTest, clsctx, NULL, &IID_IClassFactory,
973 (void **)&pcf);
975 if (SUCCEEDED(hr))
977 hr = IClassFactory_QueryInterface(pcf, &IID_IMultiQI, (void **)&pMQI);
978 if (SUCCEEDED(hr))
979 IMultiQI_Release(pMQI);
980 IClassFactory_Release(pcf);
983 CoUninitialize();
985 return hr;
988 static DWORD CALLBACK register_class_object_thread(LPVOID pv)
990 HRESULT hr;
991 DWORD cookie;
993 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
995 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
996 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
998 CoUninitialize();
1000 return hr;
1003 static DWORD CALLBACK revoke_class_object_thread(LPVOID pv)
1005 DWORD cookie = (DWORD_PTR)pv;
1006 HRESULT hr;
1008 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1010 hr = CoRevokeClassObject(cookie);
1012 CoUninitialize();
1014 return hr;
1017 static void test_registered_object_thread_affinity(void)
1019 HRESULT hr;
1020 DWORD cookie;
1021 HANDLE thread;
1022 DWORD tid;
1023 DWORD exitcode;
1025 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1027 /* CLSCTX_INPROC_SERVER */
1029 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1030 CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie);
1031 ok_ole_success(hr, "CoRegisterClassObject");
1033 thread = CreateThread(NULL, 0, get_class_object_thread, (LPVOID)CLSCTX_INPROC_SERVER, 0, &tid);
1034 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1035 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1036 GetExitCodeThread(thread, &exitcode);
1037 hr = exitcode;
1038 ok(hr == REGDB_E_CLASSNOTREG, "CoGetClassObject on inproc object "
1039 "registered in different thread should return REGDB_E_CLASSNOTREG "
1040 "instead of 0x%08x\n", hr);
1042 hr = get_class_object(CLSCTX_INPROC_SERVER);
1043 ok(hr == S_OK, "CoGetClassObject on inproc object registered in same "
1044 "thread should return S_OK instead of 0x%08x\n", hr);
1046 thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
1047 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1048 ok ( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1049 GetExitCodeThread(thread, &exitcode);
1050 hr = exitcode;
1051 ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different thread should return S_OK instead of 0x%08x\n", hr);
1053 hr = CoRevokeClassObject(cookie);
1054 ok_ole_success(hr, "CoRevokeClassObject");
1056 /* CLSCTX_LOCAL_SERVER */
1058 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory,
1059 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
1060 ok_ole_success(hr, "CoRegisterClassObject");
1062 thread = CreateThread(NULL, 0, get_class_object_proxy_thread, (LPVOID)CLSCTX_LOCAL_SERVER, 0, &tid);
1063 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1064 while (MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)
1066 MSG msg;
1067 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
1069 TranslateMessage(&msg);
1070 DispatchMessageA(&msg);
1073 GetExitCodeThread(thread, &exitcode);
1074 hr = exitcode;
1075 ok(hr == S_OK, "CoGetClassObject on local server object "
1076 "registered in different thread should return S_OK "
1077 "instead of 0x%08x\n", hr);
1079 hr = get_class_object(CLSCTX_LOCAL_SERVER);
1080 ok(hr == S_OK, "CoGetClassObject on local server object registered in same "
1081 "thread should return S_OK instead of 0x%08x\n", hr);
1083 thread = CreateThread(NULL, 0, revoke_class_object_thread, (LPVOID)(DWORD_PTR)cookie, 0, &tid);
1084 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1085 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1086 GetExitCodeThread(thread, &exitcode);
1087 hr = exitcode;
1088 ok(hr == RPC_E_WRONG_THREAD, "CoRevokeClassObject called from different "
1089 "thread to where registered should return RPC_E_WRONG_THREAD instead of 0x%08x\n", hr);
1091 thread = CreateThread(NULL, 0, register_class_object_thread, NULL, 0, &tid);
1092 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1093 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1094 GetExitCodeThread(thread, &exitcode);
1095 hr = exitcode;
1096 ok(hr == S_OK, "CoRegisterClassObject with same CLSID but in different "
1097 "thread should return S_OK instead of 0x%08x\n", hr);
1099 hr = CoRevokeClassObject(cookie);
1100 ok_ole_success(hr, "CoRevokeClassObject");
1102 CoUninitialize();
1105 static DWORD CALLBACK free_libraries_thread(LPVOID p)
1107 CoFreeUnusedLibraries();
1108 return 0;
1111 static inline BOOL is_module_loaded(const char *module)
1113 return GetModuleHandle(module) ? TRUE : FALSE;
1116 static void test_CoFreeUnusedLibraries(void)
1118 HRESULT hr;
1119 IUnknown *pUnk;
1120 DWORD tid;
1121 HANDLE thread;
1123 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1125 ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1127 hr = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pUnk);
1128 if (hr == REGDB_E_CLASSNOTREG)
1130 skip("IE not installed so can't run CoFreeUnusedLibraries test\n");
1131 CoUninitialize();
1132 return;
1134 ok_ole_success(hr, "CoCreateInstance");
1136 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1138 ok(pUnk != NULL ||
1139 broken(pUnk == NULL), /* win9x */
1140 "Expected a valid pointer\n");
1141 if (pUnk)
1142 IUnknown_Release(pUnk);
1144 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1146 thread = CreateThread(NULL, 0, free_libraries_thread, NULL, 0, &tid);
1147 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1148 CloseHandle(thread);
1150 ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n");
1152 CoFreeUnusedLibraries();
1154 ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n");
1156 CoUninitialize();
1159 static void test_CoGetObjectContext(void)
1161 HRESULT hr;
1162 ULONG refs;
1163 IComThreadingInfo *pComThreadingInfo;
1164 IContextCallback *pContextCallback;
1165 IObjContext *pObjContext;
1166 APTTYPE apttype;
1167 THDTYPE thdtype;
1168 struct info info;
1169 HANDLE thread;
1170 DWORD tid, exitcode;
1172 if (!pCoGetObjectContext)
1174 skip("CoGetObjectContext not present\n");
1175 return;
1178 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1179 ok(hr == CO_E_NOTINITIALIZED, "CoGetObjectContext should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
1180 ok(pComThreadingInfo == NULL, "pComThreadingInfo should have been set to NULL\n");
1182 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
1183 thread has already done so */
1185 info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
1186 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
1188 info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
1189 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
1191 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
1192 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1194 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
1196 pComThreadingInfo = NULL;
1197 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1198 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1199 IComThreadingInfo_Release(pComThreadingInfo);
1201 SetEvent(info.stop);
1202 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1204 GetExitCodeThread(thread, &exitcode);
1205 hr = exitcode;
1206 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
1208 CloseHandle(thread);
1209 CloseHandle(info.wait);
1210 CloseHandle(info.stop);
1212 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1214 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1215 ok_ole_success(hr, "CoGetObjectContext");
1217 hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1218 ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1219 ok(apttype == APTTYPE_MAINSTA, "apartment type should be APTTYPE_MAINSTA instead of %d\n", apttype);
1221 hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1222 ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1223 ok(thdtype == THDTYPE_PROCESSMESSAGES, "thread type should be THDTYPE_PROCESSMESSAGES instead of %d\n", thdtype);
1225 refs = IComThreadingInfo_Release(pComThreadingInfo);
1226 ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1228 hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1229 ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1231 if (hr == S_OK)
1233 refs = IContextCallback_Release(pContextCallback);
1234 ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1237 CoUninitialize();
1239 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1241 hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
1242 ok_ole_success(hr, "CoGetObjectContext");
1244 hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
1245 ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
1246 ok(apttype == APTTYPE_MTA, "apartment type should be APTTYPE_MTA instead of %d\n", apttype);
1248 hr = IComThreadingInfo_GetCurrentThreadType(pComThreadingInfo, &thdtype);
1249 ok_ole_success(hr, "IComThreadingInfo_GetCurrentThreadType");
1250 ok(thdtype == THDTYPE_BLOCKMESSAGES, "thread type should be THDTYPE_BLOCKMESSAGES instead of %d\n", thdtype);
1252 refs = IComThreadingInfo_Release(pComThreadingInfo);
1253 ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs);
1255 hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
1256 ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
1258 if (hr == S_OK)
1260 refs = IContextCallback_Release(pContextCallback);
1261 ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
1264 hr = pCoGetObjectContext(&IID_IObjContext, (void **)&pObjContext);
1265 ok_ole_success(hr, "CoGetObjectContext");
1267 refs = IObjContext_Release(pObjContext);
1268 ok(refs == 0, "pObjContext should have 0 refs instead of %d refs\n", refs);
1270 CoUninitialize();
1273 typedef struct {
1274 IUnknown IUnknown_iface;
1275 LONG refs;
1276 } Test_CallContext;
1278 static inline Test_CallContext *impl_from_IUnknown(IUnknown *iface)
1280 return CONTAINING_RECORD(iface, Test_CallContext, IUnknown_iface);
1283 static HRESULT WINAPI Test_CallContext_QueryInterface(
1284 IUnknown *iface,
1285 REFIID riid,
1286 LPVOID *ppvObj)
1288 if (ppvObj == NULL) return E_POINTER;
1290 if (IsEqualGUID(riid, &IID_IUnknown))
1292 *ppvObj = iface;
1293 IUnknown_AddRef(iface);
1294 return S_OK;
1297 *ppvObj = NULL;
1298 return E_NOINTERFACE;
1301 static ULONG WINAPI Test_CallContext_AddRef(IUnknown *iface)
1303 Test_CallContext *This = impl_from_IUnknown(iface);
1304 return InterlockedIncrement(&This->refs);
1307 static ULONG WINAPI Test_CallContext_Release(IUnknown *iface)
1309 Test_CallContext *This = impl_from_IUnknown(iface);
1310 ULONG refs = InterlockedDecrement(&This->refs);
1311 if (!refs)
1312 HeapFree(GetProcessHeap(), 0, This);
1313 return refs;
1316 static const IUnknownVtbl TestCallContext_Vtbl =
1318 Test_CallContext_QueryInterface,
1319 Test_CallContext_AddRef,
1320 Test_CallContext_Release
1323 static void test_CoGetCallContext(void)
1325 HRESULT hr;
1326 ULONG refs;
1327 IUnknown *pUnk;
1328 Test_CallContext *test_object;
1330 if (!pCoSwitchCallContext)
1332 skip("CoSwitchCallContext not present\n");
1333 return;
1336 CoInitialize(NULL);
1338 test_object = HeapAlloc(GetProcessHeap(), 0, sizeof(Test_CallContext));
1339 test_object->IUnknown_iface.lpVtbl = &TestCallContext_Vtbl;
1340 test_object->refs = 1;
1342 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1343 ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
1345 pUnk = (IUnknown*)0xdeadbeef;
1346 hr = pCoSwitchCallContext(&test_object->IUnknown_iface, &pUnk);
1347 ok_ole_success(hr, "CoSwitchCallContext");
1348 ok(pUnk == NULL, "expected NULL, got %p\n", pUnk);
1349 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
1350 ok(refs == 2, "Expected refcount 2, got %d\n", refs);
1351 IUnknown_Release(&test_object->IUnknown_iface);
1353 pUnk = (IUnknown*)0xdeadbeef;
1354 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1355 ok_ole_success(hr, "CoGetCallContext");
1356 ok(pUnk == &test_object->IUnknown_iface, "expected %p, got %p\n",
1357 &test_object->IUnknown_iface, pUnk);
1358 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
1359 ok(refs == 3, "Expected refcount 3, got %d\n", refs);
1360 IUnknown_Release(&test_object->IUnknown_iface);
1361 IUnknown_Release(pUnk);
1363 pUnk = (IUnknown*)0xdeadbeef;
1364 hr = pCoSwitchCallContext(NULL, &pUnk);
1365 ok_ole_success(hr, "CoSwitchCallContext");
1366 ok(pUnk == &test_object->IUnknown_iface, "expected %p, got %p\n",
1367 &test_object->IUnknown_iface, pUnk);
1368 refs = IUnknown_AddRef(&test_object->IUnknown_iface);
1369 ok(refs == 2, "Expected refcount 2, got %d\n", refs);
1370 IUnknown_Release(&test_object->IUnknown_iface);
1372 hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk);
1373 ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr);
1375 IUnknown_Release(&test_object->IUnknown_iface);
1377 CoUninitialize();
1380 static void test_CoGetContextToken(void)
1382 HRESULT hr;
1383 ULONG refs;
1384 ULONG_PTR token;
1385 IObjContext *ctx;
1386 struct info info;
1387 HANDLE thread;
1388 DWORD tid, exitcode;
1390 if (!pCoGetContextToken)
1392 win_skip("CoGetContextToken not present\n");
1393 return;
1396 token = 0xdeadbeef;
1397 hr = pCoGetContextToken(&token);
1398 ok(hr == CO_E_NOTINITIALIZED, "Expected CO_E_NOTINITIALIZED, got 0x%08x\n", hr);
1399 ok(token == 0xdeadbeef, "Expected 0, got 0x%lx\n", token);
1401 /* show that COM doesn't have to be initialized for multi-threaded apartments if another
1402 thread has already done so */
1404 info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
1405 ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
1407 info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
1408 ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
1410 thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
1411 ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
1413 ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
1415 token = 0;
1416 hr = pCoGetContextToken(&token);
1417 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1419 SetEvent(info.stop);
1420 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1422 GetExitCodeThread(thread, &exitcode);
1423 hr = exitcode;
1424 ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
1426 CloseHandle(thread);
1427 CloseHandle(info.wait);
1428 CloseHandle(info.stop);
1430 CoInitialize(NULL);
1432 hr = pCoGetContextToken(NULL);
1433 ok(hr == E_POINTER, "Expected E_POINTER, got 0x%08x\n", hr);
1435 token = 0;
1436 hr = pCoGetContextToken(&token);
1437 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1438 ok(token, "Expected token != 0\n");
1440 refs = IUnknown_AddRef((IUnknown *)token);
1441 todo_wine ok(refs == 1, "Expected 1, got %u\n", refs);
1443 hr = pCoGetObjectContext(&IID_IObjContext, (void **)&ctx);
1444 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1445 todo_wine ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
1447 refs = IUnknown_AddRef((IUnknown *)ctx);
1448 todo_wine ok(refs == 3, "Expected 3, got %u\n", refs);
1450 refs = IUnknown_Release((IUnknown *)ctx);
1451 todo_wine ok(refs == 2, "Expected 2, got %u\n", refs);
1453 refs = IUnknown_Release((IUnknown *)token);
1454 ok(refs == 1, "Expected 1, got %u\n", refs);
1456 /* CoGetContextToken does not add a reference */
1457 token = 0;
1458 hr = pCoGetContextToken(&token);
1459 ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
1460 ok(token, "Expected token != 0\n");
1461 todo_wine ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
1463 refs = IUnknown_AddRef((IUnknown *)ctx);
1464 ok(refs == 2, "Expected 1, got %u\n", refs);
1466 refs = IUnknown_Release((IUnknown *)ctx);
1467 ok(refs == 1, "Expected 0, got %u\n", refs);
1469 refs = IUnknown_Release((IUnknown *)ctx);
1470 ok(refs == 0, "Expected 0, got %u\n", refs);
1472 CoUninitialize();
1475 static void test_CoGetTreatAsClass(void)
1477 HRESULT hr;
1478 CLSID out;
1479 static GUID deadbeef = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
1481 if (!pCoGetTreatAsClass)
1483 win_skip("CoGetTreatAsClass not present\n");
1484 return;
1486 hr = pCoGetTreatAsClass(&deadbeef,&out);
1487 ok (hr == S_FALSE, "expected S_FALSE got %x\n",hr);
1488 ok (IsEqualGUID(&out,&deadbeef), "expected to get same clsid back\n");
1491 static void test_CoInitializeEx(void)
1493 HRESULT hr;
1495 hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1496 ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr);
1498 /* Calling OleInitialize for the first time should yield S_OK even with
1499 * apartment already initialized by previous CoInitialize(Ex) calls. */
1500 hr = OleInitialize(NULL);
1501 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
1503 /* Subsequent calls to OleInitialize should return S_FALSE */
1504 hr = OleInitialize(NULL);
1505 ok(hr == S_FALSE, "Expected S_FALSE, hr = 0x%08x\n", hr);
1507 /* Cleanup */
1508 CoUninitialize();
1509 OleUninitialize();
1512 START_TEST(compobj)
1514 HMODULE hOle32 = GetModuleHandle("ole32");
1515 pCoGetObjectContext = (void*)GetProcAddress(hOle32, "CoGetObjectContext");
1516 pCoSwitchCallContext = (void*)GetProcAddress(hOle32, "CoSwitchCallContext");
1517 pCoGetTreatAsClass = (void*)GetProcAddress(hOle32,"CoGetTreatAsClass");
1518 pCoGetContextToken = (void*)GetProcAddress(hOle32, "CoGetContextToken");
1519 if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx")))
1521 trace("You need DCOM95 installed to run this test\n");
1522 return;
1525 test_ProgIDFromCLSID();
1526 test_CLSIDFromProgID();
1527 test_CLSIDFromString();
1528 test_StringFromGUID2();
1529 test_CoCreateInstance();
1530 test_ole_menu();
1531 test_CoGetClassObject();
1532 test_CoRegisterMessageFilter();
1533 test_CoRegisterPSClsid();
1534 test_CoGetPSClsid();
1535 test_CoUnmarshalInterface();
1536 test_CoGetInterfaceAndReleaseStream();
1537 test_CoMarshalInterface();
1538 test_CoMarshalInterThreadInterfaceInStream();
1539 test_CoRegisterClassObject();
1540 test_registered_object_thread_affinity();
1541 test_CoFreeUnusedLibraries();
1542 test_CoGetObjectContext();
1543 test_CoGetCallContext();
1544 test_CoGetContextToken();
1545 test_CoGetTreatAsClass();
1546 test_CoInitializeEx();