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 static void COM_TlsDestroy(void) 1706 { 1707 struct oletls *info = NtCurrentTeb()->ReservedForOle; 1708 if (info) 1709 { 1710 if (info->apt) apartment_release(info->apt); 1711 if (info->errorinfo) IErrorInfo_Release(info->errorinfo); 1712 if (info->state) IUnknown_Release(info->state); 1713 if (info->spy) IInitializeSpy_Release(info->spy); 1714 if (info->context_token) IObjContext_Release(info->context_token); 1715 HeapFree(GetProcessHeap(), 0, info); 1716 NtCurrentTeb()->ReservedForOle = NULL; 1717 } 1718 } 1719 1720 /****************************************************************************** 1721 * CoBuildVersion [OLE32.@] 1722 * 1723 * Gets the build version of the DLL. 1724 * 1725 * PARAMS 1726 * 1727 * RETURNS 1728 * Current build version, hiword is majornumber, loword is minornumber 1729 */ 1730 DWORD WINAPI CoBuildVersion(void) 1731 { 1732 TRACE("Returning version %d, build %d.\n", rmm, rup); 1733 return (rmm<<16)+rup; 1734 } 1735 1736 /****************************************************************************** 1737 * CoRegisterInitializeSpy [OLE32.@] 1738 * 1739 * Add a Spy that watches CoInitializeEx calls 1740 * 1741 * PARAMS 1742 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd. 1743 * cookie [II] cookie receiver 1744 * 1745 * RETURNS 1746 * Success: S_OK if not already initialized, S_FALSE otherwise. 1747 * Failure: HRESULT code. 1748 * 1749 * SEE ALSO 1750 * CoInitializeEx 1751 */ 1752 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie) 1753 { 1754 struct oletls *info = COM_CurrentInfo(); 1755 HRESULT hr; 1756 1757 TRACE("(%p, %p)\n", spy, cookie); 1758 1759 if (!spy || !cookie || !info) 1760 { 1761 if (!info) 1762 WARN("Could not allocate tls\n"); 1763 return E_INVALIDARG; 1764 } 1765 1766 if (info->spy) 1767 { 1768 FIXME("Already registered?\n"); 1769 return E_UNEXPECTED; 1770 } 1771 1772 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy); 1773 if (SUCCEEDED(hr)) 1774 { 1775 cookie->QuadPart = (DWORD_PTR)spy; 1776 return S_OK; 1777 } 1778 return hr; 1779 } 1780 1781 /****************************************************************************** 1782 * CoRevokeInitializeSpy [OLE32.@] 1783 * 1784 * Remove a spy that previously watched CoInitializeEx calls 1785 * 1786 * PARAMS 1787 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call 1788 * 1789 * RETURNS 1790 * Success: S_OK if a spy is removed 1791 * Failure: E_INVALIDARG 1792 * 1793 * SEE ALSO 1794 * CoInitializeEx 1795 */ 1796 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie) 1797 { 1798 struct oletls *info = COM_CurrentInfo(); 1799 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart)); 1800 1801 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy) 1802 return E_INVALIDARG; 1803 1804 IInitializeSpy_Release(info->spy); 1805 info->spy = NULL; 1806 return S_OK; 1807 } 1808 1809 HRESULT enter_apartment( struct oletls *info, DWORD model ) 1810 { 1811 HRESULT hr = S_OK; 1812 1813 if (!info->apt) 1814 { 1815 if (!apartment_get_or_create( model )) 1816 return E_OUTOFMEMORY; 1817 } 1818 else if (!apartment_is_model( info->apt, model )) 1819 { 1820 WARN( "Attempt to change threading model of this apartment from %s to %s\n", 1821 info->apt->multi_threaded ? "multi-threaded" : "apartment threaded", 1822 model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" ); 1823 return RPC_E_CHANGED_MODE; 1824 } 1825 else 1826 hr = S_FALSE; 1827 1828 info->inits++; 1829 1830 return hr; 1831 } 1832 1833 void leave_apartment( struct oletls *info ) 1834 { 1835 if (!--info->inits) 1836 { 1837 if (info->ole_inits) 1838 WARN( "Uninitializing apartment while Ole is still initialized\n" ); 1839 apartment_release( info->apt ); 1840 info->apt = NULL; 1841 } 1842 } 1843 1844 /****************************************************************************** 1845 * CoInitialize [OLE32.@] 1846 * 1847 * Initializes the COM libraries by calling CoInitializeEx with 1848 * COINIT_APARTMENTTHREADED, ie it enters a STA thread. 1849 * 1850 * PARAMS 1851 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). 1852 * 1853 * RETURNS 1854 * Success: S_OK if not already initialized, S_FALSE otherwise. 1855 * Failure: HRESULT code. 1856 * 1857 * SEE ALSO 1858 * CoInitializeEx 1859 */ 1860 HRESULT WINAPI CoInitialize(LPVOID lpReserved) 1861 { 1862 /* 1863 * Just delegate to the newer method. 1864 */ 1865 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED); 1866 } 1867 1868 /****************************************************************************** 1869 * CoInitializeEx [OLE32.@] 1870 * 1871 * Initializes the COM libraries. 1872 * 1873 * PARAMS 1874 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). 1875 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes. 1876 * 1877 * RETURNS 1878 * S_OK if successful, 1879 * S_FALSE if this function was called already. 1880 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another 1881 * threading model. 1882 * 1883 * NOTES 1884 * 1885 * The behavior used to set the IMalloc used for memory management is 1886 * obsolete. 1887 * The dwCoInit parameter must specify one of the following apartment 1888 * threading models: 1889 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA). 1890 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA). 1891 * The parameter may also specify zero or more of the following flags: 1892 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support. 1893 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed. 1894 * 1895 * SEE ALSO 1896 * CoUninitialize 1897 */ 1898 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit) 1899 { 1900 struct oletls *info = COM_CurrentInfo(); 1901 HRESULT hr; 1902 1903 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit); 1904 1905 if (lpReserved!=NULL) 1906 { 1907 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved); 1908 } 1909 1910 /* 1911 * Check the lock count. If this is the first time going through the initialize 1912 * process, we have to initialize the libraries. 1913 * 1914 * And crank-up that lock count. 1915 */ 1916 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0) 1917 { 1918 /* 1919 * Initialize the various COM libraries and data structures. 1920 */ 1921 TRACE("() - Initializing the COM libraries\n"); 1922 1923 /* we may need to defer this until after apartment initialisation */ 1924 RunningObjectTableImpl_Initialize(); 1925 } 1926 1927 if (info->spy) 1928 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits); 1929 1930 hr = enter_apartment( info, dwCoInit ); 1931 1932 if (info->spy) 1933 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits); 1934 1935 return hr; 1936 } 1937 1938 /*********************************************************************** 1939 * CoUninitialize [OLE32.@] 1940 * 1941 * This method will decrement the refcount on the current apartment, freeing 1942 * the resources associated with it if it is the last thread in the apartment. 1943 * If the last apartment is freed, the function will additionally release 1944 * any COM resources associated with the process. 1945 * 1946 * PARAMS 1947 * 1948 * RETURNS 1949 * Nothing. 1950 * 1951 * SEE ALSO 1952 * CoInitializeEx 1953 */ 1954 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void) 1955 { 1956 struct oletls * info = COM_CurrentInfo(); 1957 LONG lCOMRefCnt; 1958 1959 TRACE("()\n"); 1960 1961 /* will only happen on OOM */ 1962 if (!info) return; 1963 1964 if (info->spy) 1965 IInitializeSpy_PreUninitialize(info->spy, info->inits); 1966 1967 /* sanity check */ 1968 if (!info->inits) 1969 { 1970 ERR("Mismatched CoUninitialize\n"); 1971 1972 if (info->spy) 1973 IInitializeSpy_PostUninitialize(info->spy, info->inits); 1974 return; 1975 } 1976 1977 leave_apartment( info ); 1978 1979 /* 1980 * Decrease the reference count. 1981 * If we are back to 0 locks on the COM library, make sure we free 1982 * all the associated data structures. 1983 */ 1984 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1); 1985 if (lCOMRefCnt==1) 1986 { 1987 TRACE("() - Releasing the COM libraries\n"); 1988 1989 revoke_registered_psclsids(); 1990 RunningObjectTableImpl_UnInitialize(); 1991 } 1992 else if (lCOMRefCnt<1) { 1993 ERR( "CoUninitialize() - not CoInitialized.\n" ); 1994 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */ 1995 } 1996 if (info->spy) 1997 IInitializeSpy_PostUninitialize(info->spy, info->inits); 1998 } 1999 2000 /****************************************************************************** 2001 * CoDisconnectObject [OLE32.@] 2002 * 2003 * Disconnects all connections to this object from remote processes. Dispatches 2004 * pending RPCs while blocking new RPCs from occurring, and then calls 2005 * IMarshal::DisconnectObject on the given object. 2006 * 2007 * Typically called when the object server is forced to shut down, for instance by 2008 * the user. 2009 * 2010 * PARAMS 2011 * lpUnk [I] The object whose stub should be disconnected. 2012 * reserved [I] Reserved. Should be set to 0. 2013 * 2014 * RETURNS 2015 * Success: S_OK. 2016 * Failure: HRESULT code. 2017 * 2018 * SEE ALSO 2019 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal 2020 */ 2021 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) 2022 { 2023 struct stub_manager *manager; 2024 HRESULT hr; 2025 IMarshal *marshal; 2026 APARTMENT *apt; 2027 2028 TRACE("(%p, 0x%08x)\n", lpUnk, reserved); 2029 2030 if (!lpUnk) return E_INVALIDARG; 2031 2032 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal); 2033 if (hr == S_OK) 2034 { 2035 hr = IMarshal_DisconnectObject(marshal, reserved); 2036 IMarshal_Release(marshal); 2037 return hr; 2038 } 2039 2040 apt = COM_CurrentApt(); 2041 if (!apt) 2042 return CO_E_NOTINITIALIZED; 2043 2044 manager = get_stub_manager_from_object(apt, lpUnk, FALSE); 2045 if (manager) { 2046 stub_manager_disconnect(manager); 2047 /* Release stub manager twice, to remove the apartment reference. */ 2048 stub_manager_int_release(manager); 2049 stub_manager_int_release(manager); 2050 } 2051 2052 /* Note: native is pretty broken here because it just silently 2053 * fails, without returning an appropriate error code if the object was 2054 * not found, making apps think that the object was disconnected, when 2055 * it actually wasn't */ 2056 2057 return S_OK; 2058 } 2059 2060 /****************************************************************************** 2061 * CoCreateGuid [OLE32.@] 2062 * 2063 * Simply forwards to UuidCreate in RPCRT4. 2064 * 2065 * PARAMS 2066 * pguid [O] Points to the GUID to initialize. 2067 * 2068 * RETURNS 2069 * Success: S_OK. 2070 * Failure: HRESULT code. 2071 * 2072 * SEE ALSO 2073 * UuidCreate 2074 */ 2075 HRESULT WINAPI CoCreateGuid(GUID *pguid) 2076 { 2077 DWORD status; 2078 2079 if(!pguid) return E_INVALIDARG; 2080 2081 status = UuidCreate(pguid); 2082 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK; 2083 return HRESULT_FROM_WIN32( status ); 2084 } 2085 2086 static inline BOOL is_valid_hex(WCHAR c) 2087 { 2088 if (!(((c >= '0') && (c <= '9')) || 2089 ((c >= 'a') && (c <= 'f')) || 2090 ((c >= 'A') && (c <= 'F')))) 2091 return FALSE; 2092 return TRUE; 2093 } 2094 2095 static const BYTE guid_conv_table[256] = 2096 { 2097 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ 2098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ 2099 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ 2100 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */ 2101 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */ 2102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */ 2103 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */ 2104 }; 2105 2106 /* conversion helper for CLSIDFromString/IIDFromString */ 2107 static BOOL guid_from_string(LPCWSTR s, GUID *id) 2108 { 2109 int i; 2110 2111 if (!s || s[0]!='{') { 2112 memset( id, 0, sizeof (CLSID) ); 2113 if(!s) return TRUE; 2114 return FALSE; 2115 } 2116 2117 TRACE("%s -> %p\n", debugstr_w(s), id); 2118 2119 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ 2120 2121 id->Data1 = 0; 2122 for (i = 1; i < 9; i++) { 2123 if (!is_valid_hex(s[i])) return FALSE; 2124 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]]; 2125 } 2126 if (s[9]!='-') return FALSE; 2127 2128 id->Data2 = 0; 2129 for (i = 10; i < 14; i++) { 2130 if (!is_valid_hex(s[i])) return FALSE; 2131 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]]; 2132 } 2133 if (s[14]!='-') return FALSE; 2134 2135 id->Data3 = 0; 2136 for (i = 15; i < 19; i++) { 2137 if (!is_valid_hex(s[i])) return FALSE; 2138 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]]; 2139 } 2140 if (s[19]!='-') return FALSE; 2141 2142 for (i = 20; i < 37; i+=2) { 2143 if (i == 24) { 2144 if (s[i]!='-') return FALSE; 2145 i++; 2146 } 2147 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE; 2148 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]]; 2149 } 2150 2151 if (s[37] == '}' && s[38] == '\0') 2152 return TRUE; 2153 2154 return FALSE; 2155 } 2156 2157 /*****************************************************************************/ 2158 2159 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) 2160 { 2161 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 }; 2162 WCHAR buf2[CHARS_IN_GUID]; 2163 LONG buf2len = sizeof(buf2); 2164 HKEY xhkey; 2165 WCHAR *buf; 2166 2167 memset(clsid, 0, sizeof(*clsid)); 2168 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) ); 2169 if (!buf) return E_OUTOFMEMORY; 2170 strcpyW( buf, progid ); 2171 strcatW( buf, clsidW ); 2172 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey)) 2173 { 2174 HeapFree(GetProcessHeap(),0,buf); 2175 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); 2176 return CO_E_CLASSSTRING; 2177 } 2178 HeapFree(GetProcessHeap(),0,buf); 2179 2180 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len)) 2181 { 2182 RegCloseKey(xhkey); 2183 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid)); 2184 return CO_E_CLASSSTRING; 2185 } 2186 RegCloseKey(xhkey); 2187 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING; 2188 } 2189 2190 /****************************************************************************** 2191 * CLSIDFromString [OLE32.@] 2192 * 2193 * Converts a unique identifier from its string representation into 2194 * the GUID struct. 2195 * 2196 * PARAMS 2197 * idstr [I] The string representation of the GUID. 2198 * id [O] GUID converted from the string. 2199 * 2200 * RETURNS 2201 * S_OK on success 2202 * CO_E_CLASSSTRING if idstr is not a valid CLSID 2203 * 2204 * SEE ALSO 2205 * StringFromCLSID 2206 */ 2207 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id ) 2208 { 2209 HRESULT ret = CO_E_CLASSSTRING; 2210 CLSID tmp_id; 2211 2212 if (!id) 2213 return E_INVALIDARG; 2214 2215 if (guid_from_string(idstr, id)) 2216 return S_OK; 2217 2218 /* It appears a ProgID is also valid */ 2219 ret = clsid_from_string_reg(idstr, &tmp_id); 2220 if(SUCCEEDED(ret)) 2221 *id = tmp_id; 2222 2223 return ret; 2224 } 2225 2226 /****************************************************************************** 2227 * IIDFromString [OLE32.@] 2228 * 2229 * Converts an interface identifier from its string representation to 2230 * the IID struct. 2231 * 2232 * PARAMS 2233 * idstr [I] The string representation of the GUID. 2234 * id [O] IID converted from the string. 2235 * 2236 * RETURNS 2237 * S_OK on success 2238 * CO_E_IIDSTRING if idstr is not a valid IID 2239 * 2240 * SEE ALSO 2241 * StringFromIID 2242 */ 2243 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid) 2244 { 2245 TRACE("%s -> %p\n", debugstr_w(s), iid); 2246 2247 if (!s) 2248 { 2249 memset(iid, 0, sizeof(*iid)); 2250 return S_OK; 2251 } 2252 2253 /* length mismatch is a special case */ 2254 if (strlenW(s) + 1 != CHARS_IN_GUID) 2255 return E_INVALIDARG; 2256 2257 if (s[0] != '{') 2258 return CO_E_IIDSTRING; 2259 2260 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING; 2261 } 2262 2263 /****************************************************************************** 2264 * StringFromCLSID [OLE32.@] 2265 * StringFromIID [OLE32.@] 2266 * 2267 * Converts a GUID into the respective string representation. 2268 * The target string is allocated using the OLE IMalloc. 2269 * 2270 * PARAMS 2271 * id [I] the GUID to be converted. 2272 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string. 2273 * 2274 * RETURNS 2275 * S_OK 2276 * E_FAIL 2277 * 2278 * SEE ALSO 2279 * StringFromGUID2, CLSIDFromString 2280 */ 2281 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr) 2282 { 2283 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY; 2284 StringFromGUID2( id, *idstr, CHARS_IN_GUID ); 2285 return S_OK; 2286 } 2287 2288 /****************************************************************************** 2289 * StringFromGUID2 [OLE32.@] 2290 * 2291 * Modified version of StringFromCLSID that allows you to specify max 2292 * buffer size. 2293 * 2294 * PARAMS 2295 * id [I] GUID to convert to string. 2296 * str [O] Buffer where the result will be stored. 2297 * cmax [I] Size of the buffer in characters. 2298 * 2299 * RETURNS 2300 * Success: The length of the resulting string in characters. 2301 * Failure: 0. 2302 */ 2303 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax) 2304 { 2305 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-', 2306 '%','0','4','X','-','%','0','2','X','%','0','2','X','-', 2307 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X', 2308 '%','0','2','X','%','0','2','X','}',0 }; 2309 if (!id || cmax < CHARS_IN_GUID) return 0; 2310 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3, 2311 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], 2312 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); 2313 return CHARS_IN_GUID; 2314 } 2315 2316 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */ 2317 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey) 2318 { 2319 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0}; 2320 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1]; 2321 LONG res; 2322 HKEY key; 2323 2324 strcpyW(path, wszCLSIDSlash); 2325 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID); 2326 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key); 2327 if (res == ERROR_FILE_NOT_FOUND) 2328 return REGDB_E_CLASSNOTREG; 2329 else if (res != ERROR_SUCCESS) 2330 return REGDB_E_READREGDB; 2331 2332 if (!keyname) 2333 { 2334 *subkey = key; 2335 return S_OK; 2336 } 2337 2338 res = open_classes_key(key, keyname, access, subkey); 2339 RegCloseKey(key); 2340 if (res == ERROR_FILE_NOT_FOUND) 2341 return REGDB_E_KEYMISSING; 2342 else if (res != ERROR_SUCCESS) 2343 return REGDB_E_READREGDB; 2344 2345 return S_OK; 2346 } 2347 2348 /* open HKCR\\AppId\\{string form of appid clsid} key */ 2349 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey) 2350 { 2351 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 }; 2352 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 }; 2353 DWORD res; 2354 WCHAR buf[CHARS_IN_GUID]; 2355 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID]; 2356 DWORD size; 2357 HKEY hkey; 2358 DWORD type; 2359 HRESULT hr; 2360 2361 /* read the AppID value under the class's key */ 2362 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey); 2363 if (FAILED(hr)) 2364 return hr; 2365 2366 size = sizeof(buf); 2367 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size); 2368 RegCloseKey(hkey); 2369 if (res == ERROR_FILE_NOT_FOUND) 2370 return REGDB_E_KEYMISSING; 2371 else if (res != ERROR_SUCCESS || type!=REG_SZ) 2372 return REGDB_E_READREGDB; 2373 2374 strcpyW(keyname, szAppIdKey); 2375 strcatW(keyname, buf); 2376 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey); 2377 if (res == ERROR_FILE_NOT_FOUND) 2378 return REGDB_E_KEYMISSING; 2379 else if (res != ERROR_SUCCESS) 2380 return REGDB_E_READREGDB; 2381 2382 return S_OK; 2383 } 2384 2385 /****************************************************************************** 2386 * ProgIDFromCLSID [OLE32.@] 2387 * 2388 * Converts a class id into the respective program ID. 2389 * 2390 * PARAMS 2391 * clsid [I] Class ID, as found in registry. 2392 * ppszProgID [O] Associated ProgID. 2393 * 2394 * RETURNS 2395 * S_OK 2396 * E_OUTOFMEMORY 2397 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID 2398 */ 2399 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID) 2400 { 2401 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0}; 2402 ACTCTX_SECTION_KEYED_DATA data; 2403 HKEY hkey; 2404 HRESULT ret; 2405 LONG progidlen = 0; 2406 2407 if (!ppszProgID) 2408 return E_INVALIDARG; 2409 2410 *ppszProgID = NULL; 2411 2412 data.cbSize = sizeof(data); 2413 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, 2414 clsid, &data)) 2415 { 2416 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData; 2417 if (comclass->progid_len) 2418 { 2419 WCHAR *ptrW; 2420 2421 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR)); 2422 if (!*ppszProgID) return E_OUTOFMEMORY; 2423 2424 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset); 2425 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR)); 2426 return S_OK; 2427 } 2428 else 2429 return REGDB_E_CLASSNOTREG; 2430 } 2431 2432 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey); 2433 if (FAILED(ret)) 2434 return ret; 2435 2436 if (RegQueryValueW(hkey, NULL, NULL, &progidlen)) 2437 ret = REGDB_E_CLASSNOTREG; 2438 2439 if (ret == S_OK) 2440 { 2441 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR)); 2442 if (*ppszProgID) 2443 { 2444 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) { 2445 ret = REGDB_E_CLASSNOTREG; 2446 CoTaskMemFree(*ppszProgID); 2447 *ppszProgID = NULL; 2448 } 2449 } 2450 else 2451 ret = E_OUTOFMEMORY; 2452 } 2453 2454 RegCloseKey(hkey); 2455 return ret; 2456 } 2457 2458 /****************************************************************************** 2459 * CLSIDFromProgID [OLE32.@] 2460 * 2461 * Converts a program id into the respective GUID. 2462 * 2463 * PARAMS 2464 * progid [I] Unicode program ID, as found in registry. 2465 * clsid [O] Associated CLSID. 2466 * 2467 * RETURNS 2468 * Success: S_OK 2469 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found. 2470 */ 2471 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid) 2472 { 2473 ACTCTX_SECTION_KEYED_DATA data; 2474 2475 if (!progid || !clsid) 2476 return E_INVALIDARG; 2477 2478 data.cbSize = sizeof(data); 2479 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION, 2480 progid, &data)) 2481 { 2482 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData; 2483 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset); 2484 *clsid = *alias; 2485 return S_OK; 2486 } 2487 2488 return clsid_from_string_reg(progid, clsid); 2489 } 2490 2491 /****************************************************************************** 2492 * CLSIDFromProgIDEx [OLE32.@] 2493 */ 2494 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid) 2495 { 2496 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid); 2497 2498 return CLSIDFromProgID(progid, clsid); 2499 } 2500 2501 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid) 2502 { 2503 HKEY hkey; 2504 WCHAR value[CHARS_IN_GUID]; 2505 DWORD len; 2506 2507 access |= KEY_READ; 2508 2509 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey)) 2510 return REGDB_E_IIDNOTREG; 2511 2512 len = sizeof(value); 2513 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len)) 2514 return REGDB_E_IIDNOTREG; 2515 RegCloseKey(hkey); 2516 2517 if (CLSIDFromString(value, pclsid) != NOERROR) 2518 return REGDB_E_IIDNOTREG; 2519 2520 return S_OK; 2521 } 2522 2523 /***************************************************************************** 2524 * CoGetPSClsid [OLE32.@] 2525 * 2526 * Retrieves the CLSID of the proxy/stub factory that implements 2527 * IPSFactoryBuffer for the specified interface. 2528 * 2529 * PARAMS 2530 * riid [I] Interface whose proxy/stub CLSID is to be returned. 2531 * pclsid [O] Where to store returned proxy/stub CLSID. 2532 * 2533 * RETURNS 2534 * S_OK 2535 * E_OUTOFMEMORY 2536 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed 2537 * 2538 * NOTES 2539 * 2540 * The standard marshaller activates the object with the CLSID 2541 * returned and uses the CreateProxy and CreateStub methods on its 2542 * IPSFactoryBuffer interface to construct the proxies and stubs for a 2543 * given object. 2544 * 2545 * CoGetPSClsid determines this CLSID by searching the 2546 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 2547 * in the registry and any interface id registered by 2548 * CoRegisterPSClsid within the current process. 2549 * 2550 * BUGS 2551 * 2552 * Native returns S_OK for interfaces with a key in HKCR\Interface, but 2553 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be 2554 * considered a bug in native unless an application depends on this (unlikely). 2555 * 2556 * SEE ALSO 2557 * CoRegisterPSClsid. 2558 */ 2559 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) 2560 { 2561 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0}; 2562 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0}; 2563 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)]; 2564 APARTMENT *apt = COM_CurrentApt(); 2565 struct registered_psclsid *registered_psclsid; 2566 ACTCTX_SECTION_KEYED_DATA data; 2567 HRESULT hr; 2568 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY; 2569 BOOL is_wow64; 2570 2571 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid); 2572 2573 if (!apt) 2574 { 2575 ERR("apartment not initialised\n"); 2576 return CO_E_NOTINITIALIZED; 2577 } 2578 2579 if (!pclsid) 2580 return E_INVALIDARG; 2581 2582 EnterCriticalSection(&cs_registered_psclsid_list); 2583 2584 LIST_FOR_EACH_ENTRY(registered_psclsid, ®istered_psclsid_list, struct registered_psclsid, entry) 2585 if (IsEqualIID(®istered_psclsid->iid, riid)) 2586 { 2587 *pclsid = registered_psclsid->clsid; 2588 LeaveCriticalSection(&cs_registered_psclsid_list); 2589 return S_OK; 2590 } 2591 2592 LeaveCriticalSection(&cs_registered_psclsid_list); 2593 2594 data.cbSize = sizeof(data); 2595 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION, 2596 riid, &data)) 2597 { 2598 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData; 2599 *pclsid = ifaceps->iid; 2600 return S_OK; 2601 } 2602 2603 /* Interface\\{string form of riid}\\ProxyStubClsid32 */ 2604 strcpyW(path, wszInterface); 2605 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID); 2606 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC); 2607 2608 hr = get_ps_clsid_from_registry(path, 0, pclsid); 2609 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || 2610 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64))) 2611 hr = get_ps_clsid_from_registry(path, opposite, pclsid); 2612 2613 if (hr == S_OK) 2614 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid)); 2615 else 2616 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid)); 2617 2618 return hr; 2619 } 2620 2621 /***************************************************************************** 2622 * CoRegisterPSClsid [OLE32.@] 2623 * 2624 * Register a proxy/stub CLSID for the given interface in the current process 2625 * only. 2626 * 2627 * PARAMS 2628 * riid [I] Interface whose proxy/stub CLSID is to be registered. 2629 * rclsid [I] CLSID of the proxy/stub. 2630 * 2631 * RETURNS 2632 * Success: S_OK 2633 * Failure: E_OUTOFMEMORY 2634 * 2635 * NOTES 2636 * 2637 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid() 2638 * will be returned from other apartments in the same process. 2639 * 2640 * This function does not add anything to the registry and the effects are 2641 * limited to the lifetime of the current process. 2642 * 2643 * SEE ALSO 2644 * CoGetPSClsid. 2645 */ 2646 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid) 2647 { 2648 APARTMENT *apt = COM_CurrentApt(); 2649 struct registered_psclsid *registered_psclsid; 2650 2651 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid)); 2652 2653 if (!apt) 2654 { 2655 ERR("apartment not initialised\n"); 2656 return CO_E_NOTINITIALIZED; 2657 } 2658 2659 EnterCriticalSection(&cs_registered_psclsid_list); 2660 2661 LIST_FOR_EACH_ENTRY(registered_psclsid, ®istered_psclsid_list, struct registered_psclsid, entry) 2662 if (IsEqualIID(®istered_psclsid->iid, riid)) 2663 { 2664 registered_psclsid->clsid = *rclsid; 2665 LeaveCriticalSection(&cs_registered_psclsid_list); 2666 return S_OK; 2667 } 2668 2669 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid)); 2670 if (!registered_psclsid) 2671 { 2672 LeaveCriticalSection(&cs_registered_psclsid_list); 2673 return E_OUTOFMEMORY; 2674 } 2675 2676 registered_psclsid->iid = *riid; 2677 registered_psclsid->clsid = *rclsid; 2678 list_add_head(®istered_psclsid_list, ®istered_psclsid->entry); 2679 2680 LeaveCriticalSection(&cs_registered_psclsid_list); 2681 2682 return S_OK; 2683 } 2684 2685 2686 /*** 2687 * COM_GetRegisteredClassObject 2688 * 2689 * This internal method is used to scan the registered class list to 2690 * find a class object. 2691 * 2692 * Params: 2693 * rclsid Class ID of the class to find. 2694 * dwClsContext Class context to match. 2695 * ppv [out] returns a pointer to the class object. Complying 2696 * to normal COM usage, this method will increase the 2697 * reference count on this object. 2698 */ 2699 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, 2700 DWORD dwClsContext, LPUNKNOWN* ppUnk) 2701 { 2702 HRESULT hr = S_FALSE; 2703 RegisteredClass *curClass; 2704 2705 EnterCriticalSection( &csRegisteredClassList ); 2706 2707 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) 2708 { 2709 /* 2710 * Check if we have a match on the class ID and context. 2711 */ 2712 if ((apt->oxid == curClass->apartment_id) && 2713 (dwClsContext & curClass->runContext) && 2714 IsEqualGUID(&(curClass->classIdentifier), rclsid)) 2715 { 2716 /* 2717 * We have a match, return the pointer to the class object. 2718 */ 2719 *ppUnk = curClass->classObject; 2720 2721 IUnknown_AddRef(curClass->classObject); 2722 2723 hr = S_OK; 2724 break; 2725 } 2726 } 2727 2728 LeaveCriticalSection( &csRegisteredClassList ); 2729 2730 return hr; 2731 } 2732 2733 /****************************************************************************** 2734 * CoRegisterClassObject [OLE32.@] 2735 * 2736 * Registers the class object for a given class ID. Servers housed in EXE 2737 * files use this method instead of exporting DllGetClassObject to allow 2738 * other code to connect to their objects. 2739 * 2740 * PARAMS 2741 * rclsid [I] CLSID of the object to register. 2742 * pUnk [I] IUnknown of the object. 2743 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable. 2744 * flags [I] REGCLS flags indicating how connections are made. 2745 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject. 2746 * 2747 * RETURNS 2748 * S_OK on success, 2749 * E_INVALIDARG if lpdwRegister or pUnk are NULL, 2750 * CO_E_OBJISREG if the object is already registered. We should not return this. 2751 * 2752 * SEE ALSO 2753 * CoRevokeClassObject, CoGetClassObject 2754 * 2755 * NOTES 2756 * In-process objects are only registered for the current apartment. 2757 * CoGetClassObject() and CoCreateInstance() will not return objects registered 2758 * in other apartments. 2759 * 2760 * BUGS 2761 * MSDN claims that multiple interface registrations are legal, but we 2762 * can't do that with our current implementation. 2763 */ 2764 HRESULT WINAPI CoRegisterClassObject( 2765 REFCLSID rclsid, 2766 LPUNKNOWN pUnk, 2767 DWORD dwClsContext, 2768 DWORD flags, 2769 LPDWORD lpdwRegister) 2770 { 2771 static LONG next_cookie; 2772 RegisteredClass* newClass; 2773 LPUNKNOWN foundObject; 2774 HRESULT hr; 2775 APARTMENT *apt; 2776 2777 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n", 2778 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister); 2779 2780 if ( (lpdwRegister==0) || (pUnk==0) ) 2781 return E_INVALIDARG; 2782 2783 apt = COM_CurrentApt(); 2784 if (!apt) 2785 { 2786 ERR("COM was not initialized\n"); 2787 return CO_E_NOTINITIALIZED; 2788 } 2789 2790 *lpdwRegister = 0; 2791 2792 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what 2793 * differentiates the flag from REGCLS_MULTI_SEPARATE. */ 2794 if (flags & REGCLS_MULTIPLEUSE) 2795 dwClsContext |= CLSCTX_INPROC_SERVER; 2796 2797 /* 2798 * First, check if the class is already registered. 2799 * If it is, this should cause an error. 2800 */ 2801 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject); 2802 if (hr == S_OK) { 2803 if (flags & REGCLS_MULTIPLEUSE) { 2804 if (dwClsContext & CLSCTX_LOCAL_SERVER) 2805 hr = CoLockObjectExternal(foundObject, TRUE, FALSE); 2806 IUnknown_Release(foundObject); 2807 return hr; 2808 } 2809 IUnknown_Release(foundObject); 2810 ERR("object already registered for class %s\n", debugstr_guid(rclsid)); 2811 return CO_E_OBJISREG; 2812 } 2813 2814 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass)); 2815 if ( newClass == NULL ) 2816 return E_OUTOFMEMORY; 2817 2818 newClass->classIdentifier = *rclsid; 2819 newClass->apartment_id = apt->oxid; 2820 newClass->runContext = dwClsContext; 2821 newClass->connectFlags = flags; 2822 newClass->RpcRegistration = NULL; 2823 2824 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie ))) 2825 newClass->dwCookie = InterlockedIncrement( &next_cookie ); 2826 2827 /* 2828 * Since we're making a copy of the object pointer, we have to increase its 2829 * reference count. 2830 */ 2831 newClass->classObject = pUnk; 2832 IUnknown_AddRef(newClass->classObject); 2833 2834 EnterCriticalSection( &csRegisteredClassList ); 2835 list_add_tail(&RegisteredClassList, &newClass->entry); 2836 LeaveCriticalSection( &csRegisteredClassList ); 2837 2838 *lpdwRegister = newClass->dwCookie; 2839 2840 if (dwClsContext & CLSCTX_LOCAL_SERVER) { 2841 IStream *marshal_stream; 2842 2843 hr = get_local_server_stream(apt, &marshal_stream); 2844 if(FAILED(hr)) 2845 return hr; 2846 2847 hr = RPC_StartLocalServer(&newClass->classIdentifier, 2848 marshal_stream, 2849 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE), 2850 &newClass->RpcRegistration); 2851 IStream_Release(marshal_stream); 2852 } 2853 return S_OK; 2854 } 2855 2856 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data) 2857 { 2858 if (data->hkey) 2859 { 2860 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0}; 2861 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0}; 2862 static const WCHAR wszFree[] = {'F','r','e','e',0}; 2863 static const WCHAR wszBoth[] = {'B','o','t','h',0}; 2864 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */]; 2865 DWORD dwLength = sizeof(threading_model); 2866 DWORD keytype; 2867 DWORD ret; 2868 2869 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength); 2870 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ)) 2871 threading_model[0] = '\0'; 2872 2873 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment; 2874 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free; 2875 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both; 2876 2877 /* there's not specific handling for this case */ 2878 if (threading_model[0]) return ThreadingModel_Neutral; 2879 return ThreadingModel_No; 2880 } 2881 else 2882 return data->u.actctx.data->model; 2883 } 2884 2885 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata, 2886 REFCLSID rclsid, REFIID riid, 2887 BOOL hostifnecessary, void **ppv) 2888 { 2889 WCHAR dllpath[MAX_PATH+1]; 2890 BOOL apartment_threaded; 2891 2892 if (hostifnecessary) 2893 { 2894 enum comclass_threadingmodel model = get_threading_model(regdata); 2895 2896 if (model == ThreadingModel_Apartment) 2897 { 2898 apartment_threaded = TRUE; 2899 if (apt->multi_threaded) 2900 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv); 2901 } 2902 else if (model == ThreadingModel_Free) 2903 { 2904 apartment_threaded = FALSE; 2905 if (!apt->multi_threaded) 2906 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv); 2907 } 2908 /* everything except "Apartment", "Free" and "Both" */ 2909 else if (model != ThreadingModel_Both) 2910 { 2911 apartment_threaded = TRUE; 2912 /* everything else is main-threaded */ 2913 if (model != ThreadingModel_No) 2914 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid)); 2915 2916 if (apt->multi_threaded || !apt->main) 2917 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv); 2918 } 2919 else 2920 apartment_threaded = FALSE; 2921 } 2922 else 2923 apartment_threaded = !apt->multi_threaded; 2924 2925 if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS) 2926 { 2927 /* failure: CLSID is not found in registry */ 2928 WARN("class %s not registered inproc\n", debugstr_guid(rclsid)); 2929 return REGDB_E_CLASSNOTREG; 2930 } 2931 2932 return apartment_getclassobject(apt, dllpath, apartment_threaded, 2933 rclsid, riid, ppv); 2934 } 2935 2936 /*********************************************************************** 2937 * CoGetClassObject [OLE32.@] 2938 * 2939 * Creates an object of the specified class. 2940 * 2941 * PARAMS 2942 * rclsid [I] Class ID to create an instance of. 2943 * dwClsContext [I] Flags to restrict the location of the created instance. 2944 * pServerInfo [I] Optional. Details for connecting to a remote server. 2945 * iid [I] The ID of the interface of the instance to return. 2946 * ppv [O] On returns, contains a pointer to the specified interface of the object. 2947 * 2948 * RETURNS 2949 * Success: S_OK 2950 * Failure: HRESULT code. 2951 * 2952 * NOTES 2953 * The dwClsContext parameter can be one or more of the following: 2954 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL. 2955 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process. 2956 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process. 2957 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine. 2958 * 2959 * SEE ALSO 2960 * CoCreateInstance() 2961 */ 2962 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( 2963 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo, 2964 REFIID iid, LPVOID *ppv) 2965 { 2966 struct class_reg_data clsreg; 2967 IUnknown *regClassObject; 2968 HRESULT hres = E_UNEXPECTED; 2969 APARTMENT *apt; 2970 BOOL release_apt = FALSE; 2971 2972 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid)); 2973 2974 if (!ppv) 2975 return E_INVALIDARG; 2976 2977 *ppv = NULL; 2978 2979 if (!(apt = COM_CurrentApt())) 2980 { 2981 if (!(apt = apartment_find_multi_threaded())) 2982 { 2983 ERR("apartment not initialised\n"); 2984 return CO_E_NOTINITIALIZED; 2985 } 2986 release_apt = TRUE; 2987 } 2988 2989 if (pServerInfo) { 2990 FIXME("pServerInfo->name=%s pAuthInfo=%p\n", 2991 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo); 2992 } 2993 2994 if (CLSCTX_INPROC_SERVER & dwClsContext) 2995 { 2996 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler)) 2997 { 2998 if (release_apt) apartment_release(apt); 2999 return FTMarshalCF_Create(iid, ppv); 3000 } 3001 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions)) 3002 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv); 3003 } 3004 3005 if (CLSCTX_INPROC & dwClsContext) 3006 { 3007 ACTCTX_SECTION_KEYED_DATA data; 3008 3009 data.cbSize = sizeof(data); 3010 /* search activation context first */ 3011 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, 3012 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, 3013 rclsid, &data)) 3014 { 3015 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData; 3016 3017 clsreg.u.actctx.hactctx = data.hActCtx; 3018 clsreg.u.actctx.data = data.lpData; 3019 clsreg.u.actctx.section = data.lpSectionBase; 3020 clsreg.hkey = FALSE; 3021 3022 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 3023 ReleaseActCtx(data.hActCtx); 3024 if (release_apt) apartment_release(apt); 3025 return hres; 3026 } 3027 } 3028 3029 /* 3030 * First, try and see if we can't match the class ID with one of the 3031 * registered classes. 3032 */ 3033 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, 3034 ®ClassObject)) 3035 { 3036 /* Get the required interface from the retrieved pointer. */ 3037 hres = IUnknown_QueryInterface(regClassObject, iid, ppv); 3038 3039 /* 3040 * Since QI got another reference on the pointer, we want to release the 3041 * one we already have. If QI was unsuccessful, this will release the object. This 3042 * is good since we are not returning it in the "out" parameter. 3043 */ 3044 IUnknown_Release(regClassObject); 3045 if (release_apt) apartment_release(apt); 3046 return hres; 3047 } 3048 3049 /* First try in-process server */ 3050 if (CLSCTX_INPROC_SERVER & dwClsContext) 3051 { 3052 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; 3053 HKEY hkey; 3054 3055 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey); 3056 if (FAILED(hres)) 3057 { 3058 if (hres == REGDB_E_CLASSNOTREG) 3059 ERR("class %s not registered\n", debugstr_guid(rclsid)); 3060 else if (hres == REGDB_E_KEYMISSING) 3061 { 3062 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid)); 3063 hres = REGDB_E_CLASSNOTREG; 3064 } 3065 } 3066 3067 if (SUCCEEDED(hres)) 3068 { 3069 clsreg.u.hkey = hkey; 3070 clsreg.hkey = TRUE; 3071 3072 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 3073 RegCloseKey(hkey); 3074 } 3075 3076 /* return if we got a class, otherwise fall through to one of the 3077 * other types */ 3078 if (SUCCEEDED(hres)) 3079 { 3080 if (release_apt) apartment_release(apt); 3081 return hres; 3082 } 3083 } 3084 3085 /* Next try in-process handler */ 3086 if (CLSCTX_INPROC_HANDLER & dwClsContext) 3087 { 3088 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; 3089 HKEY hkey; 3090 3091 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey); 3092 if (FAILED(hres)) 3093 { 3094 if (hres == REGDB_E_CLASSNOTREG) 3095 ERR("class %s not registered\n", debugstr_guid(rclsid)); 3096 else if (hres == REGDB_E_KEYMISSING) 3097 { 3098 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid)); 3099 hres = REGDB_E_CLASSNOTREG; 3100 } 3101 } 3102 3103 if (SUCCEEDED(hres)) 3104 { 3105 clsreg.u.hkey = hkey; 3106 clsreg.hkey = TRUE; 3107 3108 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 3109 RegCloseKey(hkey); 3110 } 3111 3112 /* return if we got a class, otherwise fall through to one of the 3113 * other types */ 3114 if (SUCCEEDED(hres)) 3115 { 3116 if (release_apt) apartment_release(apt); 3117 return hres; 3118 } 3119 } 3120 if (release_apt) apartment_release(apt); 3121 3122 /* Next try out of process */ 3123 if (CLSCTX_LOCAL_SERVER & dwClsContext) 3124 { 3125 hres = RPC_GetLocalClassObject(rclsid,iid,ppv); 3126 if (SUCCEEDED(hres)) 3127 return hres; 3128 } 3129 3130 /* Finally try remote: this requires networked DCOM (a lot of work) */ 3131 if (CLSCTX_REMOTE_SERVER & dwClsContext) 3132 { 3133 FIXME ("CLSCTX_REMOTE_SERVER not supported\n"); 3134 hres = REGDB_E_CLASSNOTREG; 3135 } 3136 3137 if (FAILED(hres)) 3138 ERR("no class object %s could be created for context 0x%x\n", 3139 debugstr_guid(rclsid), dwClsContext); 3140 return hres; 3141 } 3142 3143 /*********************************************************************** 3144 * CoResumeClassObjects (OLE32.@) 3145 * 3146 * Resumes all class objects registered with REGCLS_SUSPENDED. 3147 * 3148 * RETURNS 3149 * Success: S_OK. 3150 * Failure: HRESULT code. 3151 */ 3152 HRESULT WINAPI CoResumeClassObjects(void) 3153 { 3154 FIXME("stub\n"); 3155 return S_OK; 3156 } 3157 3158 /*********************************************************************** 3159 * CoCreateInstance [OLE32.@] 3160 * 3161 * Creates an instance of the specified class. 3162 * 3163 * PARAMS 3164 * rclsid [I] Class ID to create an instance of. 3165 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object. 3166 * dwClsContext [I] Flags to restrict the location of the created instance. 3167 * iid [I] The ID of the interface of the instance to return. 3168 * ppv [O] On returns, contains a pointer to the specified interface of the instance. 3169 * 3170 * RETURNS 3171 * Success: S_OK 3172 * Failure: HRESULT code. 3173 * 3174 * NOTES 3175 * The dwClsContext parameter can be one or more of the following: 3176 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL. 3177 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process. 3178 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process. 3179 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine. 3180 * 3181 * Aggregation is the concept of deferring the IUnknown of an object to another 3182 * object. This allows a separate object to behave as though it was part of 3183 * the object and to allow this the pUnkOuter parameter can be set. Note that 3184 * not all objects support having an outer of unknown. 3185 * 3186 * SEE ALSO 3187 * CoGetClassObject() 3188 */ 3189 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance( 3190 REFCLSID rclsid, 3191 LPUNKNOWN pUnkOuter, 3192 DWORD dwClsContext, 3193 REFIID iid, 3194 LPVOID *ppv) 3195 { 3196 MULTI_QI multi_qi = { iid }; 3197 HRESULT hres; 3198 3199 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid), 3200 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv); 3201 3202 if (ppv==0) 3203 return E_POINTER; 3204 3205 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi); 3206 *ppv = multi_qi.pItf; 3207 return hres; 3208 } 3209 3210 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr) 3211 { 3212 ULONG i; 3213 3214 for (i = 0; i < count; i++) 3215 { 3216 mqi[i].pItf = NULL; 3217 mqi[i].hr = hr; 3218 } 3219 } 3220 3221 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk) 3222 { 3223 ULONG index = 0, fetched = 0; 3224 3225 if (include_unk) 3226 { 3227 mqi[0].hr = S_OK; 3228 mqi[0].pItf = unk; 3229 index = fetched = 1; 3230 } 3231 3232 for (; index < count; index++) 3233 { 3234 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf); 3235 if (mqi[index].hr == S_OK) 3236 fetched++; 3237 } 3238 3239 if (!include_unk) 3240 IUnknown_Release(unk); 3241 3242 if (fetched == 0) 3243 return E_NOINTERFACE; 3244 3245 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES; 3246 } 3247 3248 /*********************************************************************** 3249 * CoCreateInstanceEx [OLE32.@] 3250 */ 3251 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx( 3252 REFCLSID rclsid, 3253 LPUNKNOWN pUnkOuter, 3254 DWORD dwClsContext, 3255 COSERVERINFO* pServerInfo, 3256 ULONG cmq, 3257 MULTI_QI* pResults) 3258 { 3259 IUnknown *unk = NULL; 3260 IClassFactory *cf; 3261 APARTMENT *apt; 3262 CLSID clsid; 3263 HRESULT hres; 3264 3265 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults); 3266 3267 if (!cmq || !pResults) 3268 return E_INVALIDARG; 3269 3270 if (pServerInfo) 3271 FIXME("() non-NULL pServerInfo not supported!\n"); 3272 3273 init_multi_qi(cmq, pResults, E_NOINTERFACE); 3274 3275 hres = CoGetTreatAsClass(rclsid, &clsid); 3276 if(FAILED(hres)) 3277 clsid = *rclsid; 3278 3279 if (!(apt = COM_CurrentApt())) 3280 { 3281 if (!(apt = apartment_find_multi_threaded())) 3282 { 3283 ERR("apartment not initialised\n"); 3284 return CO_E_NOTINITIALIZED; 3285 } 3286 apartment_release(apt); 3287 } 3288 3289 /* 3290 * The Standard Global Interface Table (GIT) object is a process-wide singleton. 3291 */ 3292 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable)) 3293 { 3294 IGlobalInterfaceTable *git = get_std_git(); 3295 TRACE("Retrieving GIT\n"); 3296 return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE); 3297 } 3298 3299 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) { 3300 hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk); 3301 if (FAILED(hres)) 3302 return hres; 3303 return return_multi_qi(unk, cmq, pResults, TRUE); 3304 } 3305 3306 /* 3307 * Get a class factory to construct the object we want. 3308 */ 3309 hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf); 3310 if (FAILED(hres)) 3311 return hres; 3312 3313 /* 3314 * Create the object and don't forget to release the factory 3315 */ 3316 hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk); 3317 IClassFactory_Release(cf); 3318 if (FAILED(hres)) 3319 { 3320 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter) 3321 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid)); 3322 else 3323 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", 3324 debugstr_guid(pResults[0].pIID), 3325 debugstr_guid(&clsid),hres); 3326 return hres; 3327 } 3328 3329 return return_multi_qi(unk, cmq, pResults, TRUE); 3330 } 3331 3332 /*********************************************************************** 3333 * CoGetInstanceFromFile [OLE32.@] 3334 */ 3335 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile( 3336 COSERVERINFO *server_info, 3337 CLSID *rclsid, 3338 IUnknown *outer, 3339 DWORD cls_context, 3340 DWORD grfmode, 3341 OLECHAR *filename, 3342 DWORD count, 3343 MULTI_QI *results 3344 ) 3345 { 3346 IPersistFile *pf = NULL; 3347 IUnknown* unk = NULL; 3348 CLSID clsid; 3349 HRESULT hr; 3350 3351 if (count == 0 || !results) 3352 return E_INVALIDARG; 3353 3354 if (server_info) 3355 FIXME("() non-NULL server_info not supported\n"); 3356 3357 init_multi_qi(count, results, E_NOINTERFACE); 3358 3359 /* optionally get CLSID from a file */ 3360 if (!rclsid) 3361 { 3362 hr = GetClassFile(filename, &clsid); 3363 if (FAILED(hr)) 3364 { 3365 ERR("failed to get CLSID from a file\n"); 3366 return hr; 3367 } 3368 3369 rclsid = &clsid; 3370 } 3371 3372 hr = CoCreateInstance(rclsid, 3373 outer, 3374 cls_context, 3375 &IID_IUnknown, 3376 (void**)&unk); 3377 3378 if (hr != S_OK) 3379 { 3380 init_multi_qi(count, results, hr); 3381 return hr; 3382 } 3383 3384 /* init from file */ 3385 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf); 3386 if (FAILED(hr)) 3387 { 3388 init_multi_qi(count, results, hr); 3389 IUnknown_Release(unk); 3390 return hr; 3391 } 3392 3393 hr = IPersistFile_Load(pf, filename, grfmode); 3394 IPersistFile_Release(pf); 3395 if (SUCCEEDED(hr)) 3396 return return_multi_qi(unk, count, results, FALSE); 3397 else 3398 { 3399 init_multi_qi(count, results, hr); 3400 IUnknown_Release(unk); 3401 return hr; 3402 } 3403 } 3404 3405 /*********************************************************************** 3406 * CoGetInstanceFromIStorage [OLE32.@] 3407 */ 3408 HRESULT WINAPI CoGetInstanceFromIStorage( 3409 COSERVERINFO *server_info, 3410 CLSID *rclsid, 3411 IUnknown *outer, 3412 DWORD cls_context, 3413 IStorage *storage, 3414 DWORD count, 3415 MULTI_QI *results 3416 ) 3417 { 3418 IPersistStorage *ps = NULL; 3419 IUnknown* unk = NULL; 3420 STATSTG stat; 3421 HRESULT hr; 3422 3423 if (count == 0 || !results || !storage) 3424 return E_INVALIDARG; 3425 3426 if (server_info) 3427 FIXME("() non-NULL server_info not supported\n"); 3428 3429 init_multi_qi(count, results, E_NOINTERFACE); 3430 3431 /* optionally get CLSID from a file */ 3432 if (!rclsid) 3433 { 3434 memset(&stat.clsid, 0, sizeof(stat.clsid)); 3435 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME); 3436 if (FAILED(hr)) 3437 { 3438 ERR("failed to get CLSID from a file\n"); 3439 return hr; 3440 } 3441 3442 rclsid = &stat.clsid; 3443 } 3444 3445 hr = CoCreateInstance(rclsid, 3446 outer, 3447 cls_context, 3448 &IID_IUnknown, 3449 (void**)&unk); 3450 3451 if (hr != S_OK) 3452 return hr; 3453 3454 /* init from IStorage */ 3455 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps); 3456 if (FAILED(hr)) 3457 ERR("failed to get IPersistStorage\n"); 3458 3459 if (ps) 3460 { 3461 IPersistStorage_Load(ps, storage); 3462 IPersistStorage_Release(ps); 3463 } 3464 3465 return return_multi_qi(unk, count, results, FALSE); 3466 } 3467 3468 /*********************************************************************** 3469 * CoLoadLibrary (OLE32.@) 3470 * 3471 * Loads a library. 3472 * 3473 * PARAMS 3474 * lpszLibName [I] Path to library. 3475 * bAutoFree [I] Whether the library should automatically be freed. 3476 * 3477 * RETURNS 3478 * Success: Handle to loaded library. 3479 * Failure: NULL. 3480 * 3481 * SEE ALSO 3482 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries 3483 */ 3484 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree) 3485 { 3486 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree); 3487 3488 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH); 3489 } 3490 3491 /*********************************************************************** 3492 * CoFreeLibrary [OLE32.@] 3493 * 3494 * Unloads a library from memory. 3495 * 3496 * PARAMS 3497 * hLibrary [I] Handle to library to unload. 3498 * 3499 * RETURNS 3500 * Nothing 3501 * 3502 * SEE ALSO 3503 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries 3504 */ 3505 void WINAPI CoFreeLibrary(HINSTANCE hLibrary) 3506 { 3507 FreeLibrary(hLibrary); 3508 } 3509 3510 3511 /*********************************************************************** 3512 * CoFreeAllLibraries [OLE32.@] 3513 * 3514 * Function for backwards compatibility only. Does nothing. 3515 * 3516 * RETURNS 3517 * Nothing. 3518 * 3519 * SEE ALSO 3520 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries 3521 */ 3522 void WINAPI CoFreeAllLibraries(void) 3523 { 3524 /* NOP */ 3525 } 3526 3527 /*********************************************************************** 3528 * CoFreeUnusedLibrariesEx [OLE32.@] 3529 * 3530 * Frees any previously unused libraries whose delay has expired and marks 3531 * currently unused libraries for unloading. Unused are identified as those that 3532 * return S_OK from their DllCanUnloadNow function. 3533 * 3534 * PARAMS 3535 * dwUnloadDelay [I] Unload delay in milliseconds. 3536 * dwReserved [I] Reserved. Set to 0. 3537 * 3538 * RETURNS 3539 * Nothing. 3540 * 3541 * SEE ALSO 3542 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary 3543 */ 3544 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved) 3545 { 3546 struct apartment *apt = COM_CurrentApt(); 3547 if (!apt) 3548 { 3549 ERR("apartment not initialised\n"); 3550 return; 3551 } 3552 3553 apartment_freeunusedlibraries(apt, dwUnloadDelay); 3554 } 3555 3556 /*********************************************************************** 3557 * CoFreeUnusedLibraries [OLE32.@] 3558 * 3559 * Frees any unused libraries. Unused are identified as those that return 3560 * S_OK from their DllCanUnloadNow function. 3561 * 3562 * RETURNS 3563 * Nothing. 3564 * 3565 * SEE ALSO 3566 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary 3567 */ 3568 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void) 3569 { 3570 CoFreeUnusedLibrariesEx(INFINITE, 0); 3571 } 3572 3573 /*********************************************************************** 3574 * CoFileTimeNow [OLE32.@] 3575 * 3576 * Retrieves the current time in FILETIME format. 3577 * 3578 * PARAMS 3579 * lpFileTime [O] The current time. 3580 * 3581 * RETURNS 3582 * S_OK. 3583 */ 3584 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) 3585 { 3586 GetSystemTimeAsFileTime( lpFileTime ); 3587 return S_OK; 3588 } 3589 3590 /****************************************************************************** 3591 * CoLockObjectExternal [OLE32.@] 3592 * 3593 * Increments or decrements the external reference count of a stub object. 3594 * 3595 * PARAMS 3596 * pUnk [I] Stub object. 3597 * fLock [I] If TRUE then increments the external ref-count, 3598 * otherwise decrements. 3599 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of 3600 * calling CoDisconnectObject. 3601 * 3602 * RETURNS 3603 * Success: S_OK. 3604 * Failure: HRESULT code. 3605 * 3606 * NOTES 3607 * If fLock is TRUE and an object is passed in that doesn't have a stub 3608 * manager then a new stub manager is created for the object. 3609 */ 3610 HRESULT WINAPI CoLockObjectExternal( 3611 LPUNKNOWN pUnk, 3612 BOOL fLock, 3613 BOOL fLastUnlockReleases) 3614 { 3615 struct stub_manager *stubmgr; 3616 struct apartment *apt; 3617 3618 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", 3619 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE"); 3620 3621 apt = COM_CurrentApt(); 3622 if (!apt) return CO_E_NOTINITIALIZED; 3623 3624 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock); 3625 if (!stubmgr) 3626 { 3627 WARN("stub object not found %p\n", pUnk); 3628 /* Note: native is pretty broken here because it just silently 3629 * fails, without returning an appropriate error code, making apps 3630 * think that the object was disconnected, when it actually wasn't */ 3631 return S_OK; 3632 } 3633 3634 if (fLock) 3635 stub_manager_ext_addref(stubmgr, 1, FALSE); 3636 else 3637 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases); 3638 3639 stub_manager_int_release(stubmgr); 3640 return S_OK; 3641 } 3642 3643 /*********************************************************************** 3644 * CoInitializeWOW (OLE32.@) 3645 * 3646 * WOW equivalent of CoInitialize? 3647 * 3648 * PARAMS 3649 * x [I] Unknown. 3650 * y [I] Unknown. 3651 * 3652 * RETURNS 3653 * Unknown. 3654 */ 3655 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) 3656 { 3657 FIXME("(0x%08x,0x%08x),stub!\n",x,y); 3658 return 0; 3659 } 3660 3661 /*********************************************************************** 3662 * CoGetState [OLE32.@] 3663 * 3664 * Retrieves the thread state object previously stored by CoSetState(). 3665 * 3666 * PARAMS 3667 * ppv [I] Address where pointer to object will be stored. 3668 * 3669 * RETURNS 3670 * Success: S_OK. 3671 * Failure: E_OUTOFMEMORY. 3672 * 3673 * NOTES 3674 * Crashes on all invalid ppv addresses, including NULL. 3675 * If the function returns a non-NULL object then the caller must release its 3676 * reference on the object when the object is no longer required. 3677 * 3678 * SEE ALSO 3679 * CoSetState(). 3680 */ 3681 HRESULT WINAPI CoGetState(IUnknown ** ppv) 3682 { 3683 struct oletls *info = COM_CurrentInfo(); 3684 if (!info) return E_OUTOFMEMORY; 3685 3686 *ppv = NULL; 3687 3688 if (info->state) 3689 { 3690 IUnknown_AddRef(info->state); 3691 *ppv = info->state; 3692 TRACE("apt->state=%p\n", info->state); 3693 } 3694 3695 return S_OK; 3696 } 3697 3698 /*********************************************************************** 3699 * CoSetState [OLE32.@] 3700 * 3701 * Sets the thread state object. 3702 * 3703 * PARAMS 3704 * pv [I] Pointer to state object to be stored. 3705 * 3706 * NOTES 3707 * The system keeps a reference on the object while the object stored. 3708 * 3709 * RETURNS 3710 * Success: S_OK. 3711 * Failure: E_OUTOFMEMORY. 3712 */ 3713 HRESULT WINAPI CoSetState(IUnknown * pv) 3714 { 3715 struct oletls *info = COM_CurrentInfo(); 3716 if (!info) return E_OUTOFMEMORY; 3717 3718 if (pv) IUnknown_AddRef(pv); 3719 3720 if (info->state) 3721 { 3722 TRACE("-- release %p now\n", info->state); 3723 IUnknown_Release(info->state); 3724 } 3725 3726 info->state = pv; 3727 3728 return S_OK; 3729 } 3730 3731 3732 /****************************************************************************** 3733 * CoTreatAsClass [OLE32.@] 3734 * 3735 * Sets the TreatAs value of a class. 3736 * 3737 * PARAMS 3738 * clsidOld [I] Class to set TreatAs value on. 3739 * clsidNew [I] The class the clsidOld should be treated as. 3740 * 3741 * RETURNS 3742 * Success: S_OK. 3743 * Failure: HRESULT code. 3744 * 3745 * SEE ALSO 3746 * CoGetTreatAsClass 3747 */ 3748 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew) 3749 { 3750 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0}; 3751 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0}; 3752 HKEY hkey = NULL; 3753 WCHAR szClsidNew[CHARS_IN_GUID]; 3754 HRESULT res = S_OK; 3755 WCHAR auto_treat_as[CHARS_IN_GUID]; 3756 LONG auto_treat_as_size = sizeof(auto_treat_as); 3757 CLSID id; 3758 3759 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey); 3760 if (FAILED(res)) 3761 goto done; 3762 3763 if (IsEqualGUID( clsidOld, clsidNew )) 3764 { 3765 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) && 3766 CLSIDFromString(auto_treat_as, &id) == S_OK) 3767 { 3768 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as))) 3769 { 3770 res = REGDB_E_WRITEREGDB; 3771 goto done; 3772 } 3773 } 3774 else 3775 { 3776 if(RegDeleteKeyW(hkey, wszTreatAs)) 3777 res = REGDB_E_WRITEREGDB; 3778 goto done; 3779 } 3780 } 3781 else 3782 { 3783 if(IsEqualGUID(clsidNew, &CLSID_NULL)){ 3784 RegDeleteKeyW(hkey, wszTreatAs); 3785 }else{ 3786 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){ 3787 WARN("StringFromGUID2 failed\n"); 3788 res = E_FAIL; 3789 goto done; 3790 } 3791 3792 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){ 3793 WARN("RegSetValue failed\n"); 3794 res = REGDB_E_WRITEREGDB; 3795 goto done; 3796 } 3797 } 3798 } 3799 3800 done: 3801 if (hkey) RegCloseKey(hkey); 3802 return res; 3803 } 3804 3805 /****************************************************************************** 3806 * CoGetTreatAsClass [OLE32.@] 3807 * 3808 * Gets the TreatAs value of a class. 3809 * 3810 * PARAMS 3811 * clsidOld [I] Class to get the TreatAs value of. 3812 * clsidNew [I] The class the clsidOld should be treated as. 3813 * 3814 * RETURNS 3815 * Success: S_OK. 3816 * Failure: HRESULT code. 3817 * 3818 * SEE ALSO 3819 * CoSetTreatAsClass 3820 */ 3821 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew) 3822 { 3823 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0}; 3824 HKEY hkey = NULL; 3825 WCHAR szClsidNew[CHARS_IN_GUID]; 3826 HRESULT res = S_OK; 3827 LONG len = sizeof(szClsidNew); 3828 3829 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew); 3830 3831 if (!clsidOld || !clsidNew) 3832 return E_INVALIDARG; 3833 3834 *clsidNew = *clsidOld; /* copy over old value */ 3835 3836 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey); 3837 if (FAILED(res)) 3838 { 3839 res = S_FALSE; 3840 goto done; 3841 } 3842 if (RegQueryValueW(hkey, NULL, szClsidNew, &len)) 3843 { 3844 res = S_FALSE; 3845 goto done; 3846 } 3847 res = CLSIDFromString(szClsidNew,clsidNew); 3848 if (FAILED(res)) 3849 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res); 3850 done: 3851 if (hkey) RegCloseKey(hkey); 3852 return res; 3853 } 3854 3855 /****************************************************************************** 3856 * CoGetCurrentProcess [OLE32.@] 3857 * 3858 * Gets the current process ID. 3859 * 3860 * RETURNS 3861 * The current process ID. 3862 * 3863 * NOTES 3864 * Is DWORD really the correct return type for this function? 3865 */ 3866 DWORD WINAPI CoGetCurrentProcess(void) 3867 { 3868 return GetCurrentProcessId(); 3869 } 3870 3871 /*********************************************************************** 3872 * CoGetCurrentLogicalThreadId [OLE32.@] 3873 */ 3874 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id) 3875 { 3876 TRACE("(%p)\n", id); 3877 3878 if (!id) 3879 return E_INVALIDARG; 3880 3881 *id = COM_CurrentCausalityId(); 3882 return S_OK; 3883 } 3884 3885 /****************************************************************************** 3886 * CoRegisterMessageFilter [OLE32.@] 3887 * 3888 * Registers a message filter. 3889 * 3890 * PARAMS 3891 * lpMessageFilter [I] Pointer to interface. 3892 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL. 3893 * 3894 * RETURNS 3895 * Success: S_OK. 3896 * Failure: HRESULT code. 3897 * 3898 * NOTES 3899 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL 3900 * lpMessageFilter removes the message filter. 3901 * 3902 * If lplpMessageFilter is not NULL the previous message filter will be 3903 * returned in the memory pointer to this parameter and the caller is 3904 * responsible for releasing the object. 3905 * 3906 * The current thread be in an apartment otherwise the function will crash. 3907 */ 3908 HRESULT WINAPI CoRegisterMessageFilter( 3909 LPMESSAGEFILTER lpMessageFilter, 3910 LPMESSAGEFILTER *lplpMessageFilter) 3911 { 3912 struct apartment *apt; 3913 IMessageFilter *lpOldMessageFilter; 3914 3915 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter); 3916 3917 apt = COM_CurrentApt(); 3918 3919 /* can't set a message filter in a multi-threaded apartment */ 3920 if (!apt || apt->multi_threaded) 3921 { 3922 WARN("can't set message filter in MTA or uninitialized apt\n"); 3923 return CO_E_NOT_SUPPORTED; 3924 } 3925 3926 if (lpMessageFilter) 3927 IMessageFilter_AddRef(lpMessageFilter); 3928 3929 EnterCriticalSection(&apt->cs); 3930 3931 lpOldMessageFilter = apt->filter; 3932 apt->filter = lpMessageFilter; 3933 3934 LeaveCriticalSection(&apt->cs); 3935 3936 if (lplpMessageFilter) 3937 *lplpMessageFilter = lpOldMessageFilter; 3938 else if (lpOldMessageFilter) 3939 IMessageFilter_Release(lpOldMessageFilter); 3940 3941 return S_OK; 3942 } 3943 3944 /*********************************************************************** 3945 * CoIsOle1Class [OLE32.@] 3946 * 3947 * Determines whether the specified class an OLE v1 class. 3948 * 3949 * PARAMS 3950 * clsid [I] Class to test. 3951 * 3952 * RETURNS 3953 * TRUE if the class is an OLE v1 class, or FALSE otherwise. 3954 */ 3955 BOOL WINAPI CoIsOle1Class(REFCLSID clsid) 3956 { 3957 FIXME("%s\n", debugstr_guid(clsid)); 3958 return FALSE; 3959 } 3960 3961 /*********************************************************************** 3962 * IsEqualGUID [OLE32.@] 3963 * 3964 * Compares two Unique Identifiers. 3965 * 3966 * PARAMS 3967 * rguid1 [I] The first GUID to compare. 3968 * rguid2 [I] The other GUID to compare. 3969 * 3970 * RETURNS 3971 * TRUE if equal 3972 */ 3973 #undef IsEqualGUID 3974 BOOL WINAPI IsEqualGUID( 3975 REFGUID rguid1, 3976 REFGUID rguid2) 3977 { 3978 return !memcmp(rguid1,rguid2,sizeof(GUID)); 3979 } 3980 3981 /*********************************************************************** 3982 * CoInitializeSecurity [OLE32.@] 3983 */ 3984 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc, 3985 SOLE_AUTHENTICATION_SERVICE* asAuthSvc, 3986 void* pReserved1, DWORD dwAuthnLevel, 3987 DWORD dwImpLevel, void* pReserved2, 3988 DWORD dwCapabilities, void* pReserved3) 3989 { 3990 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc, 3991 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2, 3992 dwCapabilities, pReserved3); 3993 return S_OK; 3994 } 3995 3996 /*********************************************************************** 3997 * CoSuspendClassObjects [OLE32.@] 3998 * 3999 * Suspends all registered class objects to prevent further requests coming in 4000 * for those objects. 4001 * 4002 * RETURNS 4003 * Success: S_OK. 4004 * Failure: HRESULT code. 4005 */ 4006 HRESULT WINAPI CoSuspendClassObjects(void) 4007 { 4008 FIXME("\n"); 4009 return S_OK; 4010 } 4011 4012 /*********************************************************************** 4013 * CoAddRefServerProcess [OLE32.@] 4014 * 4015 * Helper function for incrementing the reference count of a local-server 4016 * process. 4017 * 4018 * RETURNS 4019 * New reference count. 4020 * 4021 * SEE ALSO 4022 * CoReleaseServerProcess(). 4023 */ 4024 ULONG WINAPI CoAddRefServerProcess(void) 4025 { 4026 ULONG refs; 4027 4028 TRACE("\n"); 4029 4030 EnterCriticalSection(&csRegisteredClassList); 4031 refs = ++s_COMServerProcessReferences; 4032 LeaveCriticalSection(&csRegisteredClassList); 4033 4034 TRACE("refs before: %d\n", refs - 1); 4035 4036 return refs; 4037 } 4038 4039 /*********************************************************************** 4040 * CoReleaseServerProcess [OLE32.@] 4041 * 4042 * Helper function for decrementing the reference count of a local-server 4043 * process. 4044 * 4045 * RETURNS 4046 * New reference count. 4047 * 4048 * NOTES 4049 * When reference count reaches 0, this function suspends all registered 4050 * classes so no new connections are accepted. 4051 * 4052 * SEE ALSO 4053 * CoAddRefServerProcess(), CoSuspendClassObjects(). 4054 */ 4055 ULONG WINAPI CoReleaseServerProcess(void) 4056 { 4057 ULONG refs; 4058 4059 TRACE("\n"); 4060 4061 EnterCriticalSection(&csRegisteredClassList); 4062 4063 refs = --s_COMServerProcessReferences; 4064 /* FIXME: if (!refs) COM_SuspendClassObjects(); */ 4065 4066 LeaveCriticalSection(&csRegisteredClassList); 4067 4068 TRACE("refs after: %d\n", refs); 4069 4070 return refs; 4071 } 4072 4073 /*********************************************************************** 4074 * CoIsHandlerConnected [OLE32.@] 4075 * 4076 * Determines whether a proxy is connected to a remote stub. 4077 * 4078 * PARAMS 4079 * pUnk [I] Pointer to object that may or may not be connected. 4080 * 4081 * RETURNS 4082 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or 4083 * FALSE otherwise. 4084 */ 4085 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk) 4086 { 4087 FIXME("%p\n", pUnk); 4088 4089 return TRUE; 4090 } 4091 4092 /*********************************************************************** 4093 * CoAllowSetForegroundWindow [OLE32.@] 4094 * 4095 */ 4096 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved) 4097 { 4098 FIXME("(%p, %p): stub\n", pUnk, pvReserved); 4099 return S_OK; 4100 } 4101 4102 /*********************************************************************** 4103 * CoQueryProxyBlanket [OLE32.@] 4104 * 4105 * Retrieves the security settings being used by a proxy. 4106 * 4107 * PARAMS 4108 * pProxy [I] Pointer to the proxy object. 4109 * pAuthnSvc [O] The type of authentication service. 4110 * pAuthzSvc [O] The type of authorization service. 4111 * ppServerPrincName [O] Optional. The server prinicple name. 4112 * pAuthnLevel [O] The authentication level. 4113 * pImpLevel [O] The impersonation level. 4114 * ppAuthInfo [O] Information specific to the authorization/authentication service. 4115 * pCapabilities [O] Flags affecting the security behaviour. 4116 * 4117 * RETURNS 4118 * Success: S_OK. 4119 * Failure: HRESULT code. 4120 * 4121 * SEE ALSO 4122 * CoCopyProxy, CoSetProxyBlanket. 4123 */ 4124 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc, 4125 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel, 4126 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities) 4127 { 4128 IClientSecurity *pCliSec; 4129 HRESULT hr; 4130 4131 TRACE("%p\n", pProxy); 4132 4133 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 4134 if (SUCCEEDED(hr)) 4135 { 4136 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc, 4137 pAuthzSvc, ppServerPrincName, 4138 pAuthnLevel, pImpLevel, ppAuthInfo, 4139 pCapabilities); 4140 IClientSecurity_Release(pCliSec); 4141 } 4142 4143 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 4144 return hr; 4145 } 4146 4147 /*********************************************************************** 4148 * CoSetProxyBlanket [OLE32.@] 4149 * 4150 * Sets the security settings for a proxy. 4151 * 4152 * PARAMS 4153 * pProxy [I] Pointer to the proxy object. 4154 * AuthnSvc [I] The type of authentication service. 4155 * AuthzSvc [I] The type of authorization service. 4156 * pServerPrincName [I] The server prinicple name. 4157 * AuthnLevel [I] The authentication level. 4158 * ImpLevel [I] The impersonation level. 4159 * pAuthInfo [I] Information specific to the authorization/authentication service. 4160 * Capabilities [I] Flags affecting the security behaviour. 4161 * 4162 * RETURNS 4163 * Success: S_OK. 4164 * Failure: HRESULT code. 4165 * 4166 * SEE ALSO 4167 * CoQueryProxyBlanket, CoCopyProxy. 4168 */ 4169 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc, 4170 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel, 4171 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities) 4172 { 4173 IClientSecurity *pCliSec; 4174 HRESULT hr; 4175 4176 TRACE("%p\n", pProxy); 4177 4178 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 4179 if (SUCCEEDED(hr)) 4180 { 4181 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc, 4182 AuthzSvc, pServerPrincName, 4183 AuthnLevel, ImpLevel, pAuthInfo, 4184 Capabilities); 4185 IClientSecurity_Release(pCliSec); 4186 } 4187 4188 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 4189 return hr; 4190 } 4191 4192 /*********************************************************************** 4193 * CoCopyProxy [OLE32.@] 4194 * 4195 * Copies a proxy. 4196 * 4197 * PARAMS 4198 * pProxy [I] Pointer to the proxy object. 4199 * ppCopy [O] Copy of the proxy. 4200 * 4201 * RETURNS 4202 * Success: S_OK. 4203 * Failure: HRESULT code. 4204 * 4205 * SEE ALSO 4206 * CoQueryProxyBlanket, CoSetProxyBlanket. 4207 */ 4208 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy) 4209 { 4210 IClientSecurity *pCliSec; 4211 HRESULT hr; 4212 4213 TRACE("%p\n", pProxy); 4214 4215 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 4216 if (SUCCEEDED(hr)) 4217 { 4218 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy); 4219 IClientSecurity_Release(pCliSec); 4220 } 4221 4222 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 4223 return hr; 4224 } 4225 4226 4227 /*********************************************************************** 4228 * CoGetCallContext [OLE32.@] 4229 * 4230 * Gets the context of the currently executing server call in the current 4231 * thread. 4232 * 4233 * PARAMS 4234 * riid [I] Context interface to return. 4235 * ppv [O] Pointer to memory that will receive the context on return. 4236 * 4237 * RETURNS 4238 * Success: S_OK. 4239 * Failure: HRESULT code. 4240 */ 4241 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv) 4242 { 4243 struct oletls *info = COM_CurrentInfo(); 4244 4245 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 4246 4247 if (!info) 4248 return E_OUTOFMEMORY; 4249 4250 if (!info->call_state) 4251 return RPC_E_CALL_COMPLETE; 4252 4253 return IUnknown_QueryInterface(info->call_state, riid, ppv); 4254 } 4255 4256 /*********************************************************************** 4257 * CoSwitchCallContext [OLE32.@] 4258 * 4259 * Switches the context of the currently executing server call in the current 4260 * thread. 4261 * 4262 * PARAMS 4263 * pObject [I] Pointer to new context object 4264 * ppOldObject [O] Pointer to memory that will receive old context object pointer 4265 * 4266 * RETURNS 4267 * Success: S_OK. 4268 * Failure: HRESULT code. 4269 */ 4270 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject) 4271 { 4272 struct oletls *info = COM_CurrentInfo(); 4273 4274 TRACE("(%p, %p)\n", pObject, ppOldObject); 4275 4276 if (!info) 4277 return E_OUTOFMEMORY; 4278 4279 *ppOldObject = info->call_state; 4280 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */ 4281 4282 return S_OK; 4283 } 4284 4285 /*********************************************************************** 4286 * CoQueryClientBlanket [OLE32.@] 4287 * 4288 * Retrieves the authentication information about the client of the currently 4289 * executing server call in the current thread. 4290 * 4291 * PARAMS 4292 * pAuthnSvc [O] Optional. The type of authentication service. 4293 * pAuthzSvc [O] Optional. The type of authorization service. 4294 * pServerPrincName [O] Optional. The server prinicple name. 4295 * pAuthnLevel [O] Optional. The authentication level. 4296 * pImpLevel [O] Optional. The impersonation level. 4297 * pPrivs [O] Optional. Information about the privileges of the client. 4298 * pCapabilities [IO] Optional. Flags affecting the security behaviour. 4299 * 4300 * RETURNS 4301 * Success: S_OK. 4302 * Failure: HRESULT code. 4303 * 4304 * SEE ALSO 4305 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext. 4306 */ 4307 HRESULT WINAPI CoQueryClientBlanket( 4308 DWORD *pAuthnSvc, 4309 DWORD *pAuthzSvc, 4310 OLECHAR **pServerPrincName, 4311 DWORD *pAuthnLevel, 4312 DWORD *pImpLevel, 4313 RPC_AUTHZ_HANDLE *pPrivs, 4314 DWORD *pCapabilities) 4315 { 4316 IServerSecurity *pSrvSec; 4317 HRESULT hr; 4318 4319 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n", 4320 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel, 4321 pPrivs, pCapabilities); 4322 4323 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 4324 if (SUCCEEDED(hr)) 4325 { 4326 hr = IServerSecurity_QueryBlanket( 4327 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, 4328 pImpLevel, pPrivs, pCapabilities); 4329 IServerSecurity_Release(pSrvSec); 4330 } 4331 4332 return hr; 4333 } 4334 4335 /*********************************************************************** 4336 * CoImpersonateClient [OLE32.@] 4337 * 4338 * Impersonates the client of the currently executing server call in the 4339 * current thread. 4340 * 4341 * PARAMS 4342 * None. 4343 * 4344 * RETURNS 4345 * Success: S_OK. 4346 * Failure: HRESULT code. 4347 * 4348 * NOTES 4349 * If this function fails then the current thread will not be impersonating 4350 * the client and all actions will take place on behalf of the server. 4351 * Therefore, it is important to check the return value from this function. 4352 * 4353 * SEE ALSO 4354 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext. 4355 */ 4356 HRESULT WINAPI CoImpersonateClient(void) 4357 { 4358 IServerSecurity *pSrvSec; 4359 HRESULT hr; 4360 4361 TRACE("\n"); 4362 4363 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 4364 if (SUCCEEDED(hr)) 4365 { 4366 hr = IServerSecurity_ImpersonateClient(pSrvSec); 4367 IServerSecurity_Release(pSrvSec); 4368 } 4369 4370 return hr; 4371 } 4372 4373 /*********************************************************************** 4374 * CoRevertToSelf [OLE32.@] 4375 * 4376 * Ends the impersonation of the client of the currently executing server 4377 * call in the current thread. 4378 * 4379 * PARAMS 4380 * None. 4381 * 4382 * RETURNS 4383 * Success: S_OK. 4384 * Failure: HRESULT code. 4385 * 4386 * SEE ALSO 4387 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext. 4388 */ 4389 HRESULT WINAPI CoRevertToSelf(void) 4390 { 4391 IServerSecurity *pSrvSec; 4392 HRESULT hr; 4393 4394 TRACE("\n"); 4395 4396 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 4397 if (SUCCEEDED(hr)) 4398 { 4399 hr = IServerSecurity_RevertToSelf(pSrvSec); 4400 IServerSecurity_Release(pSrvSec); 4401 } 4402 4403 return hr; 4404 } 4405 4406 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg) 4407 { 4408 /* first try to retrieve messages for incoming COM calls to the apartment window */ 4409 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) || 4410 /* next retrieve other messages necessary for the app to remain responsive */ 4411 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) || 4412 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD); 4413 } 4414 4415 /*********************************************************************** 4416 * CoWaitForMultipleHandles [OLE32.@] 4417 * 4418 * Waits for one or more handles to become signaled. 4419 * 4420 * PARAMS 4421 * dwFlags [I] Flags. See notes. 4422 * dwTimeout [I] Timeout in milliseconds. 4423 * cHandles [I] Number of handles pointed to by pHandles. 4424 * pHandles [I] Handles to wait for. 4425 * lpdwindex [O] Index of handle that was signaled. 4426 * 4427 * RETURNS 4428 * Success: S_OK. 4429 * Failure: RPC_S_CALLPENDING on timeout. 4430 * 4431 * NOTES 4432 * 4433 * The dwFlags parameter can be zero or more of the following: 4434 *| COWAIT_WAITALL - Wait for all of the handles to become signaled. 4435 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait. 4436 * 4437 * SEE ALSO 4438 * MsgWaitForMultipleObjects, WaitForMultipleObjects. 4439 */ 4440 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, 4441 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex) 4442 { 4443 HRESULT hr = S_OK; 4444 DWORD start_time = GetTickCount(); 4445 APARTMENT *apt = COM_CurrentApt(); 4446 BOOL message_loop = apt && !apt->multi_threaded; 4447 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0; 4448 4449 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles, 4450 pHandles, lpdwindex); 4451 4452 if (!lpdwindex) 4453 return E_INVALIDARG; 4454 4455 *lpdwindex = 0; 4456 4457 if (!pHandles) 4458 return E_INVALIDARG; 4459 4460 if (!cHandles) 4461 return RPC_E_NO_SYNC; 4462 4463 while (TRUE) 4464 { 4465 DWORD now = GetTickCount(); 4466 DWORD res; 4467 4468 if (now - start_time > dwTimeout) 4469 { 4470 hr = RPC_S_CALLPENDING; 4471 break; 4472 } 4473 4474 if (message_loop) 4475 { 4476 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) | 4477 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0); 4478 4479 TRACE("waiting for rpc completion or window message\n"); 4480 4481 res = WAIT_TIMEOUT; 4482 4483 if (check_apc) 4484 { 4485 res = WaitForMultipleObjectsEx(cHandles, pHandles, 4486 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE); 4487 check_apc = FALSE; 4488 } 4489 4490 if (res == WAIT_TIMEOUT) 4491 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles, 4492 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, 4493 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags); 4494 4495 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */ 4496 { 4497 MSG msg; 4498 int count = 0; 4499 4500 /* call message filter */ 4501 4502 if (COM_CurrentApt()->filter) 4503 { 4504 PENDINGTYPE pendingtype = 4505 COM_CurrentInfo()->pending_call_count_server ? 4506 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL; 4507 DWORD be_handled = IMessageFilter_MessagePending( 4508 COM_CurrentApt()->filter, 0 /* FIXME */, 4509 now - start_time, pendingtype); 4510 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled); 4511 switch (be_handled) 4512 { 4513 case PENDINGMSG_CANCELCALL: 4514 WARN("call canceled\n"); 4515 hr = RPC_E_CALL_CANCELED; 4516 break; 4517 case PENDINGMSG_WAITNOPROCESS: 4518 case PENDINGMSG_WAITDEFPROCESS: 4519 default: 4520 /* FIXME: MSDN is very vague about the difference 4521 * between WAITNOPROCESS and WAITDEFPROCESS - there 4522 * appears to be none, so it is possibly a left-over 4523 * from the 16-bit world. */ 4524 break; 4525 } 4526 } 4527 4528 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever, 4529 * so after processing 100 messages we go back to checking the wait handles */ 4530 while (count++ < 100 && COM_PeekMessage(apt, &msg)) 4531 { 4532 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message); 4533 TranslateMessage(&msg); 4534 DispatchMessageW(&msg); 4535 if (msg.message == WM_QUIT) 4536 { 4537 TRACE("resending WM_QUIT to outer message loop\n"); 4538 PostQuitMessage(msg.wParam); 4539 /* no longer need to process messages */ 4540 message_loop = FALSE; 4541 break; 4542 } 4543 } 4544 continue; 4545 } 4546 } 4547 else 4548 { 4549 TRACE("waiting for rpc completion\n"); 4550 4551 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0, 4552 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, 4553 (dwFlags & COWAIT_ALERTABLE) != 0); 4554 } 4555 4556 switch (res) 4557 { 4558 case WAIT_TIMEOUT: 4559 hr = RPC_S_CALLPENDING; 4560 break; 4561 case WAIT_FAILED: 4562 hr = HRESULT_FROM_WIN32( GetLastError() ); 4563 break; 4564 default: 4565 *lpdwindex = res; 4566 break; 4567 } 4568 break; 4569 } 4570 TRACE("-- 0x%08x\n", hr); 4571 return hr; 4572 } 4573 4574 4575 /*********************************************************************** 4576 * CoGetObject [OLE32.@] 4577 * 4578 * Gets the object named by converting the name to a moniker and binding to it. 4579 * 4580 * PARAMS 4581 * pszName [I] String representing the object. 4582 * pBindOptions [I] Parameters affecting the binding to the named object. 4583 * riid [I] Interface to bind to on the objecct. 4584 * ppv [O] On output, the interface riid of the object represented 4585 * by pszName. 4586 * 4587 * RETURNS 4588 * Success: S_OK. 4589 * Failure: HRESULT code. 4590 * 4591 * SEE ALSO 4592 * MkParseDisplayName. 4593 */ 4594 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions, 4595 REFIID riid, void **ppv) 4596 { 4597 IBindCtx *pbc; 4598 HRESULT hr; 4599 4600 *ppv = NULL; 4601 4602 hr = CreateBindCtx(0, &pbc); 4603 if (SUCCEEDED(hr)) 4604 { 4605 if (pBindOptions) 4606 hr = IBindCtx_SetBindOptions(pbc, pBindOptions); 4607 4608 if (SUCCEEDED(hr)) 4609 { 4610 ULONG chEaten; 4611 IMoniker *pmk; 4612 4613 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk); 4614 if (SUCCEEDED(hr)) 4615 { 4616 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv); 4617 IMoniker_Release(pmk); 4618 } 4619 } 4620 4621 IBindCtx_Release(pbc); 4622 } 4623 return hr; 4624 } 4625 4626 /*********************************************************************** 4627 * CoRegisterChannelHook [OLE32.@] 4628 * 4629 * Registers a process-wide hook that is called during ORPC calls. 4630 * 4631 * PARAMS 4632 * guidExtension [I] GUID of the channel hook to register. 4633 * pChannelHook [I] Channel hook object to register. 4634 * 4635 * RETURNS 4636 * Success: S_OK. 4637 * Failure: HRESULT code. 4638 */ 4639 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook) 4640 { 4641 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook); 4642 4643 return RPC_RegisterChannelHook(guidExtension, pChannelHook); 4644 } 4645 4646 typedef struct Context 4647 { 4648 IComThreadingInfo IComThreadingInfo_iface; 4649 IContextCallback IContextCallback_iface; 4650 IObjContext IObjContext_iface; 4651 LONG refs; 4652 } Context; 4653 4654 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface ) 4655 { 4656 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface); 4657 } 4658 4659 static inline Context *impl_from_IContextCallback( IContextCallback *iface ) 4660 { 4661 return CONTAINING_RECORD(iface, Context, IContextCallback_iface); 4662 } 4663 4664 static inline Context *impl_from_IObjContext( IObjContext *iface ) 4665 { 4666 return CONTAINING_RECORD(iface, Context, IObjContext_iface); 4667 } 4668 4669 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv) 4670 { 4671 *ppv = NULL; 4672 4673 if (IsEqualIID(riid, &IID_IComThreadingInfo) || 4674 IsEqualIID(riid, &IID_IUnknown)) 4675 { 4676 *ppv = &iface->IComThreadingInfo_iface; 4677 } 4678 else if (IsEqualIID(riid, &IID_IContextCallback)) 4679 { 4680 *ppv = &iface->IContextCallback_iface; 4681 } 4682 else if (IsEqualIID(riid, &IID_IObjContext)) 4683 { 4684 *ppv = &iface->IObjContext_iface; 4685 } 4686 4687 if (*ppv) 4688 { 4689 IUnknown_AddRef((IUnknown*)*ppv); 4690 return S_OK; 4691 } 4692 4693 FIXME("interface not implemented %s\n", debugstr_guid(riid)); 4694 return E_NOINTERFACE; 4695 } 4696 4697 static ULONG Context_AddRef(Context *This) 4698 { 4699 return InterlockedIncrement(&This->refs); 4700 } 4701 4702 static ULONG Context_Release(Context *This) 4703 { 4704 /* Context instance is initially created with CoGetContextToken() with refcount set to 0, 4705 releasing context while refcount is at 0 destroys it. */ 4706 if (!This->refs) 4707 { 4708 HeapFree(GetProcessHeap(), 0, This); 4709 return 0; 4710 } 4711 4712 return InterlockedDecrement(&This->refs); 4713 } 4714 4715 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv) 4716 { 4717 Context *This = impl_from_IComThreadingInfo(iface); 4718 return Context_QueryInterface(This, riid, ppv); 4719 } 4720 4721 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface) 4722 { 4723 Context *This = impl_from_IComThreadingInfo(iface); 4724 return Context_AddRef(This); 4725 } 4726 4727 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface) 4728 { 4729 Context *This = impl_from_IComThreadingInfo(iface); 4730 return Context_Release(This); 4731 } 4732 4733 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype) 4734 { 4735 APTTYPEQUALIFIER qualifier; 4736 4737 TRACE("(%p)\n", apttype); 4738 4739 return CoGetApartmentType(apttype, &qualifier); 4740 } 4741 4742 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype) 4743 { 4744 APTTYPEQUALIFIER qualifier; 4745 APTTYPE apttype; 4746 HRESULT hr; 4747 4748 hr = CoGetApartmentType(&apttype, &qualifier); 4749 if (FAILED(hr)) 4750 return hr; 4751 4752 TRACE("(%p)\n", thdtype); 4753 4754 switch (apttype) 4755 { 4756 case APTTYPE_STA: 4757 case APTTYPE_MAINSTA: 4758 *thdtype = THDTYPE_PROCESSMESSAGES; 4759 break; 4760 default: 4761 *thdtype = THDTYPE_BLOCKMESSAGES; 4762 break; 4763 } 4764 return S_OK; 4765 } 4766 4767 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id) 4768 { 4769 TRACE("(%p)\n", logical_thread_id); 4770 return CoGetCurrentLogicalThreadId(logical_thread_id); 4771 } 4772 4773 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id) 4774 { 4775 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id)); 4776 return E_NOTIMPL; 4777 } 4778 4779 static const IComThreadingInfoVtbl Context_Threading_Vtbl = 4780 { 4781 Context_CTI_QueryInterface, 4782 Context_CTI_AddRef, 4783 Context_CTI_Release, 4784 Context_CTI_GetCurrentApartmentType, 4785 Context_CTI_GetCurrentThreadType, 4786 Context_CTI_GetCurrentLogicalThreadId, 4787 Context_CTI_SetCurrentLogicalThreadId 4788 }; 4789 4790 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv) 4791 { 4792 Context *This = impl_from_IContextCallback(iface); 4793 return Context_QueryInterface(This, riid, ppv); 4794 } 4795 4796 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface) 4797 { 4798 Context *This = impl_from_IContextCallback(iface); 4799 return Context_AddRef(This); 4800 } 4801 4802 static ULONG WINAPI Context_CC_Release(IContextCallback *iface) 4803 { 4804 Context *This = impl_from_IContextCallback(iface); 4805 return Context_Release(This); 4806 } 4807 4808 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback, 4809 ComCallData *param, REFIID riid, int method, IUnknown *punk) 4810 { 4811 Context *This = impl_from_IContextCallback(iface); 4812 4813 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk); 4814 return E_NOTIMPL; 4815 } 4816 4817 static const IContextCallbackVtbl Context_Callback_Vtbl = 4818 { 4819 Context_CC_QueryInterface, 4820 Context_CC_AddRef, 4821 Context_CC_Release, 4822 Context_CC_ContextCallback 4823 }; 4824 4825 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv) 4826 { 4827 Context *This = impl_from_IObjContext(iface); 4828 return Context_QueryInterface(This, riid, ppv); 4829 } 4830 4831 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface) 4832 { 4833 Context *This = impl_from_IObjContext(iface); 4834 return Context_AddRef(This); 4835 } 4836 4837 static ULONG WINAPI Context_OC_Release(IObjContext *iface) 4838 { 4839 Context *This = impl_from_IObjContext(iface); 4840 return Context_Release(This); 4841 } 4842 4843 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk) 4844 { 4845 Context *This = impl_from_IObjContext(iface); 4846 4847 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk); 4848 return E_NOTIMPL; 4849 } 4850 4851 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid) 4852 { 4853 Context *This = impl_from_IObjContext(iface); 4854 4855 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid)); 4856 return E_NOTIMPL; 4857 } 4858 4859 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk) 4860 { 4861 Context *This = impl_from_IObjContext(iface); 4862 4863 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk); 4864 return E_NOTIMPL; 4865 } 4866 4867 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props) 4868 { 4869 Context *This = impl_from_IObjContext(iface); 4870 4871 FIXME("(%p/%p)->(%p)\n", This, iface, props); 4872 return E_NOTIMPL; 4873 } 4874 4875 static void WINAPI Context_OC_Reserved1(IObjContext *iface) 4876 { 4877 Context *This = impl_from_IObjContext(iface); 4878 FIXME("(%p/%p)\n", This, iface); 4879 } 4880 4881 static void WINAPI Context_OC_Reserved2(IObjContext *iface) 4882 { 4883 Context *This = impl_from_IObjContext(iface); 4884 FIXME("(%p/%p)\n", This, iface); 4885 } 4886 4887 static void WINAPI Context_OC_Reserved3(IObjContext *iface) 4888 { 4889 Context *This = impl_from_IObjContext(iface); 4890 FIXME("(%p/%p)\n", This, iface); 4891 } 4892 4893 static void WINAPI Context_OC_Reserved4(IObjContext *iface) 4894 { 4895 Context *This = impl_from_IObjContext(iface); 4896 FIXME("(%p/%p)\n", This, iface); 4897 } 4898 4899 static void WINAPI Context_OC_Reserved5(IObjContext *iface) 4900 { 4901 Context *This = impl_from_IObjContext(iface); 4902 FIXME("(%p/%p)\n", This, iface); 4903 } 4904 4905 static void WINAPI Context_OC_Reserved6(IObjContext *iface) 4906 { 4907 Context *This = impl_from_IObjContext(iface); 4908 FIXME("(%p/%p)\n", This, iface); 4909 } 4910 4911 static void WINAPI Context_OC_Reserved7(IObjContext *iface) 4912 { 4913 Context *This = impl_from_IObjContext(iface); 4914 FIXME("(%p/%p)\n", This, iface); 4915 } 4916 4917 static const IObjContextVtbl Context_Object_Vtbl = 4918 { 4919 Context_OC_QueryInterface, 4920 Context_OC_AddRef, 4921 Context_OC_Release, 4922 Context_OC_SetProperty, 4923 Context_OC_RemoveProperty, 4924 Context_OC_GetProperty, 4925 Context_OC_EnumContextProps, 4926 Context_OC_Reserved1, 4927 Context_OC_Reserved2, 4928 Context_OC_Reserved3, 4929 Context_OC_Reserved4, 4930 Context_OC_Reserved5, 4931 Context_OC_Reserved6, 4932 Context_OC_Reserved7 4933 }; 4934 4935 /*********************************************************************** 4936 * CoGetObjectContext [OLE32.@] 4937 * 4938 * Retrieves an object associated with the current context (i.e. apartment). 4939 * 4940 * PARAMS 4941 * riid [I] ID of the interface of the object to retrieve. 4942 * ppv [O] Address where object will be stored on return. 4943 * 4944 * RETURNS 4945 * Success: S_OK. 4946 * Failure: HRESULT code. 4947 */ 4948 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) 4949 { 4950 IObjContext *context; 4951 HRESULT hr; 4952 4953 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 4954 4955 *ppv = NULL; 4956 hr = CoGetContextToken((ULONG_PTR*)&context); 4957 if (FAILED(hr)) 4958 return hr; 4959 4960 return IObjContext_QueryInterface(context, riid, ppv); 4961 } 4962 4963 /*********************************************************************** 4964 * CoGetContextToken [OLE32.@] 4965 */ 4966 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token ) 4967 { 4968 struct oletls *info = COM_CurrentInfo(); 4969 4970 TRACE("(%p)\n", token); 4971 4972 if (!info) 4973 return E_OUTOFMEMORY; 4974 4975 if (!info->apt) 4976 { 4977 APARTMENT *apt; 4978 if (!(apt = apartment_find_multi_threaded())) 4979 { 4980 ERR("apartment not initialised\n"); 4981 return CO_E_NOTINITIALIZED; 4982 } 4983 apartment_release(apt); 4984 } 4985 4986 if (!token) 4987 return E_POINTER; 4988 4989 if (!info->context_token) 4990 { 4991 Context *context; 4992 4993 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context)); 4994 if (!context) 4995 return E_OUTOFMEMORY; 4996 4997 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl; 4998 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl; 4999 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl; 5000 /* Context token does not take a reference, it's always zero until the 5001 interface is explicitly requested with CoGetObjectContext(). */ 5002 context->refs = 0; 5003 5004 info->context_token = &context->IObjContext_iface; 5005 } 5006 5007 *token = (ULONG_PTR)info->context_token; 5008 TRACE("context_token=%p\n", info->context_token); 5009 5010 return S_OK; 5011 } 5012 5013 /*********************************************************************** 5014 * CoGetDefaultContext [OLE32.@] 5015 */ 5016 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv) 5017 { 5018 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv); 5019 return E_NOINTERFACE; 5020 } 5021 5022 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 5023 { 5024 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; 5025 HKEY hkey; 5026 HRESULT hres; 5027 5028 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey); 5029 if (SUCCEEDED(hres)) 5030 { 5031 struct class_reg_data regdata; 5032 WCHAR dllpath[MAX_PATH+1]; 5033 5034 regdata.u.hkey = hkey; 5035 regdata.hkey = TRUE; 5036 5037 if (COM_RegReadPath(®data, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS) 5038 { 5039 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; 5040 if (!strcmpiW(dllpath, wszOle32)) 5041 { 5042 RegCloseKey(hkey); 5043 return HandlerCF_Create(rclsid, riid, ppv); 5044 } 5045 } 5046 else 5047 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath)); 5048 RegCloseKey(hkey); 5049 } 5050 5051 return CLASS_E_CLASSNOTAVAILABLE; 5052 } 5053 5054 /*********************************************************************** 5055 * CoGetApartmentType [OLE32.@] 5056 */ 5057 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) 5058 { 5059 struct oletls *info = COM_CurrentInfo(); 5060 5061 FIXME("(%p, %p): semi-stub\n", type, qualifier); 5062 5063 if (!type || !qualifier) 5064 return E_INVALIDARG; 5065 5066 if (!info) 5067 return E_OUTOFMEMORY; 5068 5069 if (!info->apt) 5070 *type = APTTYPE_CURRENT; 5071 else if (info->apt->multi_threaded) 5072 *type = APTTYPE_MTA; 5073 else if (info->apt->main) 5074 *type = APTTYPE_MAINSTA; 5075 else 5076 *type = APTTYPE_STA; 5077 5078 *qualifier = APTTYPEQUALIFIER_NONE; 5079 5080 return info->apt ? S_OK : CO_E_NOTINITIALIZED; 5081 } 5082 5083 /*********************************************************************** 5084 * CoRegisterSurrogate [OLE32.@] 5085 */ 5086 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate) 5087 { 5088 FIXME("(%p): stub\n", surrogate); 5089 5090 return E_NOTIMPL; 5091 } 5092 5093 /*********************************************************************** 5094 * CoRegisterSurrogateEx [OLE32.@] 5095 */ 5096 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved) 5097 { 5098 FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved); 5099 5100 return E_NOTIMPL; 5101 } 5102 5103 typedef struct { 5104 IGlobalOptions IGlobalOptions_iface; 5105 LONG ref; 5106 } GlobalOptions; 5107 5108 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface) 5109 { 5110 return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface); 5111 } 5112 5113 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv) 5114 { 5115 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5116 5117 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 5118 5119 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid)) 5120 { 5121 *ppv = iface; 5122 } 5123 else 5124 { 5125 *ppv = NULL; 5126 return E_NOINTERFACE; 5127 } 5128 5129 IUnknown_AddRef((IUnknown*)*ppv); 5130 return S_OK; 5131 } 5132 5133 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface) 5134 { 5135 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5136 LONG ref = InterlockedIncrement(&This->ref); 5137 5138 TRACE("(%p) ref=%d\n", This, ref); 5139 5140 return ref; 5141 } 5142 5143 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface) 5144 { 5145 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5146 LONG ref = InterlockedDecrement(&This->ref); 5147 5148 TRACE("(%p) ref=%d\n", This, ref); 5149 5150 if (!ref) 5151 heap_free(This); 5152 5153 return ref; 5154 } 5155 5156 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value) 5157 { 5158 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5159 FIXME("(%p)->(%u %lx)\n", This, property, value); 5160 return S_OK; 5161 } 5162 5163 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value) 5164 { 5165 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5166 FIXME("(%p)->(%u %p)\n", This, property, value); 5167 return E_NOTIMPL; 5168 } 5169 5170 static const IGlobalOptionsVtbl GlobalOptionsVtbl = { 5171 GlobalOptions_QueryInterface, 5172 GlobalOptions_AddRef, 5173 GlobalOptions_Release, 5174 GlobalOptions_Set, 5175 GlobalOptions_Query 5176 }; 5177 5178 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) 5179 { 5180 GlobalOptions *global_options; 5181 HRESULT hres; 5182 5183 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv); 5184 5185 if (outer) 5186 return E_INVALIDARG; 5187 5188 global_options = heap_alloc(sizeof(*global_options)); 5189 if (!global_options) 5190 return E_OUTOFMEMORY; 5191 global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl; 5192 global_options->ref = 1; 5193 5194 hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv); 5195 IGlobalOptions_Release(&global_options->IGlobalOptions_iface); 5196 return hres; 5197 } 5198 5199 /*********************************************************************** 5200 * DllMain (OLE32.@) 5201 */ 5202 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved) 5203 { 5204 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved); 5205 5206 switch(fdwReason) { 5207 case DLL_PROCESS_ATTACH: 5208 hProxyDll = hinstDLL; 5209 break; 5210 5211 case DLL_PROCESS_DETACH: 5212 if (reserved) break; 5213 release_std_git(); 5214 UnregisterClassW( wszAptWinClass, hProxyDll ); 5215 RPC_UnregisterAllChannelHooks(); 5216 COMPOBJ_DllList_Free(); 5217 DeleteCriticalSection(&csRegisteredClassList); 5218 DeleteCriticalSection(&csApartment); 5219 break; 5220 5221 case DLL_THREAD_DETACH: 5222 COM_TlsDestroy(); 5223 break; 5224 } 5225 return TRUE; 5226 } 5227 5228 /*********************************************************************** 5229 * DllRegisterServer (OLE32.@) 5230 */ 5231 HRESULT WINAPI DllRegisterServer(void) 5232 { 5233 return OLE32_DllRegisterServer(); 5234 } 5235 5236 /*********************************************************************** 5237 * DllUnregisterServer (OLE32.@) 5238 */ 5239 HRESULT WINAPI DllUnregisterServer(void) 5240 { 5241 return OLE32_DllUnregisterServer(); 5242 } 5243