1 /* 2 * COMPOBJ library 3 * 4 * Copyright 1995 Martin von Loewis 5 * Copyright 1998 Justin Bradford 6 * Copyright 1999 Francis Beaudet 7 * Copyright 1999 Sylvain St-Germain 8 * Copyright 2002 Marcus Meissner 9 * Copyright 2004 Mike Hearn 10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers) 11 * 12 * This library is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU Lesser General Public 14 * License as published by the Free Software Foundation; either 15 * version 2.1 of the License, or (at your option) any later version. 16 * 17 * This library is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 * Lesser General Public License for more details. 21 * 22 * You should have received a copy of the GNU Lesser General Public 23 * License along with this library; if not, write to the Free Software 24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 25 * 26 * Note 27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED 28 * Therefore do not test against COINIT_MULTITHREADED 29 * 30 * TODO list: (items bunched together depend on each other) 31 * 32 * - Implement the service control manager (in rpcss) to keep track 33 * of registered class objects: ISCM::ServerRegisterClsid et al 34 * - Implement the OXID resolver so we don't need magic endpoint names for 35 * clients and servers to meet up 36 * 37 */ 38 39 #include "precomp.h" 40 41 #include <ctxtcall.h> 42 #include <dde.h> 43 44 WINE_DEFAULT_DEBUG_CHANNEL(ole); 45 46 #undef ARRAYSIZE 47 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0])) 48 49 /**************************************************************************** 50 * This section defines variables internal to the COM module. 51 */ 52 53 static APARTMENT *MTA; /* protected by csApartment */ 54 static APARTMENT *MainApartment; /* the first STA apartment */ 55 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */ 56 57 static CRITICAL_SECTION csApartment; 58 static CRITICAL_SECTION_DEBUG critsect_debug = 59 { 60 0, 0, &csApartment, 61 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 62 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") } 63 }; 64 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 }; 65 66 enum comclass_threadingmodel 67 { 68 ThreadingModel_Apartment = 1, 69 ThreadingModel_Free = 2, 70 ThreadingModel_No = 3, 71 ThreadingModel_Both = 4, 72 ThreadingModel_Neutral = 5 73 }; 74 75 enum comclass_miscfields 76 { 77 MiscStatus = 1, 78 MiscStatusIcon = 2, 79 MiscStatusContent = 4, 80 MiscStatusThumbnail = 8, 81 MiscStatusDocPrint = 16 82 }; 83 84 struct comclassredirect_data 85 { 86 ULONG size; 87 BYTE res; 88 BYTE miscmask; 89 BYTE res1[2]; 90 DWORD model; 91 GUID clsid; 92 GUID alias; 93 GUID clsid2; 94 GUID tlbid; 95 ULONG name_len; 96 ULONG name_offset; 97 ULONG progid_len; 98 ULONG progid_offset; 99 ULONG clrdata_len; 100 ULONG clrdata_offset; 101 DWORD miscstatus; 102 DWORD miscstatuscontent; 103 DWORD miscstatusthumbnail; 104 DWORD miscstatusicon; 105 DWORD miscstatusdocprint; 106 }; 107 108 struct ifacepsredirect_data 109 { 110 ULONG size; 111 DWORD mask; 112 GUID iid; 113 ULONG nummethods; 114 GUID tlbid; 115 GUID base; 116 ULONG name_len; 117 ULONG name_offset; 118 }; 119 120 struct progidredirect_data 121 { 122 ULONG size; 123 DWORD reserved; 124 ULONG clsid_offset; 125 }; 126 127 struct class_reg_data 128 { 129 union 130 { 131 struct 132 { 133 struct comclassredirect_data *data; 134 void *section; 135 HANDLE hactctx; 136 } actctx; 137 HKEY hkey; 138 } u; 139 BOOL hkey; 140 }; 141 142 struct registered_psclsid 143 { 144 struct list entry; 145 IID iid; 146 CLSID clsid; 147 }; 148 149 static struct list registered_psclsid_list = LIST_INIT(registered_psclsid_list); 150 151 static CRITICAL_SECTION cs_registered_psclsid_list; 152 static CRITICAL_SECTION_DEBUG psclsid_cs_debug = 153 { 154 0, 0, &cs_registered_psclsid_list, 155 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList }, 156 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") } 157 }; 158 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 }; 159 160 /* 161 * This is a marshallable object exposing registered local servers. 162 * IServiceProvider is used only because it happens meet requirements 163 * and already has proxy/stub code. If more functionality is needed, 164 * a custom interface may be used instead. 165 */ 166 struct LocalServer 167 { 168 IServiceProvider IServiceProvider_iface; 169 LONG ref; 170 APARTMENT *apt; 171 IStream *marshal_stream; 172 }; 173 174 /* 175 * This lock count counts the number of times CoInitialize is called. It is 176 * decreased every time CoUninitialize is called. When it hits 0, the COM 177 * libraries are freed 178 */ 179 static LONG s_COMLockCount = 0; 180 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */ 181 static LONG s_COMServerProcessReferences = 0; 182 183 /* 184 * This linked list contains the list of registered class objects. These 185 * are mostly used to register the factories for out-of-proc servers of OLE 186 * objects. 187 * 188 * TODO: Make this data structure aware of inter-process communication. This 189 * means that parts of this will be exported to rpcss. 190 */ 191 typedef struct tagRegisteredClass 192 { 193 struct list entry; 194 CLSID classIdentifier; 195 OXID apartment_id; 196 LPUNKNOWN classObject; 197 DWORD runContext; 198 DWORD connectFlags; 199 DWORD dwCookie; 200 void *RpcRegistration; 201 } RegisteredClass; 202 203 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList); 204 205 static CRITICAL_SECTION csRegisteredClassList; 206 static CRITICAL_SECTION_DEBUG class_cs_debug = 207 { 208 0, 0, &csRegisteredClassList, 209 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList }, 210 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") } 211 }; 212 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 }; 213 214 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect) 215 { 216 switch (aspect) 217 { 218 case DVASPECT_CONTENT: 219 return MiscStatusContent; 220 case DVASPECT_THUMBNAIL: 221 return MiscStatusThumbnail; 222 case DVASPECT_ICON: 223 return MiscStatusIcon; 224 case DVASPECT_DOCPRINT: 225 return MiscStatusDocPrint; 226 default: 227 return MiscStatus; 228 }; 229 } 230 231 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status) 232 { 233 ACTCTX_SECTION_KEYED_DATA data; 234 235 data.cbSize = sizeof(data); 236 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, 237 clsid, &data)) 238 { 239 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData; 240 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect); 241 242 if (!(comclass->miscmask & misc)) 243 { 244 if (!(comclass->miscmask & MiscStatus)) 245 { 246 *status = 0; 247 return TRUE; 248 } 249 misc = MiscStatus; 250 } 251 252 switch (misc) 253 { 254 case MiscStatus: 255 *status = comclass->miscstatus; 256 break; 257 case MiscStatusIcon: 258 *status = comclass->miscstatusicon; 259 break; 260 case MiscStatusContent: 261 *status = comclass->miscstatuscontent; 262 break; 263 case MiscStatusThumbnail: 264 *status = comclass->miscstatusthumbnail; 265 break; 266 case MiscStatusDocPrint: 267 *status = comclass->miscstatusdocprint; 268 break; 269 default: 270 ; 271 }; 272 273 return TRUE; 274 } 275 else 276 return FALSE; 277 } 278 279 /* wrapper for NtCreateKey that creates the key recursively if necessary */ 280 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) 281 { 282 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL ); 283 284 if (status == STATUS_OBJECT_NAME_NOT_FOUND) 285 { 286 HANDLE subkey, root = attr->RootDirectory; 287 WCHAR *buffer = attr->ObjectName->Buffer; 288 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); 289 UNICODE_STRING str; 290 291 while (i < len && buffer[i] != '\\') i++; 292 if (i == len) return status; 293 294 attrs = attr->Attributes; 295 attr->ObjectName = &str; 296 297 while (i < len) 298 { 299 str.Buffer = buffer + pos; 300 str.Length = (i - pos) * sizeof(WCHAR); 301 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL ); 302 if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); 303 if (status) return status; 304 attr->RootDirectory = subkey; 305 while (i < len && buffer[i] == '\\') i++; 306 pos = i; 307 while (i < len && buffer[i] != '\\') i++; 308 } 309 str.Buffer = buffer + pos; 310 str.Length = (i - pos) * sizeof(WCHAR); 311 attr->Attributes = attrs; 312 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL ); 313 if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); 314 } 315 return status; 316 } 317 318 #ifdef __REACTOS__ 319 static const WCHAR classes_rootW[] = L"\\REGISTRY\\Machine\\Software\\Classes"; 320 #else 321 static const WCHAR classes_rootW[] = 322 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e', 323 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0}; 324 #endif 325 326 static HKEY classes_root_hkey; 327 328 /* create the special HKEY_CLASSES_ROOT key */ 329 static HKEY create_classes_root_hkey(DWORD access) 330 { 331 HKEY hkey, ret = 0; 332 OBJECT_ATTRIBUTES attr; 333 UNICODE_STRING name; 334 335 attr.Length = sizeof(attr); 336 attr.RootDirectory = 0; 337 attr.ObjectName = &name; 338 attr.Attributes = 0; 339 attr.SecurityDescriptor = NULL; 340 attr.SecurityQualityOfService = NULL; 341 RtlInitUnicodeString( &name, classes_rootW ); 342 if (create_key( &hkey, access, &attr )) return 0; 343 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey ); 344 345 if (!(access & KEY_WOW64_64KEY)) 346 { 347 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 ))) 348 ret = hkey; 349 else 350 NtClose( hkey ); /* somebody beat us to it */ 351 } 352 else 353 ret = hkey; 354 return ret; 355 } 356 357 /* map the hkey from special root to normal key if necessary */ 358 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access ) 359 { 360 HKEY ret = hkey; 361 const BOOL is_win64 = sizeof(void*) > sizeof(int); 362 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); 363 364 if (hkey == HKEY_CLASSES_ROOT && 365 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey))) 366 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY)); 367 if (force_wow32 && ret && ret == classes_root_hkey) 368 { 369 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0}; 370 access &= ~KEY_WOW64_32KEY; 371 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey)) 372 return 0; 373 ret = hkey; 374 } 375 376 return ret; 377 } 378 379 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey ) 380 { 381 OBJECT_ATTRIBUTES attr; 382 UNICODE_STRING nameW; 383 384 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; 385 386 attr.Length = sizeof(attr); 387 attr.RootDirectory = hkey; 388 attr.ObjectName = &nameW; 389 attr.Attributes = 0; 390 attr.SecurityDescriptor = NULL; 391 attr.SecurityQualityOfService = NULL; 392 RtlInitUnicodeString( &nameW, name ); 393 394 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) ); 395 } 396 397 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey ) 398 { 399 OBJECT_ATTRIBUTES attr; 400 UNICODE_STRING nameW; 401 402 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; 403 404 attr.Length = sizeof(attr); 405 attr.RootDirectory = hkey; 406 attr.ObjectName = &nameW; 407 attr.Attributes = 0; 408 attr.SecurityDescriptor = NULL; 409 attr.SecurityQualityOfService = NULL; 410 RtlInitUnicodeString( &nameW, name ); 411 412 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) ); 413 } 414 415 /***************************************************************************** 416 * This section contains OpenDllList definitions 417 * 418 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or 419 * other functions that do LoadLibrary _without_ giving back a HMODULE. 420 * Without this list these handles would never be freed. 421 * 422 * FIXME: a DLL that says OK when asked for unloading is unloaded in the 423 * next unload-call but not before 600 sec. 424 */ 425 426 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); 427 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void); 428 429 typedef struct tagOpenDll 430 { 431 LONG refs; 432 LPWSTR library_name; 433 HANDLE library; 434 DllGetClassObjectFunc DllGetClassObject; 435 DllCanUnloadNowFunc DllCanUnloadNow; 436 struct list entry; 437 } OpenDll; 438 439 static struct list openDllList = LIST_INIT(openDllList); 440 441 static CRITICAL_SECTION csOpenDllList; 442 static CRITICAL_SECTION_DEBUG dll_cs_debug = 443 { 444 0, 0, &csOpenDllList, 445 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList }, 446 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") } 447 }; 448 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 }; 449 450 struct apartment_loaded_dll 451 { 452 struct list entry; 453 OpenDll *dll; 454 DWORD unload_time; 455 BOOL multi_threaded; 456 }; 457 458 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',0}; 459 460 /***************************************************************************** 461 * This section contains OpenDllList implementation 462 */ 463 464 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name) 465 { 466 OpenDll *ptr; 467 OpenDll *ret = NULL; 468 EnterCriticalSection(&csOpenDllList); 469 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry) 470 { 471 if (!strcmpiW(library_name, ptr->library_name) && 472 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */) 473 { 474 ret = ptr; 475 break; 476 } 477 } 478 LeaveCriticalSection(&csOpenDllList); 479 return ret; 480 } 481 482 /* caller must ensure that library_name is not already in the open dll list */ 483 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret) 484 { 485 OpenDll *entry; 486 int len; 487 HRESULT hr = S_OK; 488 HANDLE hLibrary; 489 DllCanUnloadNowFunc DllCanUnloadNow; 490 DllGetClassObjectFunc DllGetClassObject; 491 492 TRACE("%s\n", debugstr_w(library_name)); 493 494 *ret = COMPOBJ_DllList_Get(library_name); 495 if (*ret) return S_OK; 496 497 /* do this outside the csOpenDllList to avoid creating a lock dependency on 498 * the loader lock */ 499 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH); 500 if (!hLibrary) 501 { 502 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name)); 503 /* failure: DLL could not be loaded */ 504 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */ 505 } 506 507 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow"); 508 /* Note: failing to find DllCanUnloadNow is not a failure */ 509 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject"); 510 if (!DllGetClassObject) 511 { 512 /* failure: the dll did not export DllGetClassObject */ 513 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name)); 514 FreeLibrary(hLibrary); 515 return CO_E_DLLNOTFOUND; 516 } 517 518 EnterCriticalSection( &csOpenDllList ); 519 520 *ret = COMPOBJ_DllList_Get(library_name); 521 if (*ret) 522 { 523 /* another caller to this function already added the dll while we 524 * weren't in the critical section */ 525 FreeLibrary(hLibrary); 526 } 527 else 528 { 529 len = strlenW(library_name); 530 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); 531 if (entry) 532 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); 533 if (entry && entry->library_name) 534 { 535 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR)); 536 entry->library = hLibrary; 537 entry->refs = 1; 538 entry->DllCanUnloadNow = DllCanUnloadNow; 539 entry->DllGetClassObject = DllGetClassObject; 540 list_add_tail(&openDllList, &entry->entry); 541 *ret = entry; 542 } 543 else 544 { 545 HeapFree(GetProcessHeap(), 0, entry); 546 hr = E_OUTOFMEMORY; 547 FreeLibrary(hLibrary); 548 } 549 } 550 551 LeaveCriticalSection( &csOpenDllList ); 552 553 return hr; 554 } 555 556 /* pass FALSE for free_entry to release a reference without destroying the 557 * entry if it reaches zero or TRUE otherwise */ 558 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry) 559 { 560 if (!InterlockedDecrement(&entry->refs) && free_entry) 561 { 562 EnterCriticalSection(&csOpenDllList); 563 list_remove(&entry->entry); 564 LeaveCriticalSection(&csOpenDllList); 565 566 TRACE("freeing %p\n", entry->library); 567 FreeLibrary(entry->library); 568 569 HeapFree(GetProcessHeap(), 0, entry->library_name); 570 HeapFree(GetProcessHeap(), 0, entry); 571 } 572 } 573 574 /* frees memory associated with active dll list */ 575 static void COMPOBJ_DllList_Free(void) 576 { 577 OpenDll *entry, *cursor2; 578 EnterCriticalSection(&csOpenDllList); 579 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry) 580 { 581 list_remove(&entry->entry); 582 583 HeapFree(GetProcessHeap(), 0, entry->library_name); 584 HeapFree(GetProcessHeap(), 0, entry); 585 } 586 LeaveCriticalSection(&csOpenDllList); 587 DeleteCriticalSection(&csOpenDllList); 588 } 589 590 /****************************************************************************** 591 * Manage apartments. 592 */ 593 594 static DWORD apartment_addref(struct apartment *apt) 595 { 596 DWORD refs = InterlockedIncrement(&apt->refs); 597 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1); 598 return refs; 599 } 600 601 /* allocates memory and fills in the necessary fields for a new apartment 602 * object. must be called inside apartment cs */ 603 static APARTMENT *apartment_construct(DWORD model) 604 { 605 APARTMENT *apt; 606 607 TRACE("creating new apartment, model=%d\n", model); 608 609 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt)); 610 apt->tid = GetCurrentThreadId(); 611 612 list_init(&apt->proxies); 613 list_init(&apt->stubmgrs); 614 list_init(&apt->loaded_dlls); 615 apt->ipidc = 0; 616 apt->refs = 1; 617 apt->remunk_exported = FALSE; 618 apt->oidc = 1; 619 InitializeCriticalSection(&apt->cs); 620 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment"); 621 622 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED); 623 624 if (apt->multi_threaded) 625 { 626 /* FIXME: should be randomly generated by in an RPC call to rpcss */ 627 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe; 628 } 629 else 630 { 631 /* FIXME: should be randomly generated by in an RPC call to rpcss */ 632 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId(); 633 } 634 635 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid)); 636 637 list_add_head(&apts, &apt->entry); 638 639 return apt; 640 } 641 642 /* gets and existing apartment if one exists or otherwise creates an apartment 643 * structure which stores OLE apartment-local information and stores a pointer 644 * to it in the thread-local storage */ 645 static APARTMENT *apartment_get_or_create(DWORD model) 646 { 647 APARTMENT *apt = COM_CurrentApt(); 648 649 if (!apt) 650 { 651 if (model & COINIT_APARTMENTTHREADED) 652 { 653 EnterCriticalSection(&csApartment); 654 655 apt = apartment_construct(model); 656 if (!MainApartment) 657 { 658 MainApartment = apt; 659 apt->main = TRUE; 660 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid)); 661 } 662 663 LeaveCriticalSection(&csApartment); 664 665 if (apt->main) 666 apartment_createwindowifneeded(apt); 667 } 668 else 669 { 670 EnterCriticalSection(&csApartment); 671 672 /* The multi-threaded apartment (MTA) contains zero or more threads interacting 673 * with free threaded (ie thread safe) COM objects. There is only ever one MTA 674 * in a process */ 675 if (MTA) 676 { 677 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid)); 678 apartment_addref(MTA); 679 } 680 else 681 MTA = apartment_construct(model); 682 683 apt = MTA; 684 685 LeaveCriticalSection(&csApartment); 686 } 687 COM_CurrentInfo()->apt = apt; 688 } 689 690 return apt; 691 } 692 693 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model) 694 { 695 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED)); 696 } 697 698 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass) 699 { 700 list_remove(&curClass->entry); 701 702 if (curClass->runContext & CLSCTX_LOCAL_SERVER) 703 RPC_StopLocalServer(curClass->RpcRegistration); 704 705 IUnknown_Release(curClass->classObject); 706 HeapFree(GetProcessHeap(), 0, curClass); 707 } 708 709 static void COM_RevokeAllClasses(const struct apartment *apt) 710 { 711 RegisteredClass *curClass, *cursor; 712 713 EnterCriticalSection( &csRegisteredClassList ); 714 715 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry) 716 { 717 if (curClass->apartment_id == apt->oxid) 718 COM_RevokeRegisteredClassObject(curClass); 719 } 720 721 LeaveCriticalSection( &csRegisteredClassList ); 722 } 723 724 static void revoke_registered_psclsids(void) 725 { 726 struct registered_psclsid *psclsid, *psclsid2; 727 728 EnterCriticalSection( &cs_registered_psclsid_list ); 729 730 LIST_FOR_EACH_ENTRY_SAFE(psclsid, psclsid2, ®istered_psclsid_list, struct registered_psclsid, entry) 731 { 732 list_remove(&psclsid->entry); 733 HeapFree(GetProcessHeap(), 0, psclsid); 734 } 735 736 LeaveCriticalSection( &cs_registered_psclsid_list ); 737 } 738 739 /****************************************************************************** 740 * Implementation of the manual reset event object. (CLSID_ManualResetEvent) 741 */ 742 743 typedef struct ManualResetEvent { 744 ISynchronize ISynchronize_iface; 745 ISynchronizeHandle ISynchronizeHandle_iface; 746 LONG ref; 747 HANDLE event; 748 } MREImpl; 749 750 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface) 751 { 752 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface); 753 } 754 755 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv) 756 { 757 MREImpl *This = impl_from_ISynchronize(iface); 758 759 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv); 760 761 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) { 762 *ppv = &This->ISynchronize_iface; 763 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) { 764 *ppv = &This->ISynchronizeHandle_iface; 765 }else { 766 ERR("Unknown interface %s requested.\n", debugstr_guid(riid)); 767 *ppv = NULL; 768 return E_NOINTERFACE; 769 } 770 771 IUnknown_AddRef((IUnknown*)*ppv); 772 return S_OK; 773 } 774 775 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface) 776 { 777 MREImpl *This = impl_from_ISynchronize(iface); 778 LONG ref = InterlockedIncrement(&This->ref); 779 TRACE("%p - ref %d\n", This, ref); 780 781 return ref; 782 } 783 784 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface) 785 { 786 MREImpl *This = impl_from_ISynchronize(iface); 787 LONG ref = InterlockedDecrement(&This->ref); 788 TRACE("%p - ref %d\n", This, ref); 789 790 if(!ref) 791 { 792 CloseHandle(This->event); 793 HeapFree(GetProcessHeap(), 0, This); 794 } 795 796 return ref; 797 } 798 799 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds) 800 { 801 MREImpl *This = impl_from_ISynchronize(iface); 802 UINT index; 803 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds); 804 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index); 805 } 806 807 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface) 808 { 809 MREImpl *This = impl_from_ISynchronize(iface); 810 TRACE("%p\n", This); 811 SetEvent(This->event); 812 return S_OK; 813 } 814 815 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface) 816 { 817 MREImpl *This = impl_from_ISynchronize(iface); 818 TRACE("%p\n", This); 819 ResetEvent(This->event); 820 return S_OK; 821 } 822 823 static ISynchronizeVtbl vt_ISynchronize = { 824 ISynchronize_fnQueryInterface, 825 ISynchronize_fnAddRef, 826 ISynchronize_fnRelease, 827 ISynchronize_fnWait, 828 ISynchronize_fnSignal, 829 ISynchronize_fnReset 830 }; 831 832 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface) 833 { 834 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface); 835 } 836 837 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv) 838 { 839 MREImpl *This = impl_from_ISynchronizeHandle(iface); 840 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv); 841 } 842 843 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface) 844 { 845 MREImpl *This = impl_from_ISynchronizeHandle(iface); 846 return ISynchronize_AddRef(&This->ISynchronize_iface); 847 } 848 849 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface) 850 { 851 MREImpl *This = impl_from_ISynchronizeHandle(iface); 852 return ISynchronize_Release(&This->ISynchronize_iface); 853 } 854 855 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph) 856 { 857 MREImpl *This = impl_from_ISynchronizeHandle(iface); 858 859 *ph = This->event; 860 return S_OK; 861 } 862 863 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = { 864 SynchronizeHandle_QueryInterface, 865 SynchronizeHandle_AddRef, 866 SynchronizeHandle_Release, 867 SynchronizeHandle_GetHandle 868 }; 869 870 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv) 871 { 872 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl)); 873 HRESULT hr; 874 875 if(punkouter) 876 FIXME("Aggregation not implemented.\n"); 877 878 This->ref = 1; 879 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize; 880 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl; 881 This->event = CreateEventW(NULL, TRUE, FALSE, NULL); 882 883 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv); 884 ISynchronize_Release(&This->ISynchronize_iface); 885 return hr; 886 } 887 888 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface) 889 { 890 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface); 891 } 892 893 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) 894 { 895 LocalServer *This = impl_from_IServiceProvider(iface); 896 897 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 898 899 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) { 900 *ppv = &This->IServiceProvider_iface; 901 }else { 902 *ppv = NULL; 903 return E_NOINTERFACE; 904 } 905 906 IUnknown_AddRef((IUnknown*)*ppv); 907 return S_OK; 908 } 909 910 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface) 911 { 912 LocalServer *This = impl_from_IServiceProvider(iface); 913 LONG ref = InterlockedIncrement(&This->ref); 914 915 TRACE("(%p) ref=%d\n", This, ref); 916 917 return ref; 918 } 919 920 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface) 921 { 922 LocalServer *This = impl_from_IServiceProvider(iface); 923 LONG ref = InterlockedDecrement(&This->ref); 924 925 TRACE("(%p) ref=%d\n", This, ref); 926 927 if(!ref) { 928 assert(!This->apt); 929 HeapFree(GetProcessHeap(), 0, This); 930 } 931 932 return ref; 933 } 934 935 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv) 936 { 937 LocalServer *This = impl_from_IServiceProvider(iface); 938 APARTMENT *apt = COM_CurrentApt(); 939 RegisteredClass *iter; 940 HRESULT hres = E_FAIL; 941 942 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv); 943 944 if(!This->apt) 945 return E_UNEXPECTED; 946 947 EnterCriticalSection(&csRegisteredClassList); 948 949 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) { 950 if(iter->apartment_id == apt->oxid 951 && (iter->runContext & CLSCTX_LOCAL_SERVER) 952 && IsEqualGUID(&iter->classIdentifier, guid)) { 953 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv); 954 break; 955 } 956 } 957 958 LeaveCriticalSection( &csRegisteredClassList ); 959 960 return hres; 961 } 962 963 static const IServiceProviderVtbl LocalServerVtbl = { 964 LocalServer_QueryInterface, 965 LocalServer_AddRef, 966 LocalServer_Release, 967 LocalServer_QueryService 968 }; 969 970 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret) 971 { 972 HRESULT hres = S_OK; 973 974 EnterCriticalSection(&apt->cs); 975 976 if(!apt->local_server) { 977 LocalServer *obj; 978 979 obj = heap_alloc(sizeof(*obj)); 980 if(obj) { 981 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl; 982 obj->ref = 1; 983 obj->apt = apt; 984 985 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream); 986 if(SUCCEEDED(hres)) { 987 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface, 988 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); 989 if(FAILED(hres)) 990 IStream_Release(obj->marshal_stream); 991 } 992 993 if(SUCCEEDED(hres)) 994 apt->local_server = obj; 995 else 996 heap_free(obj); 997 }else { 998 hres = E_OUTOFMEMORY; 999 } 1000 } 1001 1002 if(SUCCEEDED(hres)) 1003 hres = IStream_Clone(apt->local_server->marshal_stream, ret); 1004 1005 LeaveCriticalSection(&apt->cs); 1006 1007 if(FAILED(hres)) 1008 ERR("Failed: %08x\n", hres); 1009 return hres; 1010 } 1011 1012 /*********************************************************************** 1013 * CoRevokeClassObject [OLE32.@] 1014 * 1015 * Removes a class object from the class registry. 1016 * 1017 * PARAMS 1018 * dwRegister [I] Cookie returned from CoRegisterClassObject(). 1019 * 1020 * RETURNS 1021 * Success: S_OK. 1022 * Failure: HRESULT code. 1023 * 1024 * NOTES 1025 * Must be called from the same apartment that called CoRegisterClassObject(), 1026 * otherwise it will fail with RPC_E_WRONG_THREAD. 1027 * 1028 * SEE ALSO 1029 * CoRegisterClassObject 1030 */ 1031 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject( 1032 DWORD dwRegister) 1033 { 1034 HRESULT hr = E_INVALIDARG; 1035 RegisteredClass *curClass; 1036 APARTMENT *apt; 1037 1038 TRACE("(%08x)\n",dwRegister); 1039 1040 apt = COM_CurrentApt(); 1041 if (!apt) 1042 { 1043 ERR("COM was not initialized\n"); 1044 return CO_E_NOTINITIALIZED; 1045 } 1046 1047 EnterCriticalSection( &csRegisteredClassList ); 1048 1049 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) 1050 { 1051 /* 1052 * Check if we have a match on the cookie. 1053 */ 1054 if (curClass->dwCookie == dwRegister) 1055 { 1056 if (curClass->apartment_id == apt->oxid) 1057 { 1058 COM_RevokeRegisteredClassObject(curClass); 1059 hr = S_OK; 1060 } 1061 else 1062 { 1063 ERR("called from wrong apartment, should be called from %s\n", 1064 wine_dbgstr_longlong(curClass->apartment_id)); 1065 hr = RPC_E_WRONG_THREAD; 1066 } 1067 break; 1068 } 1069 } 1070 1071 LeaveCriticalSection( &csRegisteredClassList ); 1072 1073 return hr; 1074 } 1075 1076 /* frees unused libraries loaded by apartment_getclassobject by calling the 1077 * DLL's DllCanUnloadNow entry point */ 1078 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) 1079 { 1080 struct apartment_loaded_dll *entry, *next; 1081 EnterCriticalSection(&apt->cs); 1082 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry) 1083 { 1084 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK)) 1085 { 1086 DWORD real_delay = delay; 1087 1088 if (real_delay == INFINITE) 1089 { 1090 /* DLLs that return multi-threaded objects aren't unloaded 1091 * straight away to cope for programs that have races between 1092 * last object destruction and threads in the DLLs that haven't 1093 * finished, despite DllCanUnloadNow returning S_OK */ 1094 if (entry->multi_threaded) 1095 real_delay = 10 * 60 * 1000; /* 10 minutes */ 1096 else 1097 real_delay = 0; 1098 } 1099 1100 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0))) 1101 { 1102 list_remove(&entry->entry); 1103 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE); 1104 HeapFree(GetProcessHeap(), 0, entry); 1105 } 1106 else 1107 { 1108 entry->unload_time = GetTickCount() + real_delay; 1109 if (!entry->unload_time) entry->unload_time = 1; 1110 } 1111 } 1112 else if (entry->unload_time) 1113 entry->unload_time = 0; 1114 } 1115 LeaveCriticalSection(&apt->cs); 1116 } 1117 1118 DWORD apartment_release(struct apartment *apt) 1119 { 1120 DWORD ret; 1121 1122 EnterCriticalSection(&csApartment); 1123 1124 ret = InterlockedDecrement(&apt->refs); 1125 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret); 1126 /* destruction stuff that needs to happen under csApartment CS */ 1127 if (ret == 0) 1128 { 1129 if (apt == MTA) MTA = NULL; 1130 else if (apt == MainApartment) MainApartment = NULL; 1131 list_remove(&apt->entry); 1132 } 1133 1134 LeaveCriticalSection(&csApartment); 1135 1136 if (ret == 0) 1137 { 1138 struct list *cursor, *cursor2; 1139 1140 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid)); 1141 1142 if(apt->local_server) { 1143 LocalServer *local_server = apt->local_server; 1144 LARGE_INTEGER zero; 1145 1146 memset(&zero, 0, sizeof(zero)); 1147 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL); 1148 CoReleaseMarshalData(local_server->marshal_stream); 1149 IStream_Release(local_server->marshal_stream); 1150 local_server->marshal_stream = NULL; 1151 1152 apt->local_server = NULL; 1153 local_server->apt = NULL; 1154 IServiceProvider_Release(&local_server->IServiceProvider_iface); 1155 } 1156 1157 /* Release the references to the registered class objects */ 1158 COM_RevokeAllClasses(apt); 1159 1160 /* no locking is needed for this apartment, because no other thread 1161 * can access it at this point */ 1162 1163 apartment_disconnectproxies(apt); 1164 1165 if (apt->win) DestroyWindow(apt->win); 1166 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0); 1167 1168 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs) 1169 { 1170 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry); 1171 /* release the implicit reference given by the fact that the 1172 * stub has external references (it must do since it is in the 1173 * stub manager list in the apartment and all non-apartment users 1174 * must have a ref on the apartment and so it cannot be destroyed). 1175 */ 1176 stub_manager_int_release(stubmgr); 1177 } 1178 1179 /* if this assert fires, then another thread took a reference to a 1180 * stub manager without taking a reference to the containing 1181 * apartment, which it must do. */ 1182 assert(list_empty(&apt->stubmgrs)); 1183 1184 if (apt->filter) IMessageFilter_Release(apt->filter); 1185 1186 /* free as many unused libraries as possible... */ 1187 apartment_freeunusedlibraries(apt, 0); 1188 1189 /* ... and free the memory for the apartment loaded dll entry and 1190 * release the dll list reference without freeing the library for the 1191 * rest */ 1192 while ((cursor = list_head(&apt->loaded_dlls))) 1193 { 1194 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry); 1195 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE); 1196 list_remove(cursor); 1197 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); 1198 } 1199 1200 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs); 1201 DeleteCriticalSection(&apt->cs); 1202 1203 HeapFree(GetProcessHeap(), 0, apt); 1204 } 1205 1206 return ret; 1207 } 1208 1209 /* The given OXID must be local to this process: 1210 * 1211 * The ref parameter is here mostly to ensure people remember that 1212 * they get one, you should normally take a ref for thread safety. 1213 */ 1214 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref) 1215 { 1216 APARTMENT *result = NULL; 1217 struct list *cursor; 1218 1219 EnterCriticalSection(&csApartment); 1220 LIST_FOR_EACH( cursor, &apts ) 1221 { 1222 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); 1223 if (apt->oxid == oxid) 1224 { 1225 result = apt; 1226 if (ref) apartment_addref(result); 1227 break; 1228 } 1229 } 1230 LeaveCriticalSection(&csApartment); 1231 1232 return result; 1233 } 1234 1235 /* gets the apartment which has a given creator thread ID. The caller must 1236 * release the reference from the apartment as soon as the apartment pointer 1237 * is no longer required. */ 1238 APARTMENT *apartment_findfromtid(DWORD tid) 1239 { 1240 APARTMENT *result = NULL; 1241 struct list *cursor; 1242 1243 EnterCriticalSection(&csApartment); 1244 LIST_FOR_EACH( cursor, &apts ) 1245 { 1246 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); 1247 if (apt->tid == tid) 1248 { 1249 result = apt; 1250 apartment_addref(result); 1251 break; 1252 } 1253 } 1254 LeaveCriticalSection(&csApartment); 1255 1256 return result; 1257 } 1258 1259 /* gets the main apartment if it exists. The caller must 1260 * release the reference from the apartment as soon as the apartment pointer 1261 * is no longer required. */ 1262 static APARTMENT *apartment_findmain(void) 1263 { 1264 APARTMENT *result; 1265 1266 EnterCriticalSection(&csApartment); 1267 1268 result = MainApartment; 1269 if (result) apartment_addref(result); 1270 1271 LeaveCriticalSection(&csApartment); 1272 1273 return result; 1274 } 1275 1276 /* gets the multi-threaded apartment if it exists. The caller must 1277 * release the reference from the apartment as soon as the apartment pointer 1278 * is no longer required. */ 1279 static APARTMENT *apartment_find_multi_threaded(void) 1280 { 1281 APARTMENT *result = NULL; 1282 struct list *cursor; 1283 1284 EnterCriticalSection(&csApartment); 1285 1286 LIST_FOR_EACH( cursor, &apts ) 1287 { 1288 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); 1289 if (apt->multi_threaded) 1290 { 1291 result = apt; 1292 apartment_addref(result); 1293 break; 1294 } 1295 } 1296 1297 LeaveCriticalSection(&csApartment); 1298 return result; 1299 } 1300 1301 /* gets the specified class object by loading the appropriate DLL, if 1302 * necessary and calls the DllGetClassObject function for the DLL */ 1303 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, 1304 BOOL apartment_threaded, 1305 REFCLSID rclsid, REFIID riid, void **ppv) 1306 { 1307 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; 1308 HRESULT hr = S_OK; 1309 BOOL found = FALSE; 1310 struct apartment_loaded_dll *apartment_loaded_dll; 1311 1312 if (!strcmpiW(dllpath, wszOle32)) 1313 { 1314 /* we don't need to control the lifetime of this dll, so use the local 1315 * implementation of DllGetClassObject directly */ 1316 TRACE("calling ole32!DllGetClassObject\n"); 1317 hr = DllGetClassObject(rclsid, riid, ppv); 1318 1319 if (hr != S_OK) 1320 ERR("DllGetClassObject returned error 0x%08x\n", hr); 1321 1322 return hr; 1323 } 1324 1325 EnterCriticalSection(&apt->cs); 1326 1327 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry) 1328 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name)) 1329 { 1330 TRACE("found %s already loaded\n", debugstr_w(dllpath)); 1331 found = TRUE; 1332 break; 1333 } 1334 1335 if (!found) 1336 { 1337 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll)); 1338 if (!apartment_loaded_dll) 1339 hr = E_OUTOFMEMORY; 1340 if (SUCCEEDED(hr)) 1341 { 1342 apartment_loaded_dll->unload_time = 0; 1343 apartment_loaded_dll->multi_threaded = FALSE; 1344 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll ); 1345 if (FAILED(hr)) 1346 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); 1347 } 1348 if (SUCCEEDED(hr)) 1349 { 1350 TRACE("added new loaded dll %s\n", debugstr_w(dllpath)); 1351 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry); 1352 } 1353 } 1354 1355 LeaveCriticalSection(&apt->cs); 1356 1357 if (SUCCEEDED(hr)) 1358 { 1359 /* one component being multi-threaded overrides any number of 1360 * apartment-threaded components */ 1361 if (!apartment_threaded) 1362 apartment_loaded_dll->multi_threaded = TRUE; 1363 1364 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject); 1365 /* OK: get the ClassObject */ 1366 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv); 1367 1368 if (hr != S_OK) 1369 ERR("DllGetClassObject returned error 0x%08x\n", hr); 1370 } 1371 1372 return hr; 1373 } 1374 1375 /*********************************************************************** 1376 * COM_RegReadPath [internal] 1377 * 1378 * Reads a registry value and expands it when necessary 1379 */ 1380 static DWORD COM_RegReadPath(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen) 1381 { 1382 DWORD ret; 1383 1384 if (regdata->hkey) 1385 { 1386 DWORD keytype; 1387 WCHAR src[MAX_PATH]; 1388 DWORD dwLength = dstlen * sizeof(WCHAR); 1389 1390 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) { 1391 if (keytype == REG_EXPAND_SZ) { 1392 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA; 1393 } else { 1394 const WCHAR *quote_start; 1395 quote_start = strchrW(src, '\"'); 1396 if (quote_start) { 1397 const WCHAR *quote_end = strchrW(quote_start + 1, '\"'); 1398 if (quote_end) { 1399 memmove(src, quote_start + 1, 1400 (quote_end - quote_start - 1) * sizeof(WCHAR)); 1401 src[quote_end - quote_start - 1] = '\0'; 1402 } 1403 } 1404 lstrcpynW(dst, src, dstlen); 1405 } 1406 } 1407 return ret; 1408 } 1409 else 1410 { 1411 ULONG_PTR cookie; 1412 WCHAR *nameW; 1413 1414 *dst = 0; 1415 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset); 1416 ActivateActCtx(regdata->u.actctx.hactctx, &cookie); 1417 ret = SearchPathW(NULL, nameW, NULL, dstlen, dst, NULL); 1418 DeactivateActCtx(0, cookie); 1419 return !*dst; 1420 } 1421 } 1422 1423 struct host_object_params 1424 { 1425 struct class_reg_data regdata; 1426 CLSID clsid; /* clsid of object to marshal */ 1427 IID iid; /* interface to marshal */ 1428 HANDLE event; /* event signalling when ready for multi-threaded case */ 1429 HRESULT hr; /* result for multi-threaded case */ 1430 IStream *stream; /* stream that the object will be marshaled into */ 1431 BOOL apartment_threaded; /* is the component purely apartment-threaded? */ 1432 }; 1433 1434 static HRESULT apartment_hostobject(struct apartment *apt, 1435 const struct host_object_params *params) 1436 { 1437 IUnknown *object; 1438 HRESULT hr; 1439 static const LARGE_INTEGER llZero; 1440 WCHAR dllpath[MAX_PATH+1]; 1441 1442 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid)); 1443 1444 if (COM_RegReadPath(¶ms->regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS) 1445 { 1446 /* failure: CLSID is not found in registry */ 1447 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid)); 1448 return REGDB_E_CLASSNOTREG; 1449 } 1450 1451 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded, 1452 ¶ms->clsid, ¶ms->iid, (void **)&object); 1453 if (FAILED(hr)) 1454 return hr; 1455 1456 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); 1457 if (FAILED(hr)) 1458 IUnknown_Release(object); 1459 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL); 1460 1461 return hr; 1462 } 1463 1464 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 1465 { 1466 switch (msg) 1467 { 1468 case DM_EXECUTERPC: 1469 RPC_ExecuteCall((struct dispatch_params *)lParam); 1470 return 0; 1471 case DM_HOSTOBJECT: 1472 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam); 1473 default: 1474 return DefWindowProcW(hWnd, msg, wParam, lParam); 1475 } 1476 } 1477 1478 struct host_thread_params 1479 { 1480 COINIT threading_model; 1481 HANDLE ready_event; 1482 HWND apartment_hwnd; 1483 }; 1484 1485 /* thread for hosting an object to allow an object to appear to be created in 1486 * an apartment with an incompatible threading model */ 1487 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p) 1488 { 1489 struct host_thread_params *params = p; 1490 MSG msg; 1491 HRESULT hr; 1492 struct apartment *apt; 1493 1494 TRACE("\n"); 1495 1496 hr = CoInitializeEx(NULL, params->threading_model); 1497 if (FAILED(hr)) return hr; 1498 1499 apt = COM_CurrentApt(); 1500 if (params->threading_model == COINIT_APARTMENTTHREADED) 1501 { 1502 apartment_createwindowifneeded(apt); 1503 params->apartment_hwnd = apartment_getwindow(apt); 1504 } 1505 else 1506 params->apartment_hwnd = NULL; 1507 1508 /* force the message queue to be created before signaling parent thread */ 1509 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); 1510 1511 SetEvent(params->ready_event); 1512 params = NULL; /* can't touch params after here as it may be invalid */ 1513 1514 while (GetMessageW(&msg, NULL, 0, 0)) 1515 { 1516 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT)) 1517 { 1518 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam; 1519 obj_params->hr = apartment_hostobject(apt, obj_params); 1520 SetEvent(obj_params->event); 1521 } 1522 else 1523 { 1524 TranslateMessage(&msg); 1525 DispatchMessageW(&msg); 1526 } 1527 } 1528 1529 TRACE("exiting\n"); 1530 1531 CoUninitialize(); 1532 1533 return S_OK; 1534 } 1535 1536 /* finds or creates a host apartment, creates the object inside it and returns 1537 * a proxy to it so that the object can be used in the apartment of the 1538 * caller of this function */ 1539 static HRESULT apartment_hostobject_in_hostapt( 1540 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment, 1541 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv) 1542 { 1543 struct host_object_params params; 1544 HWND apartment_hwnd = NULL; 1545 DWORD apartment_tid = 0; 1546 HRESULT hr; 1547 1548 if (!multi_threaded && main_apartment) 1549 { 1550 APARTMENT *host_apt = apartment_findmain(); 1551 if (host_apt) 1552 { 1553 apartment_hwnd = apartment_getwindow(host_apt); 1554 apartment_release(host_apt); 1555 } 1556 } 1557 1558 if (!apartment_hwnd) 1559 { 1560 EnterCriticalSection(&apt->cs); 1561 1562 if (!apt->host_apt_tid) 1563 { 1564 struct host_thread_params thread_params; 1565 HANDLE handles[2]; 1566 DWORD wait_value; 1567 1568 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED; 1569 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1570 thread_params.apartment_hwnd = NULL; 1571 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid); 1572 if (!handles[1]) 1573 { 1574 CloseHandle(handles[0]); 1575 LeaveCriticalSection(&apt->cs); 1576 return E_OUTOFMEMORY; 1577 } 1578 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE); 1579 CloseHandle(handles[0]); 1580 CloseHandle(handles[1]); 1581 if (wait_value == WAIT_OBJECT_0) 1582 apt->host_apt_hwnd = thread_params.apartment_hwnd; 1583 else 1584 { 1585 LeaveCriticalSection(&apt->cs); 1586 return E_OUTOFMEMORY; 1587 } 1588 } 1589 1590 if (multi_threaded || !main_apartment) 1591 { 1592 apartment_hwnd = apt->host_apt_hwnd; 1593 apartment_tid = apt->host_apt_tid; 1594 } 1595 1596 LeaveCriticalSection(&apt->cs); 1597 } 1598 1599 /* another thread may have become the main apartment in the time it took 1600 * us to create the thread for the host apartment */ 1601 if (!apartment_hwnd && !multi_threaded && main_apartment) 1602 { 1603 APARTMENT *host_apt = apartment_findmain(); 1604 if (host_apt) 1605 { 1606 apartment_hwnd = apartment_getwindow(host_apt); 1607 apartment_release(host_apt); 1608 } 1609 } 1610 1611 params.regdata = *regdata; 1612 params.clsid = *rclsid; 1613 params.iid = *riid; 1614 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); 1615 if (FAILED(hr)) 1616 return hr; 1617 params.apartment_threaded = !multi_threaded; 1618 if (multi_threaded) 1619 { 1620 params.hr = S_OK; 1621 params.event = CreateEventW(NULL, FALSE, FALSE, NULL); 1622 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms)) 1623 hr = E_OUTOFMEMORY; 1624 else 1625 { 1626 WaitForSingleObject(params.event, INFINITE); 1627 hr = params.hr; 1628 } 1629 CloseHandle(params.event); 1630 } 1631 else 1632 { 1633 if (!apartment_hwnd) 1634 { 1635 ERR("host apartment didn't create window\n"); 1636 hr = E_OUTOFMEMORY; 1637 } 1638 else 1639 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); 1640 } 1641 if (SUCCEEDED(hr)) 1642 hr = CoUnmarshalInterface(params.stream, riid, ppv); 1643 IStream_Release(params.stream); 1644 return hr; 1645 } 1646 1647 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context ) 1648 { 1649 WNDCLASSW wclass; 1650 1651 /* Dispatching to the correct thread in an apartment is done through 1652 * window messages rather than RPC transports. When an interface is 1653 * marshalled into another apartment in the same process, a window of the 1654 * following class is created. The *caller* of CoMarshalInterface (i.e., the 1655 * application) is responsible for pumping the message loop in that thread. 1656 * The WM_USER messages which point to the RPCs are then dispatched to 1657 * apartment_wndproc by the user's code from the apartment in which the 1658 * interface was unmarshalled. 1659 */ 1660 memset(&wclass, 0, sizeof(wclass)); 1661 wclass.lpfnWndProc = apartment_wndproc; 1662 wclass.hInstance = hProxyDll; 1663 wclass.lpszClassName = wszAptWinClass; 1664 RegisterClassW(&wclass); 1665 return TRUE; 1666 } 1667 1668 /* create a window for the apartment or return the current one if one has 1669 * already been created */ 1670 HRESULT apartment_createwindowifneeded(struct apartment *apt) 1671 { 1672 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT; 1673 1674 if (apt->multi_threaded) 1675 return S_OK; 1676 1677 if (!apt->win) 1678 { 1679 HWND hwnd; 1680 1681 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL ); 1682 1683 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0, 1684 HWND_MESSAGE, 0, hProxyDll, NULL); 1685 if (!hwnd) 1686 { 1687 ERR("CreateWindow failed with error %d\n", GetLastError()); 1688 return HRESULT_FROM_WIN32(GetLastError()); 1689 } 1690 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL)) 1691 /* someone beat us to it */ 1692 DestroyWindow(hwnd); 1693 } 1694 1695 return S_OK; 1696 } 1697 1698 /* retrieves the window for the main- or apartment-threaded apartment */ 1699 HWND apartment_getwindow(const struct apartment *apt) 1700 { 1701 assert(!apt->multi_threaded); 1702 return apt->win; 1703 } 1704 1705 void apartment_joinmta(void) 1706 { 1707 apartment_addref(MTA); 1708 COM_CurrentInfo()->apt = MTA; 1709 } 1710 1711 static void COM_TlsDestroy(void) 1712 { 1713 struct oletls *info = NtCurrentTeb()->ReservedForOle; 1714 if (info) 1715 { 1716 if (info->apt) apartment_release(info->apt); 1717 if (info->errorinfo) IErrorInfo_Release(info->errorinfo); 1718 if (info->state) IUnknown_Release(info->state); 1719 if (info->spy) IInitializeSpy_Release(info->spy); 1720 if (info->context_token) IObjContext_Release(info->context_token); 1721 HeapFree(GetProcessHeap(), 0, info); 1722 NtCurrentTeb()->ReservedForOle = NULL; 1723 } 1724 } 1725 1726 /****************************************************************************** 1727 * CoBuildVersion [OLE32.@] 1728 * 1729 * Gets the build version of the DLL. 1730 * 1731 * PARAMS 1732 * 1733 * RETURNS 1734 * Current build version, hiword is majornumber, loword is minornumber 1735 */ 1736 DWORD WINAPI CoBuildVersion(void) 1737 { 1738 TRACE("Returning version %d, build %d.\n", rmm, rup); 1739 return (rmm<<16)+rup; 1740 } 1741 1742 /****************************************************************************** 1743 * CoRegisterInitializeSpy [OLE32.@] 1744 * 1745 * Add a Spy that watches CoInitializeEx calls 1746 * 1747 * PARAMS 1748 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd. 1749 * cookie [II] cookie receiver 1750 * 1751 * RETURNS 1752 * Success: S_OK if not already initialized, S_FALSE otherwise. 1753 * Failure: HRESULT code. 1754 * 1755 * SEE ALSO 1756 * CoInitializeEx 1757 */ 1758 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie) 1759 { 1760 struct oletls *info = COM_CurrentInfo(); 1761 HRESULT hr; 1762 1763 TRACE("(%p, %p)\n", spy, cookie); 1764 1765 if (!spy || !cookie || !info) 1766 { 1767 if (!info) 1768 WARN("Could not allocate tls\n"); 1769 return E_INVALIDARG; 1770 } 1771 1772 if (info->spy) 1773 { 1774 FIXME("Already registered?\n"); 1775 return E_UNEXPECTED; 1776 } 1777 1778 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy); 1779 if (SUCCEEDED(hr)) 1780 { 1781 cookie->QuadPart = (DWORD_PTR)spy; 1782 return S_OK; 1783 } 1784 return hr; 1785 } 1786 1787 /****************************************************************************** 1788 * CoRevokeInitializeSpy [OLE32.@] 1789 * 1790 * Remove a spy that previously watched CoInitializeEx calls 1791 * 1792 * PARAMS 1793 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call 1794 * 1795 * RETURNS 1796 * Success: S_OK if a spy is removed 1797 * Failure: E_INVALIDARG 1798 * 1799 * SEE ALSO 1800 * CoInitializeEx 1801 */ 1802 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie) 1803 { 1804 struct oletls *info = COM_CurrentInfo(); 1805 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart)); 1806 1807 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy) 1808 return E_INVALIDARG; 1809 1810 IInitializeSpy_Release(info->spy); 1811 info->spy = NULL; 1812 return S_OK; 1813 } 1814 1815 1816 /****************************************************************************** 1817 * CoInitialize [OLE32.@] 1818 * 1819 * Initializes the COM libraries by calling CoInitializeEx with 1820 * COINIT_APARTMENTTHREADED, ie it enters a STA thread. 1821 * 1822 * PARAMS 1823 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). 1824 * 1825 * RETURNS 1826 * Success: S_OK if not already initialized, S_FALSE otherwise. 1827 * Failure: HRESULT code. 1828 * 1829 * SEE ALSO 1830 * CoInitializeEx 1831 */ 1832 HRESULT WINAPI CoInitialize(LPVOID lpReserved) 1833 { 1834 /* 1835 * Just delegate to the newer method. 1836 */ 1837 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED); 1838 } 1839 1840 /****************************************************************************** 1841 * CoInitializeEx [OLE32.@] 1842 * 1843 * Initializes the COM libraries. 1844 * 1845 * PARAMS 1846 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). 1847 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes. 1848 * 1849 * RETURNS 1850 * S_OK if successful, 1851 * S_FALSE if this function was called already. 1852 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another 1853 * threading model. 1854 * 1855 * NOTES 1856 * 1857 * The behavior used to set the IMalloc used for memory management is 1858 * obsolete. 1859 * The dwCoInit parameter must specify one of the following apartment 1860 * threading models: 1861 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA). 1862 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA). 1863 * The parameter may also specify zero or more of the following flags: 1864 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support. 1865 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed. 1866 * 1867 * SEE ALSO 1868 * CoUninitialize 1869 */ 1870 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit) 1871 { 1872 struct oletls *info = COM_CurrentInfo(); 1873 HRESULT hr = S_OK; 1874 APARTMENT *apt; 1875 1876 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit); 1877 1878 if (lpReserved!=NULL) 1879 { 1880 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved); 1881 } 1882 1883 /* 1884 * Check the lock count. If this is the first time going through the initialize 1885 * process, we have to initialize the libraries. 1886 * 1887 * And crank-up that lock count. 1888 */ 1889 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0) 1890 { 1891 /* 1892 * Initialize the various COM libraries and data structures. 1893 */ 1894 TRACE("() - Initializing the COM libraries\n"); 1895 1896 /* we may need to defer this until after apartment initialisation */ 1897 RunningObjectTableImpl_Initialize(); 1898 } 1899 1900 if (info->spy) 1901 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits); 1902 1903 if (!(apt = info->apt)) 1904 { 1905 apt = apartment_get_or_create(dwCoInit); 1906 if (!apt) return E_OUTOFMEMORY; 1907 } 1908 else if (!apartment_is_model(apt, dwCoInit)) 1909 { 1910 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine 1911 code then we are probably using the wrong threading model to implement that API. */ 1912 ERR("Attempt to change threading model of this apartment from %s to %s\n", 1913 apt->multi_threaded ? "multi-threaded" : "apartment threaded", 1914 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded"); 1915 return RPC_E_CHANGED_MODE; 1916 } 1917 else 1918 hr = S_FALSE; 1919 1920 info->inits++; 1921 1922 if (info->spy) 1923 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits); 1924 1925 return hr; 1926 } 1927 1928 /*********************************************************************** 1929 * CoUninitialize [OLE32.@] 1930 * 1931 * This method will decrement the refcount on the current apartment, freeing 1932 * the resources associated with it if it is the last thread in the apartment. 1933 * If the last apartment is freed, the function will additionally release 1934 * any COM resources associated with the process. 1935 * 1936 * PARAMS 1937 * 1938 * RETURNS 1939 * Nothing. 1940 * 1941 * SEE ALSO 1942 * CoInitializeEx 1943 */ 1944 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void) 1945 { 1946 struct oletls * info = COM_CurrentInfo(); 1947 LONG lCOMRefCnt; 1948 1949 TRACE("()\n"); 1950 1951 /* will only happen on OOM */ 1952 if (!info) return; 1953 1954 if (info->spy) 1955 IInitializeSpy_PreUninitialize(info->spy, info->inits); 1956 1957 /* sanity check */ 1958 if (!info->inits) 1959 { 1960 ERR("Mismatched CoUninitialize\n"); 1961 1962 if (info->spy) 1963 IInitializeSpy_PostUninitialize(info->spy, info->inits); 1964 return; 1965 } 1966 1967 if (!--info->inits) 1968 { 1969 if (info->ole_inits) 1970 WARN("uninitializing apartment while Ole is still initialized\n"); 1971 apartment_release(info->apt); 1972 info->apt = NULL; 1973 } 1974 1975 /* 1976 * Decrease the reference count. 1977 * If we are back to 0 locks on the COM library, make sure we free 1978 * all the associated data structures. 1979 */ 1980 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1); 1981 if (lCOMRefCnt==1) 1982 { 1983 TRACE("() - Releasing the COM libraries\n"); 1984 1985 revoke_registered_psclsids(); 1986 RunningObjectTableImpl_UnInitialize(); 1987 } 1988 else if (lCOMRefCnt<1) { 1989 ERR( "CoUninitialize() - not CoInitialized.\n" ); 1990 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */ 1991 } 1992 if (info->spy) 1993 IInitializeSpy_PostUninitialize(info->spy, info->inits); 1994 } 1995 1996 /****************************************************************************** 1997 * CoDisconnectObject [OLE32.@] 1998 * 1999 * Disconnects all connections to this object from remote processes. Dispatches 2000 * pending RPCs while blocking new RPCs from occurring, and then calls 2001 * IMarshal::DisconnectObject on the given object. 2002 * 2003 * Typically called when the object server is forced to shut down, for instance by 2004 * the user. 2005 * 2006 * PARAMS 2007 * lpUnk [I] The object whose stub should be disconnected. 2008 * reserved [I] Reserved. Should be set to 0. 2009 * 2010 * RETURNS 2011 * Success: S_OK. 2012 * Failure: HRESULT code. 2013 * 2014 * SEE ALSO 2015 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal 2016 */ 2017 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) 2018 { 2019 struct stub_manager *manager; 2020 HRESULT hr; 2021 IMarshal *marshal; 2022 APARTMENT *apt; 2023 2024 TRACE("(%p, 0x%08x)\n", lpUnk, reserved); 2025 2026 if (!lpUnk) return E_INVALIDARG; 2027 2028 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal); 2029 if (hr == S_OK) 2030 { 2031 hr = IMarshal_DisconnectObject(marshal, reserved); 2032 IMarshal_Release(marshal); 2033 return hr; 2034 } 2035 2036 apt = COM_CurrentApt(); 2037 if (!apt) 2038 return CO_E_NOTINITIALIZED; 2039 2040 manager = get_stub_manager_from_object(apt, lpUnk, FALSE); 2041 if (manager) { 2042 stub_manager_disconnect(manager); 2043 /* Release stub manager twice, to remove the apartment reference. */ 2044 stub_manager_int_release(manager); 2045 stub_manager_int_release(manager); 2046 } 2047 2048 /* Note: native is pretty broken here because it just silently 2049 * fails, without returning an appropriate error code if the object was 2050 * not found, making apps think that the object was disconnected, when 2051 * it actually wasn't */ 2052 2053 return S_OK; 2054 } 2055 2056 /****************************************************************************** 2057 * CoCreateGuid [OLE32.@] 2058 * 2059 * Simply forwards to UuidCreate in RPCRT4. 2060 * 2061 * PARAMS 2062 * pguid [O] Points to the GUID to initialize. 2063 * 2064 * RETURNS 2065 * Success: S_OK. 2066 * Failure: HRESULT code. 2067 * 2068 * SEE ALSO 2069 * UuidCreate 2070 */ 2071 HRESULT WINAPI CoCreateGuid(GUID *pguid) 2072 { 2073 DWORD status; 2074 2075 if(!pguid) return E_INVALIDARG; 2076 2077 status = UuidCreate(pguid); 2078 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK; 2079 return HRESULT_FROM_WIN32( status ); 2080 } 2081 2082 static inline BOOL is_valid_hex(WCHAR c) 2083 { 2084 if (!(((c >= '0') && (c <= '9')) || 2085 ((c >= 'a') && (c <= 'f')) || 2086 ((c >= 'A') && (c <= 'F')))) 2087 return FALSE; 2088 return TRUE; 2089 } 2090 2091 static const BYTE guid_conv_table[256] = 2092 { 2093 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ 2094 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ 2095 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ 2096 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */ 2097 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */ 2098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */ 2099 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */ 2100 }; 2101 2102 /* conversion helper for CLSIDFromString/IIDFromString */ 2103 static BOOL guid_from_string(LPCWSTR s, GUID *id) 2104 { 2105 int i; 2106 2107 if (!s || s[0]!='{') { 2108 memset( id, 0, sizeof (CLSID) ); 2109 if(!s) return TRUE; 2110 return FALSE; 2111 } 2112 2113 TRACE("%s -> %p\n", debugstr_w(s), id); 2114 2115 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ 2116 2117 id->Data1 = 0; 2118 for (i = 1; i < 9; i++) { 2119 if (!is_valid_hex(s[i])) return FALSE; 2120 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]]; 2121 } 2122 if (s[9]!='-') return FALSE; 2123 2124 id->Data2 = 0; 2125 for (i = 10; i < 14; i++) { 2126 if (!is_valid_hex(s[i])) return FALSE; 2127 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]]; 2128 } 2129 if (s[14]!='-') return FALSE; 2130 2131 id->Data3 = 0; 2132 for (i = 15; i < 19; i++) { 2133 if (!is_valid_hex(s[i])) return FALSE; 2134 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]]; 2135 } 2136 if (s[19]!='-') return FALSE; 2137 2138 for (i = 20; i < 37; i+=2) { 2139 if (i == 24) { 2140 if (s[i]!='-') return FALSE; 2141 i++; 2142 } 2143 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE; 2144 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]]; 2145 } 2146 2147 if (s[37] == '}' && s[38] == '\0') 2148 return TRUE; 2149 2150 return FALSE; 2151 } 2152 2153 /*****************************************************************************/ 2154 2155 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) 2156 { 2157 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 }; 2158 WCHAR buf2[CHARS_IN_GUID]; 2159 LONG buf2len = sizeof(buf2); 2160 HKEY xhkey; 2161 WCHAR *buf; 2162 2163 memset(clsid, 0, sizeof(*clsid)); 2164 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) ); 2165 if (!buf) return E_OUTOFMEMORY; 2166 strcpyW( buf, progid ); 2167 strcatW( buf, clsidW ); 2168 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey)) 2169 { 2170 HeapFree(GetProcessHeap(),0,buf); 2171 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); 2172 return CO_E_CLASSSTRING; 2173 } 2174 HeapFree(GetProcessHeap(),0,buf); 2175 2176 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len)) 2177 { 2178 RegCloseKey(xhkey); 2179 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid)); 2180 return CO_E_CLASSSTRING; 2181 } 2182 RegCloseKey(xhkey); 2183 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING; 2184 } 2185 2186 /****************************************************************************** 2187 * CLSIDFromString [OLE32.@] 2188 * 2189 * Converts a unique identifier from its string representation into 2190 * the GUID struct. 2191 * 2192 * PARAMS 2193 * idstr [I] The string representation of the GUID. 2194 * id [O] GUID converted from the string. 2195 * 2196 * RETURNS 2197 * S_OK on success 2198 * CO_E_CLASSSTRING if idstr is not a valid CLSID 2199 * 2200 * SEE ALSO 2201 * StringFromCLSID 2202 */ 2203 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id ) 2204 { 2205 HRESULT ret = CO_E_CLASSSTRING; 2206 CLSID tmp_id; 2207 2208 if (!id) 2209 return E_INVALIDARG; 2210 2211 if (guid_from_string(idstr, id)) 2212 return S_OK; 2213 2214 /* It appears a ProgID is also valid */ 2215 ret = clsid_from_string_reg(idstr, &tmp_id); 2216 if(SUCCEEDED(ret)) 2217 *id = tmp_id; 2218 2219 return ret; 2220 } 2221 2222 /****************************************************************************** 2223 * IIDFromString [OLE32.@] 2224 * 2225 * Converts an interface identifier from its string representation to 2226 * the IID struct. 2227 * 2228 * PARAMS 2229 * idstr [I] The string representation of the GUID. 2230 * id [O] IID converted from the string. 2231 * 2232 * RETURNS 2233 * S_OK on success 2234 * CO_E_IIDSTRING if idstr is not a valid IID 2235 * 2236 * SEE ALSO 2237 * StringFromIID 2238 */ 2239 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid) 2240 { 2241 TRACE("%s -> %p\n", debugstr_w(s), iid); 2242 2243 if (!s) 2244 { 2245 memset(iid, 0, sizeof(*iid)); 2246 return S_OK; 2247 } 2248 2249 /* length mismatch is a special case */ 2250 if (strlenW(s) + 1 != CHARS_IN_GUID) 2251 return E_INVALIDARG; 2252 2253 if (s[0] != '{') 2254 return CO_E_IIDSTRING; 2255 2256 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING; 2257 } 2258 2259 /****************************************************************************** 2260 * StringFromCLSID [OLE32.@] 2261 * StringFromIID [OLE32.@] 2262 * 2263 * Converts a GUID into the respective string representation. 2264 * The target string is allocated using the OLE IMalloc. 2265 * 2266 * PARAMS 2267 * id [I] the GUID to be converted. 2268 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string. 2269 * 2270 * RETURNS 2271 * S_OK 2272 * E_FAIL 2273 * 2274 * SEE ALSO 2275 * StringFromGUID2, CLSIDFromString 2276 */ 2277 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr) 2278 { 2279 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY; 2280 StringFromGUID2( id, *idstr, CHARS_IN_GUID ); 2281 return S_OK; 2282 } 2283 2284 /****************************************************************************** 2285 * StringFromGUID2 [OLE32.@] 2286 * 2287 * Modified version of StringFromCLSID that allows you to specify max 2288 * buffer size. 2289 * 2290 * PARAMS 2291 * id [I] GUID to convert to string. 2292 * str [O] Buffer where the result will be stored. 2293 * cmax [I] Size of the buffer in characters. 2294 * 2295 * RETURNS 2296 * Success: The length of the resulting string in characters. 2297 * Failure: 0. 2298 */ 2299 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax) 2300 { 2301 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-', 2302 '%','0','4','X','-','%','0','2','X','%','0','2','X','-', 2303 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X', 2304 '%','0','2','X','%','0','2','X','}',0 }; 2305 if (!id || cmax < CHARS_IN_GUID) return 0; 2306 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3, 2307 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], 2308 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); 2309 return CHARS_IN_GUID; 2310 } 2311 2312 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */ 2313 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey) 2314 { 2315 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0}; 2316 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1]; 2317 LONG res; 2318 HKEY key; 2319 2320 strcpyW(path, wszCLSIDSlash); 2321 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID); 2322 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key); 2323 if (res == ERROR_FILE_NOT_FOUND) 2324 return REGDB_E_CLASSNOTREG; 2325 else if (res != ERROR_SUCCESS) 2326 return REGDB_E_READREGDB; 2327 2328 if (!keyname) 2329 { 2330 *subkey = key; 2331 return S_OK; 2332 } 2333 2334 res = open_classes_key(key, keyname, access, subkey); 2335 RegCloseKey(key); 2336 if (res == ERROR_FILE_NOT_FOUND) 2337 return REGDB_E_KEYMISSING; 2338 else if (res != ERROR_SUCCESS) 2339 return REGDB_E_READREGDB; 2340 2341 return S_OK; 2342 } 2343 2344 /* open HKCR\\AppId\\{string form of appid clsid} key */ 2345 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey) 2346 { 2347 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 }; 2348 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 }; 2349 DWORD res; 2350 WCHAR buf[CHARS_IN_GUID]; 2351 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID]; 2352 DWORD size; 2353 HKEY hkey; 2354 DWORD type; 2355 HRESULT hr; 2356 2357 /* read the AppID value under the class's key */ 2358 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey); 2359 if (FAILED(hr)) 2360 return hr; 2361 2362 size = sizeof(buf); 2363 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size); 2364 RegCloseKey(hkey); 2365 if (res == ERROR_FILE_NOT_FOUND) 2366 return REGDB_E_KEYMISSING; 2367 else if (res != ERROR_SUCCESS || type!=REG_SZ) 2368 return REGDB_E_READREGDB; 2369 2370 strcpyW(keyname, szAppIdKey); 2371 strcatW(keyname, buf); 2372 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey); 2373 if (res == ERROR_FILE_NOT_FOUND) 2374 return REGDB_E_KEYMISSING; 2375 else if (res != ERROR_SUCCESS) 2376 return REGDB_E_READREGDB; 2377 2378 return S_OK; 2379 } 2380 2381 /****************************************************************************** 2382 * ProgIDFromCLSID [OLE32.@] 2383 * 2384 * Converts a class id into the respective program ID. 2385 * 2386 * PARAMS 2387 * clsid [I] Class ID, as found in registry. 2388 * ppszProgID [O] Associated ProgID. 2389 * 2390 * RETURNS 2391 * S_OK 2392 * E_OUTOFMEMORY 2393 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID 2394 */ 2395 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID) 2396 { 2397 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0}; 2398 ACTCTX_SECTION_KEYED_DATA data; 2399 HKEY hkey; 2400 HRESULT ret; 2401 LONG progidlen = 0; 2402 2403 if (!ppszProgID) 2404 return E_INVALIDARG; 2405 2406 *ppszProgID = NULL; 2407 2408 data.cbSize = sizeof(data); 2409 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, 2410 clsid, &data)) 2411 { 2412 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData; 2413 if (comclass->progid_len) 2414 { 2415 WCHAR *ptrW; 2416 2417 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR)); 2418 if (!*ppszProgID) return E_OUTOFMEMORY; 2419 2420 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset); 2421 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR)); 2422 return S_OK; 2423 } 2424 else 2425 return REGDB_E_CLASSNOTREG; 2426 } 2427 2428 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey); 2429 if (FAILED(ret)) 2430 return ret; 2431 2432 if (RegQueryValueW(hkey, NULL, NULL, &progidlen)) 2433 ret = REGDB_E_CLASSNOTREG; 2434 2435 if (ret == S_OK) 2436 { 2437 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR)); 2438 if (*ppszProgID) 2439 { 2440 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) { 2441 ret = REGDB_E_CLASSNOTREG; 2442 CoTaskMemFree(*ppszProgID); 2443 *ppszProgID = NULL; 2444 } 2445 } 2446 else 2447 ret = E_OUTOFMEMORY; 2448 } 2449 2450 RegCloseKey(hkey); 2451 return ret; 2452 } 2453 2454 /****************************************************************************** 2455 * CLSIDFromProgID [OLE32.@] 2456 * 2457 * Converts a program id into the respective GUID. 2458 * 2459 * PARAMS 2460 * progid [I] Unicode program ID, as found in registry. 2461 * clsid [O] Associated CLSID. 2462 * 2463 * RETURNS 2464 * Success: S_OK 2465 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found. 2466 */ 2467 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid) 2468 { 2469 ACTCTX_SECTION_KEYED_DATA data; 2470 2471 if (!progid || !clsid) 2472 return E_INVALIDARG; 2473 2474 data.cbSize = sizeof(data); 2475 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION, 2476 progid, &data)) 2477 { 2478 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData; 2479 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset); 2480 *clsid = *alias; 2481 return S_OK; 2482 } 2483 2484 return clsid_from_string_reg(progid, clsid); 2485 } 2486 2487 /****************************************************************************** 2488 * CLSIDFromProgIDEx [OLE32.@] 2489 */ 2490 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid) 2491 { 2492 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid); 2493 2494 return CLSIDFromProgID(progid, clsid); 2495 } 2496 2497 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid) 2498 { 2499 HKEY hkey; 2500 WCHAR value[CHARS_IN_GUID]; 2501 DWORD len; 2502 2503 access |= KEY_READ; 2504 2505 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey)) 2506 return REGDB_E_IIDNOTREG; 2507 2508 len = sizeof(value); 2509 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len)) 2510 return REGDB_E_IIDNOTREG; 2511 RegCloseKey(hkey); 2512 2513 if (CLSIDFromString(value, pclsid) != NOERROR) 2514 return REGDB_E_IIDNOTREG; 2515 2516 return S_OK; 2517 } 2518 2519 /***************************************************************************** 2520 * CoGetPSClsid [OLE32.@] 2521 * 2522 * Retrieves the CLSID of the proxy/stub factory that implements 2523 * IPSFactoryBuffer for the specified interface. 2524 * 2525 * PARAMS 2526 * riid [I] Interface whose proxy/stub CLSID is to be returned. 2527 * pclsid [O] Where to store returned proxy/stub CLSID. 2528 * 2529 * RETURNS 2530 * S_OK 2531 * E_OUTOFMEMORY 2532 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed 2533 * 2534 * NOTES 2535 * 2536 * The standard marshaller activates the object with the CLSID 2537 * returned and uses the CreateProxy and CreateStub methods on its 2538 * IPSFactoryBuffer interface to construct the proxies and stubs for a 2539 * given object. 2540 * 2541 * CoGetPSClsid determines this CLSID by searching the 2542 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 2543 * in the registry and any interface id registered by 2544 * CoRegisterPSClsid within the current process. 2545 * 2546 * BUGS 2547 * 2548 * Native returns S_OK for interfaces with a key in HKCR\Interface, but 2549 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be 2550 * considered a bug in native unless an application depends on this (unlikely). 2551 * 2552 * SEE ALSO 2553 * CoRegisterPSClsid. 2554 */ 2555 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) 2556 { 2557 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0}; 2558 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0}; 2559 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)]; 2560 APARTMENT *apt = COM_CurrentApt(); 2561 struct registered_psclsid *registered_psclsid; 2562 ACTCTX_SECTION_KEYED_DATA data; 2563 HRESULT hr; 2564 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY; 2565 BOOL is_wow64; 2566 2567 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid); 2568 2569 if (!apt) 2570 { 2571 ERR("apartment not initialised\n"); 2572 return CO_E_NOTINITIALIZED; 2573 } 2574 2575 if (!pclsid) 2576 return E_INVALIDARG; 2577 2578 EnterCriticalSection(&cs_registered_psclsid_list); 2579 2580 LIST_FOR_EACH_ENTRY(registered_psclsid, ®istered_psclsid_list, struct registered_psclsid, entry) 2581 if (IsEqualIID(®istered_psclsid->iid, riid)) 2582 { 2583 *pclsid = registered_psclsid->clsid; 2584 LeaveCriticalSection(&cs_registered_psclsid_list); 2585 return S_OK; 2586 } 2587 2588 LeaveCriticalSection(&cs_registered_psclsid_list); 2589 2590 data.cbSize = sizeof(data); 2591 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION, 2592 riid, &data)) 2593 { 2594 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData; 2595 *pclsid = ifaceps->iid; 2596 return S_OK; 2597 } 2598 2599 /* Interface\\{string form of riid}\\ProxyStubClsid32 */ 2600 strcpyW(path, wszInterface); 2601 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID); 2602 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC); 2603 2604 hr = get_ps_clsid_from_registry(path, 0, pclsid); 2605 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || 2606 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64))) 2607 hr = get_ps_clsid_from_registry(path, opposite, pclsid); 2608 2609 if (hr == S_OK) 2610 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid)); 2611 else 2612 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid)); 2613 2614 return hr; 2615 } 2616 2617 /***************************************************************************** 2618 * CoRegisterPSClsid [OLE32.@] 2619 * 2620 * Register a proxy/stub CLSID for the given interface in the current process 2621 * only. 2622 * 2623 * PARAMS 2624 * riid [I] Interface whose proxy/stub CLSID is to be registered. 2625 * rclsid [I] CLSID of the proxy/stub. 2626 * 2627 * RETURNS 2628 * Success: S_OK 2629 * Failure: E_OUTOFMEMORY 2630 * 2631 * NOTES 2632 * 2633 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid() 2634 * will be returned from other apartments in the same process. 2635 * 2636 * This function does not add anything to the registry and the effects are 2637 * limited to the lifetime of the current process. 2638 * 2639 * SEE ALSO 2640 * CoGetPSClsid. 2641 */ 2642 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid) 2643 { 2644 APARTMENT *apt = COM_CurrentApt(); 2645 struct registered_psclsid *registered_psclsid; 2646 2647 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid)); 2648 2649 if (!apt) 2650 { 2651 ERR("apartment not initialised\n"); 2652 return CO_E_NOTINITIALIZED; 2653 } 2654 2655 EnterCriticalSection(&cs_registered_psclsid_list); 2656 2657 LIST_FOR_EACH_ENTRY(registered_psclsid, ®istered_psclsid_list, struct registered_psclsid, entry) 2658 if (IsEqualIID(®istered_psclsid->iid, riid)) 2659 { 2660 registered_psclsid->clsid = *rclsid; 2661 LeaveCriticalSection(&cs_registered_psclsid_list); 2662 return S_OK; 2663 } 2664 2665 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid)); 2666 if (!registered_psclsid) 2667 { 2668 LeaveCriticalSection(&cs_registered_psclsid_list); 2669 return E_OUTOFMEMORY; 2670 } 2671 2672 registered_psclsid->iid = *riid; 2673 registered_psclsid->clsid = *rclsid; 2674 list_add_head(®istered_psclsid_list, ®istered_psclsid->entry); 2675 2676 LeaveCriticalSection(&cs_registered_psclsid_list); 2677 2678 return S_OK; 2679 } 2680 2681 2682 /*** 2683 * COM_GetRegisteredClassObject 2684 * 2685 * This internal method is used to scan the registered class list to 2686 * find a class object. 2687 * 2688 * Params: 2689 * rclsid Class ID of the class to find. 2690 * dwClsContext Class context to match. 2691 * ppv [out] returns a pointer to the class object. Complying 2692 * to normal COM usage, this method will increase the 2693 * reference count on this object. 2694 */ 2695 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, 2696 DWORD dwClsContext, LPUNKNOWN* ppUnk) 2697 { 2698 HRESULT hr = S_FALSE; 2699 RegisteredClass *curClass; 2700 2701 EnterCriticalSection( &csRegisteredClassList ); 2702 2703 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) 2704 { 2705 /* 2706 * Check if we have a match on the class ID and context. 2707 */ 2708 if ((apt->oxid == curClass->apartment_id) && 2709 (dwClsContext & curClass->runContext) && 2710 IsEqualGUID(&(curClass->classIdentifier), rclsid)) 2711 { 2712 /* 2713 * We have a match, return the pointer to the class object. 2714 */ 2715 *ppUnk = curClass->classObject; 2716 2717 IUnknown_AddRef(curClass->classObject); 2718 2719 hr = S_OK; 2720 break; 2721 } 2722 } 2723 2724 LeaveCriticalSection( &csRegisteredClassList ); 2725 2726 return hr; 2727 } 2728 2729 /****************************************************************************** 2730 * CoRegisterClassObject [OLE32.@] 2731 * 2732 * Registers the class object for a given class ID. Servers housed in EXE 2733 * files use this method instead of exporting DllGetClassObject to allow 2734 * other code to connect to their objects. 2735 * 2736 * PARAMS 2737 * rclsid [I] CLSID of the object to register. 2738 * pUnk [I] IUnknown of the object. 2739 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable. 2740 * flags [I] REGCLS flags indicating how connections are made. 2741 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject. 2742 * 2743 * RETURNS 2744 * S_OK on success, 2745 * E_INVALIDARG if lpdwRegister or pUnk are NULL, 2746 * CO_E_OBJISREG if the object is already registered. We should not return this. 2747 * 2748 * SEE ALSO 2749 * CoRevokeClassObject, CoGetClassObject 2750 * 2751 * NOTES 2752 * In-process objects are only registered for the current apartment. 2753 * CoGetClassObject() and CoCreateInstance() will not return objects registered 2754 * in other apartments. 2755 * 2756 * BUGS 2757 * MSDN claims that multiple interface registrations are legal, but we 2758 * can't do that with our current implementation. 2759 */ 2760 HRESULT WINAPI CoRegisterClassObject( 2761 REFCLSID rclsid, 2762 LPUNKNOWN pUnk, 2763 DWORD dwClsContext, 2764 DWORD flags, 2765 LPDWORD lpdwRegister) 2766 { 2767 static LONG next_cookie; 2768 RegisteredClass* newClass; 2769 LPUNKNOWN foundObject; 2770 HRESULT hr; 2771 APARTMENT *apt; 2772 2773 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n", 2774 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister); 2775 2776 if ( (lpdwRegister==0) || (pUnk==0) ) 2777 return E_INVALIDARG; 2778 2779 apt = COM_CurrentApt(); 2780 if (!apt) 2781 { 2782 ERR("COM was not initialized\n"); 2783 return CO_E_NOTINITIALIZED; 2784 } 2785 2786 *lpdwRegister = 0; 2787 2788 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what 2789 * differentiates the flag from REGCLS_MULTI_SEPARATE. */ 2790 if (flags & REGCLS_MULTIPLEUSE) 2791 dwClsContext |= CLSCTX_INPROC_SERVER; 2792 2793 /* 2794 * First, check if the class is already registered. 2795 * If it is, this should cause an error. 2796 */ 2797 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject); 2798 if (hr == S_OK) { 2799 if (flags & REGCLS_MULTIPLEUSE) { 2800 if (dwClsContext & CLSCTX_LOCAL_SERVER) 2801 hr = CoLockObjectExternal(foundObject, TRUE, FALSE); 2802 IUnknown_Release(foundObject); 2803 return hr; 2804 } 2805 IUnknown_Release(foundObject); 2806 ERR("object already registered for class %s\n", debugstr_guid(rclsid)); 2807 return CO_E_OBJISREG; 2808 } 2809 2810 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass)); 2811 if ( newClass == NULL ) 2812 return E_OUTOFMEMORY; 2813 2814 newClass->classIdentifier = *rclsid; 2815 newClass->apartment_id = apt->oxid; 2816 newClass->runContext = dwClsContext; 2817 newClass->connectFlags = flags; 2818 newClass->RpcRegistration = NULL; 2819 2820 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie ))) 2821 newClass->dwCookie = InterlockedIncrement( &next_cookie ); 2822 2823 /* 2824 * Since we're making a copy of the object pointer, we have to increase its 2825 * reference count. 2826 */ 2827 newClass->classObject = pUnk; 2828 IUnknown_AddRef(newClass->classObject); 2829 2830 EnterCriticalSection( &csRegisteredClassList ); 2831 list_add_tail(&RegisteredClassList, &newClass->entry); 2832 LeaveCriticalSection( &csRegisteredClassList ); 2833 2834 *lpdwRegister = newClass->dwCookie; 2835 2836 if (dwClsContext & CLSCTX_LOCAL_SERVER) { 2837 IStream *marshal_stream; 2838 2839 hr = get_local_server_stream(apt, &marshal_stream); 2840 if(FAILED(hr)) 2841 return hr; 2842 2843 hr = RPC_StartLocalServer(&newClass->classIdentifier, 2844 marshal_stream, 2845 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE), 2846 &newClass->RpcRegistration); 2847 IStream_Release(marshal_stream); 2848 } 2849 return S_OK; 2850 } 2851 2852 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data) 2853 { 2854 if (data->hkey) 2855 { 2856 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0}; 2857 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0}; 2858 static const WCHAR wszFree[] = {'F','r','e','e',0}; 2859 static const WCHAR wszBoth[] = {'B','o','t','h',0}; 2860 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */]; 2861 DWORD dwLength = sizeof(threading_model); 2862 DWORD keytype; 2863 DWORD ret; 2864 2865 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength); 2866 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ)) 2867 threading_model[0] = '\0'; 2868 2869 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment; 2870 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free; 2871 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both; 2872 2873 /* there's not specific handling for this case */ 2874 if (threading_model[0]) return ThreadingModel_Neutral; 2875 return ThreadingModel_No; 2876 } 2877 else 2878 return data->u.actctx.data->model; 2879 } 2880 2881 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata, 2882 REFCLSID rclsid, REFIID riid, 2883 BOOL hostifnecessary, void **ppv) 2884 { 2885 WCHAR dllpath[MAX_PATH+1]; 2886 BOOL apartment_threaded; 2887 2888 if (hostifnecessary) 2889 { 2890 enum comclass_threadingmodel model = get_threading_model(regdata); 2891 2892 if (model == ThreadingModel_Apartment) 2893 { 2894 apartment_threaded = TRUE; 2895 if (apt->multi_threaded) 2896 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv); 2897 } 2898 else if (model == ThreadingModel_Free) 2899 { 2900 apartment_threaded = FALSE; 2901 if (!apt->multi_threaded) 2902 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv); 2903 } 2904 /* everything except "Apartment", "Free" and "Both" */ 2905 else if (model != ThreadingModel_Both) 2906 { 2907 apartment_threaded = TRUE; 2908 /* everything else is main-threaded */ 2909 if (model != ThreadingModel_No) 2910 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid)); 2911 2912 if (apt->multi_threaded || !apt->main) 2913 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv); 2914 } 2915 else 2916 apartment_threaded = FALSE; 2917 } 2918 else 2919 apartment_threaded = !apt->multi_threaded; 2920 2921 if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS) 2922 { 2923 /* failure: CLSID is not found in registry */ 2924 WARN("class %s not registered inproc\n", debugstr_guid(rclsid)); 2925 return REGDB_E_CLASSNOTREG; 2926 } 2927 2928 return apartment_getclassobject(apt, dllpath, apartment_threaded, 2929 rclsid, riid, ppv); 2930 } 2931 2932 /*********************************************************************** 2933 * CoGetClassObject [OLE32.@] 2934 * 2935 * Creates an object of the specified class. 2936 * 2937 * PARAMS 2938 * rclsid [I] Class ID to create an instance of. 2939 * dwClsContext [I] Flags to restrict the location of the created instance. 2940 * pServerInfo [I] Optional. Details for connecting to a remote server. 2941 * iid [I] The ID of the interface of the instance to return. 2942 * ppv [O] On returns, contains a pointer to the specified interface of the object. 2943 * 2944 * RETURNS 2945 * Success: S_OK 2946 * Failure: HRESULT code. 2947 * 2948 * NOTES 2949 * The dwClsContext parameter can be one or more of the following: 2950 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL. 2951 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process. 2952 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process. 2953 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine. 2954 * 2955 * SEE ALSO 2956 * CoCreateInstance() 2957 */ 2958 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( 2959 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo, 2960 REFIID iid, LPVOID *ppv) 2961 { 2962 struct class_reg_data clsreg; 2963 IUnknown *regClassObject; 2964 HRESULT hres = E_UNEXPECTED; 2965 APARTMENT *apt; 2966 BOOL release_apt = FALSE; 2967 2968 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid)); 2969 2970 if (!ppv) 2971 return E_INVALIDARG; 2972 2973 *ppv = NULL; 2974 2975 if (!(apt = COM_CurrentApt())) 2976 { 2977 if (!(apt = apartment_find_multi_threaded())) 2978 { 2979 ERR("apartment not initialised\n"); 2980 return CO_E_NOTINITIALIZED; 2981 } 2982 release_apt = TRUE; 2983 } 2984 2985 if (pServerInfo) { 2986 FIXME("pServerInfo->name=%s pAuthInfo=%p\n", 2987 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo); 2988 } 2989 2990 if (CLSCTX_INPROC_SERVER & dwClsContext) 2991 { 2992 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler)) 2993 { 2994 if (release_apt) apartment_release(apt); 2995 return FTMarshalCF_Create(iid, ppv); 2996 } 2997 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions)) 2998 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv); 2999 } 3000 3001 if (CLSCTX_INPROC & dwClsContext) 3002 { 3003 ACTCTX_SECTION_KEYED_DATA data; 3004 3005 data.cbSize = sizeof(data); 3006 /* search activation context first */ 3007 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, 3008 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, 3009 rclsid, &data)) 3010 { 3011 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData; 3012 3013 clsreg.u.actctx.hactctx = data.hActCtx; 3014 clsreg.u.actctx.data = data.lpData; 3015 clsreg.u.actctx.section = data.lpSectionBase; 3016 clsreg.hkey = FALSE; 3017 3018 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 3019 ReleaseActCtx(data.hActCtx); 3020 if (release_apt) apartment_release(apt); 3021 return hres; 3022 } 3023 } 3024 3025 /* 3026 * First, try and see if we can't match the class ID with one of the 3027 * registered classes. 3028 */ 3029 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, 3030 ®ClassObject)) 3031 { 3032 /* Get the required interface from the retrieved pointer. */ 3033 hres = IUnknown_QueryInterface(regClassObject, iid, ppv); 3034 3035 /* 3036 * Since QI got another reference on the pointer, we want to release the 3037 * one we already have. If QI was unsuccessful, this will release the object. This 3038 * is good since we are not returning it in the "out" parameter. 3039 */ 3040 IUnknown_Release(regClassObject); 3041 if (release_apt) apartment_release(apt); 3042 return hres; 3043 } 3044 3045 /* First try in-process server */ 3046 if (CLSCTX_INPROC_SERVER & dwClsContext) 3047 { 3048 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; 3049 HKEY hkey; 3050 3051 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey); 3052 if (FAILED(hres)) 3053 { 3054 if (hres == REGDB_E_CLASSNOTREG) 3055 ERR("class %s not registered\n", debugstr_guid(rclsid)); 3056 else if (hres == REGDB_E_KEYMISSING) 3057 { 3058 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid)); 3059 hres = REGDB_E_CLASSNOTREG; 3060 } 3061 } 3062 3063 if (SUCCEEDED(hres)) 3064 { 3065 clsreg.u.hkey = hkey; 3066 clsreg.hkey = TRUE; 3067 3068 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 3069 RegCloseKey(hkey); 3070 } 3071 3072 /* return if we got a class, otherwise fall through to one of the 3073 * other types */ 3074 if (SUCCEEDED(hres)) 3075 { 3076 if (release_apt) apartment_release(apt); 3077 return hres; 3078 } 3079 } 3080 3081 /* Next try in-process handler */ 3082 if (CLSCTX_INPROC_HANDLER & dwClsContext) 3083 { 3084 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; 3085 HKEY hkey; 3086 3087 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey); 3088 if (FAILED(hres)) 3089 { 3090 if (hres == REGDB_E_CLASSNOTREG) 3091 ERR("class %s not registered\n", debugstr_guid(rclsid)); 3092 else if (hres == REGDB_E_KEYMISSING) 3093 { 3094 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid)); 3095 hres = REGDB_E_CLASSNOTREG; 3096 } 3097 } 3098 3099 if (SUCCEEDED(hres)) 3100 { 3101 clsreg.u.hkey = hkey; 3102 clsreg.hkey = TRUE; 3103 3104 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 3105 RegCloseKey(hkey); 3106 } 3107 3108 /* return if we got a class, otherwise fall through to one of the 3109 * other types */ 3110 if (SUCCEEDED(hres)) 3111 { 3112 if (release_apt) apartment_release(apt); 3113 return hres; 3114 } 3115 } 3116 if (release_apt) apartment_release(apt); 3117 3118 /* Next try out of process */ 3119 if (CLSCTX_LOCAL_SERVER & dwClsContext) 3120 { 3121 hres = RPC_GetLocalClassObject(rclsid,iid,ppv); 3122 if (SUCCEEDED(hres)) 3123 return hres; 3124 } 3125 3126 /* Finally try remote: this requires networked DCOM (a lot of work) */ 3127 if (CLSCTX_REMOTE_SERVER & dwClsContext) 3128 { 3129 FIXME ("CLSCTX_REMOTE_SERVER not supported\n"); 3130 hres = REGDB_E_CLASSNOTREG; 3131 } 3132 3133 if (FAILED(hres)) 3134 ERR("no class object %s could be created for context 0x%x\n", 3135 debugstr_guid(rclsid), dwClsContext); 3136 return hres; 3137 } 3138 3139 /*********************************************************************** 3140 * CoResumeClassObjects (OLE32.@) 3141 * 3142 * Resumes all class objects registered with REGCLS_SUSPENDED. 3143 * 3144 * RETURNS 3145 * Success: S_OK. 3146 * Failure: HRESULT code. 3147 */ 3148 HRESULT WINAPI CoResumeClassObjects(void) 3149 { 3150 FIXME("stub\n"); 3151 return S_OK; 3152 } 3153 3154 /*********************************************************************** 3155 * CoCreateInstance [OLE32.@] 3156 * 3157 * Creates an instance of the specified class. 3158 * 3159 * PARAMS 3160 * rclsid [I] Class ID to create an instance of. 3161 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object. 3162 * dwClsContext [I] Flags to restrict the location of the created instance. 3163 * iid [I] The ID of the interface of the instance to return. 3164 * ppv [O] On returns, contains a pointer to the specified interface of the instance. 3165 * 3166 * RETURNS 3167 * Success: S_OK 3168 * Failure: HRESULT code. 3169 * 3170 * NOTES 3171 * The dwClsContext parameter can be one or more of the following: 3172 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL. 3173 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process. 3174 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process. 3175 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine. 3176 * 3177 * Aggregation is the concept of deferring the IUnknown of an object to another 3178 * object. This allows a separate object to behave as though it was part of 3179 * the object and to allow this the pUnkOuter parameter can be set. Note that 3180 * not all objects support having an outer of unknown. 3181 * 3182 * SEE ALSO 3183 * CoGetClassObject() 3184 */ 3185 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance( 3186 REFCLSID rclsid, 3187 LPUNKNOWN pUnkOuter, 3188 DWORD dwClsContext, 3189 REFIID iid, 3190 LPVOID *ppv) 3191 { 3192 MULTI_QI multi_qi = { iid }; 3193 HRESULT hres; 3194 3195 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid), 3196 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv); 3197 3198 if (ppv==0) 3199 return E_POINTER; 3200 3201 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi); 3202 *ppv = multi_qi.pItf; 3203 return hres; 3204 } 3205 3206 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr) 3207 { 3208 ULONG i; 3209 3210 for (i = 0; i < count; i++) 3211 { 3212 mqi[i].pItf = NULL; 3213 mqi[i].hr = hr; 3214 } 3215 } 3216 3217 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk) 3218 { 3219 ULONG index = 0, fetched = 0; 3220 3221 if (include_unk) 3222 { 3223 mqi[0].hr = S_OK; 3224 mqi[0].pItf = unk; 3225 index = fetched = 1; 3226 } 3227 3228 for (; index < count; index++) 3229 { 3230 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf); 3231 if (mqi[index].hr == S_OK) 3232 fetched++; 3233 } 3234 3235 if (!include_unk) 3236 IUnknown_Release(unk); 3237 3238 if (fetched == 0) 3239 return E_NOINTERFACE; 3240 3241 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES; 3242 } 3243 3244 /*********************************************************************** 3245 * CoCreateInstanceEx [OLE32.@] 3246 */ 3247 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx( 3248 REFCLSID rclsid, 3249 LPUNKNOWN pUnkOuter, 3250 DWORD dwClsContext, 3251 COSERVERINFO* pServerInfo, 3252 ULONG cmq, 3253 MULTI_QI* pResults) 3254 { 3255 IUnknown *unk = NULL; 3256 IClassFactory *cf; 3257 APARTMENT *apt; 3258 CLSID clsid; 3259 HRESULT hres; 3260 3261 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults); 3262 3263 if (!cmq || !pResults) 3264 return E_INVALIDARG; 3265 3266 if (pServerInfo) 3267 FIXME("() non-NULL pServerInfo not supported!\n"); 3268 3269 init_multi_qi(cmq, pResults, E_NOINTERFACE); 3270 3271 hres = CoGetTreatAsClass(rclsid, &clsid); 3272 if(FAILED(hres)) 3273 clsid = *rclsid; 3274 3275 if (!(apt = COM_CurrentApt())) 3276 { 3277 if (!(apt = apartment_find_multi_threaded())) 3278 { 3279 ERR("apartment not initialised\n"); 3280 return CO_E_NOTINITIALIZED; 3281 } 3282 apartment_release(apt); 3283 } 3284 3285 /* 3286 * The Standard Global Interface Table (GIT) object is a process-wide singleton. 3287 */ 3288 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable)) 3289 { 3290 IGlobalInterfaceTable *git = get_std_git(); 3291 TRACE("Retrieving GIT\n"); 3292 return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE); 3293 } 3294 3295 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) { 3296 hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk); 3297 if (FAILED(hres)) 3298 return hres; 3299 return return_multi_qi(unk, cmq, pResults, TRUE); 3300 } 3301 3302 /* 3303 * Get a class factory to construct the object we want. 3304 */ 3305 hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf); 3306 if (FAILED(hres)) 3307 return hres; 3308 3309 /* 3310 * Create the object and don't forget to release the factory 3311 */ 3312 hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk); 3313 IClassFactory_Release(cf); 3314 if (FAILED(hres)) 3315 { 3316 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter) 3317 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid)); 3318 else 3319 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", 3320 debugstr_guid(pResults[0].pIID), 3321 debugstr_guid(&clsid),hres); 3322 return hres; 3323 } 3324 3325 return return_multi_qi(unk, cmq, pResults, TRUE); 3326 } 3327 3328 /*********************************************************************** 3329 * CoGetInstanceFromFile [OLE32.@] 3330 */ 3331 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile( 3332 COSERVERINFO *server_info, 3333 CLSID *rclsid, 3334 IUnknown *outer, 3335 DWORD cls_context, 3336 DWORD grfmode, 3337 OLECHAR *filename, 3338 DWORD count, 3339 MULTI_QI *results 3340 ) 3341 { 3342 IPersistFile *pf = NULL; 3343 IUnknown* unk = NULL; 3344 CLSID clsid; 3345 HRESULT hr; 3346 3347 if (count == 0 || !results) 3348 return E_INVALIDARG; 3349 3350 if (server_info) 3351 FIXME("() non-NULL server_info not supported\n"); 3352 3353 init_multi_qi(count, results, E_NOINTERFACE); 3354 3355 /* optionally get CLSID from a file */ 3356 if (!rclsid) 3357 { 3358 hr = GetClassFile(filename, &clsid); 3359 if (FAILED(hr)) 3360 { 3361 ERR("failed to get CLSID from a file\n"); 3362 return hr; 3363 } 3364 3365 rclsid = &clsid; 3366 } 3367 3368 hr = CoCreateInstance(rclsid, 3369 outer, 3370 cls_context, 3371 &IID_IUnknown, 3372 (void**)&unk); 3373 3374 if (hr != S_OK) 3375 { 3376 init_multi_qi(count, results, hr); 3377 return hr; 3378 } 3379 3380 /* init from file */ 3381 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf); 3382 if (FAILED(hr)) 3383 { 3384 init_multi_qi(count, results, hr); 3385 IUnknown_Release(unk); 3386 return hr; 3387 } 3388 3389 hr = IPersistFile_Load(pf, filename, grfmode); 3390 IPersistFile_Release(pf); 3391 if (SUCCEEDED(hr)) 3392 return return_multi_qi(unk, count, results, FALSE); 3393 else 3394 { 3395 init_multi_qi(count, results, hr); 3396 IUnknown_Release(unk); 3397 return hr; 3398 } 3399 } 3400 3401 /*********************************************************************** 3402 * CoGetInstanceFromIStorage [OLE32.@] 3403 */ 3404 HRESULT WINAPI CoGetInstanceFromIStorage( 3405 COSERVERINFO *server_info, 3406 CLSID *rclsid, 3407 IUnknown *outer, 3408 DWORD cls_context, 3409 IStorage *storage, 3410 DWORD count, 3411 MULTI_QI *results 3412 ) 3413 { 3414 IPersistStorage *ps = NULL; 3415 IUnknown* unk = NULL; 3416 STATSTG stat; 3417 HRESULT hr; 3418 3419 if (count == 0 || !results || !storage) 3420 return E_INVALIDARG; 3421 3422 if (server_info) 3423 FIXME("() non-NULL server_info not supported\n"); 3424 3425 init_multi_qi(count, results, E_NOINTERFACE); 3426 3427 /* optionally get CLSID from a file */ 3428 if (!rclsid) 3429 { 3430 memset(&stat.clsid, 0, sizeof(stat.clsid)); 3431 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME); 3432 if (FAILED(hr)) 3433 { 3434 ERR("failed to get CLSID from a file\n"); 3435 return hr; 3436 } 3437 3438 rclsid = &stat.clsid; 3439 } 3440 3441 hr = CoCreateInstance(rclsid, 3442 outer, 3443 cls_context, 3444 &IID_IUnknown, 3445 (void**)&unk); 3446 3447 if (hr != S_OK) 3448 return hr; 3449 3450 /* init from IStorage */ 3451 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps); 3452 if (FAILED(hr)) 3453 ERR("failed to get IPersistStorage\n"); 3454 3455 if (ps) 3456 { 3457 IPersistStorage_Load(ps, storage); 3458 IPersistStorage_Release(ps); 3459 } 3460 3461 return return_multi_qi(unk, count, results, FALSE); 3462 } 3463 3464 /*********************************************************************** 3465 * CoLoadLibrary (OLE32.@) 3466 * 3467 * Loads a library. 3468 * 3469 * PARAMS 3470 * lpszLibName [I] Path to library. 3471 * bAutoFree [I] Whether the library should automatically be freed. 3472 * 3473 * RETURNS 3474 * Success: Handle to loaded library. 3475 * Failure: NULL. 3476 * 3477 * SEE ALSO 3478 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries 3479 */ 3480 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree) 3481 { 3482 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree); 3483 3484 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH); 3485 } 3486 3487 /*********************************************************************** 3488 * CoFreeLibrary [OLE32.@] 3489 * 3490 * Unloads a library from memory. 3491 * 3492 * PARAMS 3493 * hLibrary [I] Handle to library to unload. 3494 * 3495 * RETURNS 3496 * Nothing 3497 * 3498 * SEE ALSO 3499 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries 3500 */ 3501 void WINAPI CoFreeLibrary(HINSTANCE hLibrary) 3502 { 3503 FreeLibrary(hLibrary); 3504 } 3505 3506 3507 /*********************************************************************** 3508 * CoFreeAllLibraries [OLE32.@] 3509 * 3510 * Function for backwards compatibility only. Does nothing. 3511 * 3512 * RETURNS 3513 * Nothing. 3514 * 3515 * SEE ALSO 3516 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries 3517 */ 3518 void WINAPI CoFreeAllLibraries(void) 3519 { 3520 /* NOP */ 3521 } 3522 3523 /*********************************************************************** 3524 * CoFreeUnusedLibrariesEx [OLE32.@] 3525 * 3526 * Frees any previously unused libraries whose delay has expired and marks 3527 * currently unused libraries for unloading. Unused are identified as those that 3528 * return S_OK from their DllCanUnloadNow function. 3529 * 3530 * PARAMS 3531 * dwUnloadDelay [I] Unload delay in milliseconds. 3532 * dwReserved [I] Reserved. Set to 0. 3533 * 3534 * RETURNS 3535 * Nothing. 3536 * 3537 * SEE ALSO 3538 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary 3539 */ 3540 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved) 3541 { 3542 struct apartment *apt = COM_CurrentApt(); 3543 if (!apt) 3544 { 3545 ERR("apartment not initialised\n"); 3546 return; 3547 } 3548 3549 apartment_freeunusedlibraries(apt, dwUnloadDelay); 3550 } 3551 3552 /*********************************************************************** 3553 * CoFreeUnusedLibraries [OLE32.@] 3554 * 3555 * Frees any unused libraries. Unused are identified as those that return 3556 * S_OK from their DllCanUnloadNow function. 3557 * 3558 * RETURNS 3559 * Nothing. 3560 * 3561 * SEE ALSO 3562 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary 3563 */ 3564 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void) 3565 { 3566 CoFreeUnusedLibrariesEx(INFINITE, 0); 3567 } 3568 3569 /*********************************************************************** 3570 * CoFileTimeNow [OLE32.@] 3571 * 3572 * Retrieves the current time in FILETIME format. 3573 * 3574 * PARAMS 3575 * lpFileTime [O] The current time. 3576 * 3577 * RETURNS 3578 * S_OK. 3579 */ 3580 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) 3581 { 3582 GetSystemTimeAsFileTime( lpFileTime ); 3583 return S_OK; 3584 } 3585 3586 /****************************************************************************** 3587 * CoLockObjectExternal [OLE32.@] 3588 * 3589 * Increments or decrements the external reference count of a stub object. 3590 * 3591 * PARAMS 3592 * pUnk [I] Stub object. 3593 * fLock [I] If TRUE then increments the external ref-count, 3594 * otherwise decrements. 3595 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of 3596 * calling CoDisconnectObject. 3597 * 3598 * RETURNS 3599 * Success: S_OK. 3600 * Failure: HRESULT code. 3601 * 3602 * NOTES 3603 * If fLock is TRUE and an object is passed in that doesn't have a stub 3604 * manager then a new stub manager is created for the object. 3605 */ 3606 HRESULT WINAPI CoLockObjectExternal( 3607 LPUNKNOWN pUnk, 3608 BOOL fLock, 3609 BOOL fLastUnlockReleases) 3610 { 3611 struct stub_manager *stubmgr; 3612 struct apartment *apt; 3613 3614 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", 3615 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE"); 3616 3617 apt = COM_CurrentApt(); 3618 if (!apt) return CO_E_NOTINITIALIZED; 3619 3620 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock); 3621 if (!stubmgr) 3622 { 3623 WARN("stub object not found %p\n", pUnk); 3624 /* Note: native is pretty broken here because it just silently 3625 * fails, without returning an appropriate error code, making apps 3626 * think that the object was disconnected, when it actually wasn't */ 3627 return S_OK; 3628 } 3629 3630 if (fLock) 3631 stub_manager_ext_addref(stubmgr, 1, FALSE); 3632 else 3633 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases); 3634 3635 stub_manager_int_release(stubmgr); 3636 return S_OK; 3637 } 3638 3639 /*********************************************************************** 3640 * CoInitializeWOW (OLE32.@) 3641 * 3642 * WOW equivalent of CoInitialize? 3643 * 3644 * PARAMS 3645 * x [I] Unknown. 3646 * y [I] Unknown. 3647 * 3648 * RETURNS 3649 * Unknown. 3650 */ 3651 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) 3652 { 3653 FIXME("(0x%08x,0x%08x),stub!\n",x,y); 3654 return 0; 3655 } 3656 3657 /*********************************************************************** 3658 * CoGetState [OLE32.@] 3659 * 3660 * Retrieves the thread state object previously stored by CoSetState(). 3661 * 3662 * PARAMS 3663 * ppv [I] Address where pointer to object will be stored. 3664 * 3665 * RETURNS 3666 * Success: S_OK. 3667 * Failure: E_OUTOFMEMORY. 3668 * 3669 * NOTES 3670 * Crashes on all invalid ppv addresses, including NULL. 3671 * If the function returns a non-NULL object then the caller must release its 3672 * reference on the object when the object is no longer required. 3673 * 3674 * SEE ALSO 3675 * CoSetState(). 3676 */ 3677 HRESULT WINAPI CoGetState(IUnknown ** ppv) 3678 { 3679 struct oletls *info = COM_CurrentInfo(); 3680 if (!info) return E_OUTOFMEMORY; 3681 3682 *ppv = NULL; 3683 3684 if (info->state) 3685 { 3686 IUnknown_AddRef(info->state); 3687 *ppv = info->state; 3688 TRACE("apt->state=%p\n", info->state); 3689 } 3690 3691 return S_OK; 3692 } 3693 3694 /*********************************************************************** 3695 * CoSetState [OLE32.@] 3696 * 3697 * Sets the thread state object. 3698 * 3699 * PARAMS 3700 * pv [I] Pointer to state object to be stored. 3701 * 3702 * NOTES 3703 * The system keeps a reference on the object while the object stored. 3704 * 3705 * RETURNS 3706 * Success: S_OK. 3707 * Failure: E_OUTOFMEMORY. 3708 */ 3709 HRESULT WINAPI CoSetState(IUnknown * pv) 3710 { 3711 struct oletls *info = COM_CurrentInfo(); 3712 if (!info) return E_OUTOFMEMORY; 3713 3714 if (pv) IUnknown_AddRef(pv); 3715 3716 if (info->state) 3717 { 3718 TRACE("-- release %p now\n", info->state); 3719 IUnknown_Release(info->state); 3720 } 3721 3722 info->state = pv; 3723 3724 return S_OK; 3725 } 3726 3727 3728 /****************************************************************************** 3729 * CoTreatAsClass [OLE32.@] 3730 * 3731 * Sets the TreatAs value of a class. 3732 * 3733 * PARAMS 3734 * clsidOld [I] Class to set TreatAs value on. 3735 * clsidNew [I] The class the clsidOld should be treated as. 3736 * 3737 * RETURNS 3738 * Success: S_OK. 3739 * Failure: HRESULT code. 3740 * 3741 * SEE ALSO 3742 * CoGetTreatAsClass 3743 */ 3744 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew) 3745 { 3746 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0}; 3747 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0}; 3748 HKEY hkey = NULL; 3749 WCHAR szClsidNew[CHARS_IN_GUID]; 3750 HRESULT res = S_OK; 3751 WCHAR auto_treat_as[CHARS_IN_GUID]; 3752 LONG auto_treat_as_size = sizeof(auto_treat_as); 3753 CLSID id; 3754 3755 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey); 3756 if (FAILED(res)) 3757 goto done; 3758 3759 if (IsEqualGUID( clsidOld, clsidNew )) 3760 { 3761 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) && 3762 CLSIDFromString(auto_treat_as, &id) == S_OK) 3763 { 3764 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as))) 3765 { 3766 res = REGDB_E_WRITEREGDB; 3767 goto done; 3768 } 3769 } 3770 else 3771 { 3772 if(RegDeleteKeyW(hkey, wszTreatAs)) 3773 res = REGDB_E_WRITEREGDB; 3774 goto done; 3775 } 3776 } 3777 else 3778 { 3779 if(IsEqualGUID(clsidNew, &CLSID_NULL)){ 3780 RegDeleteKeyW(hkey, wszTreatAs); 3781 }else{ 3782 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){ 3783 WARN("StringFromGUID2 failed\n"); 3784 res = E_FAIL; 3785 goto done; 3786 } 3787 3788 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){ 3789 WARN("RegSetValue failed\n"); 3790 res = REGDB_E_WRITEREGDB; 3791 goto done; 3792 } 3793 } 3794 } 3795 3796 done: 3797 if (hkey) RegCloseKey(hkey); 3798 return res; 3799 } 3800 3801 /****************************************************************************** 3802 * CoGetTreatAsClass [OLE32.@] 3803 * 3804 * Gets the TreatAs value of a class. 3805 * 3806 * PARAMS 3807 * clsidOld [I] Class to get the TreatAs value of. 3808 * clsidNew [I] The class the clsidOld should be treated as. 3809 * 3810 * RETURNS 3811 * Success: S_OK. 3812 * Failure: HRESULT code. 3813 * 3814 * SEE ALSO 3815 * CoSetTreatAsClass 3816 */ 3817 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew) 3818 { 3819 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0}; 3820 HKEY hkey = NULL; 3821 WCHAR szClsidNew[CHARS_IN_GUID]; 3822 HRESULT res = S_OK; 3823 LONG len = sizeof(szClsidNew); 3824 3825 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew); 3826 3827 if (!clsidOld || !clsidNew) 3828 return E_INVALIDARG; 3829 3830 *clsidNew = *clsidOld; /* copy over old value */ 3831 3832 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey); 3833 if (FAILED(res)) 3834 { 3835 res = S_FALSE; 3836 goto done; 3837 } 3838 if (RegQueryValueW(hkey, NULL, szClsidNew, &len)) 3839 { 3840 res = S_FALSE; 3841 goto done; 3842 } 3843 res = CLSIDFromString(szClsidNew,clsidNew); 3844 if (FAILED(res)) 3845 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res); 3846 done: 3847 if (hkey) RegCloseKey(hkey); 3848 return res; 3849 } 3850 3851 /****************************************************************************** 3852 * CoGetCurrentProcess [OLE32.@] 3853 * 3854 * Gets the current process ID. 3855 * 3856 * RETURNS 3857 * The current process ID. 3858 * 3859 * NOTES 3860 * Is DWORD really the correct return type for this function? 3861 */ 3862 DWORD WINAPI CoGetCurrentProcess(void) 3863 { 3864 return GetCurrentProcessId(); 3865 } 3866 3867 /*********************************************************************** 3868 * CoGetCurrentLogicalThreadId [OLE32.@] 3869 */ 3870 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id) 3871 { 3872 TRACE("(%p)\n", id); 3873 3874 if (!id) 3875 return E_INVALIDARG; 3876 3877 *id = COM_CurrentCausalityId(); 3878 return S_OK; 3879 } 3880 3881 /****************************************************************************** 3882 * CoRegisterMessageFilter [OLE32.@] 3883 * 3884 * Registers a message filter. 3885 * 3886 * PARAMS 3887 * lpMessageFilter [I] Pointer to interface. 3888 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL. 3889 * 3890 * RETURNS 3891 * Success: S_OK. 3892 * Failure: HRESULT code. 3893 * 3894 * NOTES 3895 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL 3896 * lpMessageFilter removes the message filter. 3897 * 3898 * If lplpMessageFilter is not NULL the previous message filter will be 3899 * returned in the memory pointer to this parameter and the caller is 3900 * responsible for releasing the object. 3901 * 3902 * The current thread be in an apartment otherwise the function will crash. 3903 */ 3904 HRESULT WINAPI CoRegisterMessageFilter( 3905 LPMESSAGEFILTER lpMessageFilter, 3906 LPMESSAGEFILTER *lplpMessageFilter) 3907 { 3908 struct apartment *apt; 3909 IMessageFilter *lpOldMessageFilter; 3910 3911 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter); 3912 3913 apt = COM_CurrentApt(); 3914 3915 /* can't set a message filter in a multi-threaded apartment */ 3916 if (!apt || apt->multi_threaded) 3917 { 3918 WARN("can't set message filter in MTA or uninitialized apt\n"); 3919 return CO_E_NOT_SUPPORTED; 3920 } 3921 3922 if (lpMessageFilter) 3923 IMessageFilter_AddRef(lpMessageFilter); 3924 3925 EnterCriticalSection(&apt->cs); 3926 3927 lpOldMessageFilter = apt->filter; 3928 apt->filter = lpMessageFilter; 3929 3930 LeaveCriticalSection(&apt->cs); 3931 3932 if (lplpMessageFilter) 3933 *lplpMessageFilter = lpOldMessageFilter; 3934 else if (lpOldMessageFilter) 3935 IMessageFilter_Release(lpOldMessageFilter); 3936 3937 return S_OK; 3938 } 3939 3940 /*********************************************************************** 3941 * CoIsOle1Class [OLE32.@] 3942 * 3943 * Determines whether the specified class an OLE v1 class. 3944 * 3945 * PARAMS 3946 * clsid [I] Class to test. 3947 * 3948 * RETURNS 3949 * TRUE if the class is an OLE v1 class, or FALSE otherwise. 3950 */ 3951 BOOL WINAPI CoIsOle1Class(REFCLSID clsid) 3952 { 3953 FIXME("%s\n", debugstr_guid(clsid)); 3954 return FALSE; 3955 } 3956 3957 /*********************************************************************** 3958 * IsEqualGUID [OLE32.@] 3959 * 3960 * Compares two Unique Identifiers. 3961 * 3962 * PARAMS 3963 * rguid1 [I] The first GUID to compare. 3964 * rguid2 [I] The other GUID to compare. 3965 * 3966 * RETURNS 3967 * TRUE if equal 3968 */ 3969 #undef IsEqualGUID 3970 BOOL WINAPI IsEqualGUID( 3971 REFGUID rguid1, 3972 REFGUID rguid2) 3973 { 3974 return !memcmp(rguid1,rguid2,sizeof(GUID)); 3975 } 3976 3977 /*********************************************************************** 3978 * CoInitializeSecurity [OLE32.@] 3979 */ 3980 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc, 3981 SOLE_AUTHENTICATION_SERVICE* asAuthSvc, 3982 void* pReserved1, DWORD dwAuthnLevel, 3983 DWORD dwImpLevel, void* pReserved2, 3984 DWORD dwCapabilities, void* pReserved3) 3985 { 3986 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc, 3987 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2, 3988 dwCapabilities, pReserved3); 3989 return S_OK; 3990 } 3991 3992 /*********************************************************************** 3993 * CoSuspendClassObjects [OLE32.@] 3994 * 3995 * Suspends all registered class objects to prevent further requests coming in 3996 * for those objects. 3997 * 3998 * RETURNS 3999 * Success: S_OK. 4000 * Failure: HRESULT code. 4001 */ 4002 HRESULT WINAPI CoSuspendClassObjects(void) 4003 { 4004 FIXME("\n"); 4005 return S_OK; 4006 } 4007 4008 /*********************************************************************** 4009 * CoAddRefServerProcess [OLE32.@] 4010 * 4011 * Helper function for incrementing the reference count of a local-server 4012 * process. 4013 * 4014 * RETURNS 4015 * New reference count. 4016 * 4017 * SEE ALSO 4018 * CoReleaseServerProcess(). 4019 */ 4020 ULONG WINAPI CoAddRefServerProcess(void) 4021 { 4022 ULONG refs; 4023 4024 TRACE("\n"); 4025 4026 EnterCriticalSection(&csRegisteredClassList); 4027 refs = ++s_COMServerProcessReferences; 4028 LeaveCriticalSection(&csRegisteredClassList); 4029 4030 TRACE("refs before: %d\n", refs - 1); 4031 4032 return refs; 4033 } 4034 4035 /*********************************************************************** 4036 * CoReleaseServerProcess [OLE32.@] 4037 * 4038 * Helper function for decrementing the reference count of a local-server 4039 * process. 4040 * 4041 * RETURNS 4042 * New reference count. 4043 * 4044 * NOTES 4045 * When reference count reaches 0, this function suspends all registered 4046 * classes so no new connections are accepted. 4047 * 4048 * SEE ALSO 4049 * CoAddRefServerProcess(), CoSuspendClassObjects(). 4050 */ 4051 ULONG WINAPI CoReleaseServerProcess(void) 4052 { 4053 ULONG refs; 4054 4055 TRACE("\n"); 4056 4057 EnterCriticalSection(&csRegisteredClassList); 4058 4059 refs = --s_COMServerProcessReferences; 4060 /* FIXME: if (!refs) COM_SuspendClassObjects(); */ 4061 4062 LeaveCriticalSection(&csRegisteredClassList); 4063 4064 TRACE("refs after: %d\n", refs); 4065 4066 return refs; 4067 } 4068 4069 /*********************************************************************** 4070 * CoIsHandlerConnected [OLE32.@] 4071 * 4072 * Determines whether a proxy is connected to a remote stub. 4073 * 4074 * PARAMS 4075 * pUnk [I] Pointer to object that may or may not be connected. 4076 * 4077 * RETURNS 4078 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or 4079 * FALSE otherwise. 4080 */ 4081 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk) 4082 { 4083 FIXME("%p\n", pUnk); 4084 4085 return TRUE; 4086 } 4087 4088 /*********************************************************************** 4089 * CoAllowSetForegroundWindow [OLE32.@] 4090 * 4091 */ 4092 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved) 4093 { 4094 FIXME("(%p, %p): stub\n", pUnk, pvReserved); 4095 return S_OK; 4096 } 4097 4098 /*********************************************************************** 4099 * CoQueryProxyBlanket [OLE32.@] 4100 * 4101 * Retrieves the security settings being used by a proxy. 4102 * 4103 * PARAMS 4104 * pProxy [I] Pointer to the proxy object. 4105 * pAuthnSvc [O] The type of authentication service. 4106 * pAuthzSvc [O] The type of authorization service. 4107 * ppServerPrincName [O] Optional. The server prinicple name. 4108 * pAuthnLevel [O] The authentication level. 4109 * pImpLevel [O] The impersonation level. 4110 * ppAuthInfo [O] Information specific to the authorization/authentication service. 4111 * pCapabilities [O] Flags affecting the security behaviour. 4112 * 4113 * RETURNS 4114 * Success: S_OK. 4115 * Failure: HRESULT code. 4116 * 4117 * SEE ALSO 4118 * CoCopyProxy, CoSetProxyBlanket. 4119 */ 4120 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc, 4121 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel, 4122 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities) 4123 { 4124 IClientSecurity *pCliSec; 4125 HRESULT hr; 4126 4127 TRACE("%p\n", pProxy); 4128 4129 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 4130 if (SUCCEEDED(hr)) 4131 { 4132 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc, 4133 pAuthzSvc, ppServerPrincName, 4134 pAuthnLevel, pImpLevel, ppAuthInfo, 4135 pCapabilities); 4136 IClientSecurity_Release(pCliSec); 4137 } 4138 4139 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 4140 return hr; 4141 } 4142 4143 /*********************************************************************** 4144 * CoSetProxyBlanket [OLE32.@] 4145 * 4146 * Sets the security settings for a proxy. 4147 * 4148 * PARAMS 4149 * pProxy [I] Pointer to the proxy object. 4150 * AuthnSvc [I] The type of authentication service. 4151 * AuthzSvc [I] The type of authorization service. 4152 * pServerPrincName [I] The server prinicple name. 4153 * AuthnLevel [I] The authentication level. 4154 * ImpLevel [I] The impersonation level. 4155 * pAuthInfo [I] Information specific to the authorization/authentication service. 4156 * Capabilities [I] Flags affecting the security behaviour. 4157 * 4158 * RETURNS 4159 * Success: S_OK. 4160 * Failure: HRESULT code. 4161 * 4162 * SEE ALSO 4163 * CoQueryProxyBlanket, CoCopyProxy. 4164 */ 4165 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc, 4166 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel, 4167 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities) 4168 { 4169 IClientSecurity *pCliSec; 4170 HRESULT hr; 4171 4172 TRACE("%p\n", pProxy); 4173 4174 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 4175 if (SUCCEEDED(hr)) 4176 { 4177 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc, 4178 AuthzSvc, pServerPrincName, 4179 AuthnLevel, ImpLevel, pAuthInfo, 4180 Capabilities); 4181 IClientSecurity_Release(pCliSec); 4182 } 4183 4184 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 4185 return hr; 4186 } 4187 4188 /*********************************************************************** 4189 * CoCopyProxy [OLE32.@] 4190 * 4191 * Copies a proxy. 4192 * 4193 * PARAMS 4194 * pProxy [I] Pointer to the proxy object. 4195 * ppCopy [O] Copy of the proxy. 4196 * 4197 * RETURNS 4198 * Success: S_OK. 4199 * Failure: HRESULT code. 4200 * 4201 * SEE ALSO 4202 * CoQueryProxyBlanket, CoSetProxyBlanket. 4203 */ 4204 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy) 4205 { 4206 IClientSecurity *pCliSec; 4207 HRESULT hr; 4208 4209 TRACE("%p\n", pProxy); 4210 4211 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 4212 if (SUCCEEDED(hr)) 4213 { 4214 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy); 4215 IClientSecurity_Release(pCliSec); 4216 } 4217 4218 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 4219 return hr; 4220 } 4221 4222 4223 /*********************************************************************** 4224 * CoGetCallContext [OLE32.@] 4225 * 4226 * Gets the context of the currently executing server call in the current 4227 * thread. 4228 * 4229 * PARAMS 4230 * riid [I] Context interface to return. 4231 * ppv [O] Pointer to memory that will receive the context on return. 4232 * 4233 * RETURNS 4234 * Success: S_OK. 4235 * Failure: HRESULT code. 4236 */ 4237 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv) 4238 { 4239 struct oletls *info = COM_CurrentInfo(); 4240 4241 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 4242 4243 if (!info) 4244 return E_OUTOFMEMORY; 4245 4246 if (!info->call_state) 4247 return RPC_E_CALL_COMPLETE; 4248 4249 return IUnknown_QueryInterface(info->call_state, riid, ppv); 4250 } 4251 4252 /*********************************************************************** 4253 * CoSwitchCallContext [OLE32.@] 4254 * 4255 * Switches the context of the currently executing server call in the current 4256 * thread. 4257 * 4258 * PARAMS 4259 * pObject [I] Pointer to new context object 4260 * ppOldObject [O] Pointer to memory that will receive old context object pointer 4261 * 4262 * RETURNS 4263 * Success: S_OK. 4264 * Failure: HRESULT code. 4265 */ 4266 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject) 4267 { 4268 struct oletls *info = COM_CurrentInfo(); 4269 4270 TRACE("(%p, %p)\n", pObject, ppOldObject); 4271 4272 if (!info) 4273 return E_OUTOFMEMORY; 4274 4275 *ppOldObject = info->call_state; 4276 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */ 4277 4278 return S_OK; 4279 } 4280 4281 /*********************************************************************** 4282 * CoQueryClientBlanket [OLE32.@] 4283 * 4284 * Retrieves the authentication information about the client of the currently 4285 * executing server call in the current thread. 4286 * 4287 * PARAMS 4288 * pAuthnSvc [O] Optional. The type of authentication service. 4289 * pAuthzSvc [O] Optional. The type of authorization service. 4290 * pServerPrincName [O] Optional. The server prinicple name. 4291 * pAuthnLevel [O] Optional. The authentication level. 4292 * pImpLevel [O] Optional. The impersonation level. 4293 * pPrivs [O] Optional. Information about the privileges of the client. 4294 * pCapabilities [IO] Optional. Flags affecting the security behaviour. 4295 * 4296 * RETURNS 4297 * Success: S_OK. 4298 * Failure: HRESULT code. 4299 * 4300 * SEE ALSO 4301 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext. 4302 */ 4303 HRESULT WINAPI CoQueryClientBlanket( 4304 DWORD *pAuthnSvc, 4305 DWORD *pAuthzSvc, 4306 OLECHAR **pServerPrincName, 4307 DWORD *pAuthnLevel, 4308 DWORD *pImpLevel, 4309 RPC_AUTHZ_HANDLE *pPrivs, 4310 DWORD *pCapabilities) 4311 { 4312 IServerSecurity *pSrvSec; 4313 HRESULT hr; 4314 4315 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n", 4316 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel, 4317 pPrivs, pCapabilities); 4318 4319 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 4320 if (SUCCEEDED(hr)) 4321 { 4322 hr = IServerSecurity_QueryBlanket( 4323 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, 4324 pImpLevel, pPrivs, pCapabilities); 4325 IServerSecurity_Release(pSrvSec); 4326 } 4327 4328 return hr; 4329 } 4330 4331 /*********************************************************************** 4332 * CoImpersonateClient [OLE32.@] 4333 * 4334 * Impersonates the client of the currently executing server call in the 4335 * current thread. 4336 * 4337 * PARAMS 4338 * None. 4339 * 4340 * RETURNS 4341 * Success: S_OK. 4342 * Failure: HRESULT code. 4343 * 4344 * NOTES 4345 * If this function fails then the current thread will not be impersonating 4346 * the client and all actions will take place on behalf of the server. 4347 * Therefore, it is important to check the return value from this function. 4348 * 4349 * SEE ALSO 4350 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext. 4351 */ 4352 HRESULT WINAPI CoImpersonateClient(void) 4353 { 4354 IServerSecurity *pSrvSec; 4355 HRESULT hr; 4356 4357 TRACE("\n"); 4358 4359 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 4360 if (SUCCEEDED(hr)) 4361 { 4362 hr = IServerSecurity_ImpersonateClient(pSrvSec); 4363 IServerSecurity_Release(pSrvSec); 4364 } 4365 4366 return hr; 4367 } 4368 4369 /*********************************************************************** 4370 * CoRevertToSelf [OLE32.@] 4371 * 4372 * Ends the impersonation of the client of the currently executing server 4373 * call in the current thread. 4374 * 4375 * PARAMS 4376 * None. 4377 * 4378 * RETURNS 4379 * Success: S_OK. 4380 * Failure: HRESULT code. 4381 * 4382 * SEE ALSO 4383 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext. 4384 */ 4385 HRESULT WINAPI CoRevertToSelf(void) 4386 { 4387 IServerSecurity *pSrvSec; 4388 HRESULT hr; 4389 4390 TRACE("\n"); 4391 4392 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 4393 if (SUCCEEDED(hr)) 4394 { 4395 hr = IServerSecurity_RevertToSelf(pSrvSec); 4396 IServerSecurity_Release(pSrvSec); 4397 } 4398 4399 return hr; 4400 } 4401 4402 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg) 4403 { 4404 /* first try to retrieve messages for incoming COM calls to the apartment window */ 4405 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) || 4406 /* next retrieve other messages necessary for the app to remain responsive */ 4407 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) || 4408 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD); 4409 } 4410 4411 /*********************************************************************** 4412 * CoWaitForMultipleHandles [OLE32.@] 4413 * 4414 * Waits for one or more handles to become signaled. 4415 * 4416 * PARAMS 4417 * dwFlags [I] Flags. See notes. 4418 * dwTimeout [I] Timeout in milliseconds. 4419 * cHandles [I] Number of handles pointed to by pHandles. 4420 * pHandles [I] Handles to wait for. 4421 * lpdwindex [O] Index of handle that was signaled. 4422 * 4423 * RETURNS 4424 * Success: S_OK. 4425 * Failure: RPC_S_CALLPENDING on timeout. 4426 * 4427 * NOTES 4428 * 4429 * The dwFlags parameter can be zero or more of the following: 4430 *| COWAIT_WAITALL - Wait for all of the handles to become signaled. 4431 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait. 4432 * 4433 * SEE ALSO 4434 * MsgWaitForMultipleObjects, WaitForMultipleObjects. 4435 */ 4436 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, 4437 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex) 4438 { 4439 HRESULT hr = S_OK; 4440 DWORD start_time = GetTickCount(); 4441 APARTMENT *apt = COM_CurrentApt(); 4442 BOOL message_loop = apt && !apt->multi_threaded; 4443 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0; 4444 4445 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles, 4446 pHandles, lpdwindex); 4447 4448 if (!lpdwindex) 4449 return E_INVALIDARG; 4450 4451 *lpdwindex = 0; 4452 4453 if (!pHandles) 4454 return E_INVALIDARG; 4455 4456 if (!cHandles) 4457 return RPC_E_NO_SYNC; 4458 4459 while (TRUE) 4460 { 4461 DWORD now = GetTickCount(); 4462 DWORD res; 4463 4464 if (now - start_time > dwTimeout) 4465 { 4466 hr = RPC_S_CALLPENDING; 4467 break; 4468 } 4469 4470 if (message_loop) 4471 { 4472 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) | 4473 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0); 4474 4475 TRACE("waiting for rpc completion or window message\n"); 4476 4477 res = WAIT_TIMEOUT; 4478 4479 if (check_apc) 4480 { 4481 res = WaitForMultipleObjectsEx(cHandles, pHandles, 4482 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE); 4483 check_apc = FALSE; 4484 } 4485 4486 if (res == WAIT_TIMEOUT) 4487 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles, 4488 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, 4489 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags); 4490 4491 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */ 4492 { 4493 MSG msg; 4494 int count = 0; 4495 4496 /* call message filter */ 4497 4498 if (COM_CurrentApt()->filter) 4499 { 4500 PENDINGTYPE pendingtype = 4501 COM_CurrentInfo()->pending_call_count_server ? 4502 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL; 4503 DWORD be_handled = IMessageFilter_MessagePending( 4504 COM_CurrentApt()->filter, 0 /* FIXME */, 4505 now - start_time, pendingtype); 4506 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled); 4507 switch (be_handled) 4508 { 4509 case PENDINGMSG_CANCELCALL: 4510 WARN("call canceled\n"); 4511 hr = RPC_E_CALL_CANCELED; 4512 break; 4513 case PENDINGMSG_WAITNOPROCESS: 4514 case PENDINGMSG_WAITDEFPROCESS: 4515 default: 4516 /* FIXME: MSDN is very vague about the difference 4517 * between WAITNOPROCESS and WAITDEFPROCESS - there 4518 * appears to be none, so it is possibly a left-over 4519 * from the 16-bit world. */ 4520 break; 4521 } 4522 } 4523 4524 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever, 4525 * so after processing 100 messages we go back to checking the wait handles */ 4526 while (count++ < 100 && COM_PeekMessage(apt, &msg)) 4527 { 4528 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message); 4529 TranslateMessage(&msg); 4530 DispatchMessageW(&msg); 4531 if (msg.message == WM_QUIT) 4532 { 4533 TRACE("resending WM_QUIT to outer message loop\n"); 4534 PostQuitMessage(msg.wParam); 4535 /* no longer need to process messages */ 4536 message_loop = FALSE; 4537 break; 4538 } 4539 } 4540 continue; 4541 } 4542 } 4543 else 4544 { 4545 TRACE("waiting for rpc completion\n"); 4546 4547 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0, 4548 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, 4549 (dwFlags & COWAIT_ALERTABLE) != 0); 4550 } 4551 4552 switch (res) 4553 { 4554 case WAIT_TIMEOUT: 4555 hr = RPC_S_CALLPENDING; 4556 break; 4557 case WAIT_FAILED: 4558 hr = HRESULT_FROM_WIN32( GetLastError() ); 4559 break; 4560 default: 4561 *lpdwindex = res; 4562 break; 4563 } 4564 break; 4565 } 4566 TRACE("-- 0x%08x\n", hr); 4567 return hr; 4568 } 4569 4570 4571 /*********************************************************************** 4572 * CoGetObject [OLE32.@] 4573 * 4574 * Gets the object named by converting the name to a moniker and binding to it. 4575 * 4576 * PARAMS 4577 * pszName [I] String representing the object. 4578 * pBindOptions [I] Parameters affecting the binding to the named object. 4579 * riid [I] Interface to bind to on the objecct. 4580 * ppv [O] On output, the interface riid of the object represented 4581 * by pszName. 4582 * 4583 * RETURNS 4584 * Success: S_OK. 4585 * Failure: HRESULT code. 4586 * 4587 * SEE ALSO 4588 * MkParseDisplayName. 4589 */ 4590 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions, 4591 REFIID riid, void **ppv) 4592 { 4593 IBindCtx *pbc; 4594 HRESULT hr; 4595 4596 *ppv = NULL; 4597 4598 hr = CreateBindCtx(0, &pbc); 4599 if (SUCCEEDED(hr)) 4600 { 4601 if (pBindOptions) 4602 hr = IBindCtx_SetBindOptions(pbc, pBindOptions); 4603 4604 if (SUCCEEDED(hr)) 4605 { 4606 ULONG chEaten; 4607 IMoniker *pmk; 4608 4609 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk); 4610 if (SUCCEEDED(hr)) 4611 { 4612 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv); 4613 IMoniker_Release(pmk); 4614 } 4615 } 4616 4617 IBindCtx_Release(pbc); 4618 } 4619 return hr; 4620 } 4621 4622 /*********************************************************************** 4623 * CoRegisterChannelHook [OLE32.@] 4624 * 4625 * Registers a process-wide hook that is called during ORPC calls. 4626 * 4627 * PARAMS 4628 * guidExtension [I] GUID of the channel hook to register. 4629 * pChannelHook [I] Channel hook object to register. 4630 * 4631 * RETURNS 4632 * Success: S_OK. 4633 * Failure: HRESULT code. 4634 */ 4635 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook) 4636 { 4637 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook); 4638 4639 return RPC_RegisterChannelHook(guidExtension, pChannelHook); 4640 } 4641 4642 typedef struct Context 4643 { 4644 IComThreadingInfo IComThreadingInfo_iface; 4645 IContextCallback IContextCallback_iface; 4646 IObjContext IObjContext_iface; 4647 LONG refs; 4648 } Context; 4649 4650 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface ) 4651 { 4652 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface); 4653 } 4654 4655 static inline Context *impl_from_IContextCallback( IContextCallback *iface ) 4656 { 4657 return CONTAINING_RECORD(iface, Context, IContextCallback_iface); 4658 } 4659 4660 static inline Context *impl_from_IObjContext( IObjContext *iface ) 4661 { 4662 return CONTAINING_RECORD(iface, Context, IObjContext_iface); 4663 } 4664 4665 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv) 4666 { 4667 *ppv = NULL; 4668 4669 if (IsEqualIID(riid, &IID_IComThreadingInfo) || 4670 IsEqualIID(riid, &IID_IUnknown)) 4671 { 4672 *ppv = &iface->IComThreadingInfo_iface; 4673 } 4674 else if (IsEqualIID(riid, &IID_IContextCallback)) 4675 { 4676 *ppv = &iface->IContextCallback_iface; 4677 } 4678 else if (IsEqualIID(riid, &IID_IObjContext)) 4679 { 4680 *ppv = &iface->IObjContext_iface; 4681 } 4682 4683 if (*ppv) 4684 { 4685 IUnknown_AddRef((IUnknown*)*ppv); 4686 return S_OK; 4687 } 4688 4689 FIXME("interface not implemented %s\n", debugstr_guid(riid)); 4690 return E_NOINTERFACE; 4691 } 4692 4693 static ULONG Context_AddRef(Context *This) 4694 { 4695 return InterlockedIncrement(&This->refs); 4696 } 4697 4698 static ULONG Context_Release(Context *This) 4699 { 4700 /* Context instance is initially created with CoGetContextToken() with refcount set to 0, 4701 releasing context while refcount is at 0 destroys it. */ 4702 if (!This->refs) 4703 { 4704 HeapFree(GetProcessHeap(), 0, This); 4705 return 0; 4706 } 4707 4708 return InterlockedDecrement(&This->refs); 4709 } 4710 4711 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv) 4712 { 4713 Context *This = impl_from_IComThreadingInfo(iface); 4714 return Context_QueryInterface(This, riid, ppv); 4715 } 4716 4717 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface) 4718 { 4719 Context *This = impl_from_IComThreadingInfo(iface); 4720 return Context_AddRef(This); 4721 } 4722 4723 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface) 4724 { 4725 Context *This = impl_from_IComThreadingInfo(iface); 4726 return Context_Release(This); 4727 } 4728 4729 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype) 4730 { 4731 APTTYPEQUALIFIER qualifier; 4732 4733 TRACE("(%p)\n", apttype); 4734 4735 return CoGetApartmentType(apttype, &qualifier); 4736 } 4737 4738 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype) 4739 { 4740 APTTYPEQUALIFIER qualifier; 4741 APTTYPE apttype; 4742 HRESULT hr; 4743 4744 hr = CoGetApartmentType(&apttype, &qualifier); 4745 if (FAILED(hr)) 4746 return hr; 4747 4748 TRACE("(%p)\n", thdtype); 4749 4750 switch (apttype) 4751 { 4752 case APTTYPE_STA: 4753 case APTTYPE_MAINSTA: 4754 *thdtype = THDTYPE_PROCESSMESSAGES; 4755 break; 4756 default: 4757 *thdtype = THDTYPE_BLOCKMESSAGES; 4758 break; 4759 } 4760 return S_OK; 4761 } 4762 4763 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id) 4764 { 4765 TRACE("(%p)\n", logical_thread_id); 4766 return CoGetCurrentLogicalThreadId(logical_thread_id); 4767 } 4768 4769 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id) 4770 { 4771 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id)); 4772 return E_NOTIMPL; 4773 } 4774 4775 static const IComThreadingInfoVtbl Context_Threading_Vtbl = 4776 { 4777 Context_CTI_QueryInterface, 4778 Context_CTI_AddRef, 4779 Context_CTI_Release, 4780 Context_CTI_GetCurrentApartmentType, 4781 Context_CTI_GetCurrentThreadType, 4782 Context_CTI_GetCurrentLogicalThreadId, 4783 Context_CTI_SetCurrentLogicalThreadId 4784 }; 4785 4786 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv) 4787 { 4788 Context *This = impl_from_IContextCallback(iface); 4789 return Context_QueryInterface(This, riid, ppv); 4790 } 4791 4792 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface) 4793 { 4794 Context *This = impl_from_IContextCallback(iface); 4795 return Context_AddRef(This); 4796 } 4797 4798 static ULONG WINAPI Context_CC_Release(IContextCallback *iface) 4799 { 4800 Context *This = impl_from_IContextCallback(iface); 4801 return Context_Release(This); 4802 } 4803 4804 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback, 4805 ComCallData *param, REFIID riid, int method, IUnknown *punk) 4806 { 4807 Context *This = impl_from_IContextCallback(iface); 4808 4809 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk); 4810 return E_NOTIMPL; 4811 } 4812 4813 static const IContextCallbackVtbl Context_Callback_Vtbl = 4814 { 4815 Context_CC_QueryInterface, 4816 Context_CC_AddRef, 4817 Context_CC_Release, 4818 Context_CC_ContextCallback 4819 }; 4820 4821 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv) 4822 { 4823 Context *This = impl_from_IObjContext(iface); 4824 return Context_QueryInterface(This, riid, ppv); 4825 } 4826 4827 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface) 4828 { 4829 Context *This = impl_from_IObjContext(iface); 4830 return Context_AddRef(This); 4831 } 4832 4833 static ULONG WINAPI Context_OC_Release(IObjContext *iface) 4834 { 4835 Context *This = impl_from_IObjContext(iface); 4836 return Context_Release(This); 4837 } 4838 4839 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk) 4840 { 4841 Context *This = impl_from_IObjContext(iface); 4842 4843 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk); 4844 return E_NOTIMPL; 4845 } 4846 4847 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid) 4848 { 4849 Context *This = impl_from_IObjContext(iface); 4850 4851 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid)); 4852 return E_NOTIMPL; 4853 } 4854 4855 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk) 4856 { 4857 Context *This = impl_from_IObjContext(iface); 4858 4859 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk); 4860 return E_NOTIMPL; 4861 } 4862 4863 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props) 4864 { 4865 Context *This = impl_from_IObjContext(iface); 4866 4867 FIXME("(%p/%p)->(%p)\n", This, iface, props); 4868 return E_NOTIMPL; 4869 } 4870 4871 static void WINAPI Context_OC_Reserved1(IObjContext *iface) 4872 { 4873 Context *This = impl_from_IObjContext(iface); 4874 FIXME("(%p/%p)\n", This, iface); 4875 } 4876 4877 static void WINAPI Context_OC_Reserved2(IObjContext *iface) 4878 { 4879 Context *This = impl_from_IObjContext(iface); 4880 FIXME("(%p/%p)\n", This, iface); 4881 } 4882 4883 static void WINAPI Context_OC_Reserved3(IObjContext *iface) 4884 { 4885 Context *This = impl_from_IObjContext(iface); 4886 FIXME("(%p/%p)\n", This, iface); 4887 } 4888 4889 static void WINAPI Context_OC_Reserved4(IObjContext *iface) 4890 { 4891 Context *This = impl_from_IObjContext(iface); 4892 FIXME("(%p/%p)\n", This, iface); 4893 } 4894 4895 static void WINAPI Context_OC_Reserved5(IObjContext *iface) 4896 { 4897 Context *This = impl_from_IObjContext(iface); 4898 FIXME("(%p/%p)\n", This, iface); 4899 } 4900 4901 static void WINAPI Context_OC_Reserved6(IObjContext *iface) 4902 { 4903 Context *This = impl_from_IObjContext(iface); 4904 FIXME("(%p/%p)\n", This, iface); 4905 } 4906 4907 static void WINAPI Context_OC_Reserved7(IObjContext *iface) 4908 { 4909 Context *This = impl_from_IObjContext(iface); 4910 FIXME("(%p/%p)\n", This, iface); 4911 } 4912 4913 static const IObjContextVtbl Context_Object_Vtbl = 4914 { 4915 Context_OC_QueryInterface, 4916 Context_OC_AddRef, 4917 Context_OC_Release, 4918 Context_OC_SetProperty, 4919 Context_OC_RemoveProperty, 4920 Context_OC_GetProperty, 4921 Context_OC_EnumContextProps, 4922 Context_OC_Reserved1, 4923 Context_OC_Reserved2, 4924 Context_OC_Reserved3, 4925 Context_OC_Reserved4, 4926 Context_OC_Reserved5, 4927 Context_OC_Reserved6, 4928 Context_OC_Reserved7 4929 }; 4930 4931 /*********************************************************************** 4932 * CoGetObjectContext [OLE32.@] 4933 * 4934 * Retrieves an object associated with the current context (i.e. apartment). 4935 * 4936 * PARAMS 4937 * riid [I] ID of the interface of the object to retrieve. 4938 * ppv [O] Address where object will be stored on return. 4939 * 4940 * RETURNS 4941 * Success: S_OK. 4942 * Failure: HRESULT code. 4943 */ 4944 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) 4945 { 4946 IObjContext *context; 4947 HRESULT hr; 4948 4949 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 4950 4951 *ppv = NULL; 4952 hr = CoGetContextToken((ULONG_PTR*)&context); 4953 if (FAILED(hr)) 4954 return hr; 4955 4956 return IObjContext_QueryInterface(context, riid, ppv); 4957 } 4958 4959 /*********************************************************************** 4960 * CoGetContextToken [OLE32.@] 4961 */ 4962 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token ) 4963 { 4964 struct oletls *info = COM_CurrentInfo(); 4965 4966 TRACE("(%p)\n", token); 4967 4968 if (!info) 4969 return E_OUTOFMEMORY; 4970 4971 if (!info->apt) 4972 { 4973 APARTMENT *apt; 4974 if (!(apt = apartment_find_multi_threaded())) 4975 { 4976 ERR("apartment not initialised\n"); 4977 return CO_E_NOTINITIALIZED; 4978 } 4979 apartment_release(apt); 4980 } 4981 4982 if (!token) 4983 return E_POINTER; 4984 4985 if (!info->context_token) 4986 { 4987 Context *context; 4988 4989 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context)); 4990 if (!context) 4991 return E_OUTOFMEMORY; 4992 4993 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl; 4994 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl; 4995 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl; 4996 /* Context token does not take a reference, it's always zero until the 4997 interface is explicitly requested with CoGetObjectContext(). */ 4998 context->refs = 0; 4999 5000 info->context_token = &context->IObjContext_iface; 5001 } 5002 5003 *token = (ULONG_PTR)info->context_token; 5004 TRACE("context_token=%p\n", info->context_token); 5005 5006 return S_OK; 5007 } 5008 5009 /*********************************************************************** 5010 * CoGetDefaultContext [OLE32.@] 5011 */ 5012 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv) 5013 { 5014 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv); 5015 return E_NOINTERFACE; 5016 } 5017 5018 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 5019 { 5020 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; 5021 HKEY hkey; 5022 HRESULT hres; 5023 5024 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey); 5025 if (SUCCEEDED(hres)) 5026 { 5027 struct class_reg_data regdata; 5028 WCHAR dllpath[MAX_PATH+1]; 5029 5030 regdata.u.hkey = hkey; 5031 regdata.hkey = TRUE; 5032 5033 if (COM_RegReadPath(®data, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS) 5034 { 5035 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; 5036 if (!strcmpiW(dllpath, wszOle32)) 5037 { 5038 RegCloseKey(hkey); 5039 return HandlerCF_Create(rclsid, riid, ppv); 5040 } 5041 } 5042 else 5043 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath)); 5044 RegCloseKey(hkey); 5045 } 5046 5047 return CLASS_E_CLASSNOTAVAILABLE; 5048 } 5049 5050 /*********************************************************************** 5051 * CoGetApartmentType [OLE32.@] 5052 */ 5053 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) 5054 { 5055 struct oletls *info = COM_CurrentInfo(); 5056 5057 FIXME("(%p, %p): semi-stub\n", type, qualifier); 5058 5059 if (!type || !qualifier) 5060 return E_INVALIDARG; 5061 5062 if (!info) 5063 return E_OUTOFMEMORY; 5064 5065 if (!info->apt) 5066 *type = APTTYPE_CURRENT; 5067 else if (info->apt->multi_threaded) 5068 *type = APTTYPE_MTA; 5069 else if (info->apt->main) 5070 *type = APTTYPE_MAINSTA; 5071 else 5072 *type = APTTYPE_STA; 5073 5074 *qualifier = APTTYPEQUALIFIER_NONE; 5075 5076 return info->apt ? S_OK : CO_E_NOTINITIALIZED; 5077 } 5078 5079 /*********************************************************************** 5080 * CoRegisterSurrogate [OLE32.@] 5081 */ 5082 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate) 5083 { 5084 FIXME("(%p): stub\n", surrogate); 5085 5086 return E_NOTIMPL; 5087 } 5088 5089 /*********************************************************************** 5090 * CoRegisterSurrogateEx [OLE32.@] 5091 */ 5092 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved) 5093 { 5094 FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved); 5095 5096 return E_NOTIMPL; 5097 } 5098 5099 typedef struct { 5100 IGlobalOptions IGlobalOptions_iface; 5101 LONG ref; 5102 } GlobalOptions; 5103 5104 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface) 5105 { 5106 return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface); 5107 } 5108 5109 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv) 5110 { 5111 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5112 5113 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 5114 5115 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid)) 5116 { 5117 *ppv = iface; 5118 } 5119 else 5120 { 5121 *ppv = NULL; 5122 return E_NOINTERFACE; 5123 } 5124 5125 IUnknown_AddRef((IUnknown*)*ppv); 5126 return S_OK; 5127 } 5128 5129 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface) 5130 { 5131 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5132 LONG ref = InterlockedIncrement(&This->ref); 5133 5134 TRACE("(%p) ref=%d\n", This, ref); 5135 5136 return ref; 5137 } 5138 5139 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface) 5140 { 5141 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5142 LONG ref = InterlockedDecrement(&This->ref); 5143 5144 TRACE("(%p) ref=%d\n", This, ref); 5145 5146 if (!ref) 5147 heap_free(This); 5148 5149 return ref; 5150 } 5151 5152 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value) 5153 { 5154 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5155 FIXME("(%p)->(%u %lx)\n", This, property, value); 5156 return S_OK; 5157 } 5158 5159 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value) 5160 { 5161 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5162 FIXME("(%p)->(%u %p)\n", This, property, value); 5163 return E_NOTIMPL; 5164 } 5165 5166 static const IGlobalOptionsVtbl GlobalOptionsVtbl = { 5167 GlobalOptions_QueryInterface, 5168 GlobalOptions_AddRef, 5169 GlobalOptions_Release, 5170 GlobalOptions_Set, 5171 GlobalOptions_Query 5172 }; 5173 5174 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) 5175 { 5176 GlobalOptions *global_options; 5177 HRESULT hres; 5178 5179 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv); 5180 5181 if (outer) 5182 return E_INVALIDARG; 5183 5184 global_options = heap_alloc(sizeof(*global_options)); 5185 if (!global_options) 5186 return E_OUTOFMEMORY; 5187 global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl; 5188 global_options->ref = 1; 5189 5190 hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv); 5191 IGlobalOptions_Release(&global_options->IGlobalOptions_iface); 5192 return hres; 5193 } 5194 5195 /*********************************************************************** 5196 * DllMain (OLE32.@) 5197 */ 5198 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved) 5199 { 5200 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved); 5201 5202 switch(fdwReason) { 5203 case DLL_PROCESS_ATTACH: 5204 hProxyDll = hinstDLL; 5205 break; 5206 5207 case DLL_PROCESS_DETACH: 5208 if (reserved) break; 5209 release_std_git(); 5210 UnregisterClassW( wszAptWinClass, hProxyDll ); 5211 RPC_UnregisterAllChannelHooks(); 5212 COMPOBJ_DllList_Free(); 5213 DeleteCriticalSection(&csRegisteredClassList); 5214 DeleteCriticalSection(&csApartment); 5215 break; 5216 5217 case DLL_THREAD_DETACH: 5218 COM_TlsDestroy(); 5219 break; 5220 } 5221 return TRUE; 5222 } 5223 5224 /*********************************************************************** 5225 * DllRegisterServer (OLE32.@) 5226 */ 5227 HRESULT WINAPI DllRegisterServer(void) 5228 { 5229 return OLE32_DllRegisterServer(); 5230 } 5231 5232 /*********************************************************************** 5233 * DllUnregisterServer (OLE32.@) 5234 */ 5235 HRESULT WINAPI DllUnregisterServer(void) 5236 { 5237 return OLE32_DllUnregisterServer(); 5238 } 5239