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
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
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
51 #define WIN32_NO_STATUS
57 #define USE_COM_CONTEXT_DEF
65 #include "compobj_private.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole);
73 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
75 /****************************************************************************
76 * This section defines variables internal to the COM module.
79 static APARTMENT *MTA; /* protected by csApartment */
80 static APARTMENT *MainApartment; /* the first STA apartment */
81 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
92 struct registered_psclsid
100 * This lock count counts the number of times CoInitialize is called. It is
101 * decreased every time CoUninitialize is called. When it hits 0, the COM
102 * libraries are freed
104 static LONG s_COMLockCount = 0;
105 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
106 static LONG s_COMServerProcessReferences = 0;
109 * This linked list contains the list of registered class objects. These
110 * are mostly used to register the factories for out-of-proc servers of OLE
113 * TODO: Make this data structure aware of inter-process communication. This
114 * means that parts of this will be exported to rpcss.
116 typedef struct tagRegisteredClass
119 CLSID classIdentifier;
121 LPUNKNOWN classObject;
125 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
126 void *RpcRegistration;
129 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
131 static CRITICAL_SECTION csRegisteredClassList;
132 static CRITICAL_SECTION_DEBUG class_cs_debug =
134 0, 0, &csRegisteredClassList,
135 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
136 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
138 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
140 /* wrapper for NtCreateKey that creates the key recursively if necessary */
141 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
143 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
145 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
147 HANDLE subkey, root = attr->RootDirectory;
148 WCHAR *buffer = attr->ObjectName->Buffer;
149 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
152 while (i < len && buffer[i] != '\\') i++;
153 if (i == len) return status;
155 attrs = attr->Attributes;
156 attr->ObjectName = &str;
160 str.Buffer = buffer + pos;
161 str.Length = (i - pos) * sizeof(WCHAR);
162 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
163 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
164 if (status) return status;
165 attr->RootDirectory = subkey;
166 while (i < len && buffer[i] == '\\') i++;
168 while (i < len && buffer[i] != '\\') i++;
170 str.Buffer = buffer + pos;
171 str.Length = (i - pos) * sizeof(WCHAR);
172 attr->Attributes = attrs;
173 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
174 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
179 static const WCHAR classes_rootW[] =
180 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
182 static HKEY classes_root_hkey;
184 /* create the special HKEY_CLASSES_ROOT key */
185 static HKEY create_classes_root_hkey(void)
188 OBJECT_ATTRIBUTES attr;
191 attr.Length = sizeof(attr);
192 attr.RootDirectory = 0;
193 attr.ObjectName = &name;
195 attr.SecurityDescriptor = NULL;
196 attr.SecurityQualityOfService = NULL;
197 RtlInitUnicodeString( &name, classes_rootW );
198 if (create_key( &hkey, MAXIMUM_ALLOWED, &attr )) return 0;
199 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
201 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
204 NtClose( hkey ); /* somebody beat us to it */
208 /* map the hkey from special root to normal key if necessary */
209 static inline HKEY get_classes_root_hkey( HKEY hkey )
213 if (hkey == HKEY_CLASSES_ROOT && !(ret = classes_root_hkey))
214 ret = create_classes_root_hkey();
219 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
221 OBJECT_ATTRIBUTES attr;
222 UNICODE_STRING nameW;
224 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
226 attr.Length = sizeof(attr);
227 attr.RootDirectory = hkey;
228 attr.ObjectName = &nameW;
230 attr.SecurityDescriptor = NULL;
231 attr.SecurityQualityOfService = NULL;
232 RtlInitUnicodeString( &nameW, name );
234 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
237 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
239 OBJECT_ATTRIBUTES attr;
240 UNICODE_STRING nameW;
242 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
244 attr.Length = sizeof(attr);
245 attr.RootDirectory = hkey;
246 attr.ObjectName = &nameW;
248 attr.SecurityDescriptor = NULL;
249 attr.SecurityQualityOfService = NULL;
250 RtlInitUnicodeString( &nameW, name );
252 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
255 /*****************************************************************************
256 * This section contains OpenDllList definitions
258 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
259 * other functions that do LoadLibrary _without_ giving back a HMODULE.
260 * Without this list these handles would never be freed.
262 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
263 * next unload-call but not before 600 sec.
266 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
267 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
269 typedef struct tagOpenDll
274 DllGetClassObjectFunc DllGetClassObject;
275 DllCanUnloadNowFunc DllCanUnloadNow;
279 static struct list openDllList = LIST_INIT(openDllList);
281 static CRITICAL_SECTION csOpenDllList;
282 static CRITICAL_SECTION_DEBUG dll_cs_debug =
284 0, 0, &csOpenDllList,
285 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
286 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
288 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
290 struct apartment_loaded_dll
298 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',' ',
299 '0','x','#','#','#','#','#','#','#','#',' ',0};
301 /*****************************************************************************
302 * This section contains OpenDllList implementation
305 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
309 EnterCriticalSection(&csOpenDllList);
310 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
312 if (!strcmpiW(library_name, ptr->library_name) &&
313 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
319 LeaveCriticalSection(&csOpenDllList);
323 /* caller must ensure that library_name is not already in the open dll list */
324 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
330 DllCanUnloadNowFunc DllCanUnloadNow;
331 DllGetClassObjectFunc DllGetClassObject;
335 *ret = COMPOBJ_DllList_Get(library_name);
336 if (*ret) return S_OK;
338 /* do this outside the csOpenDllList to avoid creating a lock dependency on
340 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
343 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
344 /* failure: DLL could not be loaded */
345 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
348 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
349 /* Note: failing to find DllCanUnloadNow is not a failure */
350 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
351 if (!DllGetClassObject)
353 /* failure: the dll did not export DllGetClassObject */
354 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
355 FreeLibrary(hLibrary);
356 return CO_E_DLLNOTFOUND;
359 EnterCriticalSection( &csOpenDllList );
361 *ret = COMPOBJ_DllList_Get(library_name);
364 /* another caller to this function already added the dll while we
365 * weren't in the critical section */
366 FreeLibrary(hLibrary);
370 len = strlenW(library_name);
371 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
373 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
374 if (entry && entry->library_name)
376 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
377 entry->library = hLibrary;
379 entry->DllCanUnloadNow = DllCanUnloadNow;
380 entry->DllGetClassObject = DllGetClassObject;
381 list_add_tail(&openDllList, &entry->entry);
385 HeapFree(GetProcessHeap(), 0, entry);
387 FreeLibrary(hLibrary);
392 LeaveCriticalSection( &csOpenDllList );
397 /* pass FALSE for free_entry to release a reference without destroying the
398 * entry if it reaches zero or TRUE otherwise */
399 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
401 if (!InterlockedDecrement(&entry->refs) && free_entry)
403 EnterCriticalSection(&csOpenDllList);
404 list_remove(&entry->entry);
405 LeaveCriticalSection(&csOpenDllList);
407 TRACE("freeing %p\n", entry->library);
408 FreeLibrary(entry->library);
410 HeapFree(GetProcessHeap(), 0, entry->library_name);
411 HeapFree(GetProcessHeap(), 0, entry);
415 /* frees memory associated with active dll list */
416 static void COMPOBJ_DllList_Free(void)
418 OpenDll *entry, *cursor2;
419 EnterCriticalSection(&csOpenDllList);
420 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
422 list_remove(&entry->entry);
424 HeapFree(GetProcessHeap(), 0, entry->library_name);
425 HeapFree(GetProcessHeap(), 0, entry);
427 LeaveCriticalSection(&csOpenDllList);
428 DeleteCriticalSection(&csOpenDllList);
431 /******************************************************************************
435 static DWORD apartment_addref(struct apartment *apt)
437 DWORD refs = InterlockedIncrement(&apt->refs);
438 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
442 /* allocates memory and fills in the necessary fields for a new apartment
443 * object. must be called inside apartment cs */
444 static APARTMENT *apartment_construct(DWORD model)
448 TRACE("creating new apartment, model=%d\n", model);
450 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
451 apt->tid = GetCurrentThreadId();
453 list_init(&apt->proxies);
454 list_init(&apt->stubmgrs);
455 list_init(&apt->psclsids);
456 list_init(&apt->loaded_dlls);
459 apt->remunk_exported = FALSE;
461 InitializeCriticalSection(&apt->cs);
462 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
464 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
466 if (apt->multi_threaded)
468 /* FIXME: should be randomly generated by in an RPC call to rpcss */
469 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
473 /* FIXME: should be randomly generated by in an RPC call to rpcss */
474 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
477 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
479 list_add_head(&apts, &apt->entry);
484 /* gets and existing apartment if one exists or otherwise creates an apartment
485 * structure which stores OLE apartment-local information and stores a pointer
486 * to it in the thread-local storage */
487 static APARTMENT *apartment_get_or_create(DWORD model)
489 APARTMENT *apt = COM_CurrentApt();
493 if (model & COINIT_APARTMENTTHREADED)
495 EnterCriticalSection(&csApartment);
497 apt = apartment_construct(model);
502 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
505 LeaveCriticalSection(&csApartment);
508 apartment_createwindowifneeded(apt);
512 EnterCriticalSection(&csApartment);
514 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
515 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
519 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
520 apartment_addref(MTA);
523 MTA = apartment_construct(model);
527 LeaveCriticalSection(&csApartment);
529 COM_CurrentInfo()->apt = apt;
535 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
537 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
540 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
542 list_remove(&curClass->entry);
544 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
545 RPC_StopLocalServer(curClass->RpcRegistration);
548 * Release the reference to the class object.
550 IUnknown_Release(curClass->classObject);
552 if (curClass->pMarshaledData)
555 memset(&zero, 0, sizeof(zero));
556 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
557 CoReleaseMarshalData(curClass->pMarshaledData);
558 IStream_Release(curClass->pMarshaledData);
561 HeapFree(GetProcessHeap(), 0, curClass);
564 static void COM_RevokeAllClasses(const struct apartment *apt)
566 RegisteredClass *curClass, *cursor;
568 EnterCriticalSection( &csRegisteredClassList );
570 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
572 if (curClass->apartment_id == apt->oxid)
573 COM_RevokeRegisteredClassObject(curClass);
576 LeaveCriticalSection( &csRegisteredClassList );
579 /******************************************************************************
580 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
583 typedef struct ManualResetEvent {
584 ISynchronize ISynchronize_iface;
585 ISynchronizeHandle ISynchronizeHandle_iface;
590 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
592 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
595 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
597 MREImpl *This = impl_from_ISynchronize(iface);
599 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
601 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
602 *ppv = &This->ISynchronize_iface;
603 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
604 *ppv = &This->ISynchronizeHandle_iface;
606 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
608 return E_NOINTERFACE;
611 IUnknown_AddRef((IUnknown*)*ppv);
615 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
617 MREImpl *This = impl_from_ISynchronize(iface);
618 LONG ref = InterlockedIncrement(&This->ref);
619 TRACE("%p - ref %d\n", This, ref);
624 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
626 MREImpl *This = impl_from_ISynchronize(iface);
627 LONG ref = InterlockedDecrement(&This->ref);
628 TRACE("%p - ref %d\n", This, ref);
632 CloseHandle(This->event);
633 HeapFree(GetProcessHeap(), 0, This);
639 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
641 MREImpl *This = impl_from_ISynchronize(iface);
643 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
644 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
647 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
649 MREImpl *This = impl_from_ISynchronize(iface);
651 SetEvent(This->event);
655 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
657 MREImpl *This = impl_from_ISynchronize(iface);
659 ResetEvent(This->event);
663 static ISynchronizeVtbl vt_ISynchronize = {
664 ISynchronize_fnQueryInterface,
665 ISynchronize_fnAddRef,
666 ISynchronize_fnRelease,
668 ISynchronize_fnSignal,
672 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
674 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
677 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
679 MREImpl *This = impl_from_ISynchronizeHandle(iface);
680 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
683 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
685 MREImpl *This = impl_from_ISynchronizeHandle(iface);
686 return ISynchronize_AddRef(&This->ISynchronize_iface);
689 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
691 MREImpl *This = impl_from_ISynchronizeHandle(iface);
692 return ISynchronize_Release(&This->ISynchronize_iface);
695 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
697 MREImpl *This = impl_from_ISynchronizeHandle(iface);
703 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
704 SynchronizeHandle_QueryInterface,
705 SynchronizeHandle_AddRef,
706 SynchronizeHandle_Release,
707 SynchronizeHandle_GetHandle
710 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
712 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
716 FIXME("Aggregation not implemented.\n");
719 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
720 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
721 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
723 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
724 ISynchronize_Release(&This->ISynchronize_iface);
728 /***********************************************************************
729 * CoRevokeClassObject [OLE32.@]
731 * Removes a class object from the class registry.
734 * dwRegister [I] Cookie returned from CoRegisterClassObject().
738 * Failure: HRESULT code.
741 * Must be called from the same apartment that called CoRegisterClassObject(),
742 * otherwise it will fail with RPC_E_WRONG_THREAD.
745 * CoRegisterClassObject
747 HRESULT WINAPI CoRevokeClassObject(
750 HRESULT hr = E_INVALIDARG;
751 RegisteredClass *curClass;
754 TRACE("(%08x)\n",dwRegister);
756 apt = COM_CurrentApt();
759 ERR("COM was not initialized\n");
760 return CO_E_NOTINITIALIZED;
763 EnterCriticalSection( &csRegisteredClassList );
765 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
768 * Check if we have a match on the cookie.
770 if (curClass->dwCookie == dwRegister)
772 if (curClass->apartment_id == apt->oxid)
774 COM_RevokeRegisteredClassObject(curClass);
779 ERR("called from wrong apartment, should be called from %s\n",
780 wine_dbgstr_longlong(curClass->apartment_id));
781 hr = RPC_E_WRONG_THREAD;
787 LeaveCriticalSection( &csRegisteredClassList );
792 /* frees unused libraries loaded by apartment_getclassobject by calling the
793 * DLL's DllCanUnloadNow entry point */
794 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
796 struct apartment_loaded_dll *entry, *next;
797 EnterCriticalSection(&apt->cs);
798 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
800 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
802 DWORD real_delay = delay;
804 if (real_delay == INFINITE)
806 /* DLLs that return multi-threaded objects aren't unloaded
807 * straight away to cope for programs that have races between
808 * last object destruction and threads in the DLLs that haven't
809 * finished, despite DllCanUnloadNow returning S_OK */
810 if (entry->multi_threaded)
811 real_delay = 10 * 60 * 1000; /* 10 minutes */
816 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
818 list_remove(&entry->entry);
819 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
820 HeapFree(GetProcessHeap(), 0, entry);
823 entry->unload_time = GetTickCount() + real_delay;
825 else if (entry->unload_time)
826 entry->unload_time = 0;
828 LeaveCriticalSection(&apt->cs);
831 DWORD apartment_release(struct apartment *apt)
835 EnterCriticalSection(&csApartment);
837 ret = InterlockedDecrement(&apt->refs);
838 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
839 /* destruction stuff that needs to happen under csApartment CS */
842 if (apt == MTA) MTA = NULL;
843 else if (apt == MainApartment) MainApartment = NULL;
844 list_remove(&apt->entry);
847 LeaveCriticalSection(&csApartment);
851 struct list *cursor, *cursor2;
853 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
855 /* Release the references to the registered class objects */
856 COM_RevokeAllClasses(apt);
858 /* no locking is needed for this apartment, because no other thread
859 * can access it at this point */
861 apartment_disconnectproxies(apt);
863 if (apt->win) DestroyWindow(apt->win);
864 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
866 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
868 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
869 /* release the implicit reference given by the fact that the
870 * stub has external references (it must do since it is in the
871 * stub manager list in the apartment and all non-apartment users
872 * must have a ref on the apartment and so it cannot be destroyed).
874 stub_manager_int_release(stubmgr);
877 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
879 struct registered_psclsid *registered_psclsid =
880 LIST_ENTRY(cursor, struct registered_psclsid, entry);
882 list_remove(®istered_psclsid->entry);
883 HeapFree(GetProcessHeap(), 0, registered_psclsid);
886 /* if this assert fires, then another thread took a reference to a
887 * stub manager without taking a reference to the containing
888 * apartment, which it must do. */
889 assert(list_empty(&apt->stubmgrs));
891 if (apt->filter) IMessageFilter_Release(apt->filter);
893 /* free as many unused libraries as possible... */
894 apartment_freeunusedlibraries(apt, 0);
896 /* ... and free the memory for the apartment loaded dll entry and
897 * release the dll list reference without freeing the library for the
899 while ((cursor = list_head(&apt->loaded_dlls)))
901 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
902 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
904 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
907 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
908 DeleteCriticalSection(&apt->cs);
910 HeapFree(GetProcessHeap(), 0, apt);
916 /* The given OXID must be local to this process:
918 * The ref parameter is here mostly to ensure people remember that
919 * they get one, you should normally take a ref for thread safety.
921 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
923 APARTMENT *result = NULL;
926 EnterCriticalSection(&csApartment);
927 LIST_FOR_EACH( cursor, &apts )
929 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
930 if (apt->oxid == oxid)
933 if (ref) apartment_addref(result);
937 LeaveCriticalSection(&csApartment);
942 /* gets the apartment which has a given creator thread ID. The caller must
943 * release the reference from the apartment as soon as the apartment pointer
944 * is no longer required. */
945 APARTMENT *apartment_findfromtid(DWORD tid)
947 APARTMENT *result = NULL;
950 EnterCriticalSection(&csApartment);
951 LIST_FOR_EACH( cursor, &apts )
953 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
957 apartment_addref(result);
961 LeaveCriticalSection(&csApartment);
966 /* gets the main apartment if it exists. The caller must
967 * release the reference from the apartment as soon as the apartment pointer
968 * is no longer required. */
969 static APARTMENT *apartment_findmain(void)
973 EnterCriticalSection(&csApartment);
975 result = MainApartment;
976 if (result) apartment_addref(result);
978 LeaveCriticalSection(&csApartment);
983 /* gets the multi-threaded apartment if it exists. The caller must
984 * release the reference from the apartment as soon as the apartment pointer
985 * is no longer required. */
986 static APARTMENT *apartment_find_multi_threaded(void)
988 APARTMENT *result = NULL;
991 EnterCriticalSection(&csApartment);
993 LIST_FOR_EACH( cursor, &apts )
995 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
996 if (apt->multi_threaded)
999 apartment_addref(result);
1004 LeaveCriticalSection(&csApartment);
1008 /* gets the specified class object by loading the appropriate DLL, if
1009 * necessary and calls the DllGetClassObject function for the DLL */
1010 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1011 BOOL apartment_threaded,
1012 REFCLSID rclsid, REFIID riid, void **ppv)
1014 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1017 struct apartment_loaded_dll *apartment_loaded_dll;
1019 if (!strcmpiW(dllpath, wszOle32))
1021 /* we don't need to control the lifetime of this dll, so use the local
1022 * implementation of DllGetClassObject directly */
1023 TRACE("calling ole32!DllGetClassObject\n");
1024 hr = DllGetClassObject(rclsid, riid, ppv);
1027 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1032 EnterCriticalSection(&apt->cs);
1034 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1035 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1037 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1044 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1045 if (!apartment_loaded_dll)
1049 apartment_loaded_dll->unload_time = 0;
1050 apartment_loaded_dll->multi_threaded = FALSE;
1051 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1053 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1057 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1058 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1062 LeaveCriticalSection(&apt->cs);
1066 /* one component being multi-threaded overrides any number of
1067 * apartment-threaded components */
1068 if (!apartment_threaded)
1069 apartment_loaded_dll->multi_threaded = TRUE;
1071 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1072 /* OK: get the ClassObject */
1073 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1076 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1082 /***********************************************************************
1083 * COM_RegReadPath [internal]
1085 * Reads a registry value and expands it when necessary
1087 static DWORD COM_RegReadPath(HKEY hkeyroot, WCHAR * dst, DWORD dstlen)
1091 WCHAR src[MAX_PATH];
1092 DWORD dwLength = dstlen * sizeof(WCHAR);
1094 if( (ret = RegQueryValueExW(hkeyroot, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1095 if (keytype == REG_EXPAND_SZ) {
1096 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1098 const WCHAR *quote_start;
1099 quote_start = strchrW(src, '\"');
1101 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1103 memmove(src, quote_start + 1,
1104 (quote_end - quote_start - 1) * sizeof(WCHAR));
1105 src[quote_end - quote_start - 1] = '\0';
1108 lstrcpynW(dst, src, dstlen);
1114 struct host_object_params
1117 CLSID clsid; /* clsid of object to marshal */
1118 IID iid; /* interface to marshal */
1119 HANDLE event; /* event signalling when ready for multi-threaded case */
1120 HRESULT hr; /* result for multi-threaded case */
1121 IStream *stream; /* stream that the object will be marshaled into */
1122 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1125 static HRESULT apartment_hostobject(struct apartment *apt,
1126 const struct host_object_params *params)
1130 static const LARGE_INTEGER llZero;
1131 WCHAR dllpath[MAX_PATH+1];
1133 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid));
1135 if (COM_RegReadPath(params->hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1137 /* failure: CLSID is not found in registry */
1138 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid));
1139 return REGDB_E_CLASSNOTREG;
1142 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1143 ¶ms->clsid, ¶ms->iid, (void **)&object);
1147 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1149 IUnknown_Release(object);
1150 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1155 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1160 RPC_ExecuteCall((struct dispatch_params *)lParam);
1163 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1165 return DefWindowProcW(hWnd, msg, wParam, lParam);
1169 struct host_thread_params
1171 COINIT threading_model;
1173 HWND apartment_hwnd;
1176 /* thread for hosting an object to allow an object to appear to be created in
1177 * an apartment with an incompatible threading model */
1178 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1180 struct host_thread_params *params = p;
1183 struct apartment *apt;
1187 hr = CoInitializeEx(NULL, params->threading_model);
1188 if (FAILED(hr)) return hr;
1190 apt = COM_CurrentApt();
1191 if (params->threading_model == COINIT_APARTMENTTHREADED)
1193 apartment_createwindowifneeded(apt);
1194 params->apartment_hwnd = apartment_getwindow(apt);
1197 params->apartment_hwnd = NULL;
1199 /* force the message queue to be created before signaling parent thread */
1200 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1202 SetEvent(params->ready_event);
1203 params = NULL; /* can't touch params after here as it may be invalid */
1205 while (GetMessageW(&msg, NULL, 0, 0))
1207 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1209 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1210 obj_params->hr = apartment_hostobject(apt, obj_params);
1211 SetEvent(obj_params->event);
1215 TranslateMessage(&msg);
1216 DispatchMessageW(&msg);
1227 /* finds or creates a host apartment, creates the object inside it and returns
1228 * a proxy to it so that the object can be used in the apartment of the
1229 * caller of this function */
1230 static HRESULT apartment_hostobject_in_hostapt(
1231 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1232 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1234 struct host_object_params params;
1235 HWND apartment_hwnd = NULL;
1236 DWORD apartment_tid = 0;
1239 if (!multi_threaded && main_apartment)
1241 APARTMENT *host_apt = apartment_findmain();
1244 apartment_hwnd = apartment_getwindow(host_apt);
1245 apartment_release(host_apt);
1249 if (!apartment_hwnd)
1251 EnterCriticalSection(&apt->cs);
1253 if (!apt->host_apt_tid)
1255 struct host_thread_params thread_params;
1259 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1260 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1261 thread_params.apartment_hwnd = NULL;
1262 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1265 CloseHandle(handles[0]);
1266 LeaveCriticalSection(&apt->cs);
1267 return E_OUTOFMEMORY;
1269 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1270 CloseHandle(handles[0]);
1271 CloseHandle(handles[1]);
1272 if (wait_value == WAIT_OBJECT_0)
1273 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1276 LeaveCriticalSection(&apt->cs);
1277 return E_OUTOFMEMORY;
1281 if (multi_threaded || !main_apartment)
1283 apartment_hwnd = apt->host_apt_hwnd;
1284 apartment_tid = apt->host_apt_tid;
1287 LeaveCriticalSection(&apt->cs);
1290 /* another thread may have become the main apartment in the time it took
1291 * us to create the thread for the host apartment */
1292 if (!apartment_hwnd && !multi_threaded && main_apartment)
1294 APARTMENT *host_apt = apartment_findmain();
1297 apartment_hwnd = apartment_getwindow(host_apt);
1298 apartment_release(host_apt);
1302 params.hkeydll = hkeydll;
1303 params.clsid = *rclsid;
1305 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
1308 params.apartment_threaded = !multi_threaded;
1312 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1313 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms))
1317 WaitForSingleObject(params.event, INFINITE);
1320 CloseHandle(params.event);
1324 if (!apartment_hwnd)
1326 ERR("host apartment didn't create window\n");
1330 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
1333 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1334 IStream_Release(params.stream);
1338 /* create a window for the apartment or return the current one if one has
1339 * already been created */
1340 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1342 if (apt->multi_threaded)
1347 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1349 HWND_MESSAGE, 0, hProxyDll, NULL);
1352 ERR("CreateWindow failed with error %d\n", GetLastError());
1353 return HRESULT_FROM_WIN32(GetLastError());
1355 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1356 /* someone beat us to it */
1357 DestroyWindow(hwnd);
1363 /* retrieves the window for the main- or apartment-threaded apartment */
1364 HWND apartment_getwindow(const struct apartment *apt)
1366 assert(!apt->multi_threaded);
1370 void apartment_joinmta(void)
1372 apartment_addref(MTA);
1373 COM_CurrentInfo()->apt = MTA;
1376 static void COMPOBJ_InitProcess( void )
1380 /* Dispatching to the correct thread in an apartment is done through
1381 * window messages rather than RPC transports. When an interface is
1382 * marshalled into another apartment in the same process, a window of the
1383 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1384 * application) is responsible for pumping the message loop in that thread.
1385 * The WM_USER messages which point to the RPCs are then dispatched to
1386 * apartment_wndproc by the user's code from the apartment in which the
1387 * interface was unmarshalled.
1389 memset(&wclass, 0, sizeof(wclass));
1390 wclass.lpfnWndProc = apartment_wndproc;
1391 wclass.hInstance = hProxyDll;
1392 wclass.lpszClassName = wszAptWinClass;
1393 RegisterClassW(&wclass);
1396 static void COMPOBJ_UninitProcess( void )
1398 UnregisterClassW(wszAptWinClass, hProxyDll);
1401 static void COM_TlsDestroy(void)
1403 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1406 if (info->apt) apartment_release(info->apt);
1407 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1408 if (info->state) IUnknown_Release(info->state);
1409 if (info->spy) IInitializeSpy_Release(info->spy);
1410 if (info->context_token) IObjContext_Release(info->context_token);
1411 HeapFree(GetProcessHeap(), 0, info);
1412 NtCurrentTeb()->ReservedForOle = NULL;
1416 /******************************************************************************
1417 * CoBuildVersion [OLE32.@]
1419 * Gets the build version of the DLL.
1424 * Current build version, hiword is majornumber, loword is minornumber
1426 DWORD WINAPI CoBuildVersion(void)
1428 TRACE("Returning version %d, build %d.\n", rmm, rup);
1429 return (rmm<<16)+rup;
1432 /******************************************************************************
1433 * CoRegisterInitializeSpy [OLE32.@]
1435 * Add a Spy that watches CoInitializeEx calls
1438 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1439 * cookie [II] cookie receiver
1442 * Success: S_OK if not already initialized, S_FALSE otherwise.
1443 * Failure: HRESULT code.
1448 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1450 struct oletls *info = COM_CurrentInfo();
1453 TRACE("(%p, %p)\n", spy, cookie);
1455 if (!spy || !cookie || !info)
1458 WARN("Could not allocate tls\n");
1459 return E_INVALIDARG;
1464 FIXME("Already registered?\n");
1465 return E_UNEXPECTED;
1468 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1471 cookie->QuadPart = (DWORD_PTR)spy;
1477 /******************************************************************************
1478 * CoRevokeInitializeSpy [OLE32.@]
1480 * Remove a spy that previously watched CoInitializeEx calls
1483 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1486 * Success: S_OK if a spy is removed
1487 * Failure: E_INVALIDARG
1492 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1494 struct oletls *info = COM_CurrentInfo();
1495 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1497 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1498 return E_INVALIDARG;
1500 IInitializeSpy_Release(info->spy);
1506 /******************************************************************************
1507 * CoInitialize [OLE32.@]
1509 * Initializes the COM libraries by calling CoInitializeEx with
1510 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1513 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1516 * Success: S_OK if not already initialized, S_FALSE otherwise.
1517 * Failure: HRESULT code.
1522 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1525 * Just delegate to the newer method.
1527 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1530 /******************************************************************************
1531 * CoInitializeEx [OLE32.@]
1533 * Initializes the COM libraries.
1536 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1537 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1540 * S_OK if successful,
1541 * S_FALSE if this function was called already.
1542 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1547 * The behavior used to set the IMalloc used for memory management is
1549 * The dwCoInit parameter must specify one of the following apartment
1551 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1552 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1553 * The parameter may also specify zero or more of the following flags:
1554 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1555 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1560 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1562 struct oletls *info = COM_CurrentInfo();
1566 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1568 if (lpReserved!=NULL)
1570 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1574 * Check the lock count. If this is the first time going through the initialize
1575 * process, we have to initialize the libraries.
1577 * And crank-up that lock count.
1579 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1582 * Initialize the various COM libraries and data structures.
1584 TRACE("() - Initializing the COM libraries\n");
1586 /* we may need to defer this until after apartment initialisation */
1587 RunningObjectTableImpl_Initialize();
1591 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1593 if (!(apt = info->apt))
1595 apt = apartment_get_or_create(dwCoInit);
1596 if (!apt) return E_OUTOFMEMORY;
1598 else if (!apartment_is_model(apt, dwCoInit))
1600 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1601 code then we are probably using the wrong threading model to implement that API. */
1602 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1603 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1604 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1605 return RPC_E_CHANGED_MODE;
1613 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1618 /***********************************************************************
1619 * CoUninitialize [OLE32.@]
1621 * This method will decrement the refcount on the current apartment, freeing
1622 * the resources associated with it if it is the last thread in the apartment.
1623 * If the last apartment is freed, the function will additionally release
1624 * any COM resources associated with the process.
1634 void WINAPI CoUninitialize(void)
1636 struct oletls * info = COM_CurrentInfo();
1641 /* will only happen on OOM */
1645 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1650 ERR("Mismatched CoUninitialize\n");
1653 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1659 apartment_release(info->apt);
1664 * Decrease the reference count.
1665 * If we are back to 0 locks on the COM library, make sure we free
1666 * all the associated data structures.
1668 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1671 TRACE("() - Releasing the COM libraries\n");
1673 RunningObjectTableImpl_UnInitialize();
1675 else if (lCOMRefCnt<1) {
1676 ERR( "CoUninitialize() - not CoInitialized.\n" );
1677 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1680 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1683 /******************************************************************************
1684 * CoDisconnectObject [OLE32.@]
1686 * Disconnects all connections to this object from remote processes. Dispatches
1687 * pending RPCs while blocking new RPCs from occurring, and then calls
1688 * IMarshal::DisconnectObject on the given object.
1690 * Typically called when the object server is forced to shut down, for instance by
1694 * lpUnk [I] The object whose stub should be disconnected.
1695 * reserved [I] Reserved. Should be set to 0.
1699 * Failure: HRESULT code.
1702 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1704 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1710 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1712 if (!lpUnk) return E_INVALIDARG;
1714 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1717 hr = IMarshal_DisconnectObject(marshal, reserved);
1718 IMarshal_Release(marshal);
1722 apt = COM_CurrentApt();
1724 return CO_E_NOTINITIALIZED;
1726 apartment_disconnectobject(apt, lpUnk);
1728 /* Note: native is pretty broken here because it just silently
1729 * fails, without returning an appropriate error code if the object was
1730 * not found, making apps think that the object was disconnected, when
1731 * it actually wasn't */
1736 /******************************************************************************
1737 * CoCreateGuid [OLE32.@]
1739 * Simply forwards to UuidCreate in RPCRT4.
1742 * pguid [O] Points to the GUID to initialize.
1746 * Failure: HRESULT code.
1751 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1753 DWORD status = UuidCreate(pguid);
1754 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1755 return HRESULT_FROM_WIN32( status );
1758 static inline BOOL is_valid_hex(WCHAR c)
1760 if (!(((c >= '0') && (c <= '9')) ||
1761 ((c >= 'a') && (c <= 'f')) ||
1762 ((c >= 'A') && (c <= 'F'))))
1767 /******************************************************************************
1768 * CLSIDFromString [OLE32.@]
1769 * IIDFromString [OLE32.@]
1771 * Converts a unique identifier from its string representation into
1775 * idstr [I] The string representation of the GUID.
1776 * id [O] GUID converted from the string.
1780 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1785 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
1790 if (!s || s[0]!='{') {
1791 memset( id, 0, sizeof (CLSID) );
1793 return CO_E_CLASSSTRING;
1796 TRACE("%s -> %p\n", debugstr_w(s), id);
1798 /* quick lookup table */
1799 memset(table, 0, 256);
1801 for (i = 0; i < 10; i++) {
1804 for (i = 0; i < 6; i++) {
1805 table['A' + i] = i+10;
1806 table['a' + i] = i+10;
1809 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1812 for (i = 1; i < 9; i++) {
1813 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1814 id->Data1 = (id->Data1 << 4) | table[s[i]];
1816 if (s[9]!='-') return CO_E_CLASSSTRING;
1819 for (i = 10; i < 14; i++) {
1820 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1821 id->Data2 = (id->Data2 << 4) | table[s[i]];
1823 if (s[14]!='-') return CO_E_CLASSSTRING;
1826 for (i = 15; i < 19; i++) {
1827 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1828 id->Data3 = (id->Data3 << 4) | table[s[i]];
1830 if (s[19]!='-') return CO_E_CLASSSTRING;
1832 for (i = 20; i < 37; i+=2) {
1834 if (s[i]!='-') return CO_E_CLASSSTRING;
1837 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING;
1838 id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]];
1841 if (s[37] == '}' && s[38] == '\0')
1844 return CO_E_CLASSSTRING;
1847 /*****************************************************************************/
1849 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
1854 return E_INVALIDARG;
1856 ret = __CLSIDFromString(idstr, id);
1857 if(ret != S_OK) { /* It appears a ProgID is also valid */
1859 ret = CLSIDFromProgID(idstr, &tmp_id);
1867 /******************************************************************************
1868 * StringFromCLSID [OLE32.@]
1869 * StringFromIID [OLE32.@]
1871 * Converts a GUID into the respective string representation.
1872 * The target string is allocated using the OLE IMalloc.
1875 * id [I] the GUID to be converted.
1876 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1883 * StringFromGUID2, CLSIDFromString
1885 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1890 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1891 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1892 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1896 /******************************************************************************
1897 * StringFromGUID2 [OLE32.@]
1899 * Modified version of StringFromCLSID that allows you to specify max
1903 * id [I] GUID to convert to string.
1904 * str [O] Buffer where the result will be stored.
1905 * cmax [I] Size of the buffer in characters.
1908 * Success: The length of the resulting string in characters.
1911 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1913 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1914 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1915 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1916 '%','0','2','X','%','0','2','X','}',0 };
1917 if (!id || cmax < CHARS_IN_GUID) return 0;
1918 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1919 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1920 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1921 return CHARS_IN_GUID;
1924 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1925 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1927 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1928 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1932 strcpyW(path, wszCLSIDSlash);
1933 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1934 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
1935 if (res == ERROR_FILE_NOT_FOUND)
1936 return REGDB_E_CLASSNOTREG;
1937 else if (res != ERROR_SUCCESS)
1938 return REGDB_E_READREGDB;
1946 res = open_classes_key(key, keyname, access, subkey);
1948 if (res == ERROR_FILE_NOT_FOUND)
1949 return REGDB_E_KEYMISSING;
1950 else if (res != ERROR_SUCCESS)
1951 return REGDB_E_READREGDB;
1956 /* open HKCR\\AppId\\{string form of appid clsid} key */
1957 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1959 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1960 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1962 WCHAR buf[CHARS_IN_GUID];
1963 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1969 /* read the AppID value under the class's key */
1970 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1975 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1977 if (res == ERROR_FILE_NOT_FOUND)
1978 return REGDB_E_KEYMISSING;
1979 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1980 return REGDB_E_READREGDB;
1982 strcpyW(keyname, szAppIdKey);
1983 strcatW(keyname, buf);
1984 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
1985 if (res == ERROR_FILE_NOT_FOUND)
1986 return REGDB_E_KEYMISSING;
1987 else if (res != ERROR_SUCCESS)
1988 return REGDB_E_READREGDB;
1993 /******************************************************************************
1994 * ProgIDFromCLSID [OLE32.@]
1996 * Converts a class id into the respective program ID.
1999 * clsid [I] Class ID, as found in registry.
2000 * ppszProgID [O] Associated ProgID.
2005 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2007 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2009 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2016 ERR("ppszProgId isn't optional\n");
2017 return E_INVALIDARG;
2021 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2025 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2026 ret = REGDB_E_CLASSNOTREG;
2030 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2033 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
2034 ret = REGDB_E_CLASSNOTREG;
2037 ret = E_OUTOFMEMORY;
2044 /******************************************************************************
2045 * CLSIDFromProgID [OLE32.@]
2047 * Converts a program id into the respective GUID.
2050 * progid [I] Unicode program ID, as found in registry.
2051 * clsid [O] Associated CLSID.
2055 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2057 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2059 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2060 WCHAR buf2[CHARS_IN_GUID];
2061 LONG buf2len = sizeof(buf2);
2065 if (!progid || !clsid)
2067 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
2068 return E_INVALIDARG;
2071 /* initialise clsid in case of failure */
2072 memset(clsid, 0, sizeof(*clsid));
2074 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2075 strcpyW( buf, progid );
2076 strcatW( buf, clsidW );
2077 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2079 HeapFree(GetProcessHeap(),0,buf);
2080 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2081 return CO_E_CLASSSTRING;
2083 HeapFree(GetProcessHeap(),0,buf);
2085 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2088 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2089 return CO_E_CLASSSTRING;
2092 return __CLSIDFromString(buf2,clsid);
2096 /*****************************************************************************
2097 * CoGetPSClsid [OLE32.@]
2099 * Retrieves the CLSID of the proxy/stub factory that implements
2100 * IPSFactoryBuffer for the specified interface.
2103 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2104 * pclsid [O] Where to store returned proxy/stub CLSID.
2109 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2113 * The standard marshaller activates the object with the CLSID
2114 * returned and uses the CreateProxy and CreateStub methods on its
2115 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2118 * CoGetPSClsid determines this CLSID by searching the
2119 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2120 * in the registry and any interface id registered by
2121 * CoRegisterPSClsid within the current process.
2125 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2126 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2127 * considered a bug in native unless an application depends on this (unlikely).
2130 * CoRegisterPSClsid.
2132 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2134 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2135 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2136 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2137 WCHAR value[CHARS_IN_GUID];
2140 APARTMENT *apt = COM_CurrentApt();
2141 struct registered_psclsid *registered_psclsid;
2143 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2147 ERR("apartment not initialised\n");
2148 return CO_E_NOTINITIALIZED;
2153 ERR("pclsid isn't optional\n");
2154 return E_INVALIDARG;
2157 EnterCriticalSection(&apt->cs);
2159 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2160 if (IsEqualIID(®istered_psclsid->iid, riid))
2162 *pclsid = registered_psclsid->clsid;
2163 LeaveCriticalSection(&apt->cs);
2167 LeaveCriticalSection(&apt->cs);
2169 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2170 strcpyW(path, wszInterface);
2171 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2172 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2174 /* Open the key.. */
2175 if (open_classes_key(HKEY_CLASSES_ROOT, path, KEY_READ, &hkey))
2177 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2178 return REGDB_E_IIDNOTREG;
2181 /* ... Once we have the key, query the registry to get the
2182 value of CLSID as a string, and convert it into a
2183 proper CLSID structure to be passed back to the app */
2184 len = sizeof(value);
2185 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
2188 return REGDB_E_IIDNOTREG;
2192 /* We have the CLSID we want back from the registry as a string, so
2193 let's convert it into a CLSID structure */
2194 if (CLSIDFromString(value, pclsid) != NOERROR)
2195 return REGDB_E_IIDNOTREG;
2197 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2201 /*****************************************************************************
2202 * CoRegisterPSClsid [OLE32.@]
2204 * Register a proxy/stub CLSID for the given interface in the current process
2208 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2209 * rclsid [I] CLSID of the proxy/stub.
2213 * Failure: E_OUTOFMEMORY
2217 * This function does not add anything to the registry and the effects are
2218 * limited to the lifetime of the current process.
2223 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2225 APARTMENT *apt = COM_CurrentApt();
2226 struct registered_psclsid *registered_psclsid;
2228 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2232 ERR("apartment not initialised\n");
2233 return CO_E_NOTINITIALIZED;
2236 EnterCriticalSection(&apt->cs);
2238 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2239 if (IsEqualIID(®istered_psclsid->iid, riid))
2241 registered_psclsid->clsid = *rclsid;
2242 LeaveCriticalSection(&apt->cs);
2246 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2247 if (!registered_psclsid)
2249 LeaveCriticalSection(&apt->cs);
2250 return E_OUTOFMEMORY;
2253 registered_psclsid->iid = *riid;
2254 registered_psclsid->clsid = *rclsid;
2255 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
2257 LeaveCriticalSection(&apt->cs);
2264 * COM_GetRegisteredClassObject
2266 * This internal method is used to scan the registered class list to
2267 * find a class object.
2270 * rclsid Class ID of the class to find.
2271 * dwClsContext Class context to match.
2272 * ppv [out] returns a pointer to the class object. Complying
2273 * to normal COM usage, this method will increase the
2274 * reference count on this object.
2276 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2277 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2279 HRESULT hr = S_FALSE;
2280 RegisteredClass *curClass;
2282 EnterCriticalSection( &csRegisteredClassList );
2284 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2287 * Check if we have a match on the class ID and context.
2289 if ((apt->oxid == curClass->apartment_id) &&
2290 (dwClsContext & curClass->runContext) &&
2291 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2294 * We have a match, return the pointer to the class object.
2296 *ppUnk = curClass->classObject;
2298 IUnknown_AddRef(curClass->classObject);
2305 LeaveCriticalSection( &csRegisteredClassList );
2310 /******************************************************************************
2311 * CoRegisterClassObject [OLE32.@]
2313 * Registers the class object for a given class ID. Servers housed in EXE
2314 * files use this method instead of exporting DllGetClassObject to allow
2315 * other code to connect to their objects.
2318 * rclsid [I] CLSID of the object to register.
2319 * pUnk [I] IUnknown of the object.
2320 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2321 * flags [I] REGCLS flags indicating how connections are made.
2322 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2326 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2327 * CO_E_OBJISREG if the object is already registered. We should not return this.
2330 * CoRevokeClassObject, CoGetClassObject
2333 * In-process objects are only registered for the current apartment.
2334 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2335 * in other apartments.
2338 * MSDN claims that multiple interface registrations are legal, but we
2339 * can't do that with our current implementation.
2341 HRESULT WINAPI CoRegisterClassObject(
2346 LPDWORD lpdwRegister)
2348 static LONG next_cookie;
2349 RegisteredClass* newClass;
2350 LPUNKNOWN foundObject;
2354 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2355 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2357 if ( (lpdwRegister==0) || (pUnk==0) )
2358 return E_INVALIDARG;
2360 apt = COM_CurrentApt();
2363 ERR("COM was not initialized\n");
2364 return CO_E_NOTINITIALIZED;
2369 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2370 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2371 if (flags & REGCLS_MULTIPLEUSE)
2372 dwClsContext |= CLSCTX_INPROC_SERVER;
2375 * First, check if the class is already registered.
2376 * If it is, this should cause an error.
2378 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2380 if (flags & REGCLS_MULTIPLEUSE) {
2381 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2382 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2383 IUnknown_Release(foundObject);
2386 IUnknown_Release(foundObject);
2387 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2388 return CO_E_OBJISREG;
2391 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2392 if ( newClass == NULL )
2393 return E_OUTOFMEMORY;
2395 newClass->classIdentifier = *rclsid;
2396 newClass->apartment_id = apt->oxid;
2397 newClass->runContext = dwClsContext;
2398 newClass->connectFlags = flags;
2399 newClass->pMarshaledData = NULL;
2400 newClass->RpcRegistration = NULL;
2402 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2403 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2406 * Since we're making a copy of the object pointer, we have to increase its
2409 newClass->classObject = pUnk;
2410 IUnknown_AddRef(newClass->classObject);
2412 EnterCriticalSection( &csRegisteredClassList );
2413 list_add_tail(&RegisteredClassList, &newClass->entry);
2414 LeaveCriticalSection( &csRegisteredClassList );
2416 *lpdwRegister = newClass->dwCookie;
2418 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2419 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2421 FIXME("Failed to create stream on hglobal, %x\n", hr);
2424 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown,
2425 newClass->classObject, MSHCTX_LOCAL, NULL,
2426 MSHLFLAGS_TABLESTRONG);
2428 FIXME("CoMarshalInterface failed, %x!\n",hr);
2432 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2433 newClass->pMarshaledData,
2434 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2435 &newClass->RpcRegistration);
2440 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2442 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2445 DWORD dwLength = len * sizeof(WCHAR);
2447 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2448 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2452 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2453 REFCLSID rclsid, REFIID riid,
2454 BOOL hostifnecessary, void **ppv)
2456 WCHAR dllpath[MAX_PATH+1];
2457 BOOL apartment_threaded;
2459 if (hostifnecessary)
2461 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2462 static const WCHAR wszFree[] = {'F','r','e','e',0};
2463 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2464 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2466 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2468 if (!strcmpiW(threading_model, wszApartment))
2470 apartment_threaded = TRUE;
2471 if (apt->multi_threaded)
2472 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2475 else if (!strcmpiW(threading_model, wszFree))
2477 apartment_threaded = FALSE;
2478 if (!apt->multi_threaded)
2479 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2481 /* everything except "Apartment", "Free" and "Both" */
2482 else if (strcmpiW(threading_model, wszBoth))
2484 apartment_threaded = TRUE;
2485 /* everything else is main-threaded */
2486 if (threading_model[0])
2487 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2488 debugstr_w(threading_model), debugstr_guid(rclsid));
2490 if (apt->multi_threaded || !apt->main)
2491 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2494 apartment_threaded = FALSE;
2497 apartment_threaded = !apt->multi_threaded;
2499 if (COM_RegReadPath(hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2501 /* failure: CLSID is not found in registry */
2502 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2503 return REGDB_E_CLASSNOTREG;
2506 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2510 /***********************************************************************
2511 * CoGetClassObject [OLE32.@]
2513 * Creates an object of the specified class.
2516 * rclsid [I] Class ID to create an instance of.
2517 * dwClsContext [I] Flags to restrict the location of the created instance.
2518 * pServerInfo [I] Optional. Details for connecting to a remote server.
2519 * iid [I] The ID of the interface of the instance to return.
2520 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2524 * Failure: HRESULT code.
2527 * The dwClsContext parameter can be one or more of the following:
2528 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2529 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2530 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2531 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2534 * CoCreateInstance()
2536 HRESULT WINAPI CoGetClassObject(
2537 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2538 REFIID iid, LPVOID *ppv)
2540 LPUNKNOWN regClassObject;
2541 HRESULT hres = E_UNEXPECTED;
2543 BOOL release_apt = FALSE;
2545 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2548 return E_INVALIDARG;
2552 if (!(apt = COM_CurrentApt()))
2554 if (!(apt = apartment_find_multi_threaded()))
2556 ERR("apartment not initialised\n");
2557 return CO_E_NOTINITIALIZED;
2563 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2564 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2568 * First, try and see if we can't match the class ID with one of the
2569 * registered classes.
2571 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2574 /* Get the required interface from the retrieved pointer. */
2575 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2578 * Since QI got another reference on the pointer, we want to release the
2579 * one we already have. If QI was unsuccessful, this will release the object. This
2580 * is good since we are not returning it in the "out" parameter.
2582 IUnknown_Release(regClassObject);
2583 if (release_apt) apartment_release(apt);
2587 /* First try in-process server */
2588 if (CLSCTX_INPROC_SERVER & dwClsContext)
2590 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2593 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2595 if (release_apt) apartment_release(apt);
2596 return FTMarshalCF_Create(iid, ppv);
2599 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2602 if (hres == REGDB_E_CLASSNOTREG)
2603 ERR("class %s not registered\n", debugstr_guid(rclsid));
2604 else if (hres == REGDB_E_KEYMISSING)
2606 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2607 hres = REGDB_E_CLASSNOTREG;
2611 if (SUCCEEDED(hres))
2613 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2614 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2618 /* return if we got a class, otherwise fall through to one of the
2620 if (SUCCEEDED(hres))
2622 if (release_apt) apartment_release(apt);
2627 /* Next try in-process handler */
2628 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2630 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2633 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2636 if (hres == REGDB_E_CLASSNOTREG)
2637 ERR("class %s not registered\n", debugstr_guid(rclsid));
2638 else if (hres == REGDB_E_KEYMISSING)
2640 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2641 hres = REGDB_E_CLASSNOTREG;
2645 if (SUCCEEDED(hres))
2647 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2648 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2652 /* return if we got a class, otherwise fall through to one of the
2654 if (SUCCEEDED(hres))
2656 if (release_apt) apartment_release(apt);
2660 if (release_apt) apartment_release(apt);
2662 /* Next try out of process */
2663 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2665 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2666 if (SUCCEEDED(hres))
2670 /* Finally try remote: this requires networked DCOM (a lot of work) */
2671 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2673 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2674 hres = REGDB_E_CLASSNOTREG;
2678 ERR("no class object %s could be created for context 0x%x\n",
2679 debugstr_guid(rclsid), dwClsContext);
2683 /***********************************************************************
2684 * CoResumeClassObjects (OLE32.@)
2686 * Resumes all class objects registered with REGCLS_SUSPENDED.
2690 * Failure: HRESULT code.
2692 HRESULT WINAPI CoResumeClassObjects(void)
2698 /***********************************************************************
2699 * CoCreateInstance [OLE32.@]
2701 * Creates an instance of the specified class.
2704 * rclsid [I] Class ID to create an instance of.
2705 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2706 * dwClsContext [I] Flags to restrict the location of the created instance.
2707 * iid [I] The ID of the interface of the instance to return.
2708 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2712 * Failure: HRESULT code.
2715 * The dwClsContext parameter can be one or more of the following:
2716 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2717 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2718 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2719 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2721 * Aggregation is the concept of deferring the IUnknown of an object to another
2722 * object. This allows a separate object to behave as though it was part of
2723 * the object and to allow this the pUnkOuter parameter can be set. Note that
2724 * not all objects support having an outer of unknown.
2727 * CoGetClassObject()
2729 HRESULT WINAPI CoCreateInstance(
2731 LPUNKNOWN pUnkOuter,
2737 LPCLASSFACTORY lpclf = 0;
2740 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2741 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2748 if (!(apt = COM_CurrentApt()))
2750 if (!(apt = apartment_find_multi_threaded()))
2752 ERR("apartment not initialised\n");
2753 return CO_E_NOTINITIALIZED;
2755 apartment_release(apt);
2759 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2760 * Rather than create a class factory, we can just check for it here
2762 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable))
2764 if (StdGlobalInterfaceTableInstance == NULL)
2765 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2766 hres = IGlobalInterfaceTable_QueryInterface((IGlobalInterfaceTable*)StdGlobalInterfaceTableInstance,
2769 if (hres) return hres;
2771 TRACE("Retrieved GIT (%p)\n", *ppv);
2775 if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
2776 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
2779 * Get a class factory to construct the object we want.
2781 hres = CoGetClassObject(rclsid,
2791 * Create the object and don't forget to release the factory
2793 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2794 IClassFactory_Release(lpclf);
2797 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2798 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2800 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2802 debugstr_guid(rclsid),hres);
2808 /***********************************************************************
2809 * CoCreateInstanceEx [OLE32.@]
2811 HRESULT WINAPI CoCreateInstanceEx(
2813 LPUNKNOWN pUnkOuter,
2815 COSERVERINFO* pServerInfo,
2819 IUnknown* pUnk = NULL;
2822 ULONG successCount = 0;
2827 if ( (cmq==0) || (pResults==NULL))
2828 return E_INVALIDARG;
2830 if (pServerInfo!=NULL)
2831 FIXME("() non-NULL pServerInfo not supported!\n");
2834 * Initialize all the "out" parameters.
2836 for (index = 0; index < cmq; index++)
2838 pResults[index].pItf = NULL;
2839 pResults[index].hr = E_NOINTERFACE;
2843 * Get the object and get its IUnknown pointer.
2845 hr = CoCreateInstance(rclsid,
2855 * Then, query for all the interfaces requested.
2857 for (index = 0; index < cmq; index++)
2859 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2860 pResults[index].pIID,
2861 (VOID**)&(pResults[index].pItf));
2863 if (pResults[index].hr == S_OK)
2868 * Release our temporary unknown pointer.
2870 IUnknown_Release(pUnk);
2872 if (successCount == 0)
2873 return E_NOINTERFACE;
2875 if (successCount!=cmq)
2876 return CO_S_NOTALLINTERFACES;
2881 /***********************************************************************
2882 * CoLoadLibrary (OLE32.@)
2887 * lpszLibName [I] Path to library.
2888 * bAutoFree [I] Whether the library should automatically be freed.
2891 * Success: Handle to loaded library.
2895 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2897 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2899 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2901 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2904 /***********************************************************************
2905 * CoFreeLibrary [OLE32.@]
2907 * Unloads a library from memory.
2910 * hLibrary [I] Handle to library to unload.
2916 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2918 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2920 FreeLibrary(hLibrary);
2924 /***********************************************************************
2925 * CoFreeAllLibraries [OLE32.@]
2927 * Function for backwards compatibility only. Does nothing.
2933 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2935 void WINAPI CoFreeAllLibraries(void)
2940 /***********************************************************************
2941 * CoFreeUnusedLibrariesEx [OLE32.@]
2943 * Frees any previously unused libraries whose delay has expired and marks
2944 * currently unused libraries for unloading. Unused are identified as those that
2945 * return S_OK from their DllCanUnloadNow function.
2948 * dwUnloadDelay [I] Unload delay in milliseconds.
2949 * dwReserved [I] Reserved. Set to 0.
2955 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2957 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2959 struct apartment *apt = COM_CurrentApt();
2962 ERR("apartment not initialised\n");
2966 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2969 /***********************************************************************
2970 * CoFreeUnusedLibraries [OLE32.@]
2972 * Frees any unused libraries. Unused are identified as those that return
2973 * S_OK from their DllCanUnloadNow function.
2979 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2981 void WINAPI CoFreeUnusedLibraries(void)
2983 CoFreeUnusedLibrariesEx(INFINITE, 0);
2986 /***********************************************************************
2987 * CoFileTimeNow [OLE32.@]
2989 * Retrieves the current time in FILETIME format.
2992 * lpFileTime [O] The current time.
2997 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2999 GetSystemTimeAsFileTime( lpFileTime );
3003 /******************************************************************************
3004 * CoLockObjectExternal [OLE32.@]
3006 * Increments or decrements the external reference count of a stub object.
3009 * pUnk [I] Stub object.
3010 * fLock [I] If TRUE then increments the external ref-count,
3011 * otherwise decrements.
3012 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3013 * calling CoDisconnectObject.
3017 * Failure: HRESULT code.
3020 * If fLock is TRUE and an object is passed in that doesn't have a stub
3021 * manager then a new stub manager is created for the object.
3023 HRESULT WINAPI CoLockObjectExternal(
3026 BOOL fLastUnlockReleases)
3028 struct stub_manager *stubmgr;
3029 struct apartment *apt;
3031 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3032 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3034 apt = COM_CurrentApt();
3035 if (!apt) return CO_E_NOTINITIALIZED;
3037 stubmgr = get_stub_manager_from_object(apt, pUnk);
3042 stub_manager_ext_addref(stubmgr, 1, FALSE);
3044 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3046 stub_manager_int_release(stubmgr);
3052 stubmgr = new_stub_manager(apt, pUnk);
3056 stub_manager_ext_addref(stubmgr, 1, FALSE);
3057 stub_manager_int_release(stubmgr);
3064 WARN("stub object not found %p\n", pUnk);
3065 /* Note: native is pretty broken here because it just silently
3066 * fails, without returning an appropriate error code, making apps
3067 * think that the object was disconnected, when it actually wasn't */
3072 /***********************************************************************
3073 * CoInitializeWOW (OLE32.@)
3075 * WOW equivalent of CoInitialize?
3084 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3086 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3090 /***********************************************************************
3091 * CoGetState [OLE32.@]
3093 * Retrieves the thread state object previously stored by CoSetState().
3096 * ppv [I] Address where pointer to object will be stored.
3100 * Failure: E_OUTOFMEMORY.
3103 * Crashes on all invalid ppv addresses, including NULL.
3104 * If the function returns a non-NULL object then the caller must release its
3105 * reference on the object when the object is no longer required.
3110 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3112 struct oletls *info = COM_CurrentInfo();
3113 if (!info) return E_OUTOFMEMORY;
3119 IUnknown_AddRef(info->state);
3121 TRACE("apt->state=%p\n", info->state);
3127 /***********************************************************************
3128 * CoSetState [OLE32.@]
3130 * Sets the thread state object.
3133 * pv [I] Pointer to state object to be stored.
3136 * The system keeps a reference on the object while the object stored.
3140 * Failure: E_OUTOFMEMORY.
3142 HRESULT WINAPI CoSetState(IUnknown * pv)
3144 struct oletls *info = COM_CurrentInfo();
3145 if (!info) return E_OUTOFMEMORY;
3147 if (pv) IUnknown_AddRef(pv);
3151 TRACE("-- release %p now\n", info->state);
3152 IUnknown_Release(info->state);
3161 /******************************************************************************
3162 * CoTreatAsClass [OLE32.@]
3164 * Sets the TreatAs value of a class.
3167 * clsidOld [I] Class to set TreatAs value on.
3168 * clsidNew [I] The class the clsidOld should be treated as.
3172 * Failure: HRESULT code.
3177 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3179 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3180 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3182 WCHAR szClsidNew[CHARS_IN_GUID];
3184 WCHAR auto_treat_as[CHARS_IN_GUID];
3185 LONG auto_treat_as_size = sizeof(auto_treat_as);
3188 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3191 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
3193 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3194 CLSIDFromString(auto_treat_as, &id) == S_OK)
3196 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3198 res = REGDB_E_WRITEREGDB;
3204 RegDeleteKeyW(hkey, wszTreatAs);
3208 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
3209 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
3211 res = REGDB_E_WRITEREGDB;
3216 if (hkey) RegCloseKey(hkey);
3220 /******************************************************************************
3221 * CoGetTreatAsClass [OLE32.@]
3223 * Gets the TreatAs value of a class.
3226 * clsidOld [I] Class to get the TreatAs value of.
3227 * clsidNew [I] The class the clsidOld should be treated as.
3231 * Failure: HRESULT code.
3236 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3238 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3240 WCHAR szClsidNew[CHARS_IN_GUID];
3242 LONG len = sizeof(szClsidNew);
3244 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3245 *clsidNew = *clsidOld; /* copy over old value */
3247 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3253 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3258 res = CLSIDFromString(szClsidNew,clsidNew);
3260 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3262 if (hkey) RegCloseKey(hkey);
3266 /******************************************************************************
3267 * CoGetCurrentProcess [OLE32.@]
3269 * Gets the current process ID.
3272 * The current process ID.
3275 * Is DWORD really the correct return type for this function?
3277 DWORD WINAPI CoGetCurrentProcess(void)
3279 return GetCurrentProcessId();
3282 /******************************************************************************
3283 * CoRegisterMessageFilter [OLE32.@]
3285 * Registers a message filter.
3288 * lpMessageFilter [I] Pointer to interface.
3289 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3293 * Failure: HRESULT code.
3296 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3297 * lpMessageFilter removes the message filter.
3299 * If lplpMessageFilter is not NULL the previous message filter will be
3300 * returned in the memory pointer to this parameter and the caller is
3301 * responsible for releasing the object.
3303 * The current thread be in an apartment otherwise the function will crash.
3305 HRESULT WINAPI CoRegisterMessageFilter(
3306 LPMESSAGEFILTER lpMessageFilter,
3307 LPMESSAGEFILTER *lplpMessageFilter)
3309 struct apartment *apt;
3310 IMessageFilter *lpOldMessageFilter;
3312 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3314 apt = COM_CurrentApt();
3316 /* can't set a message filter in a multi-threaded apartment */
3317 if (!apt || apt->multi_threaded)
3319 WARN("can't set message filter in MTA or uninitialized apt\n");
3320 return CO_E_NOT_SUPPORTED;
3323 if (lpMessageFilter)
3324 IMessageFilter_AddRef(lpMessageFilter);
3326 EnterCriticalSection(&apt->cs);
3328 lpOldMessageFilter = apt->filter;
3329 apt->filter = lpMessageFilter;
3331 LeaveCriticalSection(&apt->cs);
3333 if (lplpMessageFilter)
3334 *lplpMessageFilter = lpOldMessageFilter;
3335 else if (lpOldMessageFilter)
3336 IMessageFilter_Release(lpOldMessageFilter);
3341 /***********************************************************************
3342 * CoIsOle1Class [OLE32.@]
3344 * Determines whether the specified class an OLE v1 class.
3347 * clsid [I] Class to test.
3350 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3352 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3354 FIXME("%s\n", debugstr_guid(clsid));
3358 /***********************************************************************
3359 * IsEqualGUID [OLE32.@]
3361 * Compares two Unique Identifiers.
3364 * rguid1 [I] The first GUID to compare.
3365 * rguid2 [I] The other GUID to compare.
3371 BOOL WINAPI IsEqualGUID(
3375 return !memcmp(rguid1,rguid2,sizeof(GUID));
3378 /***********************************************************************
3379 * CoInitializeSecurity [OLE32.@]
3381 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3382 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3383 void* pReserved1, DWORD dwAuthnLevel,
3384 DWORD dwImpLevel, void* pReserved2,
3385 DWORD dwCapabilities, void* pReserved3)
3387 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3388 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3389 dwCapabilities, pReserved3);
3393 /***********************************************************************
3394 * CoSuspendClassObjects [OLE32.@]
3396 * Suspends all registered class objects to prevent further requests coming in
3397 * for those objects.
3401 * Failure: HRESULT code.
3403 HRESULT WINAPI CoSuspendClassObjects(void)
3409 /***********************************************************************
3410 * CoAddRefServerProcess [OLE32.@]
3412 * Helper function for incrementing the reference count of a local-server
3416 * New reference count.
3419 * CoReleaseServerProcess().
3421 ULONG WINAPI CoAddRefServerProcess(void)
3427 EnterCriticalSection(&csRegisteredClassList);
3428 refs = ++s_COMServerProcessReferences;
3429 LeaveCriticalSection(&csRegisteredClassList);
3431 TRACE("refs before: %d\n", refs - 1);
3436 /***********************************************************************
3437 * CoReleaseServerProcess [OLE32.@]
3439 * Helper function for decrementing the reference count of a local-server
3443 * New reference count.
3446 * When reference count reaches 0, this function suspends all registered
3447 * classes so no new connections are accepted.
3450 * CoAddRefServerProcess(), CoSuspendClassObjects().
3452 ULONG WINAPI CoReleaseServerProcess(void)
3458 EnterCriticalSection(&csRegisteredClassList);
3460 refs = --s_COMServerProcessReferences;
3461 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3463 LeaveCriticalSection(&csRegisteredClassList);
3465 TRACE("refs after: %d\n", refs);
3470 /***********************************************************************
3471 * CoIsHandlerConnected [OLE32.@]
3473 * Determines whether a proxy is connected to a remote stub.
3476 * pUnk [I] Pointer to object that may or may not be connected.
3479 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3482 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3484 FIXME("%p\n", pUnk);
3489 /***********************************************************************
3490 * CoAllowSetForegroundWindow [OLE32.@]
3493 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3495 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3499 /***********************************************************************
3500 * CoQueryProxyBlanket [OLE32.@]
3502 * Retrieves the security settings being used by a proxy.
3505 * pProxy [I] Pointer to the proxy object.
3506 * pAuthnSvc [O] The type of authentication service.
3507 * pAuthzSvc [O] The type of authorization service.
3508 * ppServerPrincName [O] Optional. The server prinicple name.
3509 * pAuthnLevel [O] The authentication level.
3510 * pImpLevel [O] The impersonation level.
3511 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3512 * pCapabilities [O] Flags affecting the security behaviour.
3516 * Failure: HRESULT code.
3519 * CoCopyProxy, CoSetProxyBlanket.
3521 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3522 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3523 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3525 IClientSecurity *pCliSec;
3528 TRACE("%p\n", pProxy);
3530 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3533 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3534 pAuthzSvc, ppServerPrincName,
3535 pAuthnLevel, pImpLevel, ppAuthInfo,
3537 IClientSecurity_Release(pCliSec);
3540 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3544 /***********************************************************************
3545 * CoSetProxyBlanket [OLE32.@]
3547 * Sets the security settings for a proxy.
3550 * pProxy [I] Pointer to the proxy object.
3551 * AuthnSvc [I] The type of authentication service.
3552 * AuthzSvc [I] The type of authorization service.
3553 * pServerPrincName [I] The server prinicple name.
3554 * AuthnLevel [I] The authentication level.
3555 * ImpLevel [I] The impersonation level.
3556 * pAuthInfo [I] Information specific to the authorization/authentication service.
3557 * Capabilities [I] Flags affecting the security behaviour.
3561 * Failure: HRESULT code.
3564 * CoQueryProxyBlanket, CoCopyProxy.
3566 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3567 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3568 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3570 IClientSecurity *pCliSec;
3573 TRACE("%p\n", pProxy);
3575 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3578 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3579 AuthzSvc, pServerPrincName,
3580 AuthnLevel, ImpLevel, pAuthInfo,
3582 IClientSecurity_Release(pCliSec);
3585 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3589 /***********************************************************************
3590 * CoCopyProxy [OLE32.@]
3595 * pProxy [I] Pointer to the proxy object.
3596 * ppCopy [O] Copy of the proxy.
3600 * Failure: HRESULT code.
3603 * CoQueryProxyBlanket, CoSetProxyBlanket.
3605 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3607 IClientSecurity *pCliSec;
3610 TRACE("%p\n", pProxy);
3612 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3615 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3616 IClientSecurity_Release(pCliSec);
3619 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3624 /***********************************************************************
3625 * CoGetCallContext [OLE32.@]
3627 * Gets the context of the currently executing server call in the current
3631 * riid [I] Context interface to return.
3632 * ppv [O] Pointer to memory that will receive the context on return.
3636 * Failure: HRESULT code.
3638 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3640 struct oletls *info = COM_CurrentInfo();
3642 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3645 return E_OUTOFMEMORY;
3647 if (!info->call_state)
3648 return RPC_E_CALL_COMPLETE;
3650 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3653 /***********************************************************************
3654 * CoSwitchCallContext [OLE32.@]
3656 * Switches the context of the currently executing server call in the current
3660 * pObject [I] Pointer to new context object
3661 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3665 * Failure: HRESULT code.
3667 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3669 struct oletls *info = COM_CurrentInfo();
3671 TRACE("(%p, %p)\n", pObject, ppOldObject);
3674 return E_OUTOFMEMORY;
3676 *ppOldObject = info->call_state;
3677 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3682 /***********************************************************************
3683 * CoQueryClientBlanket [OLE32.@]
3685 * Retrieves the authentication information about the client of the currently
3686 * executing server call in the current thread.
3689 * pAuthnSvc [O] Optional. The type of authentication service.
3690 * pAuthzSvc [O] Optional. The type of authorization service.
3691 * pServerPrincName [O] Optional. The server prinicple name.
3692 * pAuthnLevel [O] Optional. The authentication level.
3693 * pImpLevel [O] Optional. The impersonation level.
3694 * pPrivs [O] Optional. Information about the privileges of the client.
3695 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3699 * Failure: HRESULT code.
3702 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3704 HRESULT WINAPI CoQueryClientBlanket(
3707 OLECHAR **pServerPrincName,
3710 RPC_AUTHZ_HANDLE *pPrivs,
3711 DWORD *pCapabilities)
3713 IServerSecurity *pSrvSec;
3716 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3717 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3718 pPrivs, pCapabilities);
3720 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3723 hr = IServerSecurity_QueryBlanket(
3724 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3725 pImpLevel, pPrivs, pCapabilities);
3726 IServerSecurity_Release(pSrvSec);
3732 /***********************************************************************
3733 * CoImpersonateClient [OLE32.@]
3735 * Impersonates the client of the currently executing server call in the
3743 * Failure: HRESULT code.
3746 * If this function fails then the current thread will not be impersonating
3747 * the client and all actions will take place on behalf of the server.
3748 * Therefore, it is important to check the return value from this function.
3751 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3753 HRESULT WINAPI CoImpersonateClient(void)
3755 IServerSecurity *pSrvSec;
3760 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3763 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3764 IServerSecurity_Release(pSrvSec);
3770 /***********************************************************************
3771 * CoRevertToSelf [OLE32.@]
3773 * Ends the impersonation of the client of the currently executing server
3774 * call in the current thread.
3781 * Failure: HRESULT code.
3784 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3786 HRESULT WINAPI CoRevertToSelf(void)
3788 IServerSecurity *pSrvSec;
3793 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3796 hr = IServerSecurity_RevertToSelf(pSrvSec);
3797 IServerSecurity_Release(pSrvSec);
3803 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3805 /* first try to retrieve messages for incoming COM calls to the apartment window */
3806 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
3807 /* next retrieve other messages necessary for the app to remain responsive */
3808 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3809 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3812 /***********************************************************************
3813 * CoWaitForMultipleHandles [OLE32.@]
3815 * Waits for one or more handles to become signaled.
3818 * dwFlags [I] Flags. See notes.
3819 * dwTimeout [I] Timeout in milliseconds.
3820 * cHandles [I] Number of handles pointed to by pHandles.
3821 * pHandles [I] Handles to wait for.
3822 * lpdwindex [O] Index of handle that was signaled.
3826 * Failure: RPC_S_CALLPENDING on timeout.
3830 * The dwFlags parameter can be zero or more of the following:
3831 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3832 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3835 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3837 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3838 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3841 DWORD start_time = GetTickCount();
3842 APARTMENT *apt = COM_CurrentApt();
3843 BOOL message_loop = apt && !apt->multi_threaded;
3845 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3846 pHandles, lpdwindex);
3850 DWORD now = GetTickCount();
3853 if (now - start_time > dwTimeout)
3855 hr = RPC_S_CALLPENDING;
3861 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3862 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3864 TRACE("waiting for rpc completion or window message\n");
3866 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3867 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3868 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
3870 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3875 /* call message filter */
3877 if (COM_CurrentApt()->filter)
3879 PENDINGTYPE pendingtype =
3880 COM_CurrentInfo()->pending_call_count_server ?
3881 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3882 DWORD be_handled = IMessageFilter_MessagePending(
3883 COM_CurrentApt()->filter, 0 /* FIXME */,
3884 now - start_time, pendingtype);
3885 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3888 case PENDINGMSG_CANCELCALL:
3889 WARN("call canceled\n");
3890 hr = RPC_E_CALL_CANCELED;
3892 case PENDINGMSG_WAITNOPROCESS:
3893 case PENDINGMSG_WAITDEFPROCESS:
3895 /* FIXME: MSDN is very vague about the difference
3896 * between WAITNOPROCESS and WAITDEFPROCESS - there
3897 * appears to be none, so it is possibly a left-over
3898 * from the 16-bit world. */
3903 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
3904 * so after processing 100 messages we go back to checking the wait handles */
3905 while (count++ < 100 && COM_PeekMessage(apt, &msg))
3907 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3908 TranslateMessage(&msg);
3909 DispatchMessageW(&msg);
3910 if (msg.message == WM_QUIT)
3912 TRACE("resending WM_QUIT to outer message loop\n");
3913 PostQuitMessage(msg.wParam);
3914 /* no longer need to process messages */
3915 message_loop = FALSE;
3924 TRACE("waiting for rpc completion\n");
3926 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
3927 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3928 (dwFlags & COWAIT_ALERTABLE) != 0);
3934 hr = RPC_S_CALLPENDING;
3937 hr = HRESULT_FROM_WIN32( GetLastError() );
3945 TRACE("-- 0x%08x\n", hr);
3950 /***********************************************************************
3951 * CoGetObject [OLE32.@]
3953 * Gets the object named by converting the name to a moniker and binding to it.
3956 * pszName [I] String representing the object.
3957 * pBindOptions [I] Parameters affecting the binding to the named object.
3958 * riid [I] Interface to bind to on the objecct.
3959 * ppv [O] On output, the interface riid of the object represented
3964 * Failure: HRESULT code.
3967 * MkParseDisplayName.
3969 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3970 REFIID riid, void **ppv)
3977 hr = CreateBindCtx(0, &pbc);
3981 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3988 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3991 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3992 IMoniker_Release(pmk);
3996 IBindCtx_Release(pbc);
4001 /***********************************************************************
4002 * CoRegisterChannelHook [OLE32.@]
4004 * Registers a process-wide hook that is called during ORPC calls.
4007 * guidExtension [I] GUID of the channel hook to register.
4008 * pChannelHook [I] Channel hook object to register.
4012 * Failure: HRESULT code.
4014 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4016 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4018 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4021 typedef struct Context
4023 IComThreadingInfo IComThreadingInfo_iface;
4024 IContextCallback IContextCallback_iface;
4025 IObjContext IObjContext_iface;
4030 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4032 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4035 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4037 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4040 static inline Context *impl_from_IObjContext( IObjContext *iface )
4042 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4045 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4049 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4050 IsEqualIID(riid, &IID_IUnknown))
4052 *ppv = &iface->IComThreadingInfo_iface;
4054 else if (IsEqualIID(riid, &IID_IContextCallback))
4056 *ppv = &iface->IContextCallback_iface;
4058 else if (IsEqualIID(riid, &IID_IObjContext))
4060 *ppv = &iface->IObjContext_iface;
4065 IUnknown_AddRef((IUnknown*)*ppv);
4069 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4070 return E_NOINTERFACE;
4073 static ULONG Context_AddRef(Context *This)
4075 return InterlockedIncrement(&This->refs);
4078 static ULONG Context_Release(Context *This)
4080 ULONG refs = InterlockedDecrement(&This->refs);
4082 HeapFree(GetProcessHeap(), 0, This);
4086 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4088 Context *This = impl_from_IComThreadingInfo(iface);
4089 return Context_QueryInterface(This, riid, ppv);
4092 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4094 Context *This = impl_from_IComThreadingInfo(iface);
4095 return Context_AddRef(This);
4098 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4100 Context *This = impl_from_IComThreadingInfo(iface);
4101 return Context_Release(This);
4104 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4106 Context *This = impl_from_IComThreadingInfo(iface);
4108 TRACE("(%p)\n", apttype);
4110 *apttype = This->apttype;
4114 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4116 Context *This = impl_from_IComThreadingInfo(iface);
4118 TRACE("(%p)\n", thdtype);
4120 switch (This->apttype)
4123 case APTTYPE_MAINSTA:
4124 *thdtype = THDTYPE_PROCESSMESSAGES;
4127 *thdtype = THDTYPE_BLOCKMESSAGES;
4133 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4135 FIXME("(%p): stub\n", logical_thread_id);
4139 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4141 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4145 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4147 Context_CTI_QueryInterface,
4149 Context_CTI_Release,
4150 Context_CTI_GetCurrentApartmentType,
4151 Context_CTI_GetCurrentThreadType,
4152 Context_CTI_GetCurrentLogicalThreadId,
4153 Context_CTI_SetCurrentLogicalThreadId
4156 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4158 Context *This = impl_from_IContextCallback(iface);
4159 return Context_QueryInterface(This, riid, ppv);
4162 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4164 Context *This = impl_from_IContextCallback(iface);
4165 return Context_AddRef(This);
4168 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4170 Context *This = impl_from_IContextCallback(iface);
4171 return Context_Release(This);
4174 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4175 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4177 Context *This = impl_from_IContextCallback(iface);
4179 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4183 static const IContextCallbackVtbl Context_Callback_Vtbl =
4185 Context_CC_QueryInterface,
4188 Context_CC_ContextCallback
4191 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4193 Context *This = impl_from_IObjContext(iface);
4194 return Context_QueryInterface(This, riid, ppv);
4197 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4199 Context *This = impl_from_IObjContext(iface);
4200 return Context_AddRef(This);
4203 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4205 Context *This = impl_from_IObjContext(iface);
4206 return Context_Release(This);
4209 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4211 Context *This = impl_from_IObjContext(iface);
4213 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4217 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4219 Context *This = impl_from_IObjContext(iface);
4221 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4225 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4227 Context *This = impl_from_IObjContext(iface);
4229 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4233 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4235 Context *This = impl_from_IObjContext(iface);
4237 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4241 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4243 Context *This = impl_from_IObjContext(iface);
4244 FIXME("(%p/%p)\n", This, iface);
4247 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4249 Context *This = impl_from_IObjContext(iface);
4250 FIXME("(%p/%p)\n", This, iface);
4253 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4255 Context *This = impl_from_IObjContext(iface);
4256 FIXME("(%p/%p)\n", This, iface);
4259 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4261 Context *This = impl_from_IObjContext(iface);
4262 FIXME("(%p/%p)\n", This, iface);
4265 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4267 Context *This = impl_from_IObjContext(iface);
4268 FIXME("(%p/%p)\n", This, iface);
4271 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4273 Context *This = impl_from_IObjContext(iface);
4274 FIXME("(%p/%p)\n", This, iface);
4277 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4279 Context *This = impl_from_IObjContext(iface);
4280 FIXME("(%p/%p)\n", This, iface);
4283 static const IObjContextVtbl Context_Object_Vtbl =
4285 Context_OC_QueryInterface,
4288 Context_OC_SetProperty,
4289 Context_OC_RemoveProperty,
4290 Context_OC_GetProperty,
4291 Context_OC_EnumContextProps,
4292 Context_OC_Reserved1,
4293 Context_OC_Reserved2,
4294 Context_OC_Reserved3,
4295 Context_OC_Reserved4,
4296 Context_OC_Reserved5,
4297 Context_OC_Reserved6,
4298 Context_OC_Reserved7
4301 /***********************************************************************
4302 * CoGetObjectContext [OLE32.@]
4304 * Retrieves an object associated with the current context (i.e. apartment).
4307 * riid [I] ID of the interface of the object to retrieve.
4308 * ppv [O] Address where object will be stored on return.
4312 * Failure: HRESULT code.
4314 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4316 APARTMENT *apt = COM_CurrentApt();
4320 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4325 if (!(apt = apartment_find_multi_threaded()))
4327 ERR("apartment not initialised\n");
4328 return CO_E_NOTINITIALIZED;
4330 apartment_release(apt);
4333 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4335 return E_OUTOFMEMORY;
4337 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4338 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4339 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4341 if (apt->multi_threaded)
4342 context->apttype = APTTYPE_MTA;
4344 context->apttype = APTTYPE_MAINSTA;
4346 context->apttype = APTTYPE_STA;
4348 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4349 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4355 /***********************************************************************
4356 * CoGetContextToken [OLE32.@]
4358 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4360 struct oletls *info = COM_CurrentInfo();
4362 TRACE("(%p)\n", token);
4365 return E_OUTOFMEMORY;
4370 if (!(apt = apartment_find_multi_threaded()))
4372 ERR("apartment not initialised\n");
4373 return CO_E_NOTINITIALIZED;
4375 apartment_release(apt);
4381 if (!info->context_token)
4386 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4387 if (FAILED(hr)) return hr;
4388 info->context_token = ctx;
4391 *token = (ULONG_PTR)info->context_token;
4392 TRACE("apt->context_token=%p\n", info->context_token);
4397 /***********************************************************************
4398 * CoGetDefaultContext [OLE32.@]
4400 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
4402 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
4403 return E_NOINTERFACE;
4406 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4408 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4412 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4413 if (SUCCEEDED(hres))
4415 WCHAR dllpath[MAX_PATH+1];
4417 if (COM_RegReadPath(hkey, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4419 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4420 if (!strcmpiW(dllpath, wszOle32))
4423 return HandlerCF_Create(rclsid, riid, ppv);
4427 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4431 return CLASS_E_CLASSNOTAVAILABLE;
4434 /***********************************************************************
4437 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
4439 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4442 case DLL_PROCESS_ATTACH:
4443 hProxyDll = hinstDLL;
4444 COMPOBJ_InitProcess();
4447 case DLL_PROCESS_DETACH:
4448 COMPOBJ_UninitProcess();
4449 RPC_UnregisterAllChannelHooks();
4450 COMPOBJ_DllList_Free();
4451 DeleteCriticalSection(&csRegisteredClassList);
4452 DeleteCriticalSection(&csApartment);
4455 case DLL_THREAD_DETACH:
4462 /***********************************************************************
4463 * DllRegisterServer (OLE32.@)
4465 HRESULT WINAPI DllRegisterServer(void)
4467 return OLE32_DllRegisterServer();
4470 /***********************************************************************
4471 * DllUnregisterServer (OLE32.@)
4473 HRESULT WINAPI DllUnregisterServer(void)
4475 return OLE32_DllUnregisterServer();