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);
191 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
192 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
193 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry);
195 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
197 static void COMPOBJ_InitProcess( void )
201 /* Dispatching to the correct thread in an apartment is done through
202 * window messages rather than RPC transports. When an interface is
203 * marshalled into another apartment in the same process, a window of the
204 * following class is created. The *caller* of CoMarshalInterface (ie the
205 * application) is responsible for pumping the message loop in that thread.
206 * The WM_USER messages which point to the RPCs are then dispatched to
207 * COM_AptWndProc by the user's code from the apartment in which the interface
210 memset(&wclass, 0, sizeof(wclass));
211 wclass.lpfnWndProc = apartment_wndproc;
212 wclass.hInstance = OLE32_hInstance;
213 wclass.lpszClassName = wszAptWinClass;
214 RegisterClassW(&wclass);
217 static void COMPOBJ_UninitProcess( void )
219 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
222 static void COM_TlsDestroy(void)
224 struct oletls *info = NtCurrentTeb()->ReservedForOle;
227 if (info->apt) apartment_release(info->apt);
228 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
229 if (info->state) IUnknown_Release(info->state);
230 HeapFree(GetProcessHeap(), 0, info);
231 NtCurrentTeb()->ReservedForOle = NULL;
235 /******************************************************************************
239 /* allocates memory and fills in the necessary fields for a new apartment
240 * object. must be called inside apartment cs */
241 static APARTMENT *apartment_construct(DWORD model)
245 TRACE("creating new apartment, model=%d\n", model);
247 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
248 apt->tid = GetCurrentThreadId();
250 list_init(&apt->proxies);
251 list_init(&apt->stubmgrs);
252 list_init(&apt->psclsids);
253 list_init(&apt->loaded_dlls);
256 apt->remunk_exported = FALSE;
258 InitializeCriticalSection(&apt->cs);
259 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
261 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
263 if (apt->multi_threaded)
265 /* FIXME: should be randomly generated by in an RPC call to rpcss */
266 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
270 /* FIXME: should be randomly generated by in an RPC call to rpcss */
271 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
274 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
276 list_add_head(&apts, &apt->entry);
281 /* gets and existing apartment if one exists or otherwise creates an apartment
282 * structure which stores OLE apartment-local information and stores a pointer
283 * to it in the thread-local storage */
284 static APARTMENT *apartment_get_or_create(DWORD model)
286 APARTMENT *apt = COM_CurrentApt();
290 if (model & COINIT_APARTMENTTHREADED)
292 EnterCriticalSection(&csApartment);
294 apt = apartment_construct(model);
299 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
302 LeaveCriticalSection(&csApartment);
306 EnterCriticalSection(&csApartment);
308 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
309 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
313 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
314 apartment_addref(MTA);
317 MTA = apartment_construct(model);
321 LeaveCriticalSection(&csApartment);
323 COM_CurrentInfo()->apt = apt;
329 static inline BOOL apartment_is_model(APARTMENT *apt, DWORD model)
331 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
334 DWORD apartment_addref(struct apartment *apt)
336 DWORD refs = InterlockedIncrement(&apt->refs);
337 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
341 DWORD apartment_release(struct apartment *apt)
345 EnterCriticalSection(&csApartment);
347 ret = InterlockedDecrement(&apt->refs);
348 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
349 /* destruction stuff that needs to happen under csApartment CS */
352 if (apt == MTA) MTA = NULL;
353 else if (apt == MainApartment) MainApartment = NULL;
354 list_remove(&apt->entry);
357 LeaveCriticalSection(&csApartment);
361 struct list *cursor, *cursor2;
363 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
365 /* Release the references to the registered class objects */
366 COM_RevokeAllClasses(apt);
368 /* no locking is needed for this apartment, because no other thread
369 * can access it at this point */
371 apartment_disconnectproxies(apt);
373 if (apt->win) DestroyWindow(apt->win);
375 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
377 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
378 /* release the implicit reference given by the fact that the
379 * stub has external references (it must do since it is in the
380 * stub manager list in the apartment and all non-apartment users
381 * must have a ref on the apartment and so it cannot be destroyed).
383 stub_manager_int_release(stubmgr);
386 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
388 struct registered_psclsid *registered_psclsid =
389 LIST_ENTRY(cursor, struct registered_psclsid, entry);
391 list_remove(®istered_psclsid->entry);
392 HeapFree(GetProcessHeap(), 0, registered_psclsid);
395 /* if this assert fires, then another thread took a reference to a
396 * stub manager without taking a reference to the containing
397 * apartment, which it must do. */
398 assert(list_empty(&apt->stubmgrs));
400 if (apt->filter) IUnknown_Release(apt->filter);
402 while ((cursor = list_head(&apt->loaded_dlls)))
404 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
405 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll);
407 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
410 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
411 DeleteCriticalSection(&apt->cs);
413 HeapFree(GetProcessHeap(), 0, apt);
419 /* The given OXID must be local to this process:
421 * The ref parameter is here mostly to ensure people remember that
422 * they get one, you should normally take a ref for thread safety.
424 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
426 APARTMENT *result = NULL;
429 EnterCriticalSection(&csApartment);
430 LIST_FOR_EACH( cursor, &apts )
432 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
433 if (apt->oxid == oxid)
436 if (ref) apartment_addref(result);
440 LeaveCriticalSection(&csApartment);
445 /* gets the apartment which has a given creator thread ID. The caller must
446 * release the reference from the apartment as soon as the apartment pointer
447 * is no longer required. */
448 APARTMENT *apartment_findfromtid(DWORD tid)
450 APARTMENT *result = NULL;
453 EnterCriticalSection(&csApartment);
454 LIST_FOR_EACH( cursor, &apts )
456 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
460 apartment_addref(result);
464 LeaveCriticalSection(&csApartment);
469 /* gets an apartment which has a given type. The caller must
470 * release the reference from the apartment as soon as the apartment pointer
471 * is no longer required. */
472 static APARTMENT *apartment_findfromtype(BOOL multi_threaded, BOOL main_apartment)
474 APARTMENT *result = NULL;
475 struct apartment *apt;
477 EnterCriticalSection(&csApartment);
479 if (!multi_threaded && main_apartment)
481 result = MainApartment;
482 if (result) apartment_addref(result);
483 LeaveCriticalSection(&csApartment);
487 LIST_FOR_EACH_ENTRY( apt, &apts, struct apartment, entry )
489 if (apt->multi_threaded == multi_threaded)
492 apartment_addref(result);
496 LeaveCriticalSection(&csApartment);
501 struct host_object_params
504 CLSID clsid; /* clsid of object to marshal */
505 IID iid; /* interface to marshal */
506 IStream *stream; /* stream that the object will be marshaled into */
509 static HRESULT apartment_hostobject(struct apartment *apt,
510 const struct host_object_params *params)
514 static const LARGE_INTEGER llZero;
515 WCHAR dllpath[MAX_PATH+1];
519 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
521 /* failure: CLSID is not found in registry */
522 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid));
523 return REGDB_E_CLASSNOTREG;
526 hr = apartment_getclassobject(apt, dllpath, ¶ms->clsid, ¶ms->iid, (void **)&object);
530 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
532 IUnknown_Release(object);
533 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
538 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
543 RPC_ExecuteCall((struct dispatch_params *)lParam);
546 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
548 return DefWindowProcW(hWnd, msg, wParam, lParam);
552 HRESULT apartment_createwindowifneeded(struct apartment *apt)
554 if (apt->multi_threaded)
559 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
561 0, 0, OLE32_hInstance, NULL);
564 ERR("CreateWindow failed with error %d\n", GetLastError());
565 return HRESULT_FROM_WIN32(GetLastError());
567 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
568 /* someone beat us to it */
575 HWND apartment_getwindow(struct apartment *apt)
577 assert(!apt->multi_threaded);
581 void apartment_joinmta(void)
583 apartment_addref(MTA);
584 COM_CurrentInfo()->apt = MTA;
587 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
588 REFCLSID rclsid, REFIID riid, void **ppv)
592 struct apartment_loaded_dll *apartment_loaded_dll;
594 EnterCriticalSection(&apt->cs);
596 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
597 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
599 TRACE("found %s already loaded\n", debugstr_w(dllpath));
606 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
607 if (!apartment_loaded_dll)
611 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
613 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
617 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
618 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
622 LeaveCriticalSection(&apt->cs);
626 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
627 /* OK: get the ClassObject */
628 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
631 ERR("DllGetClassObject returned error 0x%08x\n", hr);
637 static void apartment_freeunusedlibraries(struct apartment *apt)
639 struct apartment_loaded_dll *entry, *next;
640 EnterCriticalSection(&apt->cs);
641 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
643 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
645 list_remove(&entry->entry);
646 COMPOBJ_DllList_ReleaseRef(entry->dll);
647 HeapFree(GetProcessHeap(), 0, entry);
650 LeaveCriticalSection(&apt->cs);
653 /*****************************************************************************
654 * This section contains OpenDllList implementation
657 /* caller must ensure that library_name is not already in the open dll list */
658 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
664 DllCanUnloadNowFunc DllCanUnloadNow;
665 DllGetClassObjectFunc DllGetClassObject;
669 *ret = COMPOBJ_DllList_Get(library_name);
670 if (*ret) return S_OK;
672 /* do this outside the csOpenDllList to avoid creating a lock dependency on
674 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
677 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
678 /* failure: DLL could not be loaded */
679 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
682 DllCanUnloadNow = GetProcAddress(hLibrary, "DllCanUnloadNow");
683 /* Note: failing to find DllCanUnloadNow is not a failure */
684 DllGetClassObject = GetProcAddress(hLibrary, "DllGetClassObject");
685 if (!DllGetClassObject)
687 /* failure: the dll did not export DllGetClassObject */
688 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
689 FreeLibrary(hLibrary);
690 return CO_E_DLLNOTFOUND;
693 EnterCriticalSection( &csOpenDllList );
695 *ret = COMPOBJ_DllList_Get(library_name);
698 /* another caller to this function already added the dll while we
699 * weren't in the critical section */
700 FreeLibrary(hLibrary);
704 len = strlenW(library_name);
705 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
707 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
708 if (entry && entry->library_name)
710 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
711 entry->library = hLibrary;
713 entry->DllCanUnloadNow = DllCanUnloadNow;
714 entry->DllGetClassObject = DllGetClassObject;
715 list_add_tail(&openDllList, &entry->entry);
720 FreeLibrary(hLibrary);
725 LeaveCriticalSection( &csOpenDllList );
730 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
734 EnterCriticalSection(&csOpenDllList);
735 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
737 if (!strcmpiW(library_name, ptr->library_name) &&
738 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
744 LeaveCriticalSection(&csOpenDllList);
748 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry)
750 if (!InterlockedDecrement(&entry->refs))
752 EnterCriticalSection(&csOpenDllList);
753 list_remove(&entry->entry);
754 LeaveCriticalSection(&csOpenDllList);
756 TRACE("freeing %p\n", entry->library);
757 FreeLibrary(entry->library);
759 HeapFree(GetProcessHeap(), 0, entry->library_name);
760 HeapFree(GetProcessHeap(), 0, entry);
764 /******************************************************************************
765 * CoBuildVersion [OLE32.@]
766 * CoBuildVersion [COMPOBJ.1]
768 * Gets the build version of the DLL.
773 * Current build version, hiword is majornumber, loword is minornumber
775 DWORD WINAPI CoBuildVersion(void)
777 TRACE("Returning version %d, build %d.\n", rmm, rup);
778 return (rmm<<16)+rup;
781 /******************************************************************************
782 * CoInitialize [OLE32.@]
784 * Initializes the COM libraries by calling CoInitializeEx with
785 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
788 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
791 * Success: S_OK if not already initialized, S_FALSE otherwise.
792 * Failure: HRESULT code.
797 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
800 * Just delegate to the newer method.
802 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
805 /******************************************************************************
806 * CoInitializeEx [OLE32.@]
808 * Initializes the COM libraries.
811 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
812 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
815 * S_OK if successful,
816 * S_FALSE if this function was called already.
817 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
822 * The behavior used to set the IMalloc used for memory management is
824 * The dwCoInit parameter must specify one of the following apartment
826 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
827 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
828 * The parameter may also specify zero or more of the following flags:
829 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
830 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
835 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
840 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
842 if (lpReserved!=NULL)
844 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
848 * Check the lock count. If this is the first time going through the initialize
849 * process, we have to initialize the libraries.
851 * And crank-up that lock count.
853 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
856 * Initialize the various COM libraries and data structures.
858 TRACE("() - Initializing the COM libraries\n");
860 /* we may need to defer this until after apartment initialisation */
861 RunningObjectTableImpl_Initialize();
864 if (!(apt = COM_CurrentInfo()->apt))
866 apt = apartment_get_or_create(dwCoInit);
867 if (!apt) return E_OUTOFMEMORY;
869 else if (!apartment_is_model(apt, dwCoInit))
871 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
872 code then we are probably using the wrong threading model to implement that API. */
873 ERR("Attempt to change threading model of this apartment from %s to %s\n",
874 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
875 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
876 return RPC_E_CHANGED_MODE;
881 COM_CurrentInfo()->inits++;
886 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
887 pending RPCs are ignored. Non-COM messages are discarded at this point.
889 static void COM_FlushMessageQueue(void)
892 APARTMENT *apt = COM_CurrentApt();
894 if (!apt || !apt->win) return;
896 TRACE("Flushing STA message queue\n");
898 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
900 if (message.hwnd != apt->win)
902 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
906 TranslateMessage(&message);
907 DispatchMessageA(&message);
911 /***********************************************************************
912 * CoUninitialize [OLE32.@]
914 * This method will decrement the refcount on the current apartment, freeing
915 * the resources associated with it if it is the last thread in the apartment.
916 * If the last apartment is freed, the function will additionally release
917 * any COM resources associated with the process.
927 void WINAPI CoUninitialize(void)
929 struct oletls * info = COM_CurrentInfo();
934 /* will only happen on OOM */
940 ERR("Mismatched CoUninitialize\n");
946 apartment_release(info->apt);
951 * Decrease the reference count.
952 * If we are back to 0 locks on the COM library, make sure we free
953 * all the associated data structures.
955 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
958 TRACE("() - Releasing the COM libraries\n");
960 RunningObjectTableImpl_UnInitialize();
962 /* This will free the loaded COM Dlls */
963 CoFreeAllLibraries();
965 /* This ensures we deal with any pending RPCs */
966 COM_FlushMessageQueue();
968 else if (lCOMRefCnt<1) {
969 ERR( "CoUninitialize() - not CoInitialized.\n" );
970 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
974 /******************************************************************************
975 * CoDisconnectObject [OLE32.@]
977 * Disconnects all connections to this object from remote processes. Dispatches
978 * pending RPCs while blocking new RPCs from occurring, and then calls
979 * IMarshal::DisconnectObject on the given object.
981 * Typically called when the object server is forced to shut down, for instance by
985 * lpUnk [I] The object whose stub should be disconnected.
986 * reserved [I] Reserved. Should be set to 0.
990 * Failure: HRESULT code.
993 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
995 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1001 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1003 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1006 hr = IMarshal_DisconnectObject(marshal, reserved);
1007 IMarshal_Release(marshal);
1011 apt = COM_CurrentApt();
1013 return CO_E_NOTINITIALIZED;
1015 apartment_disconnectobject(apt, lpUnk);
1017 /* Note: native is pretty broken here because it just silently
1018 * fails, without returning an appropriate error code if the object was
1019 * not found, making apps think that the object was disconnected, when
1020 * it actually wasn't */
1025 /******************************************************************************
1026 * CoCreateGuid [OLE32.@]
1028 * Simply forwards to UuidCreate in RPCRT4.
1031 * pguid [O] Points to the GUID to initialize.
1035 * Failure: HRESULT code.
1040 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1042 return UuidCreate(pguid);
1045 /******************************************************************************
1046 * CLSIDFromString [OLE32.@]
1047 * IIDFromString [OLE32.@]
1049 * Converts a unique identifier from its string representation into
1053 * idstr [I] The string representation of the GUID.
1054 * id [O] GUID converted from the string.
1058 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1063 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
1069 memset( id, 0, sizeof (CLSID) );
1073 /* validate the CLSID string */
1074 if (strlenW(s) != 38)
1075 return CO_E_CLASSSTRING;
1077 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1078 return CO_E_CLASSSTRING;
1080 for (i=1; i<37; i++) {
1081 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1082 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1083 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1084 ((s[i] >= 'A') && (s[i] <= 'F'))))
1085 return CO_E_CLASSSTRING;
1088 TRACE("%s -> %p\n", debugstr_w(s), id);
1090 /* quick lookup table */
1091 memset(table, 0, 256);
1093 for (i = 0; i < 10; i++) {
1096 for (i = 0; i < 6; i++) {
1097 table['A' + i] = i+10;
1098 table['a' + i] = i+10;
1101 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1103 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1104 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1105 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1106 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1108 /* these are just sequential bytes */
1109 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1110 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1111 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1112 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1113 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1114 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1115 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1116 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1121 /*****************************************************************************/
1123 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1128 return E_INVALIDARG;
1130 ret = __CLSIDFromString(idstr, id);
1131 if(ret != S_OK) { /* It appears a ProgID is also valid */
1132 ret = CLSIDFromProgID(idstr, id);
1137 /* Converts a GUID into the respective string representation. */
1138 HRESULT WINE_StringFromCLSID(
1139 const CLSID *id, /* [in] GUID to be converted */
1140 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
1142 static const char hex[] = "0123456789ABCDEF";
1147 { ERR("called with id=Null\n");
1152 sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
1153 id->Data1, id->Data2, id->Data3,
1154 id->Data4[0], id->Data4[1]);
1158 for (i = 2; i < 8; i++) {
1159 *s++ = hex[id->Data4[i]>>4];
1160 *s++ = hex[id->Data4[i] & 0xf];
1166 TRACE("%p->%s\n", id, idstr);
1172 /******************************************************************************
1173 * StringFromCLSID [OLE32.@]
1174 * StringFromIID [OLE32.@]
1176 * Converts a GUID into the respective string representation.
1177 * The target string is allocated using the OLE IMalloc.
1180 * id [I] the GUID to be converted.
1181 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1188 * StringFromGUID2, CLSIDFromString
1190 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1196 if ((ret = CoGetMalloc(0,&mllc)))
1199 ret=WINE_StringFromCLSID(id,buf);
1201 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1202 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1203 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1208 /******************************************************************************
1209 * StringFromGUID2 [OLE32.@]
1210 * StringFromGUID2 [COMPOBJ.76]
1212 * Modified version of StringFromCLSID that allows you to specify max
1216 * id [I] GUID to convert to string.
1217 * str [O] Buffer where the result will be stored.
1218 * cmax [I] Size of the buffer in characters.
1221 * Success: The length of the resulting string in characters.
1224 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1228 if (WINE_StringFromCLSID(id,xguid))
1230 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1233 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1234 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1236 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1237 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1241 strcpyW(path, wszCLSIDSlash);
1242 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1243 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1244 if (res == ERROR_FILE_NOT_FOUND)
1245 return REGDB_E_CLASSNOTREG;
1246 else if (res != ERROR_SUCCESS)
1247 return REGDB_E_READREGDB;
1255 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1257 if (res == ERROR_FILE_NOT_FOUND)
1258 return REGDB_E_KEYMISSING;
1259 else if (res != ERROR_SUCCESS)
1260 return REGDB_E_READREGDB;
1265 /* open HKCR\\AppId\\{string form of appid clsid} key */
1266 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1268 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1269 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1271 WCHAR buf[CHARS_IN_GUID];
1272 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1278 /* read the AppID value under the class's key */
1279 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1284 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1286 if (res == ERROR_FILE_NOT_FOUND)
1287 return REGDB_E_KEYMISSING;
1288 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1289 return REGDB_E_READREGDB;
1291 strcpyW(keyname, szAppIdKey);
1292 strcatW(keyname, buf);
1293 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1294 if (res == ERROR_FILE_NOT_FOUND)
1295 return REGDB_E_KEYMISSING;
1296 else if (res != ERROR_SUCCESS)
1297 return REGDB_E_READREGDB;
1302 /******************************************************************************
1303 * ProgIDFromCLSID [OLE32.@]
1305 * Converts a class id into the respective program ID.
1308 * clsid [I] Class ID, as found in registry.
1309 * ppszProgID [O] Associated ProgID.
1314 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1316 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1318 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1325 ERR("ppszProgId isn't optional\n");
1326 return E_INVALIDARG;
1330 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1334 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1335 ret = REGDB_E_CLASSNOTREG;
1339 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1342 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1343 ret = REGDB_E_CLASSNOTREG;
1346 ret = E_OUTOFMEMORY;
1353 /******************************************************************************
1354 * CLSIDFromProgID [OLE32.@]
1356 * Converts a program id into the respective GUID.
1359 * progid [I] Unicode program ID, as found in registry.
1360 * clsid [O] Associated CLSID.
1364 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1366 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1368 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1369 WCHAR buf2[CHARS_IN_GUID];
1370 LONG buf2len = sizeof(buf2);
1374 if (!progid || !clsid)
1376 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1377 return E_INVALIDARG;
1380 /* initialise clsid in case of failure */
1381 memset(clsid, 0, sizeof(*clsid));
1383 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1384 strcpyW( buf, progid );
1385 strcatW( buf, clsidW );
1386 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1388 HeapFree(GetProcessHeap(),0,buf);
1389 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1390 return CO_E_CLASSSTRING;
1392 HeapFree(GetProcessHeap(),0,buf);
1394 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1397 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1398 return CO_E_CLASSSTRING;
1401 return CLSIDFromString(buf2,clsid);
1405 /*****************************************************************************
1406 * CoGetPSClsid [OLE32.@]
1408 * Retrieves the CLSID of the proxy/stub factory that implements
1409 * IPSFactoryBuffer for the specified interface.
1412 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1413 * pclsid [O] Where to store returned proxy/stub CLSID.
1418 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1422 * The standard marshaller activates the object with the CLSID
1423 * returned and uses the CreateProxy and CreateStub methods on its
1424 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1427 * CoGetPSClsid determines this CLSID by searching the
1428 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1429 * in the registry and any interface id registered by
1430 * CoRegisterPSClsid within the current process.
1434 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1435 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1436 * considered a bug in native unless an application depends on this (unlikely).
1439 * CoRegisterPSClsid.
1441 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1443 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1444 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1445 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1446 WCHAR value[CHARS_IN_GUID];
1449 APARTMENT *apt = COM_CurrentApt();
1450 struct registered_psclsid *registered_psclsid;
1452 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1456 ERR("apartment not initialised\n");
1457 return CO_E_NOTINITIALIZED;
1462 ERR("pclsid isn't optional\n");
1463 return E_INVALIDARG;
1466 EnterCriticalSection(&apt->cs);
1468 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1469 if (IsEqualIID(®istered_psclsid->iid, riid))
1471 *pclsid = registered_psclsid->clsid;
1472 LeaveCriticalSection(&apt->cs);
1476 LeaveCriticalSection(&apt->cs);
1478 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1479 strcpyW(path, wszInterface);
1480 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1481 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1483 /* Open the key.. */
1484 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1486 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1487 return REGDB_E_IIDNOTREG;
1490 /* ... Once we have the key, query the registry to get the
1491 value of CLSID as a string, and convert it into a
1492 proper CLSID structure to be passed back to the app */
1493 len = sizeof(value);
1494 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1497 return REGDB_E_IIDNOTREG;
1501 /* We have the CLSid we want back from the registry as a string, so
1502 lets convert it into a CLSID structure */
1503 if (CLSIDFromString(value, pclsid) != NOERROR)
1504 return REGDB_E_IIDNOTREG;
1506 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1510 /*****************************************************************************
1511 * CoRegisterPSClsid [OLE32.@]
1513 * Register a proxy/stub CLSID for the given interface in the current process
1517 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1518 * rclsid [I] CLSID of the proxy/stub.
1522 * Failure: E_OUTOFMEMORY
1526 * This function does not add anything to the registry and the effects are
1527 * limited to the lifetime of the current process.
1532 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1534 APARTMENT *apt = COM_CurrentApt();
1535 struct registered_psclsid *registered_psclsid;
1537 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1541 ERR("apartment not initialised\n");
1542 return CO_E_NOTINITIALIZED;
1545 EnterCriticalSection(&apt->cs);
1547 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1548 if (IsEqualIID(®istered_psclsid->iid, riid))
1550 registered_psclsid->clsid = *rclsid;
1551 LeaveCriticalSection(&apt->cs);
1555 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1556 if (!registered_psclsid)
1558 LeaveCriticalSection(&apt->cs);
1559 return E_OUTOFMEMORY;
1562 registered_psclsid->iid = *riid;
1563 registered_psclsid->clsid = *rclsid;
1564 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
1566 LeaveCriticalSection(&apt->cs);
1573 * COM_GetRegisteredClassObject
1575 * This internal method is used to scan the registered class list to
1576 * find a class object.
1579 * rclsid Class ID of the class to find.
1580 * dwClsContext Class context to match.
1581 * ppv [out] returns a pointer to the class object. Complying
1582 * to normal COM usage, this method will increase the
1583 * reference count on this object.
1585 static HRESULT COM_GetRegisteredClassObject(
1586 struct apartment *apt,
1591 HRESULT hr = S_FALSE;
1592 RegisteredClass *curClass;
1599 EnterCriticalSection( &csRegisteredClassList );
1601 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1604 * Check if we have a match on the class ID and context.
1606 if ((apt->oxid == curClass->apartment_id) &&
1607 (dwClsContext & curClass->runContext) &&
1608 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1611 * We have a match, return the pointer to the class object.
1613 *ppUnk = curClass->classObject;
1615 IUnknown_AddRef(curClass->classObject);
1622 LeaveCriticalSection( &csRegisteredClassList );
1627 /******************************************************************************
1628 * CoRegisterClassObject [OLE32.@]
1630 * Registers the class object for a given class ID. Servers housed in EXE
1631 * files use this method instead of exporting DllGetClassObject to allow
1632 * other code to connect to their objects.
1635 * rclsid [I] CLSID of the object to register.
1636 * pUnk [I] IUnknown of the object.
1637 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1638 * flags [I] REGCLS flags indicating how connections are made.
1639 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1643 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1644 * CO_E_OBJISREG if the object is already registered. We should not return this.
1647 * CoRevokeClassObject, CoGetClassObject
1650 * In-process objects are only registered for the current apartment.
1651 * CoGetClassObject() and CoCreateInstance() will not return objects registered
1652 * in other apartments.
1655 * MSDN claims that multiple interface registrations are legal, but we
1656 * can't do that with our current implementation.
1658 HRESULT WINAPI CoRegisterClassObject(
1663 LPDWORD lpdwRegister)
1665 RegisteredClass* newClass;
1666 LPUNKNOWN foundObject;
1670 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1671 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1673 if ( (lpdwRegister==0) || (pUnk==0) )
1674 return E_INVALIDARG;
1676 apt = COM_CurrentApt();
1679 ERR("COM was not initialized\n");
1680 return CO_E_NOTINITIALIZED;
1685 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1686 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1687 if (flags & REGCLS_MULTIPLEUSE)
1688 dwClsContext |= CLSCTX_INPROC_SERVER;
1691 * First, check if the class is already registered.
1692 * If it is, this should cause an error.
1694 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1696 if (flags & REGCLS_MULTIPLEUSE) {
1697 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1698 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1699 IUnknown_Release(foundObject);
1702 IUnknown_Release(foundObject);
1703 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1704 return CO_E_OBJISREG;
1707 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1708 if ( newClass == NULL )
1709 return E_OUTOFMEMORY;
1711 newClass->classIdentifier = *rclsid;
1712 newClass->apartment_id = apt->oxid;
1713 newClass->runContext = dwClsContext;
1714 newClass->connectFlags = flags;
1715 newClass->pMarshaledData = NULL;
1716 newClass->RpcRegistration = NULL;
1719 * Use the address of the chain node as the cookie since we are sure it's
1720 * unique. FIXME: not on 64-bit platforms.
1722 newClass->dwCookie = (DWORD)newClass;
1725 * Since we're making a copy of the object pointer, we have to increase its
1728 newClass->classObject = pUnk;
1729 IUnknown_AddRef(newClass->classObject);
1731 EnterCriticalSection( &csRegisteredClassList );
1732 list_add_tail(&RegisteredClassList, &newClass->entry);
1733 LeaveCriticalSection( &csRegisteredClassList );
1735 *lpdwRegister = newClass->dwCookie;
1737 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1738 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1740 FIXME("Failed to create stream on hglobal, %x\n", hr);
1743 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1744 newClass->classObject, MSHCTX_LOCAL, NULL,
1745 MSHLFLAGS_TABLESTRONG);
1747 FIXME("CoMarshalInterface failed, %x!\n",hr);
1751 hr = RPC_StartLocalServer(&newClass->classIdentifier,
1752 newClass->pMarshaledData,
1753 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
1754 &newClass->RpcRegistration);
1759 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
1761 list_remove(&curClass->entry);
1763 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
1764 RPC_StopLocalServer(curClass->RpcRegistration);
1767 * Release the reference to the class object.
1769 IUnknown_Release(curClass->classObject);
1771 if (curClass->pMarshaledData)
1774 memset(&zero, 0, sizeof(zero));
1775 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
1776 CoReleaseMarshalData(curClass->pMarshaledData);
1779 HeapFree(GetProcessHeap(), 0, curClass);
1782 static void COM_RevokeAllClasses(struct apartment *apt)
1784 RegisteredClass *curClass, *cursor;
1786 EnterCriticalSection( &csRegisteredClassList );
1788 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
1790 if (curClass->apartment_id == apt->oxid)
1791 COM_RevokeRegisteredClassObject(curClass);
1794 LeaveCriticalSection( &csRegisteredClassList );
1797 /***********************************************************************
1798 * CoRevokeClassObject [OLE32.@]
1800 * Removes a class object from the class registry.
1803 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1807 * Failure: HRESULT code.
1810 * Must be called from the same apartment that called CoRegisterClassObject(),
1811 * otherwise it will fail with RPC_E_WRONG_THREAD.
1814 * CoRegisterClassObject
1816 HRESULT WINAPI CoRevokeClassObject(
1819 HRESULT hr = E_INVALIDARG;
1820 RegisteredClass *curClass;
1823 TRACE("(%08x)\n",dwRegister);
1825 apt = COM_CurrentApt();
1828 ERR("COM was not initialized\n");
1829 return CO_E_NOTINITIALIZED;
1832 EnterCriticalSection( &csRegisteredClassList );
1834 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1837 * Check if we have a match on the cookie.
1839 if (curClass->dwCookie == dwRegister)
1841 if (curClass->apartment_id == apt->oxid)
1843 COM_RevokeRegisteredClassObject(curClass);
1848 ERR("called from wrong apartment, should be called from %s\n",
1849 wine_dbgstr_longlong(curClass->apartment_id));
1850 hr = RPC_E_WRONG_THREAD;
1856 LeaveCriticalSection( &csRegisteredClassList );
1861 /***********************************************************************
1862 * COM_RegReadPath [internal]
1864 * Reads a registry value and expands it when necessary
1866 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1871 WCHAR src[MAX_PATH];
1872 DWORD dwLength = dstlen * sizeof(WCHAR);
1874 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1875 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1876 if (keytype == REG_EXPAND_SZ) {
1877 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1879 lstrcpynW(dst, src, dstlen);
1887 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
1889 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
1892 DWORD dwLength = len * sizeof(WCHAR);
1894 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
1895 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
1899 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
1900 REFCLSID rclsid, REFIID riid, void **ppv)
1902 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
1903 static const WCHAR wszFree[] = {'F','r','e','e',0};
1904 static const WCHAR wszBoth[] = {'B','o','t','h',0};
1905 WCHAR dllpath[MAX_PATH+1];
1906 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
1909 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
1911 if (!strcmpiW(threading_model, wszApartment))
1913 if (apt->multi_threaded)
1915 /* try to find an STA */
1916 APARTMENT *host_apt = apartment_findfromtype(FALSE, FALSE);
1918 FIXME("create a host apartment for apartment-threaded object %s\n", debugstr_guid(rclsid));
1921 struct host_object_params params;
1922 HWND hwnd = apartment_getwindow(host_apt);
1924 params.hkeydll = hkeydll;
1925 params.clsid = *rclsid;
1927 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
1930 hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
1932 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1933 IStream_Release(params.stream);
1939 else if (!strcmpiW(threading_model, wszFree))
1941 if (!apt->multi_threaded)
1943 FIXME("should create object %s in multi-threaded apartment\n",
1944 debugstr_guid(rclsid));
1947 /* everything except "Apartment", "Free" and "Both" */
1948 else if (strcmpiW(threading_model, wszBoth))
1950 /* everything else is main-threaded */
1951 if (threading_model[0])
1952 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
1953 debugstr_w(threading_model), debugstr_guid(rclsid));
1955 if (apt->multi_threaded || !apt->main)
1957 /* try to find an STA */
1958 APARTMENT *host_apt = apartment_findfromtype(FALSE, TRUE);
1960 FIXME("create a host apartment for main-threaded object %s\n", debugstr_guid(rclsid));
1963 struct host_object_params params;
1964 HWND hwnd = apartment_getwindow(host_apt);
1966 params.hkeydll = hkeydll;
1967 params.clsid = *rclsid;
1969 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
1972 hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
1974 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1975 IStream_Release(params.stream);
1981 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1983 /* failure: CLSID is not found in registry */
1984 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1985 return REGDB_E_CLASSNOTREG;
1988 return apartment_getclassobject(apt, dllpath, rclsid, riid, ppv);
1991 /***********************************************************************
1992 * CoGetClassObject [OLE32.@]
1994 * Creates an object of the specified class.
1997 * rclsid [I] Class ID to create an instance of.
1998 * dwClsContext [I] Flags to restrict the location of the created instance.
1999 * pServerInfo [I] Optional. Details for connecting to a remote server.
2000 * iid [I] The ID of the interface of the instance to return.
2001 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2005 * Failure: HRESULT code.
2008 * The dwClsContext parameter can be one or more of the following:
2009 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2010 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2011 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2012 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2015 * CoCreateInstance()
2017 HRESULT WINAPI CoGetClassObject(
2018 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2019 REFIID iid, LPVOID *ppv)
2021 LPUNKNOWN regClassObject;
2022 HRESULT hres = E_UNEXPECTED;
2025 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2028 return E_INVALIDARG;
2032 apt = COM_CurrentApt();
2035 ERR("apartment not initialised\n");
2036 return CO_E_NOTINITIALIZED;
2040 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
2041 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
2045 * First, try and see if we can't match the class ID with one of the
2046 * registered classes.
2048 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2051 /* Get the required interface from the retrieved pointer. */
2052 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2055 * Since QI got another reference on the pointer, we want to release the
2056 * one we already have. If QI was unsuccessful, this will release the object. This
2057 * is good since we are not returning it in the "out" parameter.
2059 IUnknown_Release(regClassObject);
2064 /* First try in-process server */
2065 if (CLSCTX_INPROC_SERVER & dwClsContext)
2067 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2070 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2071 return FTMarshalCF_Create(iid, ppv);
2073 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2076 if (hres == REGDB_E_CLASSNOTREG)
2077 ERR("class %s not registered\n", debugstr_guid(rclsid));
2078 else if (hres == REGDB_E_KEYMISSING)
2080 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2081 hres = REGDB_E_CLASSNOTREG;
2085 if (SUCCEEDED(hres))
2087 hres = get_inproc_class_object(apt, hkey, rclsid, iid, ppv);
2091 /* return if we got a class, otherwise fall through to one of the
2093 if (SUCCEEDED(hres))
2097 /* Next try in-process handler */
2098 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2100 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2103 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2106 if (hres == REGDB_E_CLASSNOTREG)
2107 ERR("class %s not registered\n", debugstr_guid(rclsid));
2108 else if (hres == REGDB_E_KEYMISSING)
2110 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2111 hres = REGDB_E_CLASSNOTREG;
2115 if (SUCCEEDED(hres))
2117 hres = get_inproc_class_object(apt, hkey, rclsid, iid, ppv);
2121 /* return if we got a class, otherwise fall through to one of the
2123 if (SUCCEEDED(hres))
2127 /* Next try out of process */
2128 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2130 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2131 if (SUCCEEDED(hres))
2135 /* Finally try remote: this requires networked DCOM (a lot of work) */
2136 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2138 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2139 hres = E_NOINTERFACE;
2143 ERR("no class object %s could be created for context 0x%x\n",
2144 debugstr_guid(rclsid), dwClsContext);
2148 /***********************************************************************
2149 * CoResumeClassObjects (OLE32.@)
2151 * Resumes all class objects registered with REGCLS_SUSPENDED.
2155 * Failure: HRESULT code.
2157 HRESULT WINAPI CoResumeClassObjects(void)
2163 /***********************************************************************
2164 * CoCreateInstance [OLE32.@]
2166 * Creates an instance of the specified class.
2169 * rclsid [I] Class ID to create an instance of.
2170 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2171 * dwClsContext [I] Flags to restrict the location of the created instance.
2172 * iid [I] The ID of the interface of the instance to return.
2173 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2177 * Failure: HRESULT code.
2180 * The dwClsContext parameter can be one or more of the following:
2181 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2182 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2183 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2184 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2186 * Aggregation is the concept of deferring the IUnknown of an object to another
2187 * object. This allows a separate object to behave as though it was part of
2188 * the object and to allow this the pUnkOuter parameter can be set. Note that
2189 * not all objects support having an outer of unknown.
2192 * CoGetClassObject()
2194 HRESULT WINAPI CoCreateInstance(
2196 LPUNKNOWN pUnkOuter,
2202 LPCLASSFACTORY lpclf = 0;
2204 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2205 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2214 * Initialize the "out" parameter
2218 if (!COM_CurrentApt())
2220 ERR("apartment not initialised\n");
2221 return CO_E_NOTINITIALIZED;
2225 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2226 * Rather than create a class factory, we can just check for it here
2228 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2229 if (StdGlobalInterfaceTableInstance == NULL)
2230 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2231 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2232 if (hres) return hres;
2234 TRACE("Retrieved GIT (%p)\n", *ppv);
2239 * Get a class factory to construct the object we want.
2241 hres = CoGetClassObject(rclsid,
2251 * Create the object and don't forget to release the factory
2253 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2254 IClassFactory_Release(lpclf);
2256 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2257 debugstr_guid(iid), debugstr_guid(rclsid),hres);
2262 /***********************************************************************
2263 * CoCreateInstanceEx [OLE32.@]
2265 HRESULT WINAPI CoCreateInstanceEx(
2267 LPUNKNOWN pUnkOuter,
2269 COSERVERINFO* pServerInfo,
2273 IUnknown* pUnk = NULL;
2276 ULONG successCount = 0;
2281 if ( (cmq==0) || (pResults==NULL))
2282 return E_INVALIDARG;
2284 if (pServerInfo!=NULL)
2285 FIXME("() non-NULL pServerInfo not supported!\n");
2288 * Initialize all the "out" parameters.
2290 for (index = 0; index < cmq; index++)
2292 pResults[index].pItf = NULL;
2293 pResults[index].hr = E_NOINTERFACE;
2297 * Get the object and get its IUnknown pointer.
2299 hr = CoCreateInstance(rclsid,
2309 * Then, query for all the interfaces requested.
2311 for (index = 0; index < cmq; index++)
2313 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2314 pResults[index].pIID,
2315 (VOID**)&(pResults[index].pItf));
2317 if (pResults[index].hr == S_OK)
2322 * Release our temporary unknown pointer.
2324 IUnknown_Release(pUnk);
2326 if (successCount == 0)
2327 return E_NOINTERFACE;
2329 if (successCount!=cmq)
2330 return CO_S_NOTALLINTERFACES;
2335 /***********************************************************************
2336 * CoLoadLibrary (OLE32.@)
2341 * lpszLibName [I] Path to library.
2342 * bAutoFree [I] Whether the library should automatically be freed.
2345 * Success: Handle to loaded library.
2349 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2351 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2353 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2355 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2358 /***********************************************************************
2359 * CoFreeLibrary [OLE32.@]
2361 * Unloads a library from memory.
2364 * hLibrary [I] Handle to library to unload.
2370 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2372 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2374 FreeLibrary(hLibrary);
2378 /***********************************************************************
2379 * CoFreeAllLibraries [OLE32.@]
2381 * Function for backwards compatibility only. Does nothing.
2387 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2389 void WINAPI CoFreeAllLibraries(void)
2395 /***********************************************************************
2396 * CoFreeUnusedLibraries [OLE32.@]
2397 * CoFreeUnusedLibraries [COMPOBJ.17]
2399 * Frees any unused libraries. Unused are identified as those that return
2400 * S_OK from their DllCanUnloadNow function.
2406 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2408 void WINAPI CoFreeUnusedLibraries(void)
2410 struct apartment *apt = COM_CurrentApt();
2413 ERR("apartment not initialised\n");
2417 apartment_freeunusedlibraries(apt);
2420 /***********************************************************************
2421 * CoFileTimeNow [OLE32.@]
2422 * CoFileTimeNow [COMPOBJ.82]
2424 * Retrieves the current time in FILETIME format.
2427 * lpFileTime [O] The current time.
2432 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2434 GetSystemTimeAsFileTime( lpFileTime );
2438 /******************************************************************************
2439 * CoLockObjectExternal [OLE32.@]
2441 * Increments or decrements the external reference count of a stub object.
2444 * pUnk [I] Stub object.
2445 * fLock [I] If TRUE then increments the external ref-count,
2446 * otherwise decrements.
2447 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2448 * calling CoDisconnectObject.
2452 * Failure: HRESULT code.
2455 * If fLock is TRUE and an object is passed in that doesn't have a stub
2456 * manager then a new stub manager is created for the object.
2458 HRESULT WINAPI CoLockObjectExternal(
2461 BOOL fLastUnlockReleases)
2463 struct stub_manager *stubmgr;
2464 struct apartment *apt;
2466 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2467 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2469 apt = COM_CurrentApt();
2470 if (!apt) return CO_E_NOTINITIALIZED;
2472 stubmgr = get_stub_manager_from_object(apt, pUnk);
2477 stub_manager_ext_addref(stubmgr, 1);
2479 stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases);
2481 stub_manager_int_release(stubmgr);
2487 stubmgr = new_stub_manager(apt, pUnk);
2491 stub_manager_ext_addref(stubmgr, 1);
2492 stub_manager_int_release(stubmgr);
2499 WARN("stub object not found %p\n", pUnk);
2500 /* Note: native is pretty broken here because it just silently
2501 * fails, without returning an appropriate error code, making apps
2502 * think that the object was disconnected, when it actually wasn't */
2507 /***********************************************************************
2508 * CoInitializeWOW (OLE32.@)
2510 * WOW equivalent of CoInitialize?
2519 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2521 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2525 /***********************************************************************
2526 * CoGetState [OLE32.@]
2528 * Retrieves the thread state object previously stored by CoSetState().
2531 * ppv [I] Address where pointer to object will be stored.
2535 * Failure: E_OUTOFMEMORY.
2538 * Crashes on all invalid ppv addresses, including NULL.
2539 * If the function returns a non-NULL object then the caller must release its
2540 * reference on the object when the object is no longer required.
2545 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2547 struct oletls *info = COM_CurrentInfo();
2548 if (!info) return E_OUTOFMEMORY;
2554 IUnknown_AddRef(info->state);
2556 TRACE("apt->state=%p\n", info->state);
2562 /***********************************************************************
2563 * CoSetState [OLE32.@]
2565 * Sets the thread state object.
2568 * pv [I] Pointer to state object to be stored.
2571 * The system keeps a reference on the object while the object stored.
2575 * Failure: E_OUTOFMEMORY.
2577 HRESULT WINAPI CoSetState(IUnknown * pv)
2579 struct oletls *info = COM_CurrentInfo();
2580 if (!info) return E_OUTOFMEMORY;
2582 if (pv) IUnknown_AddRef(pv);
2586 TRACE("-- release %p now\n", info->state);
2587 IUnknown_Release(info->state);
2596 /******************************************************************************
2597 * CoTreatAsClass [OLE32.@]
2599 * Sets the TreatAs value of a class.
2602 * clsidOld [I] Class to set TreatAs value on.
2603 * clsidNew [I] The class the clsidOld should be treated as.
2607 * Failure: HRESULT code.
2612 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2614 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2615 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2617 WCHAR szClsidNew[CHARS_IN_GUID];
2619 WCHAR auto_treat_as[CHARS_IN_GUID];
2620 LONG auto_treat_as_size = sizeof(auto_treat_as);
2623 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2626 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2628 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2629 !CLSIDFromString(auto_treat_as, &id))
2631 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2633 res = REGDB_E_WRITEREGDB;
2639 RegDeleteKeyW(hkey, wszTreatAs);
2643 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2644 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2646 res = REGDB_E_WRITEREGDB;
2651 if (hkey) RegCloseKey(hkey);
2655 /******************************************************************************
2656 * CoGetTreatAsClass [OLE32.@]
2658 * Gets the TreatAs value of a class.
2661 * clsidOld [I] Class to get the TreatAs value of.
2662 * clsidNew [I] The class the clsidOld should be treated as.
2666 * Failure: HRESULT code.
2671 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2673 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2675 WCHAR szClsidNew[CHARS_IN_GUID];
2677 LONG len = sizeof(szClsidNew);
2679 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2680 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2682 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2685 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2690 res = CLSIDFromString(szClsidNew,clsidNew);
2692 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2694 if (hkey) RegCloseKey(hkey);
2698 /******************************************************************************
2699 * CoGetCurrentProcess [OLE32.@]
2700 * CoGetCurrentProcess [COMPOBJ.34]
2702 * Gets the current process ID.
2705 * The current process ID.
2708 * Is DWORD really the correct return type for this function?
2710 DWORD WINAPI CoGetCurrentProcess(void)
2712 return GetCurrentProcessId();
2715 /******************************************************************************
2716 * CoRegisterMessageFilter [OLE32.@]
2718 * Registers a message filter.
2721 * lpMessageFilter [I] Pointer to interface.
2722 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2726 * Failure: HRESULT code.
2729 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2730 * lpMessageFilter removes the message filter.
2732 * If lplpMessageFilter is not NULL the previous message filter will be
2733 * returned in the memory pointer to this parameter and the caller is
2734 * responsible for releasing the object.
2736 * The current thread be in an apartment otherwise the function will crash.
2738 HRESULT WINAPI CoRegisterMessageFilter(
2739 LPMESSAGEFILTER lpMessageFilter,
2740 LPMESSAGEFILTER *lplpMessageFilter)
2742 struct apartment *apt;
2743 IMessageFilter *lpOldMessageFilter;
2745 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2747 apt = COM_CurrentApt();
2749 /* can't set a message filter in a multi-threaded apartment */
2750 if (!apt || apt->multi_threaded)
2752 WARN("can't set message filter in MTA or uninitialized apt\n");
2753 return CO_E_NOT_SUPPORTED;
2756 if (lpMessageFilter)
2757 IMessageFilter_AddRef(lpMessageFilter);
2759 EnterCriticalSection(&apt->cs);
2761 lpOldMessageFilter = apt->filter;
2762 apt->filter = lpMessageFilter;
2764 LeaveCriticalSection(&apt->cs);
2766 if (lplpMessageFilter)
2767 *lplpMessageFilter = lpOldMessageFilter;
2768 else if (lpOldMessageFilter)
2769 IMessageFilter_Release(lpOldMessageFilter);
2774 /***********************************************************************
2775 * CoIsOle1Class [OLE32.@]
2777 * Determines whether the specified class an OLE v1 class.
2780 * clsid [I] Class to test.
2783 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2785 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2787 FIXME("%s\n", debugstr_guid(clsid));
2791 /***********************************************************************
2792 * IsEqualGUID [OLE32.@]
2794 * Compares two Unique Identifiers.
2797 * rguid1 [I] The first GUID to compare.
2798 * rguid2 [I] The other GUID to compare.
2804 BOOL WINAPI IsEqualGUID(
2808 return !memcmp(rguid1,rguid2,sizeof(GUID));
2811 /***********************************************************************
2812 * CoInitializeSecurity [OLE32.@]
2814 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2815 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2816 void* pReserved1, DWORD dwAuthnLevel,
2817 DWORD dwImpLevel, void* pReserved2,
2818 DWORD dwCapabilities, void* pReserved3)
2820 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
2821 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2822 dwCapabilities, pReserved3);
2826 /***********************************************************************
2827 * CoSuspendClassObjects [OLE32.@]
2829 * Suspends all registered class objects to prevent further requests coming in
2830 * for those objects.
2834 * Failure: HRESULT code.
2836 HRESULT WINAPI CoSuspendClassObjects(void)
2842 /***********************************************************************
2843 * CoAddRefServerProcess [OLE32.@]
2845 * Helper function for incrementing the reference count of a local-server
2849 * New reference count.
2852 * CoReleaseServerProcess().
2854 ULONG WINAPI CoAddRefServerProcess(void)
2860 EnterCriticalSection(&csRegisteredClassList);
2861 refs = ++s_COMServerProcessReferences;
2862 LeaveCriticalSection(&csRegisteredClassList);
2864 TRACE("refs before: %d\n", refs - 1);
2869 /***********************************************************************
2870 * CoReleaseServerProcess [OLE32.@]
2872 * Helper function for decrementing the reference count of a local-server
2876 * New reference count.
2879 * When reference count reaches 0, this function suspends all registered
2880 * classes so no new connections are accepted.
2883 * CoAddRefServerProcess(), CoSuspendClassObjects().
2885 ULONG WINAPI CoReleaseServerProcess(void)
2891 EnterCriticalSection(&csRegisteredClassList);
2893 refs = --s_COMServerProcessReferences;
2894 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
2896 LeaveCriticalSection(&csRegisteredClassList);
2898 TRACE("refs after: %d\n", refs);
2903 /***********************************************************************
2904 * CoIsHandlerConnected [OLE32.@]
2906 * Determines whether a proxy is connected to a remote stub.
2909 * pUnk [I] Pointer to object that may or may not be connected.
2912 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2915 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2917 FIXME("%p\n", pUnk);
2922 /***********************************************************************
2923 * CoAllowSetForegroundWindow [OLE32.@]
2926 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2928 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2932 /***********************************************************************
2933 * CoQueryProxyBlanket [OLE32.@]
2935 * Retrieves the security settings being used by a proxy.
2938 * pProxy [I] Pointer to the proxy object.
2939 * pAuthnSvc [O] The type of authentication service.
2940 * pAuthzSvc [O] The type of authorization service.
2941 * ppServerPrincName [O] Optional. The server prinicple name.
2942 * pAuthnLevel [O] The authentication level.
2943 * pImpLevel [O] The impersonation level.
2944 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2945 * pCapabilities [O] Flags affecting the security behaviour.
2949 * Failure: HRESULT code.
2952 * CoCopyProxy, CoSetProxyBlanket.
2954 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2955 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2956 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2958 IClientSecurity *pCliSec;
2961 TRACE("%p\n", pProxy);
2963 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2966 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2967 pAuthzSvc, ppServerPrincName,
2968 pAuthnLevel, pImpLevel, ppAuthInfo,
2970 IClientSecurity_Release(pCliSec);
2973 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
2977 /***********************************************************************
2978 * CoSetProxyBlanket [OLE32.@]
2980 * Sets the security settings for a proxy.
2983 * pProxy [I] Pointer to the proxy object.
2984 * AuthnSvc [I] The type of authentication service.
2985 * AuthzSvc [I] The type of authorization service.
2986 * pServerPrincName [I] The server prinicple name.
2987 * AuthnLevel [I] The authentication level.
2988 * ImpLevel [I] The impersonation level.
2989 * pAuthInfo [I] Information specific to the authorization/authentication service.
2990 * Capabilities [I] Flags affecting the security behaviour.
2994 * Failure: HRESULT code.
2997 * CoQueryProxyBlanket, CoCopyProxy.
2999 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3000 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3001 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3003 IClientSecurity *pCliSec;
3006 TRACE("%p\n", pProxy);
3008 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3011 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3012 AuthzSvc, pServerPrincName,
3013 AuthnLevel, ImpLevel, pAuthInfo,
3015 IClientSecurity_Release(pCliSec);
3018 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3022 /***********************************************************************
3023 * CoCopyProxy [OLE32.@]
3028 * pProxy [I] Pointer to the proxy object.
3029 * ppCopy [O] Copy of the proxy.
3033 * Failure: HRESULT code.
3036 * CoQueryProxyBlanket, CoSetProxyBlanket.
3038 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3040 IClientSecurity *pCliSec;
3043 TRACE("%p\n", pProxy);
3045 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3048 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3049 IClientSecurity_Release(pCliSec);
3052 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3057 /***********************************************************************
3058 * CoGetCallContext [OLE32.@]
3060 * Gets the context of the currently executing server call in the current
3064 * riid [I] Context interface to return.
3065 * ppv [O] Pointer to memory that will receive the context on return.
3069 * Failure: HRESULT code.
3071 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3073 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
3076 return E_NOINTERFACE;
3079 /***********************************************************************
3080 * CoQueryClientBlanket [OLE32.@]
3082 * Retrieves the authentication information about the client of the currently
3083 * executing server call in the current thread.
3086 * pAuthnSvc [O] Optional. The type of authentication service.
3087 * pAuthzSvc [O] Optional. The type of authorization service.
3088 * pServerPrincName [O] Optional. The server prinicple name.
3089 * pAuthnLevel [O] Optional. The authentication level.
3090 * pImpLevel [O] Optional. The impersonation level.
3091 * pPrivs [O] Optional. Information about the privileges of the client.
3092 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3096 * Failure: HRESULT code.
3099 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3101 HRESULT WINAPI CoQueryClientBlanket(
3104 OLECHAR **pServerPrincName,
3107 RPC_AUTHZ_HANDLE *pPrivs,
3108 DWORD *pCapabilities)
3110 IServerSecurity *pSrvSec;
3113 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3114 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3115 pPrivs, pCapabilities);
3117 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3120 hr = IServerSecurity_QueryBlanket(
3121 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3122 pImpLevel, pPrivs, pCapabilities);
3123 IServerSecurity_Release(pSrvSec);
3129 /***********************************************************************
3130 * CoImpersonateClient [OLE32.@]
3132 * Impersonates the client of the currently executing server call in the
3140 * Failure: HRESULT code.
3143 * If this function fails then the current thread will not be impersonating
3144 * the client and all actions will take place on behalf of the server.
3145 * Therefore, it is important to check the return value from this function.
3148 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3150 HRESULT WINAPI CoImpersonateClient(void)
3152 IServerSecurity *pSrvSec;
3157 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3160 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3161 IServerSecurity_Release(pSrvSec);
3167 /***********************************************************************
3168 * CoRevertToSelf [OLE32.@]
3170 * Ends the impersonation of the client of the currently executing server
3171 * call in the current thread.
3178 * Failure: HRESULT code.
3181 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3183 HRESULT WINAPI CoRevertToSelf(void)
3185 IServerSecurity *pSrvSec;
3190 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3193 hr = IServerSecurity_RevertToSelf(pSrvSec);
3194 IServerSecurity_Release(pSrvSec);
3200 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3202 /* first try to retrieve messages for incoming COM calls to the apartment window */
3203 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3204 /* next retrieve other messages necessary for the app to remain responsive */
3205 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
3208 /***********************************************************************
3209 * CoWaitForMultipleHandles [OLE32.@]
3211 * Waits for one or more handles to become signaled.
3214 * dwFlags [I] Flags. See notes.
3215 * dwTimeout [I] Timeout in milliseconds.
3216 * cHandles [I] Number of handles pointed to by pHandles.
3217 * pHandles [I] Handles to wait for.
3218 * lpdwindex [O] Index of handle that was signaled.
3222 * Failure: RPC_S_CALLPENDING on timeout.
3226 * The dwFlags parameter can be zero or more of the following:
3227 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3228 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3231 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3233 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3234 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3237 DWORD start_time = GetTickCount();
3238 APARTMENT *apt = COM_CurrentApt();
3239 BOOL message_loop = apt && !apt->multi_threaded;
3241 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3242 pHandles, lpdwindex);
3246 DWORD now = GetTickCount();
3249 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
3251 hr = RPC_S_CALLPENDING;
3257 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
3258 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
3260 TRACE("waiting for rpc completion or window message\n");
3262 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3263 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3264 QS_ALLINPUT, wait_flags);
3266 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3270 /* call message filter */
3272 if (COM_CurrentApt()->filter)
3274 PENDINGTYPE pendingtype =
3275 COM_CurrentInfo()->pending_call_count_server ?
3276 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3277 DWORD be_handled = IMessageFilter_MessagePending(
3278 COM_CurrentApt()->filter, 0 /* FIXME */,
3279 now - start_time, pendingtype);
3280 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3283 case PENDINGMSG_CANCELCALL:
3284 WARN("call canceled\n");
3285 hr = RPC_E_CALL_CANCELED;
3287 case PENDINGMSG_WAITNOPROCESS:
3288 case PENDINGMSG_WAITDEFPROCESS:
3290 /* FIXME: MSDN is very vague about the difference
3291 * between WAITNOPROCESS and WAITDEFPROCESS - there
3292 * appears to be none, so it is possibly a left-over
3293 * from the 16-bit world. */
3298 /* note: using "if" here instead of "while" might seem less
3299 * efficient, but only if we are optimising for quick delivery
3300 * of pending messages, rather than quick completion of the
3302 if (COM_PeekMessage(apt, &msg))
3304 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3305 TranslateMessage(&msg);
3306 DispatchMessageW(&msg);
3307 if (msg.message == WM_QUIT)
3309 TRACE("resending WM_QUIT to outer message loop\n");
3310 PostQuitMessage(msg.wParam);
3311 /* no longer need to process messages */
3312 message_loop = FALSE;
3320 TRACE("waiting for rpc completion\n");
3322 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3323 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3324 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3325 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3328 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
3330 /* handle signaled, store index */
3331 *lpdwindex = (res - WAIT_OBJECT_0);
3334 else if (res == WAIT_TIMEOUT)
3336 hr = RPC_S_CALLPENDING;
3341 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3346 TRACE("-- 0x%08x\n", hr);
3351 /***********************************************************************
3352 * CoGetObject [OLE32.@]
3354 * Gets the object named by coverting the name to a moniker and binding to it.
3357 * pszName [I] String representing the object.
3358 * pBindOptions [I] Parameters affecting the binding to the named object.
3359 * riid [I] Interface to bind to on the objecct.
3360 * ppv [O] On output, the interface riid of the object represented
3365 * Failure: HRESULT code.
3368 * MkParseDisplayName.
3370 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3371 REFIID riid, void **ppv)
3378 hr = CreateBindCtx(0, &pbc);
3382 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3389 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3392 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3393 IMoniker_Release(pmk);
3397 IBindCtx_Release(pbc);
3402 /***********************************************************************
3403 * CoRegisterChannelHook [OLE32.@]
3405 * Registers a process-wide hook that is called during ORPC calls.
3408 * guidExtension [I] GUID of the channel hook to register.
3409 * pChannelHook [I] Channel hook object to register.
3413 * Failure: HRESULT code.
3415 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3417 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3419 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3422 /***********************************************************************
3425 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3427 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3430 case DLL_PROCESS_ATTACH:
3431 OLE32_hInstance = hinstDLL;
3432 COMPOBJ_InitProcess();
3433 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3436 case DLL_PROCESS_DETACH:
3437 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3438 OLEDD_UnInitialize();
3439 COMPOBJ_UninitProcess();
3440 RPC_UnregisterAllChannelHooks();
3441 OLE32_hInstance = 0;
3444 case DLL_THREAD_DETACH:
3451 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */