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
37 * - Make all ole interface marshaling use NDR to be wire compatible with
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
62 #include "compobj_private.h"
64 #include "wine/unicode.h"
65 #include "wine/debug.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(ole);
69 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
71 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
73 /****************************************************************************
74 * This section defines variables internal to the COM module.
76 * TODO: Most of these things will have to be made thread-safe.
79 static HRESULT COM_GetRegisteredClassObject(struct apartment *apt, REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
80 static void COM_RevokeAllClasses(struct apartment *apt);
81 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv);
83 static APARTMENT *MTA; /* protected by csApartment */
84 static APARTMENT *MainApartment; /* the first STA apartment */
85 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
87 static CRITICAL_SECTION csApartment;
88 static CRITICAL_SECTION_DEBUG critsect_debug =
91 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
92 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
94 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
96 struct registered_psclsid
104 * This lock count counts the number of times CoInitialize is called. It is
105 * decreased every time CoUninitialize is called. When it hits 0, the COM
106 * libraries are freed
108 static LONG s_COMLockCount = 0;
109 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
110 static LONG s_COMServerProcessReferences = 0;
113 * This linked list contains the list of registered class objects. These
114 * are mostly used to register the factories for out-of-proc servers of OLE
117 * TODO: Make this data structure aware of inter-process communication. This
118 * means that parts of this will be exported to the Wine Server.
120 typedef struct tagRegisteredClass
123 CLSID classIdentifier;
125 LPUNKNOWN classObject;
129 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
130 void *RpcRegistration;
133 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
135 static CRITICAL_SECTION csRegisteredClassList;
136 static CRITICAL_SECTION_DEBUG class_cs_debug =
138 0, 0, &csRegisteredClassList,
139 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
140 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
142 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
144 /*****************************************************************************
145 * This section contains OpenDllList definitions
147 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
148 * other functions that do LoadLibrary _without_ giving back a HMODULE.
149 * Without this list these handles would never be freed.
151 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
152 * next unload-call but not before 600 sec.
155 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
156 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
158 typedef struct tagOpenDll
163 DllGetClassObjectFunc DllGetClassObject;
164 DllCanUnloadNowFunc DllCanUnloadNow;
168 static struct list openDllList = LIST_INIT(openDllList);
170 static CRITICAL_SECTION csOpenDllList;
171 static CRITICAL_SECTION_DEBUG dll_cs_debug =
173 0, 0, &csOpenDllList,
174 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
175 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
177 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
179 struct apartment_loaded_dll
185 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',' ',
186 '0','x','#','#','#','#','#','#','#','#',' ',0};
187 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
188 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
189 REFCLSID rclsid, REFIID riid, void **ppv);
190 static void apartment_freeunusedlibraries(struct apartment *apt);
192 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
193 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
194 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
196 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
198 static void COMPOBJ_InitProcess( void )
202 /* Dispatching to the correct thread in an apartment is done through
203 * window messages rather than RPC transports. When an interface is
204 * marshalled into another apartment in the same process, a window of the
205 * following class is created. The *caller* of CoMarshalInterface (ie the
206 * application) is responsible for pumping the message loop in that thread.
207 * The WM_USER messages which point to the RPCs are then dispatched to
208 * COM_AptWndProc by the user's code from the apartment in which the interface
211 memset(&wclass, 0, sizeof(wclass));
212 wclass.lpfnWndProc = apartment_wndproc;
213 wclass.hInstance = OLE32_hInstance;
214 wclass.lpszClassName = wszAptWinClass;
215 RegisterClassW(&wclass);
218 static void COMPOBJ_UninitProcess( void )
220 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
223 static void COM_TlsDestroy(void)
225 struct oletls *info = NtCurrentTeb()->ReservedForOle;
228 if (info->apt) apartment_release(info->apt);
229 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
230 if (info->state) IUnknown_Release(info->state);
231 HeapFree(GetProcessHeap(), 0, info);
232 NtCurrentTeb()->ReservedForOle = NULL;
236 /******************************************************************************
240 /* allocates memory and fills in the necessary fields for a new apartment
241 * object. must be called inside apartment cs */
242 static APARTMENT *apartment_construct(DWORD model)
246 TRACE("creating new apartment, model=%d\n", model);
248 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
249 apt->tid = GetCurrentThreadId();
251 list_init(&apt->proxies);
252 list_init(&apt->stubmgrs);
253 list_init(&apt->psclsids);
254 list_init(&apt->loaded_dlls);
257 apt->remunk_exported = FALSE;
259 InitializeCriticalSection(&apt->cs);
260 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
262 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
264 if (apt->multi_threaded)
266 /* FIXME: should be randomly generated by in an RPC call to rpcss */
267 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
271 /* FIXME: should be randomly generated by in an RPC call to rpcss */
272 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
275 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
277 list_add_head(&apts, &apt->entry);
282 /* gets and existing apartment if one exists or otherwise creates an apartment
283 * structure which stores OLE apartment-local information and stores a pointer
284 * to it in the thread-local storage */
285 static APARTMENT *apartment_get_or_create(DWORD model)
287 APARTMENT *apt = COM_CurrentApt();
291 if (model & COINIT_APARTMENTTHREADED)
293 EnterCriticalSection(&csApartment);
295 apt = apartment_construct(model);
300 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
303 LeaveCriticalSection(&csApartment);
307 EnterCriticalSection(&csApartment);
309 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
310 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
314 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
315 apartment_addref(MTA);
318 MTA = apartment_construct(model);
322 LeaveCriticalSection(&csApartment);
324 COM_CurrentInfo()->apt = apt;
330 static inline BOOL apartment_is_model(APARTMENT *apt, DWORD model)
332 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
335 DWORD apartment_addref(struct apartment *apt)
337 DWORD refs = InterlockedIncrement(&apt->refs);
338 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
342 DWORD apartment_release(struct apartment *apt)
346 EnterCriticalSection(&csApartment);
348 ret = InterlockedDecrement(&apt->refs);
349 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
350 /* destruction stuff that needs to happen under csApartment CS */
353 if (apt == MTA) MTA = NULL;
354 else if (apt == MainApartment) MainApartment = NULL;
355 list_remove(&apt->entry);
358 LeaveCriticalSection(&csApartment);
362 struct list *cursor, *cursor2;
364 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
366 /* Release the references to the registered class objects */
367 COM_RevokeAllClasses(apt);
369 /* no locking is needed for this apartment, because no other thread
370 * can access it at this point */
372 apartment_disconnectproxies(apt);
374 if (apt->win) DestroyWindow(apt->win);
376 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
378 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
379 /* release the implicit reference given by the fact that the
380 * stub has external references (it must do since it is in the
381 * stub manager list in the apartment and all non-apartment users
382 * must have a ref on the apartment and so it cannot be destroyed).
384 stub_manager_int_release(stubmgr);
387 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
389 struct registered_psclsid *registered_psclsid =
390 LIST_ENTRY(cursor, struct registered_psclsid, entry);
392 list_remove(®istered_psclsid->entry);
393 HeapFree(GetProcessHeap(), 0, registered_psclsid);
396 /* if this assert fires, then another thread took a reference to a
397 * stub manager without taking a reference to the containing
398 * apartment, which it must do. */
399 assert(list_empty(&apt->stubmgrs));
401 if (apt->filter) IUnknown_Release(apt->filter);
403 /* free as many unused libraries as possible... */
404 apartment_freeunusedlibraries(apt);
406 /* ... and free the memory for the apartment loaded dll entry and
407 * release the dll list reference without freeing the library for the
409 while ((cursor = list_head(&apt->loaded_dlls)))
411 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
412 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
414 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
417 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
418 DeleteCriticalSection(&apt->cs);
420 HeapFree(GetProcessHeap(), 0, apt);
426 /* The given OXID must be local to this process:
428 * The ref parameter is here mostly to ensure people remember that
429 * they get one, you should normally take a ref for thread safety.
431 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
433 APARTMENT *result = NULL;
436 EnterCriticalSection(&csApartment);
437 LIST_FOR_EACH( cursor, &apts )
439 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
440 if (apt->oxid == oxid)
443 if (ref) apartment_addref(result);
447 LeaveCriticalSection(&csApartment);
452 /* gets the apartment which has a given creator thread ID. The caller must
453 * release the reference from the apartment as soon as the apartment pointer
454 * is no longer required. */
455 APARTMENT *apartment_findfromtid(DWORD tid)
457 APARTMENT *result = NULL;
460 EnterCriticalSection(&csApartment);
461 LIST_FOR_EACH( cursor, &apts )
463 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
467 apartment_addref(result);
471 LeaveCriticalSection(&csApartment);
476 /* gets an apartment which has a given type. The caller must
477 * release the reference from the apartment as soon as the apartment pointer
478 * is no longer required. */
479 static APARTMENT *apartment_findfromtype(BOOL multi_threaded, BOOL main_apartment)
481 APARTMENT *result = NULL;
482 struct apartment *apt;
484 EnterCriticalSection(&csApartment);
486 if (!multi_threaded && main_apartment)
488 result = MainApartment;
489 if (result) apartment_addref(result);
490 LeaveCriticalSection(&csApartment);
494 LIST_FOR_EACH_ENTRY( apt, &apts, struct apartment, entry )
496 if (apt->multi_threaded == multi_threaded)
499 apartment_addref(result);
503 LeaveCriticalSection(&csApartment);
508 struct host_object_params
511 CLSID clsid; /* clsid of object to marshal */
512 IID iid; /* interface to marshal */
513 IStream *stream; /* stream that the object will be marshaled into */
516 static HRESULT apartment_hostobject(struct apartment *apt,
517 const struct host_object_params *params)
521 static const LARGE_INTEGER llZero;
522 WCHAR dllpath[MAX_PATH+1];
526 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
528 /* failure: CLSID is not found in registry */
529 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid));
530 return REGDB_E_CLASSNOTREG;
533 hr = apartment_getclassobject(apt, dllpath, ¶ms->clsid, ¶ms->iid, (void **)&object);
537 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
539 IUnknown_Release(object);
540 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
545 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
550 RPC_ExecuteCall((struct dispatch_params *)lParam);
553 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
555 return DefWindowProcW(hWnd, msg, wParam, lParam);
559 HRESULT apartment_createwindowifneeded(struct apartment *apt)
561 if (apt->multi_threaded)
566 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
568 0, 0, OLE32_hInstance, NULL);
571 ERR("CreateWindow failed with error %d\n", GetLastError());
572 return HRESULT_FROM_WIN32(GetLastError());
574 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
575 /* someone beat us to it */
582 HWND apartment_getwindow(struct apartment *apt)
584 assert(!apt->multi_threaded);
588 void apartment_joinmta(void)
590 apartment_addref(MTA);
591 COM_CurrentInfo()->apt = MTA;
594 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
595 REFCLSID rclsid, REFIID riid, void **ppv)
597 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
600 struct apartment_loaded_dll *apartment_loaded_dll;
602 if (!strcmpiW(dllpath, wszOle32))
604 /* we don't need to control the lifetime of this dll, so use the local
605 * implementation of DllGetClassObject directly */
606 TRACE("calling ole32!DllGetClassObject\n");
607 hr = DllGetClassObject(rclsid, riid, ppv);
610 ERR("DllGetClassObject returned error 0x%08x\n", hr);
615 EnterCriticalSection(&apt->cs);
617 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
618 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
620 TRACE("found %s already loaded\n", debugstr_w(dllpath));
627 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
628 if (!apartment_loaded_dll)
632 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
634 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
638 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
639 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
643 LeaveCriticalSection(&apt->cs);
647 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
648 /* OK: get the ClassObject */
649 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
652 ERR("DllGetClassObject returned error 0x%08x\n", hr);
658 static void apartment_freeunusedlibraries(struct apartment *apt)
660 struct apartment_loaded_dll *entry, *next;
661 EnterCriticalSection(&apt->cs);
662 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
664 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
666 list_remove(&entry->entry);
667 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
668 HeapFree(GetProcessHeap(), 0, entry);
671 LeaveCriticalSection(&apt->cs);
674 /*****************************************************************************
675 * This section contains OpenDllList implementation
678 /* caller must ensure that library_name is not already in the open dll list */
679 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
685 DllCanUnloadNowFunc DllCanUnloadNow;
686 DllGetClassObjectFunc DllGetClassObject;
690 *ret = COMPOBJ_DllList_Get(library_name);
691 if (*ret) return S_OK;
693 /* do this outside the csOpenDllList to avoid creating a lock dependency on
695 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
698 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
699 /* failure: DLL could not be loaded */
700 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
703 DllCanUnloadNow = GetProcAddress(hLibrary, "DllCanUnloadNow");
704 /* Note: failing to find DllCanUnloadNow is not a failure */
705 DllGetClassObject = GetProcAddress(hLibrary, "DllGetClassObject");
706 if (!DllGetClassObject)
708 /* failure: the dll did not export DllGetClassObject */
709 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
710 FreeLibrary(hLibrary);
711 return CO_E_DLLNOTFOUND;
714 EnterCriticalSection( &csOpenDllList );
716 *ret = COMPOBJ_DllList_Get(library_name);
719 /* another caller to this function already added the dll while we
720 * weren't in the critical section */
721 FreeLibrary(hLibrary);
725 len = strlenW(library_name);
726 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
728 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
729 if (entry && entry->library_name)
731 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
732 entry->library = hLibrary;
734 entry->DllCanUnloadNow = DllCanUnloadNow;
735 entry->DllGetClassObject = DllGetClassObject;
736 list_add_tail(&openDllList, &entry->entry);
741 FreeLibrary(hLibrary);
746 LeaveCriticalSection( &csOpenDllList );
751 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
755 EnterCriticalSection(&csOpenDllList);
756 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
758 if (!strcmpiW(library_name, ptr->library_name) &&
759 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
765 LeaveCriticalSection(&csOpenDllList);
769 /* pass FALSE for free_entry to release a reference without destroying the
770 * entry if it reaches zero or TRUE otherwise */
771 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
773 if (!InterlockedDecrement(&entry->refs) && free_entry)
775 EnterCriticalSection(&csOpenDllList);
776 list_remove(&entry->entry);
777 LeaveCriticalSection(&csOpenDllList);
779 TRACE("freeing %p\n", entry->library);
780 FreeLibrary(entry->library);
782 HeapFree(GetProcessHeap(), 0, entry->library_name);
783 HeapFree(GetProcessHeap(), 0, entry);
787 /******************************************************************************
788 * CoBuildVersion [OLE32.@]
789 * CoBuildVersion [COMPOBJ.1]
791 * Gets the build version of the DLL.
796 * Current build version, hiword is majornumber, loword is minornumber
798 DWORD WINAPI CoBuildVersion(void)
800 TRACE("Returning version %d, build %d.\n", rmm, rup);
801 return (rmm<<16)+rup;
804 /******************************************************************************
805 * CoInitialize [OLE32.@]
807 * Initializes the COM libraries by calling CoInitializeEx with
808 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
811 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
814 * Success: S_OK if not already initialized, S_FALSE otherwise.
815 * Failure: HRESULT code.
820 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
823 * Just delegate to the newer method.
825 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
828 /******************************************************************************
829 * CoInitializeEx [OLE32.@]
831 * Initializes the COM libraries.
834 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
835 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
838 * S_OK if successful,
839 * S_FALSE if this function was called already.
840 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
845 * The behavior used to set the IMalloc used for memory management is
847 * The dwCoInit parameter must specify one of the following apartment
849 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
850 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
851 * The parameter may also specify zero or more of the following flags:
852 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
853 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
858 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
863 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
865 if (lpReserved!=NULL)
867 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
871 * Check the lock count. If this is the first time going through the initialize
872 * process, we have to initialize the libraries.
874 * And crank-up that lock count.
876 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
879 * Initialize the various COM libraries and data structures.
881 TRACE("() - Initializing the COM libraries\n");
883 /* we may need to defer this until after apartment initialisation */
884 RunningObjectTableImpl_Initialize();
887 if (!(apt = COM_CurrentInfo()->apt))
889 apt = apartment_get_or_create(dwCoInit);
890 if (!apt) return E_OUTOFMEMORY;
892 else if (!apartment_is_model(apt, dwCoInit))
894 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
895 code then we are probably using the wrong threading model to implement that API. */
896 ERR("Attempt to change threading model of this apartment from %s to %s\n",
897 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
898 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
899 return RPC_E_CHANGED_MODE;
904 COM_CurrentInfo()->inits++;
909 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
910 pending RPCs are ignored. Non-COM messages are discarded at this point.
912 static void COM_FlushMessageQueue(void)
915 APARTMENT *apt = COM_CurrentApt();
917 if (!apt || !apt->win) return;
919 TRACE("Flushing STA message queue\n");
921 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
923 if (message.hwnd != apt->win)
925 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
929 TranslateMessage(&message);
930 DispatchMessageA(&message);
934 /***********************************************************************
935 * CoUninitialize [OLE32.@]
937 * This method will decrement the refcount on the current apartment, freeing
938 * the resources associated with it if it is the last thread in the apartment.
939 * If the last apartment is freed, the function will additionally release
940 * any COM resources associated with the process.
950 void WINAPI CoUninitialize(void)
952 struct oletls * info = COM_CurrentInfo();
957 /* will only happen on OOM */
963 ERR("Mismatched CoUninitialize\n");
969 apartment_release(info->apt);
974 * Decrease the reference count.
975 * If we are back to 0 locks on the COM library, make sure we free
976 * all the associated data structures.
978 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
981 TRACE("() - Releasing the COM libraries\n");
983 RunningObjectTableImpl_UnInitialize();
985 /* This will free the loaded COM Dlls */
986 CoFreeAllLibraries();
988 /* This ensures we deal with any pending RPCs */
989 COM_FlushMessageQueue();
991 else if (lCOMRefCnt<1) {
992 ERR( "CoUninitialize() - not CoInitialized.\n" );
993 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
997 /******************************************************************************
998 * CoDisconnectObject [OLE32.@]
1000 * Disconnects all connections to this object from remote processes. Dispatches
1001 * pending RPCs while blocking new RPCs from occurring, and then calls
1002 * IMarshal::DisconnectObject on the given object.
1004 * Typically called when the object server is forced to shut down, for instance by
1008 * lpUnk [I] The object whose stub should be disconnected.
1009 * reserved [I] Reserved. Should be set to 0.
1013 * Failure: HRESULT code.
1016 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1018 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1024 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1026 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1029 hr = IMarshal_DisconnectObject(marshal, reserved);
1030 IMarshal_Release(marshal);
1034 apt = COM_CurrentApt();
1036 return CO_E_NOTINITIALIZED;
1038 apartment_disconnectobject(apt, lpUnk);
1040 /* Note: native is pretty broken here because it just silently
1041 * fails, without returning an appropriate error code if the object was
1042 * not found, making apps think that the object was disconnected, when
1043 * it actually wasn't */
1048 /******************************************************************************
1049 * CoCreateGuid [OLE32.@]
1051 * Simply forwards to UuidCreate in RPCRT4.
1054 * pguid [O] Points to the GUID to initialize.
1058 * Failure: HRESULT code.
1063 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1065 return UuidCreate(pguid);
1068 /******************************************************************************
1069 * CLSIDFromString [OLE32.@]
1070 * IIDFromString [OLE32.@]
1072 * Converts a unique identifier from its string representation into
1076 * idstr [I] The string representation of the GUID.
1077 * id [O] GUID converted from the string.
1081 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1086 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
1092 memset( id, 0, sizeof (CLSID) );
1096 /* validate the CLSID string */
1097 if (strlenW(s) != 38)
1098 return CO_E_CLASSSTRING;
1100 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1101 return CO_E_CLASSSTRING;
1103 for (i=1; i<37; i++) {
1104 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1105 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1106 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1107 ((s[i] >= 'A') && (s[i] <= 'F'))))
1108 return CO_E_CLASSSTRING;
1111 TRACE("%s -> %p\n", debugstr_w(s), id);
1113 /* quick lookup table */
1114 memset(table, 0, 256);
1116 for (i = 0; i < 10; i++) {
1119 for (i = 0; i < 6; i++) {
1120 table['A' + i] = i+10;
1121 table['a' + i] = i+10;
1124 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1126 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1127 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1128 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1129 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1131 /* these are just sequential bytes */
1132 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1133 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1134 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1135 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1136 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1137 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1138 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1139 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1144 /*****************************************************************************/
1146 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1151 return E_INVALIDARG;
1153 ret = __CLSIDFromString(idstr, id);
1154 if(ret != S_OK) { /* It appears a ProgID is also valid */
1155 ret = CLSIDFromProgID(idstr, id);
1160 /* Converts a GUID into the respective string representation. */
1161 HRESULT WINE_StringFromCLSID(
1162 const CLSID *id, /* [in] GUID to be converted */
1163 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
1165 static const char hex[] = "0123456789ABCDEF";
1170 { ERR("called with id=Null\n");
1175 sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
1176 id->Data1, id->Data2, id->Data3,
1177 id->Data4[0], id->Data4[1]);
1181 for (i = 2; i < 8; i++) {
1182 *s++ = hex[id->Data4[i]>>4];
1183 *s++ = hex[id->Data4[i] & 0xf];
1189 TRACE("%p->%s\n", id, idstr);
1195 /******************************************************************************
1196 * StringFromCLSID [OLE32.@]
1197 * StringFromIID [OLE32.@]
1199 * Converts a GUID into the respective string representation.
1200 * The target string is allocated using the OLE IMalloc.
1203 * id [I] the GUID to be converted.
1204 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1211 * StringFromGUID2, CLSIDFromString
1213 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1219 if ((ret = CoGetMalloc(0,&mllc)))
1222 ret=WINE_StringFromCLSID(id,buf);
1224 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1225 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1226 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1231 /******************************************************************************
1232 * StringFromGUID2 [OLE32.@]
1233 * StringFromGUID2 [COMPOBJ.76]
1235 * Modified version of StringFromCLSID that allows you to specify max
1239 * id [I] GUID to convert to string.
1240 * str [O] Buffer where the result will be stored.
1241 * cmax [I] Size of the buffer in characters.
1244 * Success: The length of the resulting string in characters.
1247 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1251 if (WINE_StringFromCLSID(id,xguid))
1253 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1256 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1257 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1259 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1260 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1264 strcpyW(path, wszCLSIDSlash);
1265 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1266 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1267 if (res == ERROR_FILE_NOT_FOUND)
1268 return REGDB_E_CLASSNOTREG;
1269 else if (res != ERROR_SUCCESS)
1270 return REGDB_E_READREGDB;
1278 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1280 if (res == ERROR_FILE_NOT_FOUND)
1281 return REGDB_E_KEYMISSING;
1282 else if (res != ERROR_SUCCESS)
1283 return REGDB_E_READREGDB;
1288 /* open HKCR\\AppId\\{string form of appid clsid} key */
1289 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1291 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1292 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1294 WCHAR buf[CHARS_IN_GUID];
1295 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1301 /* read the AppID value under the class's key */
1302 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1307 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1309 if (res == ERROR_FILE_NOT_FOUND)
1310 return REGDB_E_KEYMISSING;
1311 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1312 return REGDB_E_READREGDB;
1314 strcpyW(keyname, szAppIdKey);
1315 strcatW(keyname, buf);
1316 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1317 if (res == ERROR_FILE_NOT_FOUND)
1318 return REGDB_E_KEYMISSING;
1319 else if (res != ERROR_SUCCESS)
1320 return REGDB_E_READREGDB;
1325 /******************************************************************************
1326 * ProgIDFromCLSID [OLE32.@]
1328 * Converts a class id into the respective program ID.
1331 * clsid [I] Class ID, as found in registry.
1332 * ppszProgID [O] Associated ProgID.
1337 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1339 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1341 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1348 ERR("ppszProgId isn't optional\n");
1349 return E_INVALIDARG;
1353 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1357 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1358 ret = REGDB_E_CLASSNOTREG;
1362 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1365 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1366 ret = REGDB_E_CLASSNOTREG;
1369 ret = E_OUTOFMEMORY;
1376 /******************************************************************************
1377 * CLSIDFromProgID [OLE32.@]
1379 * Converts a program id into the respective GUID.
1382 * progid [I] Unicode program ID, as found in registry.
1383 * clsid [O] Associated CLSID.
1387 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1389 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1391 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1392 WCHAR buf2[CHARS_IN_GUID];
1393 LONG buf2len = sizeof(buf2);
1397 if (!progid || !clsid)
1399 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1400 return E_INVALIDARG;
1403 /* initialise clsid in case of failure */
1404 memset(clsid, 0, sizeof(*clsid));
1406 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1407 strcpyW( buf, progid );
1408 strcatW( buf, clsidW );
1409 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1411 HeapFree(GetProcessHeap(),0,buf);
1412 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1413 return CO_E_CLASSSTRING;
1415 HeapFree(GetProcessHeap(),0,buf);
1417 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1420 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1421 return CO_E_CLASSSTRING;
1424 return CLSIDFromString(buf2,clsid);
1428 /*****************************************************************************
1429 * CoGetPSClsid [OLE32.@]
1431 * Retrieves the CLSID of the proxy/stub factory that implements
1432 * IPSFactoryBuffer for the specified interface.
1435 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1436 * pclsid [O] Where to store returned proxy/stub CLSID.
1441 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1445 * The standard marshaller activates the object with the CLSID
1446 * returned and uses the CreateProxy and CreateStub methods on its
1447 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1450 * CoGetPSClsid determines this CLSID by searching the
1451 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1452 * in the registry and any interface id registered by
1453 * CoRegisterPSClsid within the current process.
1457 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1458 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1459 * considered a bug in native unless an application depends on this (unlikely).
1462 * CoRegisterPSClsid.
1464 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1466 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1467 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1468 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1469 WCHAR value[CHARS_IN_GUID];
1472 APARTMENT *apt = COM_CurrentApt();
1473 struct registered_psclsid *registered_psclsid;
1475 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1479 ERR("apartment not initialised\n");
1480 return CO_E_NOTINITIALIZED;
1485 ERR("pclsid isn't optional\n");
1486 return E_INVALIDARG;
1489 EnterCriticalSection(&apt->cs);
1491 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1492 if (IsEqualIID(®istered_psclsid->iid, riid))
1494 *pclsid = registered_psclsid->clsid;
1495 LeaveCriticalSection(&apt->cs);
1499 LeaveCriticalSection(&apt->cs);
1501 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1502 strcpyW(path, wszInterface);
1503 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1504 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1506 /* Open the key.. */
1507 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1509 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1510 return REGDB_E_IIDNOTREG;
1513 /* ... Once we have the key, query the registry to get the
1514 value of CLSID as a string, and convert it into a
1515 proper CLSID structure to be passed back to the app */
1516 len = sizeof(value);
1517 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1520 return REGDB_E_IIDNOTREG;
1524 /* We have the CLSid we want back from the registry as a string, so
1525 lets convert it into a CLSID structure */
1526 if (CLSIDFromString(value, pclsid) != NOERROR)
1527 return REGDB_E_IIDNOTREG;
1529 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1533 /*****************************************************************************
1534 * CoRegisterPSClsid [OLE32.@]
1536 * Register a proxy/stub CLSID for the given interface in the current process
1540 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1541 * rclsid [I] CLSID of the proxy/stub.
1545 * Failure: E_OUTOFMEMORY
1549 * This function does not add anything to the registry and the effects are
1550 * limited to the lifetime of the current process.
1555 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1557 APARTMENT *apt = COM_CurrentApt();
1558 struct registered_psclsid *registered_psclsid;
1560 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1564 ERR("apartment not initialised\n");
1565 return CO_E_NOTINITIALIZED;
1568 EnterCriticalSection(&apt->cs);
1570 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1571 if (IsEqualIID(®istered_psclsid->iid, riid))
1573 registered_psclsid->clsid = *rclsid;
1574 LeaveCriticalSection(&apt->cs);
1578 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1579 if (!registered_psclsid)
1581 LeaveCriticalSection(&apt->cs);
1582 return E_OUTOFMEMORY;
1585 registered_psclsid->iid = *riid;
1586 registered_psclsid->clsid = *rclsid;
1587 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
1589 LeaveCriticalSection(&apt->cs);
1596 * COM_GetRegisteredClassObject
1598 * This internal method is used to scan the registered class list to
1599 * find a class object.
1602 * rclsid Class ID of the class to find.
1603 * dwClsContext Class context to match.
1604 * ppv [out] returns a pointer to the class object. Complying
1605 * to normal COM usage, this method will increase the
1606 * reference count on this object.
1608 static HRESULT COM_GetRegisteredClassObject(
1609 struct apartment *apt,
1614 HRESULT hr = S_FALSE;
1615 RegisteredClass *curClass;
1622 EnterCriticalSection( &csRegisteredClassList );
1624 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1627 * Check if we have a match on the class ID and context.
1629 if ((apt->oxid == curClass->apartment_id) &&
1630 (dwClsContext & curClass->runContext) &&
1631 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1634 * We have a match, return the pointer to the class object.
1636 *ppUnk = curClass->classObject;
1638 IUnknown_AddRef(curClass->classObject);
1645 LeaveCriticalSection( &csRegisteredClassList );
1650 /******************************************************************************
1651 * CoRegisterClassObject [OLE32.@]
1653 * Registers the class object for a given class ID. Servers housed in EXE
1654 * files use this method instead of exporting DllGetClassObject to allow
1655 * other code to connect to their objects.
1658 * rclsid [I] CLSID of the object to register.
1659 * pUnk [I] IUnknown of the object.
1660 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1661 * flags [I] REGCLS flags indicating how connections are made.
1662 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1666 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1667 * CO_E_OBJISREG if the object is already registered. We should not return this.
1670 * CoRevokeClassObject, CoGetClassObject
1673 * In-process objects are only registered for the current apartment.
1674 * CoGetClassObject() and CoCreateInstance() will not return objects registered
1675 * in other apartments.
1678 * MSDN claims that multiple interface registrations are legal, but we
1679 * can't do that with our current implementation.
1681 HRESULT WINAPI CoRegisterClassObject(
1686 LPDWORD lpdwRegister)
1688 RegisteredClass* newClass;
1689 LPUNKNOWN foundObject;
1693 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1694 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1696 if ( (lpdwRegister==0) || (pUnk==0) )
1697 return E_INVALIDARG;
1699 apt = COM_CurrentApt();
1702 ERR("COM was not initialized\n");
1703 return CO_E_NOTINITIALIZED;
1708 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1709 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1710 if (flags & REGCLS_MULTIPLEUSE)
1711 dwClsContext |= CLSCTX_INPROC_SERVER;
1714 * First, check if the class is already registered.
1715 * If it is, this should cause an error.
1717 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1719 if (flags & REGCLS_MULTIPLEUSE) {
1720 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1721 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1722 IUnknown_Release(foundObject);
1725 IUnknown_Release(foundObject);
1726 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1727 return CO_E_OBJISREG;
1730 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1731 if ( newClass == NULL )
1732 return E_OUTOFMEMORY;
1734 newClass->classIdentifier = *rclsid;
1735 newClass->apartment_id = apt->oxid;
1736 newClass->runContext = dwClsContext;
1737 newClass->connectFlags = flags;
1738 newClass->pMarshaledData = NULL;
1739 newClass->RpcRegistration = NULL;
1742 * Use the address of the chain node as the cookie since we are sure it's
1743 * unique. FIXME: not on 64-bit platforms.
1745 newClass->dwCookie = (DWORD)newClass;
1748 * Since we're making a copy of the object pointer, we have to increase its
1751 newClass->classObject = pUnk;
1752 IUnknown_AddRef(newClass->classObject);
1754 EnterCriticalSection( &csRegisteredClassList );
1755 list_add_tail(&RegisteredClassList, &newClass->entry);
1756 LeaveCriticalSection( &csRegisteredClassList );
1758 *lpdwRegister = newClass->dwCookie;
1760 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1761 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1763 FIXME("Failed to create stream on hglobal, %x\n", hr);
1766 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1767 newClass->classObject, MSHCTX_LOCAL, NULL,
1768 MSHLFLAGS_TABLESTRONG);
1770 FIXME("CoMarshalInterface failed, %x!\n",hr);
1774 hr = RPC_StartLocalServer(&newClass->classIdentifier,
1775 newClass->pMarshaledData,
1776 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
1777 &newClass->RpcRegistration);
1782 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
1784 list_remove(&curClass->entry);
1786 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
1787 RPC_StopLocalServer(curClass->RpcRegistration);
1790 * Release the reference to the class object.
1792 IUnknown_Release(curClass->classObject);
1794 if (curClass->pMarshaledData)
1797 memset(&zero, 0, sizeof(zero));
1798 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
1799 CoReleaseMarshalData(curClass->pMarshaledData);
1802 HeapFree(GetProcessHeap(), 0, curClass);
1805 static void COM_RevokeAllClasses(struct apartment *apt)
1807 RegisteredClass *curClass, *cursor;
1809 EnterCriticalSection( &csRegisteredClassList );
1811 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
1813 if (curClass->apartment_id == apt->oxid)
1814 COM_RevokeRegisteredClassObject(curClass);
1817 LeaveCriticalSection( &csRegisteredClassList );
1820 /***********************************************************************
1821 * CoRevokeClassObject [OLE32.@]
1823 * Removes a class object from the class registry.
1826 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1830 * Failure: HRESULT code.
1833 * Must be called from the same apartment that called CoRegisterClassObject(),
1834 * otherwise it will fail with RPC_E_WRONG_THREAD.
1837 * CoRegisterClassObject
1839 HRESULT WINAPI CoRevokeClassObject(
1842 HRESULT hr = E_INVALIDARG;
1843 RegisteredClass *curClass;
1846 TRACE("(%08x)\n",dwRegister);
1848 apt = COM_CurrentApt();
1851 ERR("COM was not initialized\n");
1852 return CO_E_NOTINITIALIZED;
1855 EnterCriticalSection( &csRegisteredClassList );
1857 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1860 * Check if we have a match on the cookie.
1862 if (curClass->dwCookie == dwRegister)
1864 if (curClass->apartment_id == apt->oxid)
1866 COM_RevokeRegisteredClassObject(curClass);
1871 ERR("called from wrong apartment, should be called from %s\n",
1872 wine_dbgstr_longlong(curClass->apartment_id));
1873 hr = RPC_E_WRONG_THREAD;
1879 LeaveCriticalSection( &csRegisteredClassList );
1884 /***********************************************************************
1885 * COM_RegReadPath [internal]
1887 * Reads a registry value and expands it when necessary
1889 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1894 WCHAR src[MAX_PATH];
1895 DWORD dwLength = dstlen * sizeof(WCHAR);
1897 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1898 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1899 if (keytype == REG_EXPAND_SZ) {
1900 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1902 lstrcpynW(dst, src, dstlen);
1910 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
1912 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
1915 DWORD dwLength = len * sizeof(WCHAR);
1917 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
1918 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
1922 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
1923 REFCLSID rclsid, REFIID riid, void **ppv)
1925 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
1926 static const WCHAR wszFree[] = {'F','r','e','e',0};
1927 static const WCHAR wszBoth[] = {'B','o','t','h',0};
1928 WCHAR dllpath[MAX_PATH+1];
1929 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
1932 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
1934 if (!strcmpiW(threading_model, wszApartment))
1936 if (apt->multi_threaded)
1938 /* try to find an STA */
1939 APARTMENT *host_apt = apartment_findfromtype(FALSE, FALSE);
1941 FIXME("create a host apartment for apartment-threaded object %s\n", debugstr_guid(rclsid));
1944 struct host_object_params params;
1945 HWND hwnd = apartment_getwindow(host_apt);
1947 params.hkeydll = hkeydll;
1948 params.clsid = *rclsid;
1950 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
1953 hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
1955 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1956 IStream_Release(params.stream);
1962 else if (!strcmpiW(threading_model, wszFree))
1964 if (!apt->multi_threaded)
1966 FIXME("should create object %s in multi-threaded apartment\n",
1967 debugstr_guid(rclsid));
1970 /* everything except "Apartment", "Free" and "Both" */
1971 else if (strcmpiW(threading_model, wszBoth))
1973 /* everything else is main-threaded */
1974 if (threading_model[0])
1975 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
1976 debugstr_w(threading_model), debugstr_guid(rclsid));
1978 if (apt->multi_threaded || !apt->main)
1980 /* try to find an STA */
1981 APARTMENT *host_apt = apartment_findfromtype(FALSE, TRUE);
1983 FIXME("create a host apartment for main-threaded object %s\n", debugstr_guid(rclsid));
1986 struct host_object_params params;
1987 HWND hwnd = apartment_getwindow(host_apt);
1989 params.hkeydll = hkeydll;
1990 params.clsid = *rclsid;
1992 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
1995 hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
1997 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1998 IStream_Release(params.stream);
2004 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2006 /* failure: CLSID is not found in registry */
2007 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2008 return REGDB_E_CLASSNOTREG;
2011 return apartment_getclassobject(apt, dllpath, rclsid, riid, ppv);
2014 /***********************************************************************
2015 * CoGetClassObject [OLE32.@]
2017 * Creates an object of the specified class.
2020 * rclsid [I] Class ID to create an instance of.
2021 * dwClsContext [I] Flags to restrict the location of the created instance.
2022 * pServerInfo [I] Optional. Details for connecting to a remote server.
2023 * iid [I] The ID of the interface of the instance to return.
2024 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2028 * Failure: HRESULT code.
2031 * The dwClsContext parameter can be one or more of the following:
2032 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2033 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2034 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2035 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2038 * CoCreateInstance()
2040 HRESULT WINAPI CoGetClassObject(
2041 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2042 REFIID iid, LPVOID *ppv)
2044 LPUNKNOWN regClassObject;
2045 HRESULT hres = E_UNEXPECTED;
2048 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2051 return E_INVALIDARG;
2055 apt = COM_CurrentApt();
2058 ERR("apartment not initialised\n");
2059 return CO_E_NOTINITIALIZED;
2063 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
2064 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
2068 * First, try and see if we can't match the class ID with one of the
2069 * registered classes.
2071 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2074 /* Get the required interface from the retrieved pointer. */
2075 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2078 * Since QI got another reference on the pointer, we want to release the
2079 * one we already have. If QI was unsuccessful, this will release the object. This
2080 * is good since we are not returning it in the "out" parameter.
2082 IUnknown_Release(regClassObject);
2087 /* First try in-process server */
2088 if (CLSCTX_INPROC_SERVER & dwClsContext)
2090 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2093 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2094 return FTMarshalCF_Create(iid, ppv);
2096 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2099 if (hres == REGDB_E_CLASSNOTREG)
2100 ERR("class %s not registered\n", debugstr_guid(rclsid));
2101 else if (hres == REGDB_E_KEYMISSING)
2103 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2104 hres = REGDB_E_CLASSNOTREG;
2108 if (SUCCEEDED(hres))
2110 hres = get_inproc_class_object(apt, hkey, rclsid, iid, ppv);
2114 /* return if we got a class, otherwise fall through to one of the
2116 if (SUCCEEDED(hres))
2120 /* Next try in-process handler */
2121 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2123 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2126 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2129 if (hres == REGDB_E_CLASSNOTREG)
2130 ERR("class %s not registered\n", debugstr_guid(rclsid));
2131 else if (hres == REGDB_E_KEYMISSING)
2133 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2134 hres = REGDB_E_CLASSNOTREG;
2138 if (SUCCEEDED(hres))
2140 hres = get_inproc_class_object(apt, hkey, rclsid, iid, ppv);
2144 /* return if we got a class, otherwise fall through to one of the
2146 if (SUCCEEDED(hres))
2150 /* Next try out of process */
2151 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2153 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2154 if (SUCCEEDED(hres))
2158 /* Finally try remote: this requires networked DCOM (a lot of work) */
2159 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2161 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2162 hres = E_NOINTERFACE;
2166 ERR("no class object %s could be created for context 0x%x\n",
2167 debugstr_guid(rclsid), dwClsContext);
2171 /***********************************************************************
2172 * CoResumeClassObjects (OLE32.@)
2174 * Resumes all class objects registered with REGCLS_SUSPENDED.
2178 * Failure: HRESULT code.
2180 HRESULT WINAPI CoResumeClassObjects(void)
2186 /***********************************************************************
2187 * CoCreateInstance [OLE32.@]
2189 * Creates an instance of the specified class.
2192 * rclsid [I] Class ID to create an instance of.
2193 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2194 * dwClsContext [I] Flags to restrict the location of the created instance.
2195 * iid [I] The ID of the interface of the instance to return.
2196 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2200 * Failure: HRESULT code.
2203 * The dwClsContext parameter can be one or more of the following:
2204 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2205 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2206 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2207 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2209 * Aggregation is the concept of deferring the IUnknown of an object to another
2210 * object. This allows a separate object to behave as though it was part of
2211 * the object and to allow this the pUnkOuter parameter can be set. Note that
2212 * not all objects support having an outer of unknown.
2215 * CoGetClassObject()
2217 HRESULT WINAPI CoCreateInstance(
2219 LPUNKNOWN pUnkOuter,
2225 LPCLASSFACTORY lpclf = 0;
2227 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2228 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2237 * Initialize the "out" parameter
2241 if (!COM_CurrentApt())
2243 ERR("apartment not initialised\n");
2244 return CO_E_NOTINITIALIZED;
2248 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2249 * Rather than create a class factory, we can just check for it here
2251 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2252 if (StdGlobalInterfaceTableInstance == NULL)
2253 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2254 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2255 if (hres) return hres;
2257 TRACE("Retrieved GIT (%p)\n", *ppv);
2262 * Get a class factory to construct the object we want.
2264 hres = CoGetClassObject(rclsid,
2274 * Create the object and don't forget to release the factory
2276 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2277 IClassFactory_Release(lpclf);
2279 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2280 debugstr_guid(iid), debugstr_guid(rclsid),hres);
2285 /***********************************************************************
2286 * CoCreateInstanceEx [OLE32.@]
2288 HRESULT WINAPI CoCreateInstanceEx(
2290 LPUNKNOWN pUnkOuter,
2292 COSERVERINFO* pServerInfo,
2296 IUnknown* pUnk = NULL;
2299 ULONG successCount = 0;
2304 if ( (cmq==0) || (pResults==NULL))
2305 return E_INVALIDARG;
2307 if (pServerInfo!=NULL)
2308 FIXME("() non-NULL pServerInfo not supported!\n");
2311 * Initialize all the "out" parameters.
2313 for (index = 0; index < cmq; index++)
2315 pResults[index].pItf = NULL;
2316 pResults[index].hr = E_NOINTERFACE;
2320 * Get the object and get its IUnknown pointer.
2322 hr = CoCreateInstance(rclsid,
2332 * Then, query for all the interfaces requested.
2334 for (index = 0; index < cmq; index++)
2336 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2337 pResults[index].pIID,
2338 (VOID**)&(pResults[index].pItf));
2340 if (pResults[index].hr == S_OK)
2345 * Release our temporary unknown pointer.
2347 IUnknown_Release(pUnk);
2349 if (successCount == 0)
2350 return E_NOINTERFACE;
2352 if (successCount!=cmq)
2353 return CO_S_NOTALLINTERFACES;
2358 /***********************************************************************
2359 * CoLoadLibrary (OLE32.@)
2364 * lpszLibName [I] Path to library.
2365 * bAutoFree [I] Whether the library should automatically be freed.
2368 * Success: Handle to loaded library.
2372 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2374 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2376 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2378 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2381 /***********************************************************************
2382 * CoFreeLibrary [OLE32.@]
2384 * Unloads a library from memory.
2387 * hLibrary [I] Handle to library to unload.
2393 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2395 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2397 FreeLibrary(hLibrary);
2401 /***********************************************************************
2402 * CoFreeAllLibraries [OLE32.@]
2404 * Function for backwards compatibility only. Does nothing.
2410 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2412 void WINAPI CoFreeAllLibraries(void)
2418 /***********************************************************************
2419 * CoFreeUnusedLibraries [OLE32.@]
2420 * CoFreeUnusedLibraries [COMPOBJ.17]
2422 * Frees any unused libraries. Unused are identified as those that return
2423 * S_OK from their DllCanUnloadNow function.
2429 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2431 void WINAPI CoFreeUnusedLibraries(void)
2433 struct apartment *apt = COM_CurrentApt();
2436 ERR("apartment not initialised\n");
2440 apartment_freeunusedlibraries(apt);
2443 /***********************************************************************
2444 * CoFileTimeNow [OLE32.@]
2445 * CoFileTimeNow [COMPOBJ.82]
2447 * Retrieves the current time in FILETIME format.
2450 * lpFileTime [O] The current time.
2455 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2457 GetSystemTimeAsFileTime( lpFileTime );
2461 /******************************************************************************
2462 * CoLockObjectExternal [OLE32.@]
2464 * Increments or decrements the external reference count of a stub object.
2467 * pUnk [I] Stub object.
2468 * fLock [I] If TRUE then increments the external ref-count,
2469 * otherwise decrements.
2470 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2471 * calling CoDisconnectObject.
2475 * Failure: HRESULT code.
2478 * If fLock is TRUE and an object is passed in that doesn't have a stub
2479 * manager then a new stub manager is created for the object.
2481 HRESULT WINAPI CoLockObjectExternal(
2484 BOOL fLastUnlockReleases)
2486 struct stub_manager *stubmgr;
2487 struct apartment *apt;
2489 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2490 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2492 apt = COM_CurrentApt();
2493 if (!apt) return CO_E_NOTINITIALIZED;
2495 stubmgr = get_stub_manager_from_object(apt, pUnk);
2500 stub_manager_ext_addref(stubmgr, 1);
2502 stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases);
2504 stub_manager_int_release(stubmgr);
2510 stubmgr = new_stub_manager(apt, pUnk);
2514 stub_manager_ext_addref(stubmgr, 1);
2515 stub_manager_int_release(stubmgr);
2522 WARN("stub object not found %p\n", pUnk);
2523 /* Note: native is pretty broken here because it just silently
2524 * fails, without returning an appropriate error code, making apps
2525 * think that the object was disconnected, when it actually wasn't */
2530 /***********************************************************************
2531 * CoInitializeWOW (OLE32.@)
2533 * WOW equivalent of CoInitialize?
2542 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2544 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2548 /***********************************************************************
2549 * CoGetState [OLE32.@]
2551 * Retrieves the thread state object previously stored by CoSetState().
2554 * ppv [I] Address where pointer to object will be stored.
2558 * Failure: E_OUTOFMEMORY.
2561 * Crashes on all invalid ppv addresses, including NULL.
2562 * If the function returns a non-NULL object then the caller must release its
2563 * reference on the object when the object is no longer required.
2568 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2570 struct oletls *info = COM_CurrentInfo();
2571 if (!info) return E_OUTOFMEMORY;
2577 IUnknown_AddRef(info->state);
2579 TRACE("apt->state=%p\n", info->state);
2585 /***********************************************************************
2586 * CoSetState [OLE32.@]
2588 * Sets the thread state object.
2591 * pv [I] Pointer to state object to be stored.
2594 * The system keeps a reference on the object while the object stored.
2598 * Failure: E_OUTOFMEMORY.
2600 HRESULT WINAPI CoSetState(IUnknown * pv)
2602 struct oletls *info = COM_CurrentInfo();
2603 if (!info) return E_OUTOFMEMORY;
2605 if (pv) IUnknown_AddRef(pv);
2609 TRACE("-- release %p now\n", info->state);
2610 IUnknown_Release(info->state);
2619 /******************************************************************************
2620 * CoTreatAsClass [OLE32.@]
2622 * Sets the TreatAs value of a class.
2625 * clsidOld [I] Class to set TreatAs value on.
2626 * clsidNew [I] The class the clsidOld should be treated as.
2630 * Failure: HRESULT code.
2635 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2637 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2638 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2640 WCHAR szClsidNew[CHARS_IN_GUID];
2642 WCHAR auto_treat_as[CHARS_IN_GUID];
2643 LONG auto_treat_as_size = sizeof(auto_treat_as);
2646 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2649 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2651 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2652 !CLSIDFromString(auto_treat_as, &id))
2654 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2656 res = REGDB_E_WRITEREGDB;
2662 RegDeleteKeyW(hkey, wszTreatAs);
2666 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2667 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2669 res = REGDB_E_WRITEREGDB;
2674 if (hkey) RegCloseKey(hkey);
2678 /******************************************************************************
2679 * CoGetTreatAsClass [OLE32.@]
2681 * Gets the TreatAs value of a class.
2684 * clsidOld [I] Class to get the TreatAs value of.
2685 * clsidNew [I] The class the clsidOld should be treated as.
2689 * Failure: HRESULT code.
2694 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2696 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2698 WCHAR szClsidNew[CHARS_IN_GUID];
2700 LONG len = sizeof(szClsidNew);
2702 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2703 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2705 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2708 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2713 res = CLSIDFromString(szClsidNew,clsidNew);
2715 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2717 if (hkey) RegCloseKey(hkey);
2721 /******************************************************************************
2722 * CoGetCurrentProcess [OLE32.@]
2723 * CoGetCurrentProcess [COMPOBJ.34]
2725 * Gets the current process ID.
2728 * The current process ID.
2731 * Is DWORD really the correct return type for this function?
2733 DWORD WINAPI CoGetCurrentProcess(void)
2735 return GetCurrentProcessId();
2738 /******************************************************************************
2739 * CoRegisterMessageFilter [OLE32.@]
2741 * Registers a message filter.
2744 * lpMessageFilter [I] Pointer to interface.
2745 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2749 * Failure: HRESULT code.
2752 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2753 * lpMessageFilter removes the message filter.
2755 * If lplpMessageFilter is not NULL the previous message filter will be
2756 * returned in the memory pointer to this parameter and the caller is
2757 * responsible for releasing the object.
2759 * The current thread be in an apartment otherwise the function will crash.
2761 HRESULT WINAPI CoRegisterMessageFilter(
2762 LPMESSAGEFILTER lpMessageFilter,
2763 LPMESSAGEFILTER *lplpMessageFilter)
2765 struct apartment *apt;
2766 IMessageFilter *lpOldMessageFilter;
2768 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2770 apt = COM_CurrentApt();
2772 /* can't set a message filter in a multi-threaded apartment */
2773 if (!apt || apt->multi_threaded)
2775 WARN("can't set message filter in MTA or uninitialized apt\n");
2776 return CO_E_NOT_SUPPORTED;
2779 if (lpMessageFilter)
2780 IMessageFilter_AddRef(lpMessageFilter);
2782 EnterCriticalSection(&apt->cs);
2784 lpOldMessageFilter = apt->filter;
2785 apt->filter = lpMessageFilter;
2787 LeaveCriticalSection(&apt->cs);
2789 if (lplpMessageFilter)
2790 *lplpMessageFilter = lpOldMessageFilter;
2791 else if (lpOldMessageFilter)
2792 IMessageFilter_Release(lpOldMessageFilter);
2797 /***********************************************************************
2798 * CoIsOle1Class [OLE32.@]
2800 * Determines whether the specified class an OLE v1 class.
2803 * clsid [I] Class to test.
2806 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2808 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2810 FIXME("%s\n", debugstr_guid(clsid));
2814 /***********************************************************************
2815 * IsEqualGUID [OLE32.@]
2817 * Compares two Unique Identifiers.
2820 * rguid1 [I] The first GUID to compare.
2821 * rguid2 [I] The other GUID to compare.
2827 BOOL WINAPI IsEqualGUID(
2831 return !memcmp(rguid1,rguid2,sizeof(GUID));
2834 /***********************************************************************
2835 * CoInitializeSecurity [OLE32.@]
2837 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2838 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2839 void* pReserved1, DWORD dwAuthnLevel,
2840 DWORD dwImpLevel, void* pReserved2,
2841 DWORD dwCapabilities, void* pReserved3)
2843 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
2844 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2845 dwCapabilities, pReserved3);
2849 /***********************************************************************
2850 * CoSuspendClassObjects [OLE32.@]
2852 * Suspends all registered class objects to prevent further requests coming in
2853 * for those objects.
2857 * Failure: HRESULT code.
2859 HRESULT WINAPI CoSuspendClassObjects(void)
2865 /***********************************************************************
2866 * CoAddRefServerProcess [OLE32.@]
2868 * Helper function for incrementing the reference count of a local-server
2872 * New reference count.
2875 * CoReleaseServerProcess().
2877 ULONG WINAPI CoAddRefServerProcess(void)
2883 EnterCriticalSection(&csRegisteredClassList);
2884 refs = ++s_COMServerProcessReferences;
2885 LeaveCriticalSection(&csRegisteredClassList);
2887 TRACE("refs before: %d\n", refs - 1);
2892 /***********************************************************************
2893 * CoReleaseServerProcess [OLE32.@]
2895 * Helper function for decrementing the reference count of a local-server
2899 * New reference count.
2902 * When reference count reaches 0, this function suspends all registered
2903 * classes so no new connections are accepted.
2906 * CoAddRefServerProcess(), CoSuspendClassObjects().
2908 ULONG WINAPI CoReleaseServerProcess(void)
2914 EnterCriticalSection(&csRegisteredClassList);
2916 refs = --s_COMServerProcessReferences;
2917 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
2919 LeaveCriticalSection(&csRegisteredClassList);
2921 TRACE("refs after: %d\n", refs);
2926 /***********************************************************************
2927 * CoIsHandlerConnected [OLE32.@]
2929 * Determines whether a proxy is connected to a remote stub.
2932 * pUnk [I] Pointer to object that may or may not be connected.
2935 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2938 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2940 FIXME("%p\n", pUnk);
2945 /***********************************************************************
2946 * CoAllowSetForegroundWindow [OLE32.@]
2949 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2951 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2955 /***********************************************************************
2956 * CoQueryProxyBlanket [OLE32.@]
2958 * Retrieves the security settings being used by a proxy.
2961 * pProxy [I] Pointer to the proxy object.
2962 * pAuthnSvc [O] The type of authentication service.
2963 * pAuthzSvc [O] The type of authorization service.
2964 * ppServerPrincName [O] Optional. The server prinicple name.
2965 * pAuthnLevel [O] The authentication level.
2966 * pImpLevel [O] The impersonation level.
2967 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2968 * pCapabilities [O] Flags affecting the security behaviour.
2972 * Failure: HRESULT code.
2975 * CoCopyProxy, CoSetProxyBlanket.
2977 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2978 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2979 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2981 IClientSecurity *pCliSec;
2984 TRACE("%p\n", pProxy);
2986 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2989 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2990 pAuthzSvc, ppServerPrincName,
2991 pAuthnLevel, pImpLevel, ppAuthInfo,
2993 IClientSecurity_Release(pCliSec);
2996 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3000 /***********************************************************************
3001 * CoSetProxyBlanket [OLE32.@]
3003 * Sets the security settings for a proxy.
3006 * pProxy [I] Pointer to the proxy object.
3007 * AuthnSvc [I] The type of authentication service.
3008 * AuthzSvc [I] The type of authorization service.
3009 * pServerPrincName [I] The server prinicple name.
3010 * AuthnLevel [I] The authentication level.
3011 * ImpLevel [I] The impersonation level.
3012 * pAuthInfo [I] Information specific to the authorization/authentication service.
3013 * Capabilities [I] Flags affecting the security behaviour.
3017 * Failure: HRESULT code.
3020 * CoQueryProxyBlanket, CoCopyProxy.
3022 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3023 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3024 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3026 IClientSecurity *pCliSec;
3029 TRACE("%p\n", pProxy);
3031 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3034 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3035 AuthzSvc, pServerPrincName,
3036 AuthnLevel, ImpLevel, pAuthInfo,
3038 IClientSecurity_Release(pCliSec);
3041 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3045 /***********************************************************************
3046 * CoCopyProxy [OLE32.@]
3051 * pProxy [I] Pointer to the proxy object.
3052 * ppCopy [O] Copy of the proxy.
3056 * Failure: HRESULT code.
3059 * CoQueryProxyBlanket, CoSetProxyBlanket.
3061 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3063 IClientSecurity *pCliSec;
3066 TRACE("%p\n", pProxy);
3068 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3071 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3072 IClientSecurity_Release(pCliSec);
3075 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3080 /***********************************************************************
3081 * CoGetCallContext [OLE32.@]
3083 * Gets the context of the currently executing server call in the current
3087 * riid [I] Context interface to return.
3088 * ppv [O] Pointer to memory that will receive the context on return.
3092 * Failure: HRESULT code.
3094 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3096 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
3099 return E_NOINTERFACE;
3102 /***********************************************************************
3103 * CoQueryClientBlanket [OLE32.@]
3105 * Retrieves the authentication information about the client of the currently
3106 * executing server call in the current thread.
3109 * pAuthnSvc [O] Optional. The type of authentication service.
3110 * pAuthzSvc [O] Optional. The type of authorization service.
3111 * pServerPrincName [O] Optional. The server prinicple name.
3112 * pAuthnLevel [O] Optional. The authentication level.
3113 * pImpLevel [O] Optional. The impersonation level.
3114 * pPrivs [O] Optional. Information about the privileges of the client.
3115 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3119 * Failure: HRESULT code.
3122 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3124 HRESULT WINAPI CoQueryClientBlanket(
3127 OLECHAR **pServerPrincName,
3130 RPC_AUTHZ_HANDLE *pPrivs,
3131 DWORD *pCapabilities)
3133 IServerSecurity *pSrvSec;
3136 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3137 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3138 pPrivs, pCapabilities);
3140 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3143 hr = IServerSecurity_QueryBlanket(
3144 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3145 pImpLevel, pPrivs, pCapabilities);
3146 IServerSecurity_Release(pSrvSec);
3152 /***********************************************************************
3153 * CoImpersonateClient [OLE32.@]
3155 * Impersonates the client of the currently executing server call in the
3163 * Failure: HRESULT code.
3166 * If this function fails then the current thread will not be impersonating
3167 * the client and all actions will take place on behalf of the server.
3168 * Therefore, it is important to check the return value from this function.
3171 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3173 HRESULT WINAPI CoImpersonateClient(void)
3175 IServerSecurity *pSrvSec;
3180 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3183 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3184 IServerSecurity_Release(pSrvSec);
3190 /***********************************************************************
3191 * CoRevertToSelf [OLE32.@]
3193 * Ends the impersonation of the client of the currently executing server
3194 * call in the current thread.
3201 * Failure: HRESULT code.
3204 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3206 HRESULT WINAPI CoRevertToSelf(void)
3208 IServerSecurity *pSrvSec;
3213 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3216 hr = IServerSecurity_RevertToSelf(pSrvSec);
3217 IServerSecurity_Release(pSrvSec);
3223 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3225 /* first try to retrieve messages for incoming COM calls to the apartment window */
3226 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3227 /* next retrieve other messages necessary for the app to remain responsive */
3228 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
3231 /***********************************************************************
3232 * CoWaitForMultipleHandles [OLE32.@]
3234 * Waits for one or more handles to become signaled.
3237 * dwFlags [I] Flags. See notes.
3238 * dwTimeout [I] Timeout in milliseconds.
3239 * cHandles [I] Number of handles pointed to by pHandles.
3240 * pHandles [I] Handles to wait for.
3241 * lpdwindex [O] Index of handle that was signaled.
3245 * Failure: RPC_S_CALLPENDING on timeout.
3249 * The dwFlags parameter can be zero or more of the following:
3250 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3251 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3254 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3256 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3257 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3260 DWORD start_time = GetTickCount();
3261 APARTMENT *apt = COM_CurrentApt();
3262 BOOL message_loop = apt && !apt->multi_threaded;
3264 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3265 pHandles, lpdwindex);
3269 DWORD now = GetTickCount();
3272 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
3274 hr = RPC_S_CALLPENDING;
3280 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
3281 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
3283 TRACE("waiting for rpc completion or window message\n");
3285 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3286 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3287 QS_ALLINPUT, wait_flags);
3289 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3293 /* call message filter */
3295 if (COM_CurrentApt()->filter)
3297 PENDINGTYPE pendingtype =
3298 COM_CurrentInfo()->pending_call_count_server ?
3299 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3300 DWORD be_handled = IMessageFilter_MessagePending(
3301 COM_CurrentApt()->filter, 0 /* FIXME */,
3302 now - start_time, pendingtype);
3303 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3306 case PENDINGMSG_CANCELCALL:
3307 WARN("call canceled\n");
3308 hr = RPC_E_CALL_CANCELED;
3310 case PENDINGMSG_WAITNOPROCESS:
3311 case PENDINGMSG_WAITDEFPROCESS:
3313 /* FIXME: MSDN is very vague about the difference
3314 * between WAITNOPROCESS and WAITDEFPROCESS - there
3315 * appears to be none, so it is possibly a left-over
3316 * from the 16-bit world. */
3321 /* note: using "if" here instead of "while" might seem less
3322 * efficient, but only if we are optimising for quick delivery
3323 * of pending messages, rather than quick completion of the
3325 if (COM_PeekMessage(apt, &msg))
3327 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3328 TranslateMessage(&msg);
3329 DispatchMessageW(&msg);
3330 if (msg.message == WM_QUIT)
3332 TRACE("resending WM_QUIT to outer message loop\n");
3333 PostQuitMessage(msg.wParam);
3334 /* no longer need to process messages */
3335 message_loop = FALSE;
3343 TRACE("waiting for rpc completion\n");
3345 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3346 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3347 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3348 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3351 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
3353 /* handle signaled, store index */
3354 *lpdwindex = (res - WAIT_OBJECT_0);
3357 else if (res == WAIT_TIMEOUT)
3359 hr = RPC_S_CALLPENDING;
3364 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3369 TRACE("-- 0x%08x\n", hr);
3374 /***********************************************************************
3375 * CoGetObject [OLE32.@]
3377 * Gets the object named by coverting the name to a moniker and binding to it.
3380 * pszName [I] String representing the object.
3381 * pBindOptions [I] Parameters affecting the binding to the named object.
3382 * riid [I] Interface to bind to on the objecct.
3383 * ppv [O] On output, the interface riid of the object represented
3388 * Failure: HRESULT code.
3391 * MkParseDisplayName.
3393 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3394 REFIID riid, void **ppv)
3401 hr = CreateBindCtx(0, &pbc);
3405 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3412 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3415 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3416 IMoniker_Release(pmk);
3420 IBindCtx_Release(pbc);
3425 /***********************************************************************
3426 * CoRegisterChannelHook [OLE32.@]
3428 * Registers a process-wide hook that is called during ORPC calls.
3431 * guidExtension [I] GUID of the channel hook to register.
3432 * pChannelHook [I] Channel hook object to register.
3436 * Failure: HRESULT code.
3438 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3440 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3442 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3445 /***********************************************************************
3448 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3450 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3453 case DLL_PROCESS_ATTACH:
3454 OLE32_hInstance = hinstDLL;
3455 COMPOBJ_InitProcess();
3456 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3459 case DLL_PROCESS_DETACH:
3460 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3461 OLEDD_UnInitialize();
3462 COMPOBJ_UninitProcess();
3463 RPC_UnregisterAllChannelHooks();
3464 OLE32_hInstance = 0;
3467 case DLL_THREAD_DETACH:
3474 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */