1 /* 2 * OLE client/server test suite 3 * 4 * Copyright 2013 Dmitry Timoshkov 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #define COBJMACROS 22 #define CONST_VTABLE 23 24 #include <windows.h> 25 #include <exdisp.h> 26 #include <tlhelp32.h> 27 #include <stdio.h> 28 #include <assert.h> 29 #include "wine/test.h" 30 31 #include <initguid.h> 32 DEFINE_GUID(CLSID_WineTestObject, 0xdeadbeef,0xdead,0xbeef,0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef); 33 #ifndef CLSID_IdentityUnmarshal 34 DEFINE_GUID(CLSID_IdentityUnmarshal,0x0000001b,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); 35 #endif 36 DEFINE_GUID(CLSID_UnknownUnmarshal,0x4c1e39e1,0xe3e3,0x4296,0xaa,0x86,0xec,0x93,0x8d,0x89,0x6e,0x92); 37 38 struct winetest_info 39 { 40 LONG child_failures; 41 }; 42 43 static const struct 44 { 45 const GUID *guid; 46 const char *name; 47 } guid_name[] = 48 { 49 #define GUID_NAME(guid) \ 50 { &IID_##guid, #guid } 51 GUID_NAME(IUnknown), 52 GUID_NAME(IClassFactory), 53 GUID_NAME(IOleObject), 54 GUID_NAME(IMarshal), 55 GUID_NAME(IStdMarshalInfo), 56 GUID_NAME(IExternalConnection), 57 GUID_NAME(IRunnableObject), 58 GUID_NAME(ICallFactory), 59 { &CLSID_IdentityUnmarshal, "CLSID_IdentityUnmarshal" }, 60 { &CLSID_UnknownUnmarshal, "CLSID_UnknownUnmarshal" }, 61 #undef GUID_NAME 62 }; 63 64 static LONG obj_ref, class_ref, server_locks; 65 66 static const char *debugstr_guid(const GUID *guid) 67 { 68 int i; 69 70 if (!guid) return "(null)"; 71 72 for (i = 0; i < sizeof(guid_name)/sizeof(guid_name[0]); i++) 73 { 74 if (IsEqualIID(guid, guid_name[i].guid)) 75 return guid_name[i].name; 76 } 77 78 return wine_dbgstr_guid(guid); 79 } 80 81 /******************************* OLE server *******************************/ 82 typedef struct 83 { 84 IUnknown IUnknown_iface; 85 LONG ref; 86 } UnknownImpl; 87 88 static inline UnknownImpl *impl_from_IUnknown(IUnknown *iface) 89 { 90 return CONTAINING_RECORD(iface, UnknownImpl, IUnknown_iface); 91 } 92 93 static HRESULT WINAPI UnknownImpl_QueryInterface(IUnknown *iface, 94 REFIID iid, void **ppv) 95 { 96 UnknownImpl *This = impl_from_IUnknown(iface); 97 98 trace("server: unknown_QueryInterface: %p,%s,%p\n", iface, debugstr_guid(iid), ppv); 99 100 if (!ppv) return E_INVALIDARG; 101 102 if (IsEqualIID(&IID_IUnknown, iid)) 103 { 104 *ppv = &This->IUnknown_iface; 105 IUnknown_AddRef(&This->IUnknown_iface); 106 return S_OK; 107 } 108 109 *ppv = NULL; 110 return E_NOINTERFACE; 111 } 112 113 static ULONG WINAPI UnknownImpl_AddRef(IUnknown *iface) 114 { 115 UnknownImpl *This = impl_from_IUnknown(iface); 116 ULONG ref = InterlockedIncrement(&This->ref); 117 118 InterlockedIncrement(&obj_ref); 119 120 trace("server: unknown_AddRef: %p, ref %u\n", iface, ref); 121 return ref; 122 } 123 124 static ULONG WINAPI UnknownImpl_Release(IUnknown *iface) 125 { 126 UnknownImpl *This = impl_from_IUnknown(iface); 127 ULONG ref = InterlockedDecrement(&This->ref); 128 129 InterlockedDecrement(&obj_ref); 130 131 trace("server: unknown_Release: %p, ref %u\n", iface, ref); 132 if (ref == 0) HeapFree(GetProcessHeap(), 0, This); 133 return ref; 134 } 135 136 static const IUnknownVtbl UnknownImpl_Vtbl = 137 { 138 UnknownImpl_QueryInterface, 139 UnknownImpl_AddRef, 140 UnknownImpl_Release, 141 }; 142 143 typedef struct 144 { 145 IClassFactory IClassFactory_iface; 146 LONG ref; 147 } ClassFactoryImpl; 148 149 static inline ClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) 150 { 151 return CONTAINING_RECORD(iface, ClassFactoryImpl, IClassFactory_iface); 152 } 153 154 static HRESULT WINAPI ClassFactoryImpl_QueryInterface(IClassFactory *iface, 155 REFIID iid, void **ppv) 156 { 157 ClassFactoryImpl *This = impl_from_IClassFactory(iface); 158 159 trace("server: factory_QueryInterface: %p,%s,%p\n", iface, debugstr_guid(iid), ppv); 160 161 if (!ppv) return E_INVALIDARG; 162 163 if (IsEqualIID(&IID_IUnknown, iid) || 164 IsEqualIID(&IID_IClassFactory, iid)) 165 { 166 IClassFactory_AddRef(&This->IClassFactory_iface); 167 *ppv = &This->IClassFactory_iface; 168 return S_OK; 169 } 170 171 *ppv = NULL; 172 return E_NOINTERFACE; 173 } 174 175 static ULONG WINAPI ClassFactoryImpl_AddRef(IClassFactory *iface) 176 { 177 ClassFactoryImpl *This = impl_from_IClassFactory(iface); 178 ULONG ref = InterlockedIncrement(&This->ref); 179 180 InterlockedIncrement(&class_ref); 181 182 trace("server: factory_AddRef: %p, ref %u\n", iface, ref); 183 return ref; 184 } 185 186 static ULONG WINAPI ClassFactoryImpl_Release(IClassFactory *iface) 187 { 188 ClassFactoryImpl *This = impl_from_IClassFactory(iface); 189 ULONG ref = InterlockedDecrement(&This->ref); 190 191 InterlockedDecrement(&class_ref); 192 193 trace("server: factory_Release: %p, ref %u\n", iface, ref); 194 return ref; 195 } 196 197 static HRESULT WINAPI ClassFactoryImpl_CreateInstance(IClassFactory *iface, 198 IUnknown *punkouter, REFIID iid, void **ppv) 199 { 200 UnknownImpl *unknown; 201 HRESULT hr; 202 203 trace("server: factory_CreateInstance: %p,%s,%p\n", iface, debugstr_guid(iid), ppv); 204 205 if (punkouter) return CLASS_E_NOAGGREGATION; 206 207 unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown)); 208 if (!unknown) return E_OUTOFMEMORY; 209 210 unknown->IUnknown_iface.lpVtbl = &UnknownImpl_Vtbl; 211 unknown->ref = 0; 212 IUnknown_AddRef(&unknown->IUnknown_iface); 213 214 hr = IUnknown_QueryInterface(&unknown->IUnknown_iface, iid, ppv); 215 IUnknown_Release(&unknown->IUnknown_iface); 216 217 return hr; 218 } 219 220 static HRESULT WINAPI ClassFactoryImpl_LockServer(IClassFactory *iface, BOOL lock) 221 { 222 ULONG ref = lock ? InterlockedIncrement(&server_locks) : InterlockedDecrement(&server_locks); 223 224 trace("server: factory_LockServer: %p,%d, ref %u\n", iface, lock, ref); 225 return S_OK; 226 } 227 228 static const IClassFactoryVtbl ClassFactoryImpl_Vtbl = 229 { 230 ClassFactoryImpl_QueryInterface, 231 ClassFactoryImpl_AddRef, 232 ClassFactoryImpl_Release, 233 ClassFactoryImpl_CreateInstance, 234 ClassFactoryImpl_LockServer 235 }; 236 237 static ClassFactoryImpl factory = { { &ClassFactoryImpl_Vtbl }, 0 }; 238 239 static void ole_server(void) 240 { 241 HRESULT hr; 242 DWORD key; 243 244 trace("server: starting %u\n", GetCurrentProcessId()); 245 246 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); 247 if (hr == S_OK) 248 { 249 trace("server: registering class object\n"); 250 hr = CoRegisterClassObject(&CLSID_WineTestObject, (IUnknown *)&factory, 251 CLSCTX_SERVER, REGCLS_MULTIPLEUSE, &key); 252 if (hr == S_OK) 253 { 254 HANDLE done_event, init_done_event; 255 256 done_event = OpenEventA(SYNCHRONIZE, FALSE, "ole_server_done_event"); 257 ok(done_event != 0, "server: OpenEvent error %d\n", GetLastError()); 258 init_done_event = OpenEventA(EVENT_MODIFY_STATE, FALSE, "ole_server_init_done_event"); 259 ok(init_done_event != 0, "server: OpenEvent error %d\n", GetLastError()); 260 261 SetEvent(init_done_event); 262 263 trace("server: waiting for requests\n"); 264 WaitForSingleObject(done_event, INFINITE); 265 266 /* 1 remainining class ref is supposed to be cleared by CoRevokeClassObject */ 267 ok(class_ref == 1, "expected 1 class refs, got %d\n", class_ref); 268 ok(!obj_ref, "expected 0 object refs, got %d\n", obj_ref); 269 ok(!server_locks, "expected 0 server locks, got %d\n", server_locks); 270 271 CloseHandle(done_event); 272 CloseHandle(init_done_event); 273 if (0) 274 { 275 /* calling CoRevokeClassObject terminates process under Win7 */ 276 trace("call CoRevokeClassObject\n"); 277 CoRevokeClassObject(key); 278 trace("ret CoRevokeClassObject\n"); 279 } 280 } 281 trace("server: call CoUninitialize\n"); 282 CoUninitialize(); 283 trace("server: ret CoUninitialize\n"); 284 } 285 286 trace("server: exiting %u\n", GetCurrentProcessId()); 287 } 288 289 /******************************* OLE client *******************************/ 290 static BOOL register_server(const char *server, BOOL inproc_handler) 291 { 292 static const WCHAR clsidW[] = {'C','L','S','I','D','\\',0}; 293 DWORD ret; 294 HKEY root; 295 WCHAR buf[39 + 6]; 296 char server_path[MAX_PATH]; 297 298 lstrcpyA(server_path, server); 299 lstrcatA(server_path, " ole_server"); 300 301 lstrcpyW(buf, clsidW); 302 StringFromGUID2(&CLSID_WineTestObject, buf + 6, 39); 303 304 ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, buf, 0, NULL, 0, 305 KEY_READ | KEY_WRITE | KEY_CREATE_SUB_KEY, NULL, &root, NULL); 306 if (ret == ERROR_SUCCESS) 307 { 308 ret = RegSetValueA(root, "LocalServer32", REG_SZ, server_path, strlen(server_path)); 309 ok(ret == ERROR_SUCCESS, "RegSetValue error %u\n", ret); 310 311 if (inproc_handler) 312 { 313 ret = RegSetValueA(root, "InprocHandler32", REG_SZ, "ole32.dll", 9); 314 ok(ret == ERROR_SUCCESS, "RegSetValue error %u\n", ret); 315 } 316 317 RegCloseKey(root); 318 } 319 320 return ret == ERROR_SUCCESS; 321 } 322 323 static void unregister_server(void) 324 { 325 static const WCHAR clsidW[] = {'C','L','S','I','D','\\',0}; 326 DWORD ret; 327 HKEY root; 328 WCHAR buf[39 + 6]; 329 330 lstrcpyW(buf, clsidW); 331 StringFromGUID2(&CLSID_WineTestObject, buf + 6, 39); 332 333 ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, buf, 0, NULL, 0, 334 DELETE, NULL, &root, NULL); 335 if (ret == ERROR_SUCCESS) 336 { 337 ret = RegDeleteKeyA(root, "InprocHandler32"); 338 ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret); 339 ret = RegDeleteKeyA(root, "LocalServer32"); 340 ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret); 341 ret = RegDeleteKeyA(root, ""); 342 ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret); 343 RegCloseKey(root); 344 } 345 } 346 347 static HANDLE start_server(const char *argv0) 348 { 349 PROCESS_INFORMATION pi; 350 STARTUPINFOA si; 351 SECURITY_ATTRIBUTES sa; 352 char cmdline[MAX_PATH * 2]; 353 BOOL ret; 354 355 memset(&si, 0, sizeof(si)); 356 si.cb = sizeof(si); 357 si.dwFlags = STARTF_USESTDHANDLES; 358 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 359 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 360 si.hStdError = si.hStdOutput; 361 362 sa.nLength = sizeof(sa); 363 sa.lpSecurityDescriptor = NULL; 364 sa.bInheritHandle = TRUE; 365 366 sprintf(cmdline, "\"%s\" ole_server -server", argv0); 367 ret = CreateProcessA(argv0, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); 368 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError()); 369 if (!ret) return 0; 370 371 CloseHandle(pi.hThread); 372 return pi.hProcess; 373 } 374 375 START_TEST(ole_server) 376 { 377 CLSID clsid = CLSID_WineTestObject; 378 HRESULT hr; 379 IClassFactory *factory; 380 IUnknown *unknown; 381 IOleObject *oleobj; 382 IRunnableObject *runobj; 383 DWORD ret; 384 HANDLE mapping, done_event, init_done_event, process; 385 struct winetest_info *info; 386 int argc; 387 char **argv; 388 389 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_ole_server"); 390 ok(mapping != 0, "CreateFileMapping failed\n"); 391 info = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096); 392 393 argc = winetest_get_mainargs(&argv); 394 395 done_event = CreateEventA(NULL, TRUE, FALSE, "ole_server_done_event"); 396 ok(done_event != 0, "CreateEvent error %d\n", GetLastError()); 397 init_done_event = CreateEventA(NULL, TRUE, FALSE, "ole_server_init_done_event"); 398 ok(init_done_event != 0, "CreateEvent error %d\n", GetLastError()); 399 400 if (argc > 2) 401 { 402 if (!lstrcmpiA(argv[2], "-Embedding")) 403 { 404 trace("server: Refusing to be run by ole32\n"); 405 return; 406 } 407 408 if (!lstrcmpiA(argv[2], "-server")) 409 { 410 info->child_failures = 0; 411 ole_server(); 412 info->child_failures = winetest_get_failures(); 413 return; 414 } 415 416 trace("server: Unknown parameter: %s\n", argv[2]); 417 return; 418 } 419 420 if (!register_server(argv[0], FALSE)) 421 { 422 win_skip("not enough permissions to create a server CLSID key\n"); 423 return; 424 } 425 426 if (!(process = start_server(argv[0]))) 427 { 428 unregister_server(); 429 return; 430 } 431 WaitForSingleObject(init_done_event, 5000); 432 433 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); 434 ok(hr == S_OK, "OleInitialize error %#x\n", hr); 435 436 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&unknown); 437 ok(hr == REGDB_E_CLASSNOTREG, "expected REGDB_E_CLASSNOTREG, got %#x\n", hr); 438 439 if (!register_server(argv[0], TRUE)) 440 { 441 win_skip("not enough permissions to create a server CLSID key\n"); 442 unregister_server(); 443 return; 444 } 445 446 trace("call CoCreateInstance(&IID_NULL)\n"); 447 hr = CoCreateInstance(&clsid, NULL, CLSCTX_LOCAL_SERVER, &IID_NULL, (void **)&unknown); 448 trace("ret CoCreateInstance(&IID_NULL)\n"); 449 ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr); 450 451 /* in-process handler supports IID_IUnknown starting from Vista */ 452 trace("call CoCreateInstance(&IID_IUnknown)\n"); 453 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&unknown); 454 trace("ret CoCreateInstance(&IID_IUnknown)\n"); 455 ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /* XP,win2000 and earlier */, "CoCreateInstance(IID_IUnknown) error %#x\n", hr); 456 if (hr != S_OK) 457 { 458 win_skip("In-process handler doesn't support IID_IUnknown on this platform\n"); 459 goto test_local_server; 460 } 461 462 trace("call CoCreateInstance(&IID_IOleObject)\n"); 463 hr = CoCreateInstance(&clsid, NULL, CLSCTX_LOCAL_SERVER, &IID_IOleObject, (void **)&oleobj); 464 trace("ret CoCreateInstance(&IID_IOleObject)\n"); 465 ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr); 466 467 trace("call IUnknown_QueryInterface(&IID_IRunnableObject)\n"); 468 hr = IUnknown_QueryInterface(unknown, &IID_IRunnableObject, (void **)&runobj); 469 trace("ret IUnknown_QueryInterface(&IID_IRunnableObject)\n"); 470 ok(hr == S_OK, "QueryInterface(&IID_IRunnableObject) error %#x\n", hr); 471 472 ret = IRunnableObject_IsRunning(runobj); 473 ok(!ret, "expected 0, got %d\n", ret); 474 475 trace("call OleRun\n"); 476 hr = OleRun(unknown); 477 trace("ret OleRun\n"); 478 todo_wine 479 ok(hr == S_OK, "OleRun error %#x\n", hr); 480 481 ret = IRunnableObject_IsRunning(runobj); 482 todo_wine 483 ok(ret == 1, "expected 1, got %d\n", ret); 484 485 trace("call IRunnableObject_Release\n"); 486 ret = IRunnableObject_Release(runobj); 487 trace("ret IRunnableObject_Release\n"); 488 ok(ret == 1, "expected ref 1, got %u\n", ret); 489 490 trace("call IUnknown_QueryInterface(&IID_IOleObject)\n"); 491 hr = IUnknown_QueryInterface(unknown, &IID_IOleObject, (void **)&oleobj); 492 trace("ret IUnknown_QueryInterface(&IID_IOleObject)\n"); 493 ok(hr == S_OK, "QueryInterface(&IID_IOleObject) error %#x\n", hr); 494 495 trace("call IOleObject_Release\n"); 496 ret = IOleObject_Release(oleobj); 497 trace("ret IOleObject_Release\n"); 498 ok(ret == 1, "expected ref 1, got %u\n", ret); 499 500 trace("call IUnknown_Release\n"); 501 ret = IUnknown_Release(unknown); 502 trace("ret IUnknown_Release\n"); 503 ok(!ret, "expected ref 0, got %u\n", ret); 504 505 test_local_server: 506 /* local server supports IID_IUnknown */ 507 trace("call CoCreateInstance(&IID_IUnknown)\n"); 508 hr = CoCreateInstance(&clsid, NULL, CLSCTX_LOCAL_SERVER, &IID_IUnknown, (void **)&unknown); 509 trace("ret CoCreateInstance(&IID_IUnknown)\n"); 510 ok(hr == S_OK, "CoCreateInstance(IID_IUnknown) error %#x\n", hr); 511 512 trace("call IUnknown_QueryInterface(&IID_IRunnableObject)\n"); 513 hr = IUnknown_QueryInterface(unknown, &IID_IRunnableObject, (void **)&runobj); 514 trace("ret IUnknown_QueryInterface(&IID_IRunnableObject)\n"); 515 ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr); 516 517 trace("call OleRun\n"); 518 hr = OleRun(unknown); 519 trace("ret OleRun\n"); 520 ok(hr == S_OK, "OleRun error %#x\n", hr); 521 522 trace("call IUnknown_QueryInterface(&IID_IOleObject)\n"); 523 hr = IUnknown_QueryInterface(unknown, &IID_IOleObject, (void **)&oleobj); 524 trace("ret IUnknown_QueryInterface(&IID_IOleObject)\n"); 525 ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr); 526 527 trace("call IUnknown_Release\n"); 528 ret = IUnknown_Release(unknown); 529 trace("ret IUnknown_Release\n"); 530 ok(!ret, "expected ref 0, got %u\n", ret); 531 532 trace("call CoGetClassObject(&IID_IClassFactory)\n"); 533 hr = CoGetClassObject(&clsid, CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (void **)&factory); 534 trace("ret CoGetClassObject(&IID_IClassFactory)\n"); 535 ok(hr == S_OK, "CoGetClassObject error %#x\n", hr); 536 537 trace("call IClassFactory_CreateInstance(&IID_NULL)\n"); 538 hr = IClassFactory_CreateInstance(factory, NULL, &IID_NULL, (void **)&oleobj); 539 trace("ret IClassFactory_CreateInstance(&IID_NULL)\n"); 540 ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr); 541 542 trace("call IClassFactory_CreateInstance(&IID_IOleObject)\n"); 543 hr = IClassFactory_CreateInstance(factory, NULL, &IID_IOleObject, (void **)&oleobj); 544 trace("ret IClassFactory_CreateInstance(&IID_IOleObject)\n"); 545 ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr); 546 547 trace("call IClassFactory_Release\n"); 548 ret = IClassFactory_Release(factory); 549 trace("ret IClassFactory_Release\n"); 550 ok(!ret, "expected ref 0, got %u\n", ret); 551 552 trace("signalling termination\n"); 553 SetEvent(done_event); 554 ret = WaitForSingleObject(process, 10000); 555 ok(ret == WAIT_OBJECT_0, "server failed to terminate\n"); 556 557 OleUninitialize(); 558 559 unregister_server(); 560 561 if (info->child_failures) 562 { 563 trace("%d failures in child process\n", info->child_failures); 564 winetest_add_failures(info->child_failures); 565 } 566 } 567