combase: Move CoFreeUnusedLibraries().
[wine.git] / dlls / ole32 / compobj.c
blobf983b07f20bb5b418d2c67ae5a896229e0616002
1 /*
2 * COMPOBJ library
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)
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.
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.
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
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
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
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <assert.h>
44 #define COBJMACROS
45 #define NONAMELESSUNION
47 #include "ntstatus.h"
48 #define WIN32_NO_STATUS
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winerror.h"
52 #include "winreg.h"
53 #include "winuser.h"
54 #define USE_COM_CONTEXT_DEF
55 #include "objbase.h"
56 #include "ole2.h"
57 #include "ole2ver.h"
58 #include "ctxtcall.h"
59 #include "dde.h"
60 #include "servprov.h"
62 #include "initguid.h"
63 #include "compobj_private.h"
64 #include "moniker.h"
66 #include "wine/debug.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(ole);
70 /****************************************************************************
71 * This section defines variables internal to the COM module.
74 static APARTMENT *MTA; /* protected by csApartment */
75 static APARTMENT *MainApartment; /* the first STA apartment */
76 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
78 static CRITICAL_SECTION csApartment;
79 static CRITICAL_SECTION_DEBUG critsect_debug =
81 0, 0, &csApartment,
82 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
83 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
85 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
87 enum comclass_threadingmodel
89 ThreadingModel_Apartment = 1,
90 ThreadingModel_Free = 2,
91 ThreadingModel_No = 3,
92 ThreadingModel_Both = 4,
93 ThreadingModel_Neutral = 5
96 enum comclass_miscfields
98 MiscStatus = 1,
99 MiscStatusIcon = 2,
100 MiscStatusContent = 4,
101 MiscStatusThumbnail = 8,
102 MiscStatusDocPrint = 16
105 struct comclassredirect_data
107 ULONG size;
108 ULONG flags;
109 DWORD model;
110 GUID clsid;
111 GUID alias;
112 GUID clsid2;
113 GUID tlbid;
114 ULONG name_len;
115 ULONG name_offset;
116 ULONG progid_len;
117 ULONG progid_offset;
118 ULONG clrdata_len;
119 ULONG clrdata_offset;
120 DWORD miscstatus;
121 DWORD miscstatuscontent;
122 DWORD miscstatusthumbnail;
123 DWORD miscstatusicon;
124 DWORD miscstatusdocprint;
127 struct ifacepsredirect_data
129 ULONG size;
130 DWORD mask;
131 GUID iid;
132 ULONG nummethods;
133 GUID tlbid;
134 GUID base;
135 ULONG name_len;
136 ULONG name_offset;
139 struct progidredirect_data
141 ULONG size;
142 DWORD reserved;
143 ULONG clsid_offset;
146 enum class_reg_data_origin
148 CLASS_REG_ACTCTX,
149 CLASS_REG_REGISTRY,
152 struct class_reg_data
154 enum class_reg_data_origin origin;
155 union
157 struct
159 const WCHAR *module_name;
160 DWORD threading_model;
161 HANDLE hactctx;
162 } actctx;
163 HKEY hkey;
164 } u;
167 struct registered_psclsid
169 struct list entry;
170 IID iid;
171 CLSID clsid;
174 static struct list registered_psclsid_list = LIST_INIT(registered_psclsid_list);
176 static CRITICAL_SECTION cs_registered_psclsid_list;
177 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
179 0, 0, &cs_registered_psclsid_list,
180 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
181 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
183 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
186 * This is a marshallable object exposing registered local servers.
187 * IServiceProvider is used only because it happens meet requirements
188 * and already has proxy/stub code. If more functionality is needed,
189 * a custom interface may be used instead.
191 struct LocalServer
193 IServiceProvider IServiceProvider_iface;
194 LONG ref;
195 APARTMENT *apt;
196 IStream *marshal_stream;
200 * This lock count counts the number of times CoInitialize is called. It is
201 * decreased every time CoUninitialize is called. When it hits 0, the COM
202 * libraries are freed
204 static LONG s_COMLockCount = 0;
205 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
206 static LONG s_COMServerProcessReferences = 0;
209 * This linked list contains the list of registered class objects. These
210 * are mostly used to register the factories for out-of-proc servers of OLE
211 * objects.
213 * TODO: Make this data structure aware of inter-process communication. This
214 * means that parts of this will be exported to rpcss.
216 typedef struct tagRegisteredClass
218 struct list entry;
219 CLSID classIdentifier;
220 OXID apartment_id;
221 LPUNKNOWN classObject;
222 DWORD runContext;
223 DWORD connectFlags;
224 DWORD dwCookie;
225 void *RpcRegistration;
226 } RegisteredClass;
228 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
230 static CRITICAL_SECTION csRegisteredClassList;
231 static CRITICAL_SECTION_DEBUG class_cs_debug =
233 0, 0, &csRegisteredClassList,
234 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
235 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
237 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
239 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
241 switch (aspect)
243 case DVASPECT_CONTENT:
244 return MiscStatusContent;
245 case DVASPECT_THUMBNAIL:
246 return MiscStatusThumbnail;
247 case DVASPECT_ICON:
248 return MiscStatusIcon;
249 case DVASPECT_DOCPRINT:
250 return MiscStatusDocPrint;
251 default:
252 return MiscStatus;
256 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
258 ACTCTX_SECTION_KEYED_DATA data;
260 data.cbSize = sizeof(data);
261 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
262 clsid, &data))
264 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
265 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
266 ULONG miscmask = (comclass->flags >> 8) & 0xff;
268 if (!(miscmask & misc))
270 if (!(miscmask & MiscStatus))
272 *status = 0;
273 return TRUE;
275 misc = MiscStatus;
278 switch (misc)
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:
299 return TRUE;
301 else
302 return FALSE;
305 /* wrapper for NtCreateKey that creates the key recursively if necessary */
306 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
308 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
310 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
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;
317 while (i < len && buffer[i] != '\\') i++;
318 if (i == len) return status;
320 attrs = attr->Attributes;
321 attr->ObjectName = &str;
323 while (i < len)
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++;
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 );
341 return status;
344 static const WCHAR classes_rootW[] =
345 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
346 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
348 static HKEY classes_root_hkey;
350 /* create the special HKEY_CLASSES_ROOT key */
351 static HKEY create_classes_root_hkey(DWORD access)
353 HKEY hkey, ret = 0;
354 OBJECT_ATTRIBUTES attr;
355 UNICODE_STRING name;
357 attr.Length = sizeof(attr);
358 attr.RootDirectory = 0;
359 attr.ObjectName = &name;
360 attr.Attributes = 0;
361 attr.SecurityDescriptor = NULL;
362 attr.SecurityQualityOfService = NULL;
363 RtlInitUnicodeString( &name, classes_rootW );
364 if (create_key( &hkey, access, &attr )) return 0;
365 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
367 if (!(access & KEY_WOW64_64KEY))
369 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
370 ret = hkey;
371 else
372 NtClose( hkey ); /* somebody beat us to it */
374 else
375 ret = hkey;
376 return ret;
379 /* map the hkey from special root to normal key if necessary */
380 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
382 HKEY ret = hkey;
383 const BOOL is_win64 = sizeof(void*) > sizeof(int);
384 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
386 if (hkey == HKEY_CLASSES_ROOT &&
387 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
388 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
389 if (force_wow32 && ret && ret == classes_root_hkey)
391 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
392 access &= ~KEY_WOW64_32KEY;
393 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
394 return 0;
395 ret = hkey;
398 return ret;
401 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
403 OBJECT_ATTRIBUTES attr;
404 UNICODE_STRING nameW;
406 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
408 attr.Length = sizeof(attr);
409 attr.RootDirectory = hkey;
410 attr.ObjectName = &nameW;
411 attr.Attributes = 0;
412 attr.SecurityDescriptor = NULL;
413 attr.SecurityQualityOfService = NULL;
414 RtlInitUnicodeString( &nameW, name );
416 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
419 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
421 OBJECT_ATTRIBUTES attr;
422 UNICODE_STRING nameW;
424 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
426 attr.Length = sizeof(attr);
427 attr.RootDirectory = hkey;
428 attr.ObjectName = &nameW;
429 attr.Attributes = 0;
430 attr.SecurityDescriptor = NULL;
431 attr.SecurityQualityOfService = NULL;
432 RtlInitUnicodeString( &nameW, name );
434 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
437 /*****************************************************************************
438 * This section contains OpenDllList definitions
440 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
441 * other functions that do LoadLibrary _without_ giving back a HMODULE.
442 * Without this list these handles would never be freed.
444 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
445 * next unload-call but not before 600 sec.
448 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
449 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
451 typedef struct tagOpenDll
453 LONG refs;
454 LPWSTR library_name;
455 HANDLE library;
456 DllGetClassObjectFunc DllGetClassObject;
457 DllCanUnloadNowFunc DllCanUnloadNow;
458 struct list entry;
459 } OpenDll;
461 static struct list openDllList = LIST_INIT(openDllList);
463 static CRITICAL_SECTION csOpenDllList;
464 static CRITICAL_SECTION_DEBUG dll_cs_debug =
466 0, 0, &csOpenDllList,
467 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
468 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
470 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
472 struct apartment_loaded_dll
474 struct list entry;
475 OpenDll *dll;
476 DWORD unload_time;
477 BOOL multi_threaded;
480 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};
482 static ATOM apt_win_class;
484 /*****************************************************************************
485 * This section contains OpenDllList implementation
488 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
490 OpenDll *ptr;
491 OpenDll *ret = NULL;
492 EnterCriticalSection(&csOpenDllList);
493 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
495 if (!wcsicmp(library_name, ptr->library_name) &&
496 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
498 ret = ptr;
499 break;
502 LeaveCriticalSection(&csOpenDllList);
503 return ret;
506 /* caller must ensure that library_name is not already in the open dll list */
507 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
509 OpenDll *entry;
510 int len;
511 HRESULT hr = S_OK;
512 HANDLE hLibrary;
513 DllCanUnloadNowFunc DllCanUnloadNow;
514 DllGetClassObjectFunc DllGetClassObject;
516 TRACE("%s\n", debugstr_w(library_name));
518 *ret = COMPOBJ_DllList_Get(library_name);
519 if (*ret) return S_OK;
521 /* do this outside the csOpenDllList to avoid creating a lock dependency on
522 * the loader lock */
523 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
524 if (!hLibrary)
526 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
527 /* failure: DLL could not be loaded */
528 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
531 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
532 /* Note: failing to find DllCanUnloadNow is not a failure */
533 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
534 if (!DllGetClassObject)
536 /* failure: the dll did not export DllGetClassObject */
537 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
538 FreeLibrary(hLibrary);
539 return CO_E_DLLNOTFOUND;
542 EnterCriticalSection( &csOpenDllList );
544 *ret = COMPOBJ_DllList_Get(library_name);
545 if (*ret)
547 /* another caller to this function already added the dll while we
548 * weren't in the critical section */
549 FreeLibrary(hLibrary);
551 else
553 len = lstrlenW(library_name);
554 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
555 if (entry)
556 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
557 if (entry && entry->library_name)
559 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
560 entry->library = hLibrary;
561 entry->refs = 1;
562 entry->DllCanUnloadNow = DllCanUnloadNow;
563 entry->DllGetClassObject = DllGetClassObject;
564 list_add_tail(&openDllList, &entry->entry);
565 *ret = entry;
567 else
569 HeapFree(GetProcessHeap(), 0, entry);
570 hr = E_OUTOFMEMORY;
571 FreeLibrary(hLibrary);
575 LeaveCriticalSection( &csOpenDllList );
577 return hr;
580 /* pass FALSE for free_entry to release a reference without destroying the
581 * entry if it reaches zero or TRUE otherwise */
582 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
584 if (!InterlockedDecrement(&entry->refs) && free_entry)
586 EnterCriticalSection(&csOpenDllList);
587 list_remove(&entry->entry);
588 LeaveCriticalSection(&csOpenDllList);
590 TRACE("freeing %p\n", entry->library);
591 FreeLibrary(entry->library);
593 HeapFree(GetProcessHeap(), 0, entry->library_name);
594 HeapFree(GetProcessHeap(), 0, entry);
598 /* frees memory associated with active dll list */
599 static void COMPOBJ_DllList_Free(void)
601 OpenDll *entry, *cursor2;
602 EnterCriticalSection(&csOpenDllList);
603 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
605 list_remove(&entry->entry);
607 HeapFree(GetProcessHeap(), 0, entry->library_name);
608 HeapFree(GetProcessHeap(), 0, entry);
610 LeaveCriticalSection(&csOpenDllList);
611 DeleteCriticalSection(&csOpenDllList);
614 /******************************************************************************
615 * Manage apartments.
618 static DWORD apartment_addref(struct apartment *apt)
620 DWORD refs = InterlockedIncrement(&apt->refs);
621 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
622 return refs;
625 /* allocates memory and fills in the necessary fields for a new apartment
626 * object. must be called inside apartment cs */
627 static APARTMENT *apartment_construct(DWORD model)
629 APARTMENT *apt;
631 TRACE("creating new apartment, model=%d\n", model);
633 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
634 apt->tid = GetCurrentThreadId();
636 list_init(&apt->proxies);
637 list_init(&apt->stubmgrs);
638 list_init(&apt->loaded_dlls);
639 list_init(&apt->usage_cookies);
640 apt->ipidc = 0;
641 apt->refs = 1;
642 apt->remunk_exported = FALSE;
643 apt->oidc = 1;
644 InitializeCriticalSection(&apt->cs);
645 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
647 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
649 if (apt->multi_threaded)
651 /* FIXME: should be randomly generated by in an RPC call to rpcss */
652 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
654 else
656 /* FIXME: should be randomly generated by in an RPC call to rpcss */
657 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
660 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
662 list_add_head(&apts, &apt->entry);
664 return apt;
667 /* gets and existing apartment if one exists or otherwise creates an apartment
668 * structure which stores OLE apartment-local information and stores a pointer
669 * to it in the thread-local storage */
670 static APARTMENT *apartment_get_or_create(DWORD model)
672 APARTMENT *apt = COM_CurrentApt();
674 if (!apt)
676 if (model & COINIT_APARTMENTTHREADED)
678 EnterCriticalSection(&csApartment);
680 apt = apartment_construct(model);
681 if (!MainApartment)
683 MainApartment = apt;
684 apt->main = TRUE;
685 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
688 LeaveCriticalSection(&csApartment);
690 if (apt->main)
691 apartment_createwindowifneeded(apt);
693 else
695 EnterCriticalSection(&csApartment);
697 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
698 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
699 * in a process */
700 if (MTA)
702 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
703 apartment_addref(MTA);
705 else
706 MTA = apartment_construct(model);
708 apt = MTA;
710 LeaveCriticalSection(&csApartment);
712 COM_CurrentInfo()->apt = apt;
715 return apt;
718 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
720 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
723 /* gets the multi-threaded apartment if it exists. The caller must
724 * release the reference from the apartment as soon as the apartment pointer
725 * is no longer required. */
726 static APARTMENT *apartment_find_mta(void)
728 APARTMENT *apt;
730 EnterCriticalSection(&csApartment);
732 if ((apt = MTA))
733 apartment_addref(apt);
735 LeaveCriticalSection(&csApartment);
737 return apt;
740 /* Return the current apartment if it exists, or, failing that, the MTA. Caller
741 * must free the returned apartment in either case. */
742 APARTMENT *apartment_get_current_or_mta(void)
744 APARTMENT *apt = COM_CurrentApt();
745 if (apt)
747 apartment_addref(apt);
748 return apt;
750 return apartment_find_mta();
753 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
755 list_remove(&curClass->entry);
757 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
758 RPC_StopLocalServer(curClass->RpcRegistration);
760 IUnknown_Release(curClass->classObject);
761 HeapFree(GetProcessHeap(), 0, curClass);
764 static void COM_RevokeAllClasses(const struct apartment *apt)
766 RegisteredClass *curClass, *cursor;
768 EnterCriticalSection( &csRegisteredClassList );
770 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
772 if (curClass->apartment_id == apt->oxid)
773 COM_RevokeRegisteredClassObject(curClass);
776 LeaveCriticalSection( &csRegisteredClassList );
779 static void revoke_registered_psclsids(void)
781 struct registered_psclsid *psclsid, *psclsid2;
783 EnterCriticalSection( &cs_registered_psclsid_list );
785 LIST_FOR_EACH_ENTRY_SAFE(psclsid, psclsid2, &registered_psclsid_list, struct registered_psclsid, entry)
787 list_remove(&psclsid->entry);
788 HeapFree(GetProcessHeap(), 0, psclsid);
791 LeaveCriticalSection( &cs_registered_psclsid_list );
794 /******************************************************************************
795 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
798 typedef struct ManualResetEvent {
799 ISynchronize ISynchronize_iface;
800 ISynchronizeHandle ISynchronizeHandle_iface;
801 LONG ref;
802 HANDLE event;
803 } MREImpl;
805 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
807 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
810 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
812 MREImpl *This = impl_from_ISynchronize(iface);
814 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
816 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
817 *ppv = &This->ISynchronize_iface;
818 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
819 *ppv = &This->ISynchronizeHandle_iface;
820 }else {
821 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
822 *ppv = NULL;
823 return E_NOINTERFACE;
826 IUnknown_AddRef((IUnknown*)*ppv);
827 return S_OK;
830 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
832 MREImpl *This = impl_from_ISynchronize(iface);
833 LONG ref = InterlockedIncrement(&This->ref);
834 TRACE("%p - ref %d\n", This, ref);
836 return ref;
839 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
841 MREImpl *This = impl_from_ISynchronize(iface);
842 LONG ref = InterlockedDecrement(&This->ref);
843 TRACE("%p - ref %d\n", This, ref);
845 if(!ref)
847 CloseHandle(This->event);
848 HeapFree(GetProcessHeap(), 0, This);
851 return ref;
854 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
856 MREImpl *This = impl_from_ISynchronize(iface);
857 UINT index;
858 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
859 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
862 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
864 MREImpl *This = impl_from_ISynchronize(iface);
865 TRACE("%p\n", This);
866 SetEvent(This->event);
867 return S_OK;
870 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
872 MREImpl *This = impl_from_ISynchronize(iface);
873 TRACE("%p\n", This);
874 ResetEvent(This->event);
875 return S_OK;
878 static ISynchronizeVtbl vt_ISynchronize = {
879 ISynchronize_fnQueryInterface,
880 ISynchronize_fnAddRef,
881 ISynchronize_fnRelease,
882 ISynchronize_fnWait,
883 ISynchronize_fnSignal,
884 ISynchronize_fnReset
887 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
889 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
892 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
894 MREImpl *This = impl_from_ISynchronizeHandle(iface);
895 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
898 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
900 MREImpl *This = impl_from_ISynchronizeHandle(iface);
901 return ISynchronize_AddRef(&This->ISynchronize_iface);
904 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
906 MREImpl *This = impl_from_ISynchronizeHandle(iface);
907 return ISynchronize_Release(&This->ISynchronize_iface);
910 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
912 MREImpl *This = impl_from_ISynchronizeHandle(iface);
914 *ph = This->event;
915 return S_OK;
918 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
919 SynchronizeHandle_QueryInterface,
920 SynchronizeHandle_AddRef,
921 SynchronizeHandle_Release,
922 SynchronizeHandle_GetHandle
925 HRESULT WINAPI ManualResetEvent_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **ppv)
927 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
928 HRESULT hr;
930 if (outer)
931 FIXME("Aggregation not implemented.\n");
933 This->ref = 1;
934 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
935 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
936 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
938 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
939 ISynchronize_Release(&This->ISynchronize_iface);
940 return hr;
943 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
945 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
948 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
950 LocalServer *This = impl_from_IServiceProvider(iface);
952 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
954 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
955 *ppv = &This->IServiceProvider_iface;
956 }else {
957 *ppv = NULL;
958 return E_NOINTERFACE;
961 IUnknown_AddRef((IUnknown*)*ppv);
962 return S_OK;
965 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
967 LocalServer *This = impl_from_IServiceProvider(iface);
968 LONG ref = InterlockedIncrement(&This->ref);
970 TRACE("(%p) ref=%d\n", This, ref);
972 return ref;
975 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
977 LocalServer *This = impl_from_IServiceProvider(iface);
978 LONG ref = InterlockedDecrement(&This->ref);
980 TRACE("(%p) ref=%d\n", This, ref);
982 if(!ref) {
983 assert(!This->apt);
984 HeapFree(GetProcessHeap(), 0, This);
987 return ref;
990 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
992 LocalServer *This = impl_from_IServiceProvider(iface);
993 APARTMENT *apt = COM_CurrentApt();
994 RegisteredClass *iter;
995 HRESULT hres = E_FAIL;
997 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
999 if(!This->apt)
1000 return E_UNEXPECTED;
1002 EnterCriticalSection(&csRegisteredClassList);
1004 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
1005 if(iter->apartment_id == apt->oxid
1006 && (iter->runContext & CLSCTX_LOCAL_SERVER)
1007 && IsEqualGUID(&iter->classIdentifier, guid)) {
1008 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
1009 break;
1013 LeaveCriticalSection( &csRegisteredClassList );
1015 return hres;
1018 static const IServiceProviderVtbl LocalServerVtbl = {
1019 LocalServer_QueryInterface,
1020 LocalServer_AddRef,
1021 LocalServer_Release,
1022 LocalServer_QueryService
1025 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
1027 HRESULT hres = S_OK;
1029 EnterCriticalSection(&apt->cs);
1031 if(!apt->local_server) {
1032 LocalServer *obj;
1034 obj = heap_alloc(sizeof(*obj));
1035 if(obj) {
1036 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
1037 obj->ref = 1;
1038 obj->apt = apt;
1040 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
1041 if(SUCCEEDED(hres)) {
1042 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
1043 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1044 if(FAILED(hres))
1045 IStream_Release(obj->marshal_stream);
1048 if(SUCCEEDED(hres))
1049 apt->local_server = obj;
1050 else
1051 heap_free(obj);
1052 }else {
1053 hres = E_OUTOFMEMORY;
1057 if(SUCCEEDED(hres))
1058 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1060 LeaveCriticalSection(&apt->cs);
1062 if(FAILED(hres))
1063 ERR("Failed: %08x\n", hres);
1064 return hres;
1067 /***********************************************************************
1068 * CoRevokeClassObject [OLE32.@]
1070 * Removes a class object from the class registry.
1072 * PARAMS
1073 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1075 * RETURNS
1076 * Success: S_OK.
1077 * Failure: HRESULT code.
1079 * NOTES
1080 * Must be called from the same apartment that called CoRegisterClassObject(),
1081 * otherwise it will fail with RPC_E_WRONG_THREAD.
1083 * SEE ALSO
1084 * CoRegisterClassObject
1086 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(
1087 DWORD dwRegister)
1089 HRESULT hr = E_INVALIDARG;
1090 RegisteredClass *curClass;
1091 APARTMENT *apt;
1093 TRACE("(%08x)\n",dwRegister);
1095 if (!(apt = apartment_get_current_or_mta()))
1097 ERR("COM was not initialized\n");
1098 return CO_E_NOTINITIALIZED;
1101 EnterCriticalSection( &csRegisteredClassList );
1103 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1106 * Check if we have a match on the cookie.
1108 if (curClass->dwCookie == dwRegister)
1110 if (curClass->apartment_id == apt->oxid)
1112 COM_RevokeRegisteredClassObject(curClass);
1113 hr = S_OK;
1115 else
1117 ERR("called from wrong apartment, should be called from %s\n",
1118 wine_dbgstr_longlong(curClass->apartment_id));
1119 hr = RPC_E_WRONG_THREAD;
1121 break;
1125 LeaveCriticalSection( &csRegisteredClassList );
1126 apartment_release(apt);
1127 return hr;
1130 /* frees unused libraries loaded by apartment_getclassobject by calling the
1131 * DLL's DllCanUnloadNow entry point */
1132 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1134 struct apartment_loaded_dll *entry, *next;
1135 EnterCriticalSection(&apt->cs);
1136 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1138 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1140 DWORD real_delay = delay;
1142 if (real_delay == INFINITE)
1144 /* DLLs that return multi-threaded objects aren't unloaded
1145 * straight away to cope for programs that have races between
1146 * last object destruction and threads in the DLLs that haven't
1147 * finished, despite DllCanUnloadNow returning S_OK */
1148 if (entry->multi_threaded)
1149 real_delay = 10 * 60 * 1000; /* 10 minutes */
1150 else
1151 real_delay = 0;
1154 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1156 list_remove(&entry->entry);
1157 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1158 HeapFree(GetProcessHeap(), 0, entry);
1160 else
1162 entry->unload_time = GetTickCount() + real_delay;
1163 if (!entry->unload_time) entry->unload_time = 1;
1166 else if (entry->unload_time)
1167 entry->unload_time = 0;
1169 LeaveCriticalSection(&apt->cs);
1172 DWORD apartment_release(struct apartment *apt)
1174 DWORD ret;
1176 EnterCriticalSection(&csApartment);
1178 ret = InterlockedDecrement(&apt->refs);
1179 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1181 if (apt->being_destroyed)
1183 LeaveCriticalSection(&csApartment);
1184 return ret;
1187 /* destruction stuff that needs to happen under csApartment CS */
1188 if (ret == 0)
1190 apt->being_destroyed = TRUE;
1191 if (apt == MTA) MTA = NULL;
1192 else if (apt == MainApartment) MainApartment = NULL;
1193 list_remove(&apt->entry);
1196 LeaveCriticalSection(&csApartment);
1198 if (ret == 0)
1200 struct list *cursor, *cursor2;
1202 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1204 if(apt->local_server) {
1205 LocalServer *local_server = apt->local_server;
1206 LARGE_INTEGER zero;
1208 memset(&zero, 0, sizeof(zero));
1209 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1210 CoReleaseMarshalData(local_server->marshal_stream);
1211 IStream_Release(local_server->marshal_stream);
1212 local_server->marshal_stream = NULL;
1214 apt->local_server = NULL;
1215 local_server->apt = NULL;
1216 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1219 /* Release the references to the registered class objects */
1220 COM_RevokeAllClasses(apt);
1222 /* no locking is needed for this apartment, because no other thread
1223 * can access it at this point */
1225 apartment_disconnectproxies(apt);
1227 if (apt->win) DestroyWindow(apt->win);
1228 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1230 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1232 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1233 /* release the implicit reference given by the fact that the
1234 * stub has external references (it must do since it is in the
1235 * stub manager list in the apartment and all non-apartment users
1236 * must have a ref on the apartment and so it cannot be destroyed).
1238 stub_manager_int_release(stubmgr);
1241 /* if this assert fires, then another thread took a reference to a
1242 * stub manager without taking a reference to the containing
1243 * apartment, which it must do. */
1244 assert(list_empty(&apt->stubmgrs));
1246 if (apt->filter) IMessageFilter_Release(apt->filter);
1248 /* free as many unused libraries as possible... */
1249 apartment_freeunusedlibraries(apt, 0);
1251 /* ... and free the memory for the apartment loaded dll entry and
1252 * release the dll list reference without freeing the library for the
1253 * rest */
1254 while ((cursor = list_head(&apt->loaded_dlls)))
1256 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1257 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1258 list_remove(cursor);
1259 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1262 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1263 DeleteCriticalSection(&apt->cs);
1265 HeapFree(GetProcessHeap(), 0, apt);
1268 return ret;
1271 /* The given OXID must be local to this process:
1273 * The ref parameter is here mostly to ensure people remember that
1274 * they get one, you should normally take a ref for thread safety.
1276 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1278 APARTMENT *result = NULL;
1279 struct list *cursor;
1281 EnterCriticalSection(&csApartment);
1282 LIST_FOR_EACH( cursor, &apts )
1284 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1285 if (apt->oxid == oxid)
1287 result = apt;
1288 if (ref) apartment_addref(result);
1289 break;
1292 LeaveCriticalSection(&csApartment);
1294 return result;
1297 /* gets the apartment which has a given creator thread ID. The caller must
1298 * release the reference from the apartment as soon as the apartment pointer
1299 * is no longer required. */
1300 APARTMENT *apartment_findfromtid(DWORD tid)
1302 APARTMENT *result = NULL;
1303 struct list *cursor;
1305 EnterCriticalSection(&csApartment);
1306 LIST_FOR_EACH( cursor, &apts )
1308 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1309 if (apt->tid == tid)
1311 result = apt;
1312 apartment_addref(result);
1313 break;
1316 LeaveCriticalSection(&csApartment);
1318 return result;
1321 /* gets the main apartment if it exists. The caller must
1322 * release the reference from the apartment as soon as the apartment pointer
1323 * is no longer required. */
1324 static APARTMENT *apartment_findmain(void)
1326 APARTMENT *result;
1328 EnterCriticalSection(&csApartment);
1330 result = MainApartment;
1331 if (result) apartment_addref(result);
1333 LeaveCriticalSection(&csApartment);
1335 return result;
1338 /* gets the specified class object by loading the appropriate DLL, if
1339 * necessary and calls the DllGetClassObject function for the DLL */
1340 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1341 BOOL apartment_threaded,
1342 REFCLSID rclsid, REFIID riid, void **ppv)
1344 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1345 HRESULT hr = S_OK;
1346 BOOL found = FALSE;
1347 struct apartment_loaded_dll *apartment_loaded_dll;
1349 if (!wcsicmp(dllpath, wszOle32))
1351 /* we don't need to control the lifetime of this dll, so use the local
1352 * implementation of DllGetClassObject directly */
1353 TRACE("calling ole32!DllGetClassObject\n");
1354 hr = DllGetClassObject(rclsid, riid, ppv);
1356 if (hr != S_OK)
1357 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1359 return hr;
1362 EnterCriticalSection(&apt->cs);
1364 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1365 if (!wcsicmp(dllpath, apartment_loaded_dll->dll->library_name))
1367 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1368 found = TRUE;
1369 break;
1372 if (!found)
1374 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1375 if (!apartment_loaded_dll)
1376 hr = E_OUTOFMEMORY;
1377 if (SUCCEEDED(hr))
1379 apartment_loaded_dll->unload_time = 0;
1380 apartment_loaded_dll->multi_threaded = FALSE;
1381 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1382 if (FAILED(hr))
1383 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1385 if (SUCCEEDED(hr))
1387 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1388 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1392 LeaveCriticalSection(&apt->cs);
1394 if (SUCCEEDED(hr))
1396 /* one component being multi-threaded overrides any number of
1397 * apartment-threaded components */
1398 if (!apartment_threaded)
1399 apartment_loaded_dll->multi_threaded = TRUE;
1401 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1402 /* OK: get the ClassObject */
1403 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1405 if (hr != S_OK)
1406 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1409 return hr;
1412 /* Returns expanded dll path from the registry or activation context. */
1413 static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1415 DWORD ret;
1417 if (regdata->origin == CLASS_REG_REGISTRY)
1419 DWORD keytype;
1420 WCHAR src[MAX_PATH];
1421 DWORD dwLength = dstlen * sizeof(WCHAR);
1423 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1424 if (keytype == REG_EXPAND_SZ) {
1425 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1426 } else {
1427 const WCHAR *quote_start;
1428 quote_start = wcschr(src, '\"');
1429 if (quote_start) {
1430 const WCHAR *quote_end = wcschr(quote_start + 1, '\"');
1431 if (quote_end) {
1432 memmove(src, quote_start + 1,
1433 (quote_end - quote_start - 1) * sizeof(WCHAR));
1434 src[quote_end - quote_start - 1] = '\0';
1437 lstrcpynW(dst, src, dstlen);
1440 return !ret;
1442 else
1444 static const WCHAR dllW[] = {'.','d','l','l',0};
1445 ULONG_PTR cookie;
1447 *dst = 0;
1448 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1449 ret = SearchPathW(NULL, regdata->u.actctx.module_name, dllW, dstlen, dst, NULL);
1450 DeactivateActCtx(0, cookie);
1451 return *dst != 0;
1455 struct host_object_params
1457 struct class_reg_data regdata;
1458 CLSID clsid; /* clsid of object to marshal */
1459 IID iid; /* interface to marshal */
1460 HANDLE event; /* event signalling when ready for multi-threaded case */
1461 HRESULT hr; /* result for multi-threaded case */
1462 IStream *stream; /* stream that the object will be marshaled into */
1463 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1466 static HRESULT apartment_hostobject(struct apartment *apt,
1467 const struct host_object_params *params)
1469 IUnknown *object;
1470 HRESULT hr;
1471 static const LARGE_INTEGER llZero;
1472 WCHAR dllpath[MAX_PATH+1];
1474 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1476 if (!get_object_dll_path(&params->regdata, dllpath, ARRAY_SIZE(dllpath)))
1478 /* failure: CLSID is not found in registry */
1479 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1480 return REGDB_E_CLASSNOTREG;
1483 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1484 &params->clsid, &params->iid, (void **)&object);
1485 if (FAILED(hr))
1486 return hr;
1488 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1489 if (FAILED(hr))
1490 IUnknown_Release(object);
1491 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1493 return hr;
1496 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1498 switch (msg)
1500 case DM_EXECUTERPC:
1501 RPC_ExecuteCall((struct dispatch_params *)lParam);
1502 return 0;
1503 case DM_HOSTOBJECT:
1504 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1505 default:
1506 return DefWindowProcW(hWnd, msg, wParam, lParam);
1510 struct host_thread_params
1512 COINIT threading_model;
1513 HANDLE ready_event;
1514 HWND apartment_hwnd;
1517 /* thread for hosting an object to allow an object to appear to be created in
1518 * an apartment with an incompatible threading model */
1519 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1521 struct host_thread_params *params = p;
1522 MSG msg;
1523 HRESULT hr;
1524 struct apartment *apt;
1526 TRACE("\n");
1528 hr = CoInitializeEx(NULL, params->threading_model);
1529 if (FAILED(hr)) return hr;
1531 apt = COM_CurrentApt();
1532 if (params->threading_model == COINIT_APARTMENTTHREADED)
1534 apartment_createwindowifneeded(apt);
1535 params->apartment_hwnd = apartment_getwindow(apt);
1537 else
1538 params->apartment_hwnd = NULL;
1540 /* force the message queue to be created before signaling parent thread */
1541 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1543 SetEvent(params->ready_event);
1544 params = NULL; /* can't touch params after here as it may be invalid */
1546 while (GetMessageW(&msg, NULL, 0, 0))
1548 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1550 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1551 obj_params->hr = apartment_hostobject(apt, obj_params);
1552 SetEvent(obj_params->event);
1554 else
1556 TranslateMessage(&msg);
1557 DispatchMessageW(&msg);
1561 TRACE("exiting\n");
1563 CoUninitialize();
1565 return S_OK;
1568 /* finds or creates a host apartment, creates the object inside it and returns
1569 * a proxy to it so that the object can be used in the apartment of the
1570 * caller of this function */
1571 static HRESULT apartment_hostobject_in_hostapt(
1572 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1573 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1575 struct host_object_params params;
1576 HWND apartment_hwnd = NULL;
1577 DWORD apartment_tid = 0;
1578 HRESULT hr;
1580 if (!multi_threaded && main_apartment)
1582 APARTMENT *host_apt = apartment_findmain();
1583 if (host_apt)
1585 apartment_hwnd = apartment_getwindow(host_apt);
1586 apartment_release(host_apt);
1590 if (!apartment_hwnd)
1592 EnterCriticalSection(&apt->cs);
1594 if (!apt->host_apt_tid)
1596 struct host_thread_params thread_params;
1597 HANDLE handles[2];
1598 DWORD wait_value;
1600 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1601 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1602 thread_params.apartment_hwnd = NULL;
1603 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1604 if (!handles[1])
1606 CloseHandle(handles[0]);
1607 LeaveCriticalSection(&apt->cs);
1608 return E_OUTOFMEMORY;
1610 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1611 CloseHandle(handles[0]);
1612 CloseHandle(handles[1]);
1613 if (wait_value == WAIT_OBJECT_0)
1614 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1615 else
1617 LeaveCriticalSection(&apt->cs);
1618 return E_OUTOFMEMORY;
1622 if (multi_threaded || !main_apartment)
1624 apartment_hwnd = apt->host_apt_hwnd;
1625 apartment_tid = apt->host_apt_tid;
1628 LeaveCriticalSection(&apt->cs);
1631 /* another thread may have become the main apartment in the time it took
1632 * us to create the thread for the host apartment */
1633 if (!apartment_hwnd && !multi_threaded && main_apartment)
1635 APARTMENT *host_apt = apartment_findmain();
1636 if (host_apt)
1638 apartment_hwnd = apartment_getwindow(host_apt);
1639 apartment_release(host_apt);
1643 params.regdata = *regdata;
1644 params.clsid = *rclsid;
1645 params.iid = *riid;
1646 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1647 if (FAILED(hr))
1648 return hr;
1649 params.apartment_threaded = !multi_threaded;
1650 if (multi_threaded)
1652 params.hr = S_OK;
1653 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1654 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1655 hr = E_OUTOFMEMORY;
1656 else
1658 WaitForSingleObject(params.event, INFINITE);
1659 hr = params.hr;
1661 CloseHandle(params.event);
1663 else
1665 if (!apartment_hwnd)
1667 ERR("host apartment didn't create window\n");
1668 hr = E_OUTOFMEMORY;
1670 else
1671 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1673 if (SUCCEEDED(hr))
1674 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1675 IStream_Release(params.stream);
1676 return hr;
1679 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1681 WNDCLASSW wclass;
1683 /* Dispatching to the correct thread in an apartment is done through
1684 * window messages rather than RPC transports. When an interface is
1685 * marshalled into another apartment in the same process, a window of the
1686 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1687 * application) is responsible for pumping the message loop in that thread.
1688 * The WM_USER messages which point to the RPCs are then dispatched to
1689 * apartment_wndproc by the user's code from the apartment in which the
1690 * interface was unmarshalled.
1692 memset(&wclass, 0, sizeof(wclass));
1693 wclass.lpfnWndProc = apartment_wndproc;
1694 wclass.hInstance = hProxyDll;
1695 wclass.lpszClassName = wszAptWinClass;
1696 apt_win_class = RegisterClassW(&wclass);
1697 return TRUE;
1700 /* create a window for the apartment or return the current one if one has
1701 * already been created */
1702 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1704 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1706 if (apt->multi_threaded)
1707 return S_OK;
1709 if (!apt->win)
1711 HWND hwnd;
1713 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1715 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1716 HWND_MESSAGE, 0, hProxyDll, NULL);
1717 if (!hwnd)
1719 ERR("CreateWindow failed with error %d\n", GetLastError());
1720 return HRESULT_FROM_WIN32(GetLastError());
1722 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1723 /* someone beat us to it */
1724 DestroyWindow(hwnd);
1727 return S_OK;
1730 /* retrieves the window for the main- or apartment-threaded apartment */
1731 HWND apartment_getwindow(const struct apartment *apt)
1733 assert(!apt->multi_threaded);
1734 return apt->win;
1737 static void COM_TlsDestroy(void)
1739 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1740 if (info)
1742 struct init_spy *cursor, *cursor2;
1744 if (info->apt) apartment_release(info->apt);
1745 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1746 if (info->state) IUnknown_Release(info->state);
1748 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &info->spies, struct init_spy, entry)
1750 list_remove(&cursor->entry);
1751 if (cursor->spy) IInitializeSpy_Release(cursor->spy);
1752 heap_free(cursor);
1755 if (info->context_token) IObjContext_Release(info->context_token);
1757 HeapFree(GetProcessHeap(), 0, info);
1758 NtCurrentTeb()->ReservedForOle = NULL;
1762 /******************************************************************************
1763 * CoBuildVersion [OLE32.@]
1765 * Gets the build version of the DLL.
1767 * PARAMS
1769 * RETURNS
1770 * Current build version, hiword is majornumber, loword is minornumber
1772 DWORD WINAPI CoBuildVersion(void)
1774 TRACE("Returning version %d, build %d.\n", rmm, rup);
1775 return (rmm<<16)+rup;
1778 static struct init_spy *get_spy_entry(struct oletls *info, unsigned int id)
1780 struct init_spy *spy;
1782 LIST_FOR_EACH_ENTRY(spy, &info->spies, struct init_spy, entry)
1784 if (id == spy->id && spy->spy)
1785 return spy;
1788 return NULL;
1792 * When locked, don't modify list (unless we add a new head), so that it's
1793 * safe to iterate it. Freeing of list entries is delayed and done on unlock.
1795 static inline void lock_init_spies(struct oletls *info)
1797 info->spies_lock++;
1800 static void unlock_init_spies(struct oletls *info)
1802 struct init_spy *spy, *next;
1804 if (--info->spies_lock) return;
1806 LIST_FOR_EACH_ENTRY_SAFE(spy, next, &info->spies, struct init_spy, entry)
1808 if (spy->spy) continue;
1809 list_remove(&spy->entry);
1810 heap_free(spy);
1814 /******************************************************************************
1815 * CoRegisterInitializeSpy [OLE32.@]
1817 * Add a Spy that watches CoInitializeEx calls
1819 * PARAMS
1820 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1821 * cookie [II] cookie receiver
1823 * RETURNS
1824 * Success: S_OK if not already initialized, S_FALSE otherwise.
1825 * Failure: HRESULT code.
1827 * SEE ALSO
1828 * CoInitializeEx
1830 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1832 struct oletls *info = COM_CurrentInfo();
1833 struct init_spy *entry;
1834 unsigned int id;
1835 HRESULT hr;
1837 TRACE("(%p, %p)\n", spy, cookie);
1839 if (!spy || !cookie || !info)
1841 if (!info)
1842 WARN("Could not allocate tls\n");
1843 return E_INVALIDARG;
1846 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1847 if (FAILED(hr))
1848 return hr;
1850 entry = heap_alloc(sizeof(*entry));
1851 if (!entry)
1853 IInitializeSpy_Release(spy);
1854 return E_OUTOFMEMORY;
1857 entry->spy = spy;
1859 id = 0;
1860 while (get_spy_entry(info, id) != NULL)
1862 id++;
1865 entry->id = id;
1866 list_add_head(&info->spies, &entry->entry);
1868 cookie->HighPart = GetCurrentThreadId();
1869 cookie->LowPart = entry->id;
1871 return S_OK;
1874 /******************************************************************************
1875 * CoRevokeInitializeSpy [OLE32.@]
1877 * Remove a spy that previously watched CoInitializeEx calls
1879 * PARAMS
1880 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1882 * RETURNS
1883 * Success: S_OK if a spy is removed
1884 * Failure: E_INVALIDARG
1886 * SEE ALSO
1887 * CoInitializeEx
1889 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1891 struct oletls *info = COM_CurrentInfo();
1892 struct init_spy *spy;
1894 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1896 if (!info || cookie.HighPart != GetCurrentThreadId())
1897 return E_INVALIDARG;
1899 if (!(spy = get_spy_entry(info, cookie.LowPart))) return E_INVALIDARG;
1901 IInitializeSpy_Release(spy->spy);
1902 spy->spy = NULL;
1903 if (!info->spies_lock)
1905 list_remove(&spy->entry);
1906 heap_free(spy);
1908 return S_OK;
1911 HRESULT enter_apartment( struct oletls *info, DWORD model )
1913 HRESULT hr = S_OK;
1915 if (!info->apt)
1917 if (!apartment_get_or_create( model ))
1918 return E_OUTOFMEMORY;
1920 else if (!apartment_is_model( info->apt, model ))
1922 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1923 info->apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1924 model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" );
1925 return RPC_E_CHANGED_MODE;
1927 else
1928 hr = S_FALSE;
1930 info->inits++;
1932 return hr;
1935 void leave_apartment( struct oletls *info )
1937 if (!--info->inits)
1939 if (info->ole_inits)
1940 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1941 apartment_release( info->apt );
1942 info->apt = NULL;
1946 /******************************************************************************
1947 * CoInitialize [OLE32.@]
1949 * Initializes the COM libraries by calling CoInitializeEx with
1950 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1952 * PARAMS
1953 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1955 * RETURNS
1956 * Success: S_OK if not already initialized, S_FALSE otherwise.
1957 * Failure: HRESULT code.
1959 * SEE ALSO
1960 * CoInitializeEx
1962 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1965 * Just delegate to the newer method.
1967 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1970 /******************************************************************************
1971 * CoInitializeEx [OLE32.@]
1973 * Initializes the COM libraries.
1975 * PARAMS
1976 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1977 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1979 * RETURNS
1980 * S_OK if successful,
1981 * S_FALSE if this function was called already.
1982 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1983 * threading model.
1985 * NOTES
1987 * The behavior used to set the IMalloc used for memory management is
1988 * obsolete.
1989 * The dwCoInit parameter must specify one of the following apartment
1990 * threading models:
1991 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1992 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1993 * The parameter may also specify zero or more of the following flags:
1994 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1995 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1997 * SEE ALSO
1998 * CoUninitialize
2000 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
2002 struct oletls *info = COM_CurrentInfo();
2003 struct init_spy *cursor;
2004 HRESULT hr;
2006 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
2008 if (lpReserved!=NULL)
2010 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
2014 * Check the lock count. If this is the first time going through the initialize
2015 * process, we have to initialize the libraries.
2017 * And crank-up that lock count.
2019 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
2022 * Initialize the various COM libraries and data structures.
2024 TRACE("() - Initializing the COM libraries\n");
2026 /* we may need to defer this until after apartment initialisation */
2027 RunningObjectTableImpl_Initialize();
2030 lock_init_spies(info);
2031 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2033 if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, dwCoInit, info->inits);
2035 unlock_init_spies(info);
2037 hr = enter_apartment( info, dwCoInit );
2039 lock_init_spies(info);
2040 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2042 if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, dwCoInit, info->inits);
2044 unlock_init_spies(info);
2046 return hr;
2049 /***********************************************************************
2050 * CoUninitialize [OLE32.@]
2052 * This method will decrement the refcount on the current apartment, freeing
2053 * the resources associated with it if it is the last thread in the apartment.
2054 * If the last apartment is freed, the function will additionally release
2055 * any COM resources associated with the process.
2057 * PARAMS
2059 * RETURNS
2060 * Nothing.
2062 * SEE ALSO
2063 * CoInitializeEx
2065 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
2067 struct oletls * info = COM_CurrentInfo();
2068 struct init_spy *cursor, *next;
2069 LONG lCOMRefCnt;
2071 TRACE("()\n");
2073 /* will only happen on OOM */
2074 if (!info) return;
2076 lock_init_spies(info);
2077 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &info->spies, struct init_spy, entry)
2079 if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, info->inits);
2081 unlock_init_spies(info);
2083 /* sanity check */
2084 if (!info->inits)
2086 ERR("Mismatched CoUninitialize\n");
2088 lock_init_spies(info);
2089 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &info->spies, struct init_spy, entry)
2091 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2093 unlock_init_spies(info);
2095 return;
2098 leave_apartment( info );
2101 * Decrease the reference count.
2102 * If we are back to 0 locks on the COM library, make sure we free
2103 * all the associated data structures.
2105 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
2106 if (lCOMRefCnt==1)
2108 TRACE("() - Releasing the COM libraries\n");
2110 revoke_registered_psclsids();
2111 RunningObjectTableImpl_UnInitialize();
2113 else if (lCOMRefCnt<1) {
2114 ERR( "CoUninitialize() - not CoInitialized.\n" );
2115 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
2118 lock_init_spies(info);
2119 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2121 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2123 unlock_init_spies(info);
2126 /******************************************************************************
2127 * CoDisconnectObject [OLE32.@]
2129 * Disconnects all connections to this object from remote processes. Dispatches
2130 * pending RPCs while blocking new RPCs from occurring, and then calls
2131 * IMarshal::DisconnectObject on the given object.
2133 * Typically called when the object server is forced to shut down, for instance by
2134 * the user.
2136 * PARAMS
2137 * lpUnk [I] The object whose stub should be disconnected.
2138 * reserved [I] Reserved. Should be set to 0.
2140 * RETURNS
2141 * Success: S_OK.
2142 * Failure: HRESULT code.
2144 * SEE ALSO
2145 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2147 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2149 struct stub_manager *manager;
2150 HRESULT hr;
2151 IMarshal *marshal;
2152 APARTMENT *apt;
2154 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2156 if (!lpUnk) return E_INVALIDARG;
2158 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2159 if (hr == S_OK)
2161 hr = IMarshal_DisconnectObject(marshal, reserved);
2162 IMarshal_Release(marshal);
2163 return hr;
2166 if (!(apt = apartment_get_current_or_mta()))
2168 ERR("apartment not initialised\n");
2169 return CO_E_NOTINITIALIZED;
2172 manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2173 if (manager) {
2174 stub_manager_disconnect(manager);
2175 /* Release stub manager twice, to remove the apartment reference. */
2176 stub_manager_int_release(manager);
2177 stub_manager_int_release(manager);
2180 /* Note: native is pretty broken here because it just silently
2181 * fails, without returning an appropriate error code if the object was
2182 * not found, making apps think that the object was disconnected, when
2183 * it actually wasn't */
2185 apartment_release(apt);
2186 return S_OK;
2189 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2190 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2192 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2193 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(wszCLSIDSlash) - 1];
2194 LONG res;
2195 HKEY key;
2197 lstrcpyW(path, wszCLSIDSlash);
2198 StringFromGUID2(clsid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
2199 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2200 if (res == ERROR_FILE_NOT_FOUND)
2201 return REGDB_E_CLASSNOTREG;
2202 else if (res != ERROR_SUCCESS)
2203 return REGDB_E_READREGDB;
2205 if (!keyname)
2207 *subkey = key;
2208 return S_OK;
2211 res = open_classes_key(key, keyname, access, subkey);
2212 RegCloseKey(key);
2213 if (res == ERROR_FILE_NOT_FOUND)
2214 return REGDB_E_KEYMISSING;
2215 else if (res != ERROR_SUCCESS)
2216 return REGDB_E_READREGDB;
2218 return S_OK;
2221 /* open HKCR\\AppId\\{string form of appid clsid} key */
2222 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2224 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2225 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2226 DWORD res;
2227 WCHAR buf[CHARS_IN_GUID];
2228 WCHAR keyname[ARRAY_SIZE(szAppIdKey) + CHARS_IN_GUID];
2229 DWORD size;
2230 HKEY hkey;
2231 DWORD type;
2232 HRESULT hr;
2234 /* read the AppID value under the class's key */
2235 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2236 if (FAILED(hr))
2237 return hr;
2239 size = sizeof(buf);
2240 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2241 RegCloseKey(hkey);
2242 if (res == ERROR_FILE_NOT_FOUND)
2243 return REGDB_E_KEYMISSING;
2244 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2245 return REGDB_E_READREGDB;
2247 lstrcpyW(keyname, szAppIdKey);
2248 lstrcatW(keyname, buf);
2249 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2250 if (res == ERROR_FILE_NOT_FOUND)
2251 return REGDB_E_KEYMISSING;
2252 else if (res != ERROR_SUCCESS)
2253 return REGDB_E_READREGDB;
2255 return S_OK;
2258 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2260 HKEY hkey;
2261 WCHAR value[CHARS_IN_GUID];
2262 DWORD len;
2264 access |= KEY_READ;
2266 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2267 return REGDB_E_IIDNOTREG;
2269 len = sizeof(value);
2270 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2271 return REGDB_E_IIDNOTREG;
2272 RegCloseKey(hkey);
2274 if (CLSIDFromString(value, pclsid) != NOERROR)
2275 return REGDB_E_IIDNOTREG;
2277 return S_OK;
2280 /*****************************************************************************
2281 * CoGetPSClsid [OLE32.@]
2283 * Retrieves the CLSID of the proxy/stub factory that implements
2284 * IPSFactoryBuffer for the specified interface.
2286 * PARAMS
2287 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2288 * pclsid [O] Where to store returned proxy/stub CLSID.
2290 * RETURNS
2291 * S_OK
2292 * E_OUTOFMEMORY
2293 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2295 * NOTES
2297 * The standard marshaller activates the object with the CLSID
2298 * returned and uses the CreateProxy and CreateStub methods on its
2299 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2300 * given object.
2302 * CoGetPSClsid determines this CLSID by searching the
2303 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2304 * in the registry and any interface id registered by
2305 * CoRegisterPSClsid within the current process.
2307 * BUGS
2309 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2310 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2311 * considered a bug in native unless an application depends on this (unlikely).
2313 * SEE ALSO
2314 * CoRegisterPSClsid.
2316 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2318 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2319 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2320 WCHAR path[ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(wszPSC)];
2321 APARTMENT *apt;
2322 struct registered_psclsid *registered_psclsid;
2323 ACTCTX_SECTION_KEYED_DATA data;
2324 HRESULT hr;
2325 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2326 BOOL is_wow64;
2328 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2330 if (!(apt = apartment_get_current_or_mta()))
2332 ERR("apartment not initialised\n");
2333 return CO_E_NOTINITIALIZED;
2335 apartment_release(apt);
2337 if (!pclsid)
2338 return E_INVALIDARG;
2340 EnterCriticalSection(&cs_registered_psclsid_list);
2342 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2343 if (IsEqualIID(&registered_psclsid->iid, riid))
2345 *pclsid = registered_psclsid->clsid;
2346 LeaveCriticalSection(&cs_registered_psclsid_list);
2347 return S_OK;
2350 LeaveCriticalSection(&cs_registered_psclsid_list);
2352 data.cbSize = sizeof(data);
2353 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2354 riid, &data))
2356 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2357 *pclsid = ifaceps->iid;
2358 return S_OK;
2361 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2362 lstrcpyW(path, wszInterface);
2363 StringFromGUID2(riid, path + ARRAY_SIZE(wszInterface) - 1, CHARS_IN_GUID);
2364 lstrcpyW(path + ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2366 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2367 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2368 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2369 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2371 if (hr == S_OK)
2372 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2373 else
2374 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2376 return hr;
2379 /*****************************************************************************
2380 * CoRegisterPSClsid [OLE32.@]
2382 * Register a proxy/stub CLSID for the given interface in the current process
2383 * only.
2385 * PARAMS
2386 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2387 * rclsid [I] CLSID of the proxy/stub.
2389 * RETURNS
2390 * Success: S_OK
2391 * Failure: E_OUTOFMEMORY
2393 * NOTES
2395 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2396 * will be returned from other apartments in the same process.
2398 * This function does not add anything to the registry and the effects are
2399 * limited to the lifetime of the current process.
2401 * SEE ALSO
2402 * CoGetPSClsid.
2404 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2406 APARTMENT *apt;
2407 struct registered_psclsid *registered_psclsid;
2409 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2411 if (!(apt = apartment_get_current_or_mta()))
2413 ERR("apartment not initialised\n");
2414 return CO_E_NOTINITIALIZED;
2416 apartment_release(apt);
2418 EnterCriticalSection(&cs_registered_psclsid_list);
2420 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2421 if (IsEqualIID(&registered_psclsid->iid, riid))
2423 registered_psclsid->clsid = *rclsid;
2424 LeaveCriticalSection(&cs_registered_psclsid_list);
2425 return S_OK;
2428 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2429 if (!registered_psclsid)
2431 LeaveCriticalSection(&cs_registered_psclsid_list);
2432 return E_OUTOFMEMORY;
2435 registered_psclsid->iid = *riid;
2436 registered_psclsid->clsid = *rclsid;
2437 list_add_head(&registered_psclsid_list, &registered_psclsid->entry);
2439 LeaveCriticalSection(&cs_registered_psclsid_list);
2441 return S_OK;
2445 /***
2446 * COM_GetRegisteredClassObject
2448 * This internal method is used to scan the registered class list to
2449 * find a class object.
2451 * Params:
2452 * rclsid Class ID of the class to find.
2453 * dwClsContext Class context to match.
2454 * ppv [out] returns a pointer to the class object. Complying
2455 * to normal COM usage, this method will increase the
2456 * reference count on this object.
2458 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2459 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2461 HRESULT hr = S_FALSE;
2462 RegisteredClass *curClass;
2464 EnterCriticalSection( &csRegisteredClassList );
2466 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2469 * Check if we have a match on the class ID and context.
2471 if ((apt->oxid == curClass->apartment_id) &&
2472 (dwClsContext & curClass->runContext) &&
2473 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2476 * We have a match, return the pointer to the class object.
2478 *ppUnk = curClass->classObject;
2480 IUnknown_AddRef(curClass->classObject);
2482 hr = S_OK;
2483 break;
2487 LeaveCriticalSection( &csRegisteredClassList );
2489 return hr;
2492 /******************************************************************************
2493 * CoRegisterClassObject [OLE32.@]
2495 * Registers the class object for a given class ID. Servers housed in EXE
2496 * files use this method instead of exporting DllGetClassObject to allow
2497 * other code to connect to their objects.
2499 * PARAMS
2500 * rclsid [I] CLSID of the object to register.
2501 * pUnk [I] IUnknown of the object.
2502 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2503 * flags [I] REGCLS flags indicating how connections are made.
2504 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2506 * RETURNS
2507 * S_OK on success,
2508 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2509 * CO_E_OBJISREG if the object is already registered. We should not return this.
2511 * SEE ALSO
2512 * CoRevokeClassObject, CoGetClassObject
2514 * NOTES
2515 * In-process objects are only registered for the current apartment.
2516 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2517 * in other apartments.
2519 * BUGS
2520 * MSDN claims that multiple interface registrations are legal, but we
2521 * can't do that with our current implementation.
2523 HRESULT WINAPI CoRegisterClassObject(
2524 REFCLSID rclsid,
2525 LPUNKNOWN pUnk,
2526 DWORD dwClsContext,
2527 DWORD flags,
2528 LPDWORD lpdwRegister)
2530 static LONG next_cookie;
2531 RegisteredClass* newClass;
2532 LPUNKNOWN foundObject;
2533 HRESULT hr;
2534 APARTMENT *apt;
2536 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2537 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2539 if ( (lpdwRegister==0) || (pUnk==0) )
2540 return E_INVALIDARG;
2542 if (!(apt = apartment_get_current_or_mta()))
2544 ERR("COM was not initialized\n");
2545 return CO_E_NOTINITIALIZED;
2548 *lpdwRegister = 0;
2550 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2551 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2552 if (flags & REGCLS_MULTIPLEUSE)
2553 dwClsContext |= CLSCTX_INPROC_SERVER;
2556 * First, check if the class is already registered.
2557 * If it is, this should cause an error.
2559 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2560 if (hr == S_OK) {
2561 if (flags & REGCLS_MULTIPLEUSE) {
2562 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2563 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2564 IUnknown_Release(foundObject);
2565 apartment_release(apt);
2566 return hr;
2568 IUnknown_Release(foundObject);
2569 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2570 apartment_release(apt);
2571 return CO_E_OBJISREG;
2574 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2575 if ( newClass == NULL )
2577 apartment_release(apt);
2578 return E_OUTOFMEMORY;
2581 newClass->classIdentifier = *rclsid;
2582 newClass->apartment_id = apt->oxid;
2583 newClass->runContext = dwClsContext;
2584 newClass->connectFlags = flags;
2585 newClass->RpcRegistration = NULL;
2587 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2588 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2591 * Since we're making a copy of the object pointer, we have to increase its
2592 * reference count.
2594 newClass->classObject = pUnk;
2595 IUnknown_AddRef(newClass->classObject);
2597 EnterCriticalSection( &csRegisteredClassList );
2598 list_add_tail(&RegisteredClassList, &newClass->entry);
2599 LeaveCriticalSection( &csRegisteredClassList );
2601 *lpdwRegister = newClass->dwCookie;
2603 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2604 IStream *marshal_stream;
2606 hr = get_local_server_stream(apt, &marshal_stream);
2607 if(FAILED(hr))
2609 apartment_release(apt);
2610 return hr;
2613 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2614 marshal_stream,
2615 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2616 &newClass->RpcRegistration);
2617 IStream_Release(marshal_stream);
2619 apartment_release(apt);
2620 return S_OK;
2623 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2625 if (data->origin == CLASS_REG_REGISTRY)
2627 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2628 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2629 static const WCHAR wszFree[] = {'F','r','e','e',0};
2630 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2631 WCHAR threading_model[10 /* lstrlenW(L"apartment")+1 */];
2632 DWORD dwLength = sizeof(threading_model);
2633 DWORD keytype;
2634 DWORD ret;
2636 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2637 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2638 threading_model[0] = '\0';
2640 if (!wcsicmp(threading_model, wszApartment)) return ThreadingModel_Apartment;
2641 if (!wcsicmp(threading_model, wszFree)) return ThreadingModel_Free;
2642 if (!wcsicmp(threading_model, wszBoth)) return ThreadingModel_Both;
2644 /* there's not specific handling for this case */
2645 if (threading_model[0]) return ThreadingModel_Neutral;
2646 return ThreadingModel_No;
2648 else
2649 return data->u.actctx.threading_model;
2652 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2653 REFCLSID rclsid, REFIID riid,
2654 BOOL hostifnecessary, void **ppv)
2656 WCHAR dllpath[MAX_PATH+1];
2657 BOOL apartment_threaded;
2659 if (hostifnecessary)
2661 enum comclass_threadingmodel model = get_threading_model(regdata);
2663 if (model == ThreadingModel_Apartment)
2665 apartment_threaded = TRUE;
2666 if (apt->multi_threaded)
2667 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2669 else if (model == ThreadingModel_Free)
2671 apartment_threaded = FALSE;
2672 if (!apt->multi_threaded)
2673 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2675 /* everything except "Apartment", "Free" and "Both" */
2676 else if (model != ThreadingModel_Both)
2678 apartment_threaded = TRUE;
2679 /* everything else is main-threaded */
2680 if (model != ThreadingModel_No)
2681 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2683 if (apt->multi_threaded || !apt->main)
2684 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2686 else
2687 apartment_threaded = FALSE;
2689 else
2690 apartment_threaded = !apt->multi_threaded;
2692 if (!get_object_dll_path(regdata, dllpath, ARRAY_SIZE(dllpath)))
2694 /* failure: CLSID is not found in registry */
2695 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2696 return REGDB_E_CLASSNOTREG;
2699 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2700 rclsid, riid, ppv);
2703 /***********************************************************************
2704 * CoGetClassObject [OLE32.@]
2706 * Creates an object of the specified class.
2708 * PARAMS
2709 * rclsid [I] Class ID to create an instance of.
2710 * dwClsContext [I] Flags to restrict the location of the created instance.
2711 * pServerInfo [I] Optional. Details for connecting to a remote server.
2712 * iid [I] The ID of the interface of the instance to return.
2713 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2715 * RETURNS
2716 * Success: S_OK
2717 * Failure: HRESULT code.
2719 * NOTES
2720 * The dwClsContext parameter can be one or more of the following:
2721 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2722 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2723 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2724 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2726 * SEE ALSO
2727 * CoCreateInstance()
2729 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2730 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2731 REFIID iid, LPVOID *ppv)
2733 struct class_reg_data clsreg = { 0 };
2734 IUnknown *regClassObject;
2735 HRESULT hres = E_UNEXPECTED;
2736 APARTMENT *apt;
2738 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2740 if (!ppv)
2741 return E_INVALIDARG;
2743 *ppv = NULL;
2745 if (!(apt = apartment_get_current_or_mta()))
2747 ERR("apartment not initialised\n");
2748 return CO_E_NOTINITIALIZED;
2751 if (pServerInfo) {
2752 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2753 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2756 if (CLSCTX_INPROC_SERVER & dwClsContext)
2758 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) ||
2759 IsEqualCLSID(rclsid, &CLSID_GlobalOptions) ||
2760 IsEqualCLSID(rclsid, &CLSID_ManualResetEvent) ||
2761 IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable))
2763 apartment_release(apt);
2764 return Ole32DllGetClassObject(rclsid, iid, ppv);
2768 if (CLSCTX_INPROC & dwClsContext)
2770 ACTCTX_SECTION_KEYED_DATA data;
2772 data.cbSize = sizeof(data);
2773 /* search activation context first */
2774 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2775 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2776 rclsid, &data))
2778 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2780 clsreg.u.actctx.module_name = (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset);
2781 clsreg.u.actctx.hactctx = data.hActCtx;
2782 clsreg.u.actctx.threading_model = comclass->model;
2783 clsreg.origin = CLASS_REG_ACTCTX;
2785 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2786 ReleaseActCtx(data.hActCtx);
2787 apartment_release(apt);
2788 return hres;
2793 * First, try and see if we can't match the class ID with one of the
2794 * registered classes.
2796 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2797 &regClassObject))
2799 /* Get the required interface from the retrieved pointer. */
2800 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2803 * Since QI got another reference on the pointer, we want to release the
2804 * one we already have. If QI was unsuccessful, this will release the object. This
2805 * is good since we are not returning it in the "out" parameter.
2807 IUnknown_Release(regClassObject);
2808 apartment_release(apt);
2809 return hres;
2812 /* First try in-process server */
2813 if (CLSCTX_INPROC_SERVER & dwClsContext)
2815 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2816 HKEY hkey;
2818 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2819 if (FAILED(hres))
2821 if (hres == REGDB_E_CLASSNOTREG)
2822 ERR("class %s not registered\n", debugstr_guid(rclsid));
2823 else if (hres == REGDB_E_KEYMISSING)
2825 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2826 hres = REGDB_E_CLASSNOTREG;
2830 if (SUCCEEDED(hres))
2832 clsreg.u.hkey = hkey;
2833 clsreg.origin = CLASS_REG_REGISTRY;
2835 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2836 RegCloseKey(hkey);
2839 /* return if we got a class, otherwise fall through to one of the
2840 * other types */
2841 if (SUCCEEDED(hres))
2843 apartment_release(apt);
2844 return hres;
2848 /* Next try in-process handler */
2849 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2851 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2852 HKEY hkey;
2854 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2855 if (FAILED(hres))
2857 if (hres == REGDB_E_CLASSNOTREG)
2858 ERR("class %s not registered\n", debugstr_guid(rclsid));
2859 else if (hres == REGDB_E_KEYMISSING)
2861 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2862 hres = REGDB_E_CLASSNOTREG;
2866 if (SUCCEEDED(hres))
2868 clsreg.u.hkey = hkey;
2869 clsreg.origin = CLASS_REG_REGISTRY;
2871 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2872 RegCloseKey(hkey);
2875 /* return if we got a class, otherwise fall through to one of the
2876 * other types */
2877 if (SUCCEEDED(hres))
2879 apartment_release(apt);
2880 return hres;
2883 apartment_release(apt);
2885 /* Next try out of process */
2886 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2888 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2889 if (SUCCEEDED(hres))
2890 return hres;
2893 /* Finally try remote: this requires networked DCOM (a lot of work) */
2894 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2896 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2897 hres = REGDB_E_CLASSNOTREG;
2900 if (FAILED(hres))
2901 ERR("no class object %s could be created for context 0x%x\n",
2902 debugstr_guid(rclsid), dwClsContext);
2903 return hres;
2906 /***********************************************************************
2907 * CoResumeClassObjects (OLE32.@)
2909 * Resumes all class objects registered with REGCLS_SUSPENDED.
2911 * RETURNS
2912 * Success: S_OK.
2913 * Failure: HRESULT code.
2915 HRESULT WINAPI CoResumeClassObjects(void)
2917 FIXME("stub\n");
2918 return S_OK;
2921 /***********************************************************************
2922 * CoLoadLibrary (OLE32.@)
2924 * Loads a library.
2926 * PARAMS
2927 * lpszLibName [I] Path to library.
2928 * bAutoFree [I] Whether the library should automatically be freed.
2930 * RETURNS
2931 * Success: Handle to loaded library.
2932 * Failure: NULL.
2934 * SEE ALSO
2935 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2937 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2939 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2941 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2944 /***********************************************************************
2945 * CoFreeLibrary [OLE32.@]
2947 * Unloads a library from memory.
2949 * PARAMS
2950 * hLibrary [I] Handle to library to unload.
2952 * RETURNS
2953 * Nothing
2955 * SEE ALSO
2956 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2958 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2960 FreeLibrary(hLibrary);
2964 /***********************************************************************
2965 * CoFreeAllLibraries [OLE32.@]
2967 * Function for backwards compatibility only. Does nothing.
2969 * RETURNS
2970 * Nothing.
2972 * SEE ALSO
2973 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2975 void WINAPI CoFreeAllLibraries(void)
2977 /* NOP */
2980 /***********************************************************************
2981 * CoFreeUnusedLibrariesEx [OLE32.@]
2983 * Frees any previously unused libraries whose delay has expired and marks
2984 * currently unused libraries for unloading. Unused are identified as those that
2985 * return S_OK from their DllCanUnloadNow function.
2987 * PARAMS
2988 * dwUnloadDelay [I] Unload delay in milliseconds.
2989 * dwReserved [I] Reserved. Set to 0.
2991 * RETURNS
2992 * Nothing.
2994 * SEE ALSO
2995 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2997 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2999 struct apartment *apt = COM_CurrentApt();
3000 if (!apt)
3002 ERR("apartment not initialised\n");
3003 return;
3006 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3009 /******************************************************************************
3010 * CoLockObjectExternal [OLE32.@]
3012 * Increments or decrements the external reference count of a stub object.
3014 * PARAMS
3015 * pUnk [I] Stub object.
3016 * fLock [I] If TRUE then increments the external ref-count,
3017 * otherwise decrements.
3018 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3019 * calling CoDisconnectObject.
3021 * RETURNS
3022 * Success: S_OK.
3023 * Failure: HRESULT code.
3025 * NOTES
3026 * If fLock is TRUE and an object is passed in that doesn't have a stub
3027 * manager then a new stub manager is created for the object.
3029 HRESULT WINAPI CoLockObjectExternal(
3030 LPUNKNOWN pUnk,
3031 BOOL fLock,
3032 BOOL fLastUnlockReleases)
3034 struct stub_manager *stubmgr;
3035 struct apartment *apt;
3037 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3038 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3040 if (!(apt = apartment_get_current_or_mta()))
3042 ERR("apartment not initialised\n");
3043 return CO_E_NOTINITIALIZED;
3046 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3047 if (!stubmgr)
3049 WARN("stub object not found %p\n", pUnk);
3050 /* Note: native is pretty broken here because it just silently
3051 * fails, without returning an appropriate error code, making apps
3052 * think that the object was disconnected, when it actually wasn't */
3053 apartment_release(apt);
3054 return S_OK;
3057 if (fLock)
3058 stub_manager_ext_addref(stubmgr, 1, FALSE);
3059 else
3060 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3062 stub_manager_int_release(stubmgr);
3063 apartment_release(apt);
3064 return S_OK;
3067 /***********************************************************************
3068 * CoInitializeWOW (OLE32.@)
3070 * WOW equivalent of CoInitialize?
3072 * PARAMS
3073 * x [I] Unknown.
3074 * y [I] Unknown.
3076 * RETURNS
3077 * Unknown.
3079 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3081 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3082 return 0;
3085 /***********************************************************************
3086 * CoGetState [OLE32.@]
3088 * Retrieves the thread state object previously stored by CoSetState().
3090 * PARAMS
3091 * ppv [I] Address where pointer to object will be stored.
3093 * RETURNS
3094 * Success: S_OK.
3095 * Failure: E_OUTOFMEMORY.
3097 * NOTES
3098 * Crashes on all invalid ppv addresses, including NULL.
3099 * If the function returns a non-NULL object then the caller must release its
3100 * reference on the object when the object is no longer required.
3102 * SEE ALSO
3103 * CoSetState().
3105 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3107 struct oletls *info = COM_CurrentInfo();
3108 if (!info) return E_OUTOFMEMORY;
3110 *ppv = NULL;
3112 if (info->state)
3114 IUnknown_AddRef(info->state);
3115 *ppv = info->state;
3116 TRACE("apt->state=%p\n", info->state);
3119 return S_OK;
3122 /***********************************************************************
3123 * CoSetState [OLE32.@]
3125 * Sets the thread state object.
3127 * PARAMS
3128 * pv [I] Pointer to state object to be stored.
3130 * NOTES
3131 * The system keeps a reference on the object while the object stored.
3133 * RETURNS
3134 * Success: S_OK.
3135 * Failure: E_OUTOFMEMORY.
3137 HRESULT WINAPI CoSetState(IUnknown * pv)
3139 struct oletls *info = COM_CurrentInfo();
3140 if (!info) return E_OUTOFMEMORY;
3142 if (pv) IUnknown_AddRef(pv);
3144 if (info->state)
3146 TRACE("-- release %p now\n", info->state);
3147 IUnknown_Release(info->state);
3150 info->state = pv;
3152 return S_OK;
3156 /******************************************************************************
3157 * CoTreatAsClass [OLE32.@]
3159 * Sets the TreatAs value of a class.
3161 * PARAMS
3162 * clsidOld [I] Class to set TreatAs value on.
3163 * clsidNew [I] The class the clsidOld should be treated as.
3165 * RETURNS
3166 * Success: S_OK.
3167 * Failure: HRESULT code.
3169 * SEE ALSO
3170 * CoGetTreatAsClass
3172 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3174 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3175 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3176 HKEY hkey = NULL;
3177 WCHAR szClsidNew[CHARS_IN_GUID];
3178 HRESULT res = S_OK;
3179 WCHAR auto_treat_as[CHARS_IN_GUID];
3180 LONG auto_treat_as_size = sizeof(auto_treat_as);
3181 CLSID id;
3183 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3184 if (FAILED(res))
3185 goto done;
3187 if (IsEqualGUID( clsidOld, clsidNew ))
3189 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3190 CLSIDFromString(auto_treat_as, &id) == S_OK)
3192 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3194 res = REGDB_E_WRITEREGDB;
3195 goto done;
3198 else
3200 if(RegDeleteKeyW(hkey, wszTreatAs))
3201 res = REGDB_E_WRITEREGDB;
3202 goto done;
3205 else
3207 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3208 RegDeleteKeyW(hkey, wszTreatAs);
3209 }else{
3210 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAY_SIZE(szClsidNew))){
3211 WARN("StringFromGUID2 failed\n");
3212 res = E_FAIL;
3213 goto done;
3216 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3217 WARN("RegSetValue failed\n");
3218 res = REGDB_E_WRITEREGDB;
3219 goto done;
3224 done:
3225 if (hkey) RegCloseKey(hkey);
3226 return res;
3229 /******************************************************************************
3230 * CoGetCurrentProcess [OLE32.@]
3232 DWORD WINAPI CoGetCurrentProcess(void)
3234 struct oletls *info = COM_CurrentInfo();
3236 if (!info)
3237 return 0;
3239 if (!info->thread_seqid)
3240 info->thread_seqid = rpcss_get_next_seqid();
3242 return info->thread_seqid;
3245 /***********************************************************************
3246 * CoGetCurrentLogicalThreadId [OLE32.@]
3248 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
3250 TRACE("(%p)\n", id);
3252 if (!id)
3253 return E_INVALIDARG;
3255 *id = COM_CurrentCausalityId();
3256 return S_OK;
3259 /******************************************************************************
3260 * CoRegisterMessageFilter [OLE32.@]
3262 * Registers a message filter.
3264 * PARAMS
3265 * lpMessageFilter [I] Pointer to interface.
3266 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3268 * RETURNS
3269 * Success: S_OK.
3270 * Failure: HRESULT code.
3272 * NOTES
3273 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3274 * lpMessageFilter removes the message filter.
3276 * If lplpMessageFilter is not NULL the previous message filter will be
3277 * returned in the memory pointer to this parameter and the caller is
3278 * responsible for releasing the object.
3280 * The current thread be in an apartment otherwise the function will crash.
3282 HRESULT WINAPI CoRegisterMessageFilter(
3283 LPMESSAGEFILTER lpMessageFilter,
3284 LPMESSAGEFILTER *lplpMessageFilter)
3286 struct apartment *apt;
3287 IMessageFilter *lpOldMessageFilter;
3289 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3291 apt = COM_CurrentApt();
3293 /* can't set a message filter in a multi-threaded apartment */
3294 if (!apt || apt->multi_threaded)
3296 WARN("can't set message filter in MTA or uninitialized apt\n");
3297 return CO_E_NOT_SUPPORTED;
3300 if (lpMessageFilter)
3301 IMessageFilter_AddRef(lpMessageFilter);
3303 EnterCriticalSection(&apt->cs);
3305 lpOldMessageFilter = apt->filter;
3306 apt->filter = lpMessageFilter;
3308 LeaveCriticalSection(&apt->cs);
3310 if (lplpMessageFilter)
3311 *lplpMessageFilter = lpOldMessageFilter;
3312 else if (lpOldMessageFilter)
3313 IMessageFilter_Release(lpOldMessageFilter);
3315 return S_OK;
3318 /***********************************************************************
3319 * CoIsOle1Class [OLE32.@]
3321 * Determines whether the specified class an OLE v1 class.
3323 * PARAMS
3324 * clsid [I] Class to test.
3326 * RETURNS
3327 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3329 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3331 FIXME("%s\n", debugstr_guid(clsid));
3332 return FALSE;
3335 /***********************************************************************
3336 * IsEqualGUID [OLE32.@]
3338 * Compares two Unique Identifiers.
3340 * PARAMS
3341 * rguid1 [I] The first GUID to compare.
3342 * rguid2 [I] The other GUID to compare.
3344 * RETURNS
3345 * TRUE if equal
3347 #undef IsEqualGUID
3348 BOOL WINAPI IsEqualGUID(
3349 REFGUID rguid1,
3350 REFGUID rguid2)
3352 return !memcmp(rguid1,rguid2,sizeof(GUID));
3355 /***********************************************************************
3356 * CoInitializeSecurity [OLE32.@]
3358 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3359 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3360 void* pReserved1, DWORD dwAuthnLevel,
3361 DWORD dwImpLevel, void* pReserved2,
3362 DWORD dwCapabilities, void* pReserved3)
3364 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3365 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3366 dwCapabilities, pReserved3);
3367 return S_OK;
3370 /***********************************************************************
3371 * CoSuspendClassObjects [OLE32.@]
3373 * Suspends all registered class objects to prevent further requests coming in
3374 * for those objects.
3376 * RETURNS
3377 * Success: S_OK.
3378 * Failure: HRESULT code.
3380 HRESULT WINAPI CoSuspendClassObjects(void)
3382 FIXME("\n");
3383 return S_OK;
3386 /***********************************************************************
3387 * CoAddRefServerProcess [OLE32.@]
3389 * Helper function for incrementing the reference count of a local-server
3390 * process.
3392 * RETURNS
3393 * New reference count.
3395 * SEE ALSO
3396 * CoReleaseServerProcess().
3398 ULONG WINAPI CoAddRefServerProcess(void)
3400 ULONG refs;
3402 TRACE("\n");
3404 EnterCriticalSection(&csRegisteredClassList);
3405 refs = ++s_COMServerProcessReferences;
3406 LeaveCriticalSection(&csRegisteredClassList);
3408 TRACE("refs before: %d\n", refs - 1);
3410 return refs;
3413 /***********************************************************************
3414 * CoReleaseServerProcess [OLE32.@]
3416 * Helper function for decrementing the reference count of a local-server
3417 * process.
3419 * RETURNS
3420 * New reference count.
3422 * NOTES
3423 * When reference count reaches 0, this function suspends all registered
3424 * classes so no new connections are accepted.
3426 * SEE ALSO
3427 * CoAddRefServerProcess(), CoSuspendClassObjects().
3429 ULONG WINAPI CoReleaseServerProcess(void)
3431 ULONG refs;
3433 TRACE("\n");
3435 EnterCriticalSection(&csRegisteredClassList);
3437 refs = --s_COMServerProcessReferences;
3438 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3440 LeaveCriticalSection(&csRegisteredClassList);
3442 TRACE("refs after: %d\n", refs);
3444 return refs;
3447 /***********************************************************************
3448 * CoIsHandlerConnected [OLE32.@]
3450 * Determines whether a proxy is connected to a remote stub.
3452 * PARAMS
3453 * pUnk [I] Pointer to object that may or may not be connected.
3455 * RETURNS
3456 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3457 * FALSE otherwise.
3459 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3461 FIXME("%p\n", pUnk);
3463 return TRUE;
3466 /***********************************************************************
3467 * CoAllowSetForegroundWindow [OLE32.@]
3470 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3472 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3473 return S_OK;
3476 /***********************************************************************
3477 * CoGetCallContext [OLE32.@]
3479 * Gets the context of the currently executing server call in the current
3480 * thread.
3482 * PARAMS
3483 * riid [I] Context interface to return.
3484 * ppv [O] Pointer to memory that will receive the context on return.
3486 * RETURNS
3487 * Success: S_OK.
3488 * Failure: HRESULT code.
3490 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3492 struct oletls *info = COM_CurrentInfo();
3494 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3496 if (!info)
3497 return E_OUTOFMEMORY;
3499 if (!info->call_state)
3500 return RPC_E_CALL_COMPLETE;
3502 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3505 /***********************************************************************
3506 * CoSwitchCallContext [OLE32.@]
3508 * Switches the context of the currently executing server call in the current
3509 * thread.
3511 * PARAMS
3512 * pObject [I] Pointer to new context object
3513 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3515 * RETURNS
3516 * Success: S_OK.
3517 * Failure: HRESULT code.
3519 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3521 struct oletls *info = COM_CurrentInfo();
3523 TRACE("(%p, %p)\n", pObject, ppOldObject);
3525 if (!info)
3526 return E_OUTOFMEMORY;
3528 *ppOldObject = info->call_state;
3529 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3531 return S_OK;
3534 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3536 /* first try to retrieve messages for incoming COM calls to the apartment window */
3537 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
3538 /* next retrieve other messages necessary for the app to remain responsive */
3539 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3540 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3543 /***********************************************************************
3544 * CoWaitForMultipleHandles [OLE32.@]
3546 * Waits for one or more handles to become signaled.
3548 * PARAMS
3549 * dwFlags [I] Flags. See notes.
3550 * dwTimeout [I] Timeout in milliseconds.
3551 * cHandles [I] Number of handles pointed to by pHandles.
3552 * pHandles [I] Handles to wait for.
3553 * lpdwindex [O] Index of handle that was signaled.
3555 * RETURNS
3556 * Success: S_OK.
3557 * Failure: RPC_S_CALLPENDING on timeout.
3559 * NOTES
3561 * The dwFlags parameter can be zero or more of the following:
3562 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3563 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3565 * SEE ALSO
3566 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3568 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3569 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3571 HRESULT hr = S_OK;
3572 DWORD start_time = GetTickCount();
3573 APARTMENT *apt = COM_CurrentApt();
3574 BOOL message_loop = apt && !apt->multi_threaded;
3575 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
3576 BOOL post_quit = FALSE;
3577 UINT exit_code;
3579 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3580 pHandles, lpdwindex);
3582 if (!lpdwindex)
3583 return E_INVALIDARG;
3585 *lpdwindex = 0;
3587 if (!pHandles)
3588 return E_INVALIDARG;
3590 if (!cHandles)
3591 return RPC_E_NO_SYNC;
3593 while (TRUE)
3595 DWORD now = GetTickCount();
3596 DWORD res;
3598 if (now - start_time > dwTimeout)
3600 hr = RPC_S_CALLPENDING;
3601 break;
3604 if (message_loop)
3606 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3607 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3609 TRACE("waiting for rpc completion or window message\n");
3611 res = WAIT_TIMEOUT;
3613 if (check_apc)
3615 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3616 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
3617 check_apc = FALSE;
3620 if (res == WAIT_TIMEOUT)
3621 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3622 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3623 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
3625 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3627 MSG msg;
3628 int count = 0;
3630 /* call message filter */
3632 if (COM_CurrentApt()->filter)
3634 PENDINGTYPE pendingtype =
3635 COM_CurrentInfo()->pending_call_count_server ?
3636 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3637 DWORD be_handled = IMessageFilter_MessagePending(
3638 COM_CurrentApt()->filter, 0 /* FIXME */,
3639 now - start_time, pendingtype);
3640 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3641 switch (be_handled)
3643 case PENDINGMSG_CANCELCALL:
3644 WARN("call canceled\n");
3645 hr = RPC_E_CALL_CANCELED;
3646 break;
3647 case PENDINGMSG_WAITNOPROCESS:
3648 case PENDINGMSG_WAITDEFPROCESS:
3649 default:
3650 /* FIXME: MSDN is very vague about the difference
3651 * between WAITNOPROCESS and WAITDEFPROCESS - there
3652 * appears to be none, so it is possibly a left-over
3653 * from the 16-bit world. */
3654 break;
3658 if (!apt->win)
3660 /* If window is NULL on apartment, peek at messages so that it will not trigger
3661 * MsgWaitForMultipleObjects next time. */
3662 PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
3664 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
3665 * so after processing 100 messages we go back to checking the wait handles */
3666 while (count++ < 100 && COM_PeekMessage(apt, &msg))
3668 if (msg.message == WM_QUIT)
3670 TRACE("received WM_QUIT message\n");
3671 post_quit = TRUE;
3672 exit_code = msg.wParam;
3674 else
3676 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3677 TranslateMessage(&msg);
3678 DispatchMessageW(&msg);
3681 continue;
3684 else
3686 TRACE("waiting for rpc completion\n");
3688 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
3689 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3690 (dwFlags & COWAIT_ALERTABLE) != 0);
3693 switch (res)
3695 case WAIT_TIMEOUT:
3696 hr = RPC_S_CALLPENDING;
3697 break;
3698 case WAIT_FAILED:
3699 hr = HRESULT_FROM_WIN32( GetLastError() );
3700 break;
3701 default:
3702 *lpdwindex = res;
3703 break;
3705 break;
3707 if (post_quit) PostQuitMessage(exit_code);
3708 TRACE("-- 0x%08x\n", hr);
3709 return hr;
3713 /***********************************************************************
3714 * CoGetObject [OLE32.@]
3716 * Gets the object named by converting the name to a moniker and binding to it.
3718 * PARAMS
3719 * pszName [I] String representing the object.
3720 * pBindOptions [I] Parameters affecting the binding to the named object.
3721 * riid [I] Interface to bind to on the object.
3722 * ppv [O] On output, the interface riid of the object represented
3723 * by pszName.
3725 * RETURNS
3726 * Success: S_OK.
3727 * Failure: HRESULT code.
3729 * SEE ALSO
3730 * MkParseDisplayName.
3732 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3733 REFIID riid, void **ppv)
3735 IBindCtx *pbc;
3736 HRESULT hr;
3738 *ppv = NULL;
3740 hr = CreateBindCtx(0, &pbc);
3741 if (SUCCEEDED(hr))
3743 if (pBindOptions)
3744 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3746 if (SUCCEEDED(hr))
3748 ULONG chEaten;
3749 IMoniker *pmk;
3751 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3752 if (SUCCEEDED(hr))
3754 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3755 IMoniker_Release(pmk);
3759 IBindCtx_Release(pbc);
3761 return hr;
3764 /***********************************************************************
3765 * CoRegisterChannelHook [OLE32.@]
3767 * Registers a process-wide hook that is called during ORPC calls.
3769 * PARAMS
3770 * guidExtension [I] GUID of the channel hook to register.
3771 * pChannelHook [I] Channel hook object to register.
3773 * RETURNS
3774 * Success: S_OK.
3775 * Failure: HRESULT code.
3777 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3779 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3781 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3784 typedef struct Context
3786 IComThreadingInfo IComThreadingInfo_iface;
3787 IContextCallback IContextCallback_iface;
3788 IObjContext IObjContext_iface;
3789 LONG refs;
3790 } Context;
3792 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
3794 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
3797 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
3799 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
3802 static inline Context *impl_from_IObjContext( IObjContext *iface )
3804 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
3807 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3809 *ppv = NULL;
3811 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3812 IsEqualIID(riid, &IID_IUnknown))
3814 *ppv = &iface->IComThreadingInfo_iface;
3816 else if (IsEqualIID(riid, &IID_IContextCallback))
3818 *ppv = &iface->IContextCallback_iface;
3820 else if (IsEqualIID(riid, &IID_IObjContext))
3822 *ppv = &iface->IObjContext_iface;
3825 if (*ppv)
3827 IUnknown_AddRef((IUnknown*)*ppv);
3828 return S_OK;
3831 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3832 return E_NOINTERFACE;
3835 static ULONG Context_AddRef(Context *This)
3837 return InterlockedIncrement(&This->refs);
3840 static ULONG Context_Release(Context *This)
3842 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
3843 releasing context while refcount is at 0 destroys it. */
3844 if (!This->refs)
3846 HeapFree(GetProcessHeap(), 0, This);
3847 return 0;
3850 return InterlockedDecrement(&This->refs);
3853 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3855 Context *This = impl_from_IComThreadingInfo(iface);
3856 return Context_QueryInterface(This, riid, ppv);
3859 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
3861 Context *This = impl_from_IComThreadingInfo(iface);
3862 return Context_AddRef(This);
3865 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
3867 Context *This = impl_from_IComThreadingInfo(iface);
3868 return Context_Release(This);
3871 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3873 APTTYPEQUALIFIER qualifier;
3875 TRACE("(%p)\n", apttype);
3877 return CoGetApartmentType(apttype, &qualifier);
3880 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3882 APTTYPEQUALIFIER qualifier;
3883 APTTYPE apttype;
3884 HRESULT hr;
3886 hr = CoGetApartmentType(&apttype, &qualifier);
3887 if (FAILED(hr))
3888 return hr;
3890 TRACE("(%p)\n", thdtype);
3892 switch (apttype)
3894 case APTTYPE_STA:
3895 case APTTYPE_MAINSTA:
3896 *thdtype = THDTYPE_PROCESSMESSAGES;
3897 break;
3898 default:
3899 *thdtype = THDTYPE_BLOCKMESSAGES;
3900 break;
3902 return S_OK;
3905 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3907 TRACE("(%p)\n", logical_thread_id);
3908 return CoGetCurrentLogicalThreadId(logical_thread_id);
3911 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3913 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3914 return E_NOTIMPL;
3917 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3919 Context_CTI_QueryInterface,
3920 Context_CTI_AddRef,
3921 Context_CTI_Release,
3922 Context_CTI_GetCurrentApartmentType,
3923 Context_CTI_GetCurrentThreadType,
3924 Context_CTI_GetCurrentLogicalThreadId,
3925 Context_CTI_SetCurrentLogicalThreadId
3928 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
3930 Context *This = impl_from_IContextCallback(iface);
3931 return Context_QueryInterface(This, riid, ppv);
3934 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
3936 Context *This = impl_from_IContextCallback(iface);
3937 return Context_AddRef(This);
3940 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
3942 Context *This = impl_from_IContextCallback(iface);
3943 return Context_Release(This);
3946 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
3947 ComCallData *param, REFIID riid, int method, IUnknown *punk)
3949 Context *This = impl_from_IContextCallback(iface);
3951 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
3952 return E_NOTIMPL;
3955 static const IContextCallbackVtbl Context_Callback_Vtbl =
3957 Context_CC_QueryInterface,
3958 Context_CC_AddRef,
3959 Context_CC_Release,
3960 Context_CC_ContextCallback
3963 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
3965 Context *This = impl_from_IObjContext(iface);
3966 return Context_QueryInterface(This, riid, ppv);
3969 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
3971 Context *This = impl_from_IObjContext(iface);
3972 return Context_AddRef(This);
3975 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
3977 Context *This = impl_from_IObjContext(iface);
3978 return Context_Release(This);
3981 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
3983 Context *This = impl_from_IObjContext(iface);
3985 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3986 return E_NOTIMPL;
3989 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
3991 Context *This = impl_from_IObjContext(iface);
3993 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
3994 return E_NOTIMPL;
3997 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
3999 Context *This = impl_from_IObjContext(iface);
4001 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4002 return E_NOTIMPL;
4005 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4007 Context *This = impl_from_IObjContext(iface);
4009 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4010 return E_NOTIMPL;
4013 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4015 Context *This = impl_from_IObjContext(iface);
4016 FIXME("(%p/%p)\n", This, iface);
4019 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4021 Context *This = impl_from_IObjContext(iface);
4022 FIXME("(%p/%p)\n", This, iface);
4025 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4027 Context *This = impl_from_IObjContext(iface);
4028 FIXME("(%p/%p)\n", This, iface);
4031 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4033 Context *This = impl_from_IObjContext(iface);
4034 FIXME("(%p/%p)\n", This, iface);
4037 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4039 Context *This = impl_from_IObjContext(iface);
4040 FIXME("(%p/%p)\n", This, iface);
4043 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4045 Context *This = impl_from_IObjContext(iface);
4046 FIXME("(%p/%p)\n", This, iface);
4049 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4051 Context *This = impl_from_IObjContext(iface);
4052 FIXME("(%p/%p)\n", This, iface);
4055 static const IObjContextVtbl Context_Object_Vtbl =
4057 Context_OC_QueryInterface,
4058 Context_OC_AddRef,
4059 Context_OC_Release,
4060 Context_OC_SetProperty,
4061 Context_OC_RemoveProperty,
4062 Context_OC_GetProperty,
4063 Context_OC_EnumContextProps,
4064 Context_OC_Reserved1,
4065 Context_OC_Reserved2,
4066 Context_OC_Reserved3,
4067 Context_OC_Reserved4,
4068 Context_OC_Reserved5,
4069 Context_OC_Reserved6,
4070 Context_OC_Reserved7
4073 /***********************************************************************
4074 * CoGetContextToken [OLE32.@]
4076 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4078 struct oletls *info = COM_CurrentInfo();
4079 APARTMENT *apt;
4081 TRACE("(%p)\n", token);
4083 if (!info)
4084 return E_OUTOFMEMORY;
4086 if (!(apt = apartment_get_current_or_mta()))
4088 ERR("apartment not initialised\n");
4089 return CO_E_NOTINITIALIZED;
4091 apartment_release(apt);
4093 if (!token)
4094 return E_POINTER;
4096 if (!info->context_token)
4098 Context *context;
4100 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4101 if (!context)
4102 return E_OUTOFMEMORY;
4104 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4105 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4106 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4107 /* Context token does not take a reference, it's always zero until the
4108 interface is explicitly requested with CoGetObjectContext(). */
4109 context->refs = 0;
4111 info->context_token = &context->IObjContext_iface;
4114 *token = (ULONG_PTR)info->context_token;
4115 TRACE("context_token=%p\n", info->context_token);
4117 return S_OK;
4120 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4122 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4123 HKEY hkey;
4124 HRESULT hres;
4126 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4127 if (SUCCEEDED(hres))
4129 struct class_reg_data regdata;
4130 WCHAR dllpath[MAX_PATH+1];
4132 regdata.u.hkey = hkey;
4133 regdata.origin = CLASS_REG_REGISTRY;
4135 if (get_object_dll_path(&regdata, dllpath, ARRAY_SIZE(dllpath)))
4137 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4138 if (!wcsicmp(dllpath, wszOle32))
4140 RegCloseKey(hkey);
4141 return HandlerCF_Create(rclsid, riid, ppv);
4144 else
4145 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4146 RegCloseKey(hkey);
4149 return CLASS_E_CLASSNOTAVAILABLE;
4152 /***********************************************************************
4153 * CoGetApartmentType [OLE32.@]
4155 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
4157 struct oletls *info = COM_CurrentInfo();
4158 APARTMENT *apt;
4160 TRACE("(%p, %p)\n", type, qualifier);
4162 if (!type || !qualifier)
4163 return E_INVALIDARG;
4165 if (!info)
4166 return E_OUTOFMEMORY;
4168 if (!info->apt)
4169 *type = APTTYPE_CURRENT;
4170 else if (info->apt->multi_threaded)
4171 *type = APTTYPE_MTA;
4172 else if (info->apt->main)
4173 *type = APTTYPE_MAINSTA;
4174 else
4175 *type = APTTYPE_STA;
4177 *qualifier = APTTYPEQUALIFIER_NONE;
4179 if (!info->apt && (apt = apartment_find_mta()))
4181 apartment_release(apt);
4182 *type = APTTYPE_MTA;
4183 *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
4184 return S_OK;
4187 return info->apt ? S_OK : CO_E_NOTINITIALIZED;
4190 struct mta_cookie
4192 struct list entry;
4195 /***********************************************************************
4196 * CoIncrementMTAUsage [OLE32.@]
4198 HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie)
4200 struct mta_cookie *mta_cookie;
4202 TRACE("%p\n", cookie);
4204 *cookie = NULL;
4206 if (!(mta_cookie = heap_alloc(sizeof(*mta_cookie))))
4207 return E_OUTOFMEMORY;
4209 EnterCriticalSection(&csApartment);
4211 if (MTA)
4212 apartment_addref(MTA);
4213 else
4214 MTA = apartment_construct(COINIT_MULTITHREADED);
4215 list_add_head(&MTA->usage_cookies, &mta_cookie->entry);
4217 LeaveCriticalSection(&csApartment);
4219 *cookie = (CO_MTA_USAGE_COOKIE)mta_cookie;
4221 return S_OK;
4224 /***********************************************************************
4225 * CoDecrementMTAUsage [OLE32.@]
4227 HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie)
4229 struct mta_cookie *mta_cookie = (struct mta_cookie *)cookie;
4231 TRACE("%p\n", cookie);
4233 EnterCriticalSection(&csApartment);
4235 if (MTA)
4237 struct mta_cookie *cur;
4239 LIST_FOR_EACH_ENTRY(cur, &MTA->usage_cookies, struct mta_cookie, entry)
4241 if (mta_cookie == cur)
4243 list_remove(&cur->entry);
4244 heap_free(cur);
4245 apartment_release(MTA);
4246 break;
4251 LeaveCriticalSection(&csApartment);
4253 return S_OK;
4256 /***********************************************************************
4257 * CoDisableCallCancellation [OLE32.@]
4259 HRESULT WINAPI CoDisableCallCancellation(void *reserved)
4261 FIXME("(%p): stub\n", reserved);
4263 return E_NOTIMPL;
4266 /***********************************************************************
4267 * CoEnableCallCancellation [OLE32.@]
4269 HRESULT WINAPI CoEnableCallCancellation(void *reserved)
4271 FIXME("(%p): stub\n", reserved);
4273 return E_NOTIMPL;
4276 /***********************************************************************
4277 * CoRegisterSurrogate [OLE32.@]
4279 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
4281 FIXME("(%p): stub\n", surrogate);
4283 return E_NOTIMPL;
4286 /***********************************************************************
4287 * CoRegisterSurrogateEx [OLE32.@]
4289 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
4291 FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved);
4293 return E_NOTIMPL;
4296 typedef struct {
4297 IGlobalOptions IGlobalOptions_iface;
4298 LONG ref;
4299 } GlobalOptions;
4301 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface)
4303 return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface);
4306 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
4308 GlobalOptions *This = impl_from_IGlobalOptions(iface);
4310 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4312 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
4314 *ppv = iface;
4316 else
4318 *ppv = NULL;
4319 return E_NOINTERFACE;
4322 IUnknown_AddRef((IUnknown*)*ppv);
4323 return S_OK;
4326 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface)
4328 GlobalOptions *This = impl_from_IGlobalOptions(iface);
4329 LONG ref = InterlockedIncrement(&This->ref);
4331 TRACE("(%p) ref=%d\n", This, ref);
4333 return ref;
4336 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface)
4338 GlobalOptions *This = impl_from_IGlobalOptions(iface);
4339 LONG ref = InterlockedDecrement(&This->ref);
4341 TRACE("(%p) ref=%d\n", This, ref);
4343 if (!ref)
4344 heap_free(This);
4346 return ref;
4349 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
4351 GlobalOptions *This = impl_from_IGlobalOptions(iface);
4352 FIXME("(%p)->(%u %lx)\n", This, property, value);
4353 return S_OK;
4356 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
4358 GlobalOptions *This = impl_from_IGlobalOptions(iface);
4359 FIXME("(%p)->(%u %p)\n", This, property, value);
4360 return E_NOTIMPL;
4363 static const IGlobalOptionsVtbl GlobalOptionsVtbl = {
4364 GlobalOptions_QueryInterface,
4365 GlobalOptions_AddRef,
4366 GlobalOptions_Release,
4367 GlobalOptions_Set,
4368 GlobalOptions_Query
4371 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
4373 GlobalOptions *global_options;
4374 HRESULT hres;
4376 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
4378 if (outer)
4379 return E_INVALIDARG;
4381 global_options = heap_alloc(sizeof(*global_options));
4382 if (!global_options)
4383 return E_OUTOFMEMORY;
4384 global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl;
4385 global_options->ref = 1;
4387 hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv);
4388 IGlobalOptions_Release(&global_options->IGlobalOptions_iface);
4389 return hres;
4392 /***********************************************************************
4393 * DllMain (OLE32.@)
4395 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
4397 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
4399 switch(fdwReason) {
4400 case DLL_PROCESS_ATTACH:
4401 hProxyDll = hinstDLL;
4402 break;
4404 case DLL_PROCESS_DETACH:
4405 if (reserved) break;
4406 release_std_git();
4407 if(apt_win_class)
4408 UnregisterClassW( (const WCHAR*)MAKEINTATOM(apt_win_class), hProxyDll );
4409 RPC_UnregisterAllChannelHooks();
4410 COMPOBJ_DllList_Free();
4411 DeleteCriticalSection(&csRegisteredClassList);
4412 DeleteCriticalSection(&csApartment);
4413 break;
4415 case DLL_THREAD_DETACH:
4416 COM_TlsDestroy();
4417 break;
4419 return TRUE;
4422 /***********************************************************************
4423 * DllRegisterServer (OLE32.@)
4425 HRESULT WINAPI DllRegisterServer(void)
4427 return OLE32_DllRegisterServer();
4430 /***********************************************************************
4431 * DllUnregisterServer (OLE32.@)
4433 HRESULT WINAPI DllUnregisterServer(void)
4435 return OLE32_DllUnregisterServer();