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