ole32: Only retrieve posted and paint messages in an STA message loop.
[wine/multimedia.git] / dlls / ole32 / compobj.c
blobfe180aa40857d908b42ad3529564b676cd12861f
1 /*
2 * COMPOBJ library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
37 * - Make all ole interface marshaling use NDR to be wire compatible with
38 * native DCOM
42 #include "config.h"
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <assert.h>
49 #define COBJMACROS
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
53 #include "windef.h"
54 #include "winbase.h"
55 #include "winerror.h"
56 #include "winreg.h"
57 #include "winuser.h"
58 #include "objbase.h"
59 #include "ole2.h"
60 #include "ole2ver.h"
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(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
80 static void COM_RevokeAllClasses(void);
81 static HRESULT get_inproc_class_object(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 =
90 0, 0, &csApartment,
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
98 struct list entry;
99 IID iid;
100 CLSID clsid;
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
115 * objects.
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
122 struct list entry;
123 CLSID classIdentifier;
124 LPUNKNOWN classObject;
125 DWORD runContext;
126 DWORD connectFlags;
127 DWORD dwCookie;
128 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
129 void *RpcRegistration;
130 } RegisteredClass;
132 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
134 static CRITICAL_SECTION csRegisteredClassList;
135 static CRITICAL_SECTION_DEBUG class_cs_debug =
137 0, 0, &csRegisteredClassList,
138 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
139 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
141 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
143 /*****************************************************************************
144 * This section contains OpenDllList definitions
146 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
147 * other functions that do LoadLibrary _without_ giving back a HMODULE.
148 * Without this list these handles would never be freed.
150 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
151 * next unload-call but not before 600 sec.
154 typedef struct tagOpenDll {
155 HINSTANCE hLibrary;
156 struct tagOpenDll *next;
157 } OpenDll;
159 static OpenDll *openDllList = NULL; /* linked list of open dlls */
161 static CRITICAL_SECTION csOpenDllList;
162 static CRITICAL_SECTION_DEBUG dll_cs_debug =
164 0, 0, &csOpenDllList,
165 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
166 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
168 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
170 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',' ',
171 '0','x','#','#','#','#','#','#','#','#',' ',0};
172 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
174 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
175 static void COMPOBJ_DllList_FreeUnused(int Timeout);
177 static void COMPOBJ_InitProcess( void )
179 WNDCLASSW wclass;
181 /* Dispatching to the correct thread in an apartment is done through
182 * window messages rather than RPC transports. When an interface is
183 * marshalled into another apartment in the same process, a window of the
184 * following class is created. The *caller* of CoMarshalInterface (ie the
185 * application) is responsible for pumping the message loop in that thread.
186 * The WM_USER messages which point to the RPCs are then dispatched to
187 * COM_AptWndProc by the user's code from the apartment in which the interface
188 * was unmarshalled.
190 memset(&wclass, 0, sizeof(wclass));
191 wclass.lpfnWndProc = apartment_wndproc;
192 wclass.hInstance = OLE32_hInstance;
193 wclass.lpszClassName = wszAptWinClass;
194 RegisterClassW(&wclass);
197 static void COMPOBJ_UninitProcess( void )
199 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
202 static void COM_TlsDestroy(void)
204 struct oletls *info = NtCurrentTeb()->ReservedForOle;
205 if (info)
207 if (info->apt) apartment_release(info->apt);
208 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
209 if (info->state) IUnknown_Release(info->state);
210 HeapFree(GetProcessHeap(), 0, info);
211 NtCurrentTeb()->ReservedForOle = NULL;
215 /******************************************************************************
216 * Manage apartments.
219 /* allocates memory and fills in the necessary fields for a new apartment
220 * object. must be called inside apartment cs */
221 static APARTMENT *apartment_construct(DWORD model)
223 APARTMENT *apt;
225 TRACE("creating new apartment, model=%d\n", model);
227 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
228 apt->tid = GetCurrentThreadId();
230 list_init(&apt->proxies);
231 list_init(&apt->stubmgrs);
232 list_init(&apt->psclsids);
233 apt->ipidc = 0;
234 apt->refs = 1;
235 apt->remunk_exported = FALSE;
236 apt->oidc = 1;
237 InitializeCriticalSection(&apt->cs);
238 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
240 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
242 if (apt->multi_threaded)
244 /* FIXME: should be randomly generated by in an RPC call to rpcss */
245 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
247 else
249 /* FIXME: should be randomly generated by in an RPC call to rpcss */
250 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
253 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
255 list_add_head(&apts, &apt->entry);
257 return apt;
260 /* gets and existing apartment if one exists or otherwise creates an apartment
261 * structure which stores OLE apartment-local information and stores a pointer
262 * to it in the thread-local storage */
263 static APARTMENT *apartment_get_or_create(DWORD model)
265 APARTMENT *apt = COM_CurrentApt();
267 if (!apt)
269 if (model & COINIT_APARTMENTTHREADED)
271 EnterCriticalSection(&csApartment);
273 apt = apartment_construct(model);
274 if (!MainApartment)
276 MainApartment = apt;
277 apt->main = TRUE;
278 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
281 LeaveCriticalSection(&csApartment);
283 else
285 EnterCriticalSection(&csApartment);
287 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
288 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
289 * in a process */
290 if (MTA)
292 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
293 apartment_addref(MTA);
295 else
296 MTA = apartment_construct(model);
298 apt = MTA;
300 LeaveCriticalSection(&csApartment);
302 COM_CurrentInfo()->apt = apt;
305 return apt;
308 static inline BOOL apartment_is_model(APARTMENT *apt, DWORD model)
310 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
313 DWORD apartment_addref(struct apartment *apt)
315 DWORD refs = InterlockedIncrement(&apt->refs);
316 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
317 return refs;
320 DWORD apartment_release(struct apartment *apt)
322 DWORD ret;
324 EnterCriticalSection(&csApartment);
326 ret = InterlockedDecrement(&apt->refs);
327 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
328 /* destruction stuff that needs to happen under csApartment CS */
329 if (ret == 0)
331 if (apt == MTA) MTA = NULL;
332 else if (apt == MainApartment) MainApartment = NULL;
333 list_remove(&apt->entry);
336 LeaveCriticalSection(&csApartment);
338 if (ret == 0)
340 struct list *cursor, *cursor2;
342 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
344 /* no locking is needed for this apartment, because no other thread
345 * can access it at this point */
347 apartment_disconnectproxies(apt);
349 if (apt->win) DestroyWindow(apt->win);
351 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
353 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
354 /* release the implicit reference given by the fact that the
355 * stub has external references (it must do since it is in the
356 * stub manager list in the apartment and all non-apartment users
357 * must have a ref on the apartment and so it cannot be destroyed).
359 stub_manager_int_release(stubmgr);
362 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
364 struct registered_psclsid *registered_psclsid =
365 LIST_ENTRY(cursor, struct registered_psclsid, entry);
367 list_remove(&registered_psclsid->entry);
368 HeapFree(GetProcessHeap(), 0, registered_psclsid);
371 /* if this assert fires, then another thread took a reference to a
372 * stub manager without taking a reference to the containing
373 * apartment, which it must do. */
374 assert(list_empty(&apt->stubmgrs));
376 if (apt->filter) IUnknown_Release(apt->filter);
378 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
379 DeleteCriticalSection(&apt->cs);
381 HeapFree(GetProcessHeap(), 0, apt);
384 return ret;
387 /* The given OXID must be local to this process:
389 * The ref parameter is here mostly to ensure people remember that
390 * they get one, you should normally take a ref for thread safety.
392 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
394 APARTMENT *result = NULL;
395 struct list *cursor;
397 EnterCriticalSection(&csApartment);
398 LIST_FOR_EACH( cursor, &apts )
400 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
401 if (apt->oxid == oxid)
403 result = apt;
404 if (ref) apartment_addref(result);
405 break;
408 LeaveCriticalSection(&csApartment);
410 return result;
413 /* gets the apartment which has a given creator thread ID. The caller must
414 * release the reference from the apartment as soon as the apartment pointer
415 * is no longer required. */
416 APARTMENT *apartment_findfromtid(DWORD tid)
418 APARTMENT *result = NULL;
419 struct list *cursor;
421 EnterCriticalSection(&csApartment);
422 LIST_FOR_EACH( cursor, &apts )
424 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
425 if (apt->tid == tid)
427 result = apt;
428 apartment_addref(result);
429 break;
432 LeaveCriticalSection(&csApartment);
434 return result;
437 /* gets an apartment which has a given type. The caller must
438 * release the reference from the apartment as soon as the apartment pointer
439 * is no longer required. */
440 static APARTMENT *apartment_findfromtype(BOOL multi_threaded, BOOL main_apartment)
442 APARTMENT *result = NULL;
443 struct apartment *apt;
445 EnterCriticalSection(&csApartment);
447 if (!multi_threaded && main_apartment)
449 result = MainApartment;
450 if (result) apartment_addref(result);
451 LeaveCriticalSection(&csApartment);
452 return result;
455 LIST_FOR_EACH_ENTRY( apt, &apts, struct apartment, entry )
457 if (apt->multi_threaded == multi_threaded)
459 result = apt;
460 apartment_addref(result);
461 break;
464 LeaveCriticalSection(&csApartment);
466 return result;
469 struct host_object_params
471 HKEY hkeydll;
472 CLSID clsid; /* clsid of object to marshal */
473 IID iid; /* interface to marshal */
474 IStream *stream; /* stream that the object will be marshaled into */
477 static HRESULT apartment_hostobject(const struct host_object_params *params)
479 IUnknown *object;
480 HRESULT hr;
481 static const LARGE_INTEGER llZero;
483 TRACE("\n");
485 hr = get_inproc_class_object(params->hkeydll, &params->clsid, &params->iid, (void **)&object);
486 if (FAILED(hr))
487 return hr;
489 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
490 if (FAILED(hr))
491 IUnknown_Release(object);
492 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
494 return hr;
497 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
499 switch (msg)
501 case DM_EXECUTERPC:
502 RPC_ExecuteCall((struct dispatch_params *)lParam);
503 return 0;
504 case DM_HOSTOBJECT:
505 return apartment_hostobject((const struct host_object_params *)lParam);
506 default:
507 return DefWindowProcW(hWnd, msg, wParam, lParam);
511 HRESULT apartment_createwindowifneeded(struct apartment *apt)
513 if (apt->multi_threaded)
514 return S_OK;
516 if (!apt->win)
518 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
519 0, 0, 0, 0,
520 0, 0, OLE32_hInstance, NULL);
521 if (!hwnd)
523 ERR("CreateWindow failed with error %d\n", GetLastError());
524 return HRESULT_FROM_WIN32(GetLastError());
526 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
527 /* someone beat us to it */
528 DestroyWindow(hwnd);
531 return S_OK;
534 HWND apartment_getwindow(struct apartment *apt)
536 assert(!apt->multi_threaded);
537 return apt->win;
540 void apartment_joinmta(void)
542 apartment_addref(MTA);
543 COM_CurrentInfo()->apt = MTA;
546 /*****************************************************************************
547 * This section contains OpenDllList implementation
550 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
552 OpenDll *ptr;
553 OpenDll *tmp;
555 TRACE("\n");
557 EnterCriticalSection( &csOpenDllList );
559 if (openDllList == NULL) {
560 /* empty list -- add first node */
561 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
562 openDllList->hLibrary=hLibrary;
563 openDllList->next = NULL;
564 } else {
565 /* search for this dll */
566 int found = FALSE;
567 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
568 if (ptr->hLibrary == hLibrary) {
569 found = TRUE;
570 break;
573 if (!found) {
574 /* dll not found, add it */
575 tmp = openDllList;
576 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
577 openDllList->hLibrary = hLibrary;
578 openDllList->next = tmp;
582 LeaveCriticalSection( &csOpenDllList );
585 static void COMPOBJ_DllList_FreeUnused(int Timeout)
587 OpenDll *curr, *next, *prev = NULL;
588 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
589 DllCanUnloadNowFunc DllCanUnloadNow;
591 TRACE("\n");
593 EnterCriticalSection( &csOpenDllList );
595 for (curr = openDllList; curr != NULL; ) {
596 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
598 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
599 next = curr->next;
601 TRACE("freeing %p\n", curr->hLibrary);
602 FreeLibrary(curr->hLibrary);
604 HeapFree(GetProcessHeap(), 0, curr);
605 if (curr == openDllList) {
606 openDllList = next;
607 } else {
608 prev->next = next;
611 curr = next;
612 } else {
613 prev = curr;
614 curr = curr->next;
618 LeaveCriticalSection( &csOpenDllList );
621 /******************************************************************************
622 * CoBuildVersion [OLE32.@]
623 * CoBuildVersion [COMPOBJ.1]
625 * Gets the build version of the DLL.
627 * PARAMS
629 * RETURNS
630 * Current build version, hiword is majornumber, loword is minornumber
632 DWORD WINAPI CoBuildVersion(void)
634 TRACE("Returning version %d, build %d.\n", rmm, rup);
635 return (rmm<<16)+rup;
638 /******************************************************************************
639 * CoInitialize [OLE32.@]
641 * Initializes the COM libraries by calling CoInitializeEx with
642 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
644 * PARAMS
645 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
647 * RETURNS
648 * Success: S_OK if not already initialized, S_FALSE otherwise.
649 * Failure: HRESULT code.
651 * SEE ALSO
652 * CoInitializeEx
654 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
657 * Just delegate to the newer method.
659 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
662 /******************************************************************************
663 * CoInitializeEx [OLE32.@]
665 * Initializes the COM libraries.
667 * PARAMS
668 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
669 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
671 * RETURNS
672 * S_OK if successful,
673 * S_FALSE if this function was called already.
674 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
675 * threading model.
677 * NOTES
679 * The behavior used to set the IMalloc used for memory management is
680 * obsolete.
681 * The dwCoInit parameter must specify one of the following apartment
682 * threading models:
683 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
684 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
685 * The parameter may also specify zero or more of the following flags:
686 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
687 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
689 * SEE ALSO
690 * CoUninitialize
692 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
694 HRESULT hr = S_OK;
695 APARTMENT *apt;
697 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
699 if (lpReserved!=NULL)
701 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
705 * Check the lock count. If this is the first time going through the initialize
706 * process, we have to initialize the libraries.
708 * And crank-up that lock count.
710 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
713 * Initialize the various COM libraries and data structures.
715 TRACE("() - Initializing the COM libraries\n");
717 /* we may need to defer this until after apartment initialisation */
718 RunningObjectTableImpl_Initialize();
721 if (!(apt = COM_CurrentInfo()->apt))
723 apt = apartment_get_or_create(dwCoInit);
724 if (!apt) return E_OUTOFMEMORY;
726 else if (!apartment_is_model(apt, dwCoInit))
728 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
729 code then we are probably using the wrong threading model to implement that API. */
730 ERR("Attempt to change threading model of this apartment from %s to %s\n",
731 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
732 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
733 return RPC_E_CHANGED_MODE;
735 else
736 hr = S_FALSE;
738 COM_CurrentInfo()->inits++;
740 return hr;
743 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
744 pending RPCs are ignored. Non-COM messages are discarded at this point.
746 static void COM_FlushMessageQueue(void)
748 MSG message;
749 APARTMENT *apt = COM_CurrentApt();
751 if (!apt || !apt->win) return;
753 TRACE("Flushing STA message queue\n");
755 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
757 if (message.hwnd != apt->win)
759 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
760 continue;
763 TranslateMessage(&message);
764 DispatchMessageA(&message);
768 /***********************************************************************
769 * CoUninitialize [OLE32.@]
771 * This method will decrement the refcount on the current apartment, freeing
772 * the resources associated with it if it is the last thread in the apartment.
773 * If the last apartment is freed, the function will additionally release
774 * any COM resources associated with the process.
776 * PARAMS
778 * RETURNS
779 * Nothing.
781 * SEE ALSO
782 * CoInitializeEx
784 void WINAPI CoUninitialize(void)
786 struct oletls * info = COM_CurrentInfo();
787 LONG lCOMRefCnt;
789 TRACE("()\n");
791 /* will only happen on OOM */
792 if (!info) return;
794 /* sanity check */
795 if (!info->inits)
797 ERR("Mismatched CoUninitialize\n");
798 return;
801 if (!--info->inits)
803 apartment_release(info->apt);
804 info->apt = NULL;
808 * Decrease the reference count.
809 * If we are back to 0 locks on the COM library, make sure we free
810 * all the associated data structures.
812 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
813 if (lCOMRefCnt==1)
815 TRACE("() - Releasing the COM libraries\n");
817 RunningObjectTableImpl_UnInitialize();
819 /* Release the references to the registered class objects */
820 COM_RevokeAllClasses();
822 /* This will free the loaded COM Dlls */
823 CoFreeAllLibraries();
825 /* This ensures we deal with any pending RPCs */
826 COM_FlushMessageQueue();
828 else if (lCOMRefCnt<1) {
829 ERR( "CoUninitialize() - not CoInitialized.\n" );
830 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
834 /******************************************************************************
835 * CoDisconnectObject [OLE32.@]
836 * CoDisconnectObject [COMPOBJ.15]
838 * Disconnects all connections to this object from remote processes. Dispatches
839 * pending RPCs while blocking new RPCs from occurring, and then calls
840 * IMarshal::DisconnectObject on the given object.
842 * Typically called when the object server is forced to shut down, for instance by
843 * the user.
845 * PARAMS
846 * lpUnk [I] The object whose stub should be disconnected.
847 * reserved [I] Reserved. Should be set to 0.
849 * RETURNS
850 * Success: S_OK.
851 * Failure: HRESULT code.
853 * SEE ALSO
854 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
856 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
858 HRESULT hr;
859 IMarshal *marshal;
860 APARTMENT *apt;
862 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
864 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
865 if (hr == S_OK)
867 hr = IMarshal_DisconnectObject(marshal, reserved);
868 IMarshal_Release(marshal);
869 return hr;
872 apt = COM_CurrentApt();
873 if (!apt)
874 return CO_E_NOTINITIALIZED;
876 apartment_disconnectobject(apt, lpUnk);
878 /* Note: native is pretty broken here because it just silently
879 * fails, without returning an appropriate error code if the object was
880 * not found, making apps think that the object was disconnected, when
881 * it actually wasn't */
883 return S_OK;
886 /******************************************************************************
887 * CoCreateGuid [OLE32.@]
889 * Simply forwards to UuidCreate in RPCRT4.
891 * PARAMS
892 * pguid [O] Points to the GUID to initialize.
894 * RETURNS
895 * Success: S_OK.
896 * Failure: HRESULT code.
898 * SEE ALSO
899 * UuidCreate
901 HRESULT WINAPI CoCreateGuid(GUID *pguid)
903 return UuidCreate(pguid);
906 /******************************************************************************
907 * CLSIDFromString [OLE32.@]
908 * IIDFromString [OLE32.@]
910 * Converts a unique identifier from its string representation into
911 * the GUID struct.
913 * PARAMS
914 * idstr [I] The string representation of the GUID.
915 * id [O] GUID converted from the string.
917 * RETURNS
918 * S_OK on success
919 * CO_E_CLASSSTRING if idstr is not a valid CLSID
921 * SEE ALSO
922 * StringFromCLSID
924 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
926 int i;
927 BYTE table[256];
929 if (!s) {
930 memset( id, 0, sizeof (CLSID) );
931 return S_OK;
934 /* validate the CLSID string */
935 if (strlenW(s) != 38)
936 return CO_E_CLASSSTRING;
938 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
939 return CO_E_CLASSSTRING;
941 for (i=1; i<37; i++) {
942 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
943 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
944 ((s[i] >= 'a') && (s[i] <= 'f')) ||
945 ((s[i] >= 'A') && (s[i] <= 'F'))))
946 return CO_E_CLASSSTRING;
949 TRACE("%s -> %p\n", debugstr_w(s), id);
951 /* quick lookup table */
952 memset(table, 0, 256);
954 for (i = 0; i < 10; i++) {
955 table['0' + i] = i;
957 for (i = 0; i < 6; i++) {
958 table['A' + i] = i+10;
959 table['a' + i] = i+10;
962 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
964 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
965 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
966 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
967 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
969 /* these are just sequential bytes */
970 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
971 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
972 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
973 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
974 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
975 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
976 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
977 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
979 return S_OK;
982 /*****************************************************************************/
984 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
986 HRESULT ret;
988 if (!id)
989 return E_INVALIDARG;
991 ret = __CLSIDFromString(idstr, id);
992 if(ret != S_OK) { /* It appears a ProgID is also valid */
993 ret = CLSIDFromProgID(idstr, id);
995 return ret;
998 /* Converts a GUID into the respective string representation. */
999 HRESULT WINE_StringFromCLSID(
1000 const CLSID *id, /* [in] GUID to be converted */
1001 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
1003 static const char hex[] = "0123456789ABCDEF";
1004 char *s;
1005 int i;
1007 if (!id)
1008 { ERR("called with id=Null\n");
1009 *idstr = 0x00;
1010 return E_FAIL;
1013 sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
1014 id->Data1, id->Data2, id->Data3,
1015 id->Data4[0], id->Data4[1]);
1016 s = &idstr[25];
1018 /* 6 hex bytes */
1019 for (i = 2; i < 8; i++) {
1020 *s++ = hex[id->Data4[i]>>4];
1021 *s++ = hex[id->Data4[i] & 0xf];
1024 *s++ = '}';
1025 *s++ = '\0';
1027 TRACE("%p->%s\n", id, idstr);
1029 return S_OK;
1033 /******************************************************************************
1034 * StringFromCLSID [OLE32.@]
1035 * StringFromIID [OLE32.@]
1037 * Converts a GUID into the respective string representation.
1038 * The target string is allocated using the OLE IMalloc.
1040 * PARAMS
1041 * id [I] the GUID to be converted.
1042 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1044 * RETURNS
1045 * S_OK
1046 * E_FAIL
1048 * SEE ALSO
1049 * StringFromGUID2, CLSIDFromString
1051 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1053 char buf[80];
1054 HRESULT ret;
1055 LPMALLOC mllc;
1057 if ((ret = CoGetMalloc(0,&mllc)))
1058 return ret;
1060 ret=WINE_StringFromCLSID(id,buf);
1061 if (!ret) {
1062 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1063 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1064 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1066 return ret;
1069 /******************************************************************************
1070 * StringFromGUID2 [OLE32.@]
1071 * StringFromGUID2 [COMPOBJ.76]
1073 * Modified version of StringFromCLSID that allows you to specify max
1074 * buffer size.
1076 * PARAMS
1077 * id [I] GUID to convert to string.
1078 * str [O] Buffer where the result will be stored.
1079 * cmax [I] Size of the buffer in characters.
1081 * RETURNS
1082 * Success: The length of the resulting string in characters.
1083 * Failure: 0.
1085 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1087 char xguid[80];
1089 if (WINE_StringFromCLSID(id,xguid))
1090 return 0;
1091 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1094 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1095 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1097 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1098 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1099 LONG res;
1100 HKEY key;
1102 strcpyW(path, wszCLSIDSlash);
1103 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1104 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1105 if (res == ERROR_FILE_NOT_FOUND)
1106 return REGDB_E_CLASSNOTREG;
1107 else if (res != ERROR_SUCCESS)
1108 return REGDB_E_READREGDB;
1110 if (!keyname)
1112 *subkey = key;
1113 return S_OK;
1116 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1117 RegCloseKey(key);
1118 if (res == ERROR_FILE_NOT_FOUND)
1119 return REGDB_E_KEYMISSING;
1120 else if (res != ERROR_SUCCESS)
1121 return REGDB_E_READREGDB;
1123 return S_OK;
1126 /* open HKCR\\AppId\\{string form of appid clsid} key */
1127 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1129 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1130 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1131 DWORD res;
1132 WCHAR buf[CHARS_IN_GUID];
1133 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1134 DWORD size;
1135 HKEY hkey;
1136 DWORD type;
1137 HRESULT hr;
1139 /* read the AppID value under the class's key */
1140 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1141 if (FAILED(hr))
1142 return hr;
1144 size = sizeof(buf);
1145 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1146 RegCloseKey(hkey);
1147 if (res == ERROR_FILE_NOT_FOUND)
1148 return REGDB_E_KEYMISSING;
1149 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1150 return REGDB_E_READREGDB;
1152 strcpyW(keyname, szAppIdKey);
1153 strcatW(keyname, buf);
1154 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1155 if (res == ERROR_FILE_NOT_FOUND)
1156 return REGDB_E_KEYMISSING;
1157 else if (res != ERROR_SUCCESS)
1158 return REGDB_E_READREGDB;
1160 return S_OK;
1163 /******************************************************************************
1164 * ProgIDFromCLSID [OLE32.@]
1166 * Converts a class id into the respective program ID.
1168 * PARAMS
1169 * clsid [I] Class ID, as found in registry.
1170 * ppszProgID [O] Associated ProgID.
1172 * RETURNS
1173 * S_OK
1174 * E_OUTOFMEMORY
1175 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1177 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1179 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1180 HKEY hkey;
1181 HRESULT ret;
1182 LONG progidlen = 0;
1184 if (!ppszProgID)
1186 ERR("ppszProgId isn't optional\n");
1187 return E_INVALIDARG;
1190 *ppszProgID = NULL;
1191 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1192 if (FAILED(ret))
1193 return ret;
1195 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1196 ret = REGDB_E_CLASSNOTREG;
1198 if (ret == S_OK)
1200 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1201 if (*ppszProgID)
1203 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1204 ret = REGDB_E_CLASSNOTREG;
1206 else
1207 ret = E_OUTOFMEMORY;
1210 RegCloseKey(hkey);
1211 return ret;
1214 /******************************************************************************
1215 * CLSIDFromProgID [OLE32.@]
1217 * Converts a program id into the respective GUID.
1219 * PARAMS
1220 * progid [I] Unicode program ID, as found in registry.
1221 * clsid [O] Associated CLSID.
1223 * RETURNS
1224 * Success: S_OK
1225 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1227 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1229 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1230 WCHAR buf2[CHARS_IN_GUID];
1231 LONG buf2len = sizeof(buf2);
1232 HKEY xhkey;
1233 WCHAR *buf;
1235 if (!progid || !clsid)
1237 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1238 return E_INVALIDARG;
1241 /* initialise clsid in case of failure */
1242 memset(clsid, 0, sizeof(*clsid));
1244 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1245 strcpyW( buf, progid );
1246 strcatW( buf, clsidW );
1247 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1249 HeapFree(GetProcessHeap(),0,buf);
1250 return CO_E_CLASSSTRING;
1252 HeapFree(GetProcessHeap(),0,buf);
1254 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1256 RegCloseKey(xhkey);
1257 return CO_E_CLASSSTRING;
1259 RegCloseKey(xhkey);
1260 return CLSIDFromString(buf2,clsid);
1264 /*****************************************************************************
1265 * CoGetPSClsid [OLE32.@]
1267 * Retrieves the CLSID of the proxy/stub factory that implements
1268 * IPSFactoryBuffer for the specified interface.
1270 * PARAMS
1271 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1272 * pclsid [O] Where to store returned proxy/stub CLSID.
1274 * RETURNS
1275 * S_OK
1276 * E_OUTOFMEMORY
1277 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1279 * NOTES
1281 * The standard marshaller activates the object with the CLSID
1282 * returned and uses the CreateProxy and CreateStub methods on its
1283 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1284 * given object.
1286 * CoGetPSClsid determines this CLSID by searching the
1287 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1288 * in the registry and any interface id registered by
1289 * CoRegisterPSClsid within the current process.
1291 * BUGS
1293 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1294 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1295 * considered a bug in native unless an application depends on this (unlikely).
1297 * SEE ALSO
1298 * CoRegisterPSClsid.
1300 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1302 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1303 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1304 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1305 WCHAR value[CHARS_IN_GUID];
1306 LONG len;
1307 HKEY hkey;
1308 APARTMENT *apt = COM_CurrentApt();
1309 struct registered_psclsid *registered_psclsid;
1311 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1313 if (!apt)
1315 ERR("apartment not initialised\n");
1316 return CO_E_NOTINITIALIZED;
1319 if (!pclsid)
1321 ERR("pclsid isn't optional\n");
1322 return E_INVALIDARG;
1325 EnterCriticalSection(&apt->cs);
1327 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1328 if (IsEqualIID(&registered_psclsid->iid, riid))
1330 *pclsid = registered_psclsid->clsid;
1331 LeaveCriticalSection(&apt->cs);
1332 return S_OK;
1335 LeaveCriticalSection(&apt->cs);
1337 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1338 strcpyW(path, wszInterface);
1339 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1340 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1342 /* Open the key.. */
1343 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1345 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1346 return REGDB_E_IIDNOTREG;
1349 /* ... Once we have the key, query the registry to get the
1350 value of CLSID as a string, and convert it into a
1351 proper CLSID structure to be passed back to the app */
1352 len = sizeof(value);
1353 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1355 RegCloseKey(hkey);
1356 return REGDB_E_IIDNOTREG;
1358 RegCloseKey(hkey);
1360 /* We have the CLSid we want back from the registry as a string, so
1361 lets convert it into a CLSID structure */
1362 if (CLSIDFromString(value, pclsid) != NOERROR)
1363 return REGDB_E_IIDNOTREG;
1365 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1366 return S_OK;
1369 /*****************************************************************************
1370 * CoRegisterPSClsid [OLE32.@]
1372 * Register a proxy/stub CLSID for the given interface in the current process
1373 * only.
1375 * PARAMS
1376 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1377 * rclsid [I] CLSID of the proxy/stub.
1379 * RETURNS
1380 * Success: S_OK
1381 * Failure: E_OUTOFMEMORY
1383 * NOTES
1385 * This function does not add anything to the registry and the effects are
1386 * limited to the lifetime of the current process.
1388 * SEE ALSO
1389 * CoGetPSClsid.
1391 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1393 APARTMENT *apt = COM_CurrentApt();
1394 struct registered_psclsid *registered_psclsid;
1396 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1398 if (!apt)
1400 ERR("apartment not initialised\n");
1401 return CO_E_NOTINITIALIZED;
1404 EnterCriticalSection(&apt->cs);
1406 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1407 if (IsEqualIID(&registered_psclsid->iid, riid))
1409 registered_psclsid->clsid = *rclsid;
1410 LeaveCriticalSection(&apt->cs);
1411 return S_OK;
1414 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1415 if (!registered_psclsid)
1417 LeaveCriticalSection(&apt->cs);
1418 return E_OUTOFMEMORY;
1421 registered_psclsid->iid = *riid;
1422 registered_psclsid->clsid = *rclsid;
1423 list_add_head(&apt->psclsids, &registered_psclsid->entry);
1425 LeaveCriticalSection(&apt->cs);
1427 return S_OK;
1431 /***
1432 * COM_GetRegisteredClassObject
1434 * This internal method is used to scan the registered class list to
1435 * find a class object.
1437 * Params:
1438 * rclsid Class ID of the class to find.
1439 * dwClsContext Class context to match.
1440 * ppv [out] returns a pointer to the class object. Complying
1441 * to normal COM usage, this method will increase the
1442 * reference count on this object.
1444 static HRESULT COM_GetRegisteredClassObject(
1445 REFCLSID rclsid,
1446 DWORD dwClsContext,
1447 LPUNKNOWN* ppUnk)
1449 HRESULT hr = S_FALSE;
1450 RegisteredClass *curClass;
1453 * Sanity check
1455 assert(ppUnk!=0);
1457 EnterCriticalSection( &csRegisteredClassList );
1459 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1462 * Check if we have a match on the class ID and context.
1464 if ((dwClsContext & curClass->runContext) &&
1465 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1468 * We have a match, return the pointer to the class object.
1470 *ppUnk = curClass->classObject;
1472 IUnknown_AddRef(curClass->classObject);
1474 hr = S_OK;
1475 break;
1479 LeaveCriticalSection( &csRegisteredClassList );
1481 return hr;
1484 /******************************************************************************
1485 * CoRegisterClassObject [OLE32.@]
1487 * Registers the class object for a given class ID. Servers housed in EXE
1488 * files use this method instead of exporting DllGetClassObject to allow
1489 * other code to connect to their objects.
1491 * PARAMS
1492 * rclsid [I] CLSID of the object to register.
1493 * pUnk [I] IUnknown of the object.
1494 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1495 * flags [I] REGCLS flags indicating how connections are made.
1496 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1498 * RETURNS
1499 * S_OK on success,
1500 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1501 * CO_E_OBJISREG if the object is already registered. We should not return this.
1503 * SEE ALSO
1504 * CoRevokeClassObject, CoGetClassObject
1506 * BUGS
1507 * MSDN claims that multiple interface registrations are legal, but we
1508 * can't do that with our current implementation.
1510 HRESULT WINAPI CoRegisterClassObject(
1511 REFCLSID rclsid,
1512 LPUNKNOWN pUnk,
1513 DWORD dwClsContext,
1514 DWORD flags,
1515 LPDWORD lpdwRegister)
1517 RegisteredClass* newClass;
1518 LPUNKNOWN foundObject;
1519 HRESULT hr;
1521 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1522 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1524 if ( (lpdwRegister==0) || (pUnk==0) )
1525 return E_INVALIDARG;
1527 if (!COM_CurrentApt())
1529 ERR("COM was not initialized\n");
1530 return CO_E_NOTINITIALIZED;
1533 *lpdwRegister = 0;
1535 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1536 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1537 if (flags & REGCLS_MULTIPLEUSE)
1538 dwClsContext |= CLSCTX_INPROC_SERVER;
1541 * First, check if the class is already registered.
1542 * If it is, this should cause an error.
1544 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1545 if (hr == S_OK) {
1546 if (flags & REGCLS_MULTIPLEUSE) {
1547 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1548 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1549 IUnknown_Release(foundObject);
1550 return hr;
1552 IUnknown_Release(foundObject);
1553 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1554 return CO_E_OBJISREG;
1557 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1558 if ( newClass == NULL )
1559 return E_OUTOFMEMORY;
1561 newClass->classIdentifier = *rclsid;
1562 newClass->runContext = dwClsContext;
1563 newClass->connectFlags = flags;
1564 newClass->pMarshaledData = NULL;
1565 newClass->RpcRegistration = NULL;
1568 * Use the address of the chain node as the cookie since we are sure it's
1569 * unique. FIXME: not on 64-bit platforms.
1571 newClass->dwCookie = (DWORD)newClass;
1574 * Since we're making a copy of the object pointer, we have to increase its
1575 * reference count.
1577 newClass->classObject = pUnk;
1578 IUnknown_AddRef(newClass->classObject);
1580 EnterCriticalSection( &csRegisteredClassList );
1581 list_add_tail(&RegisteredClassList, &newClass->entry);
1582 LeaveCriticalSection( &csRegisteredClassList );
1584 *lpdwRegister = newClass->dwCookie;
1586 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1587 IClassFactory *classfac;
1589 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1590 (LPVOID*)&classfac);
1591 if (hr) return hr;
1593 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1594 if (hr) {
1595 FIXME("Failed to create stream on hglobal, %x\n", hr);
1596 IUnknown_Release(classfac);
1597 return hr;
1599 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1600 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1601 MSHLFLAGS_TABLESTRONG);
1602 if (hr) {
1603 FIXME("CoMarshalInterface failed, %x!\n",hr);
1604 IUnknown_Release(classfac);
1605 return hr;
1608 IUnknown_Release(classfac);
1610 hr = RPC_StartLocalServer(&newClass->classIdentifier,
1611 newClass->pMarshaledData,
1612 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
1613 &newClass->RpcRegistration);
1615 return S_OK;
1618 /***********************************************************************
1619 * CoRevokeClassObject [OLE32.@]
1621 * Removes a class object from the class registry.
1623 * PARAMS
1624 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1626 * RETURNS
1627 * Success: S_OK.
1628 * Failure: HRESULT code.
1630 * SEE ALSO
1631 * CoRegisterClassObject
1633 HRESULT WINAPI CoRevokeClassObject(
1634 DWORD dwRegister)
1636 HRESULT hr = E_INVALIDARG;
1637 RegisteredClass *curClass;
1639 TRACE("(%08x)\n",dwRegister);
1641 EnterCriticalSection( &csRegisteredClassList );
1643 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1646 * Check if we have a match on the cookie.
1648 if (curClass->dwCookie == dwRegister)
1650 list_remove(&curClass->entry);
1652 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
1653 RPC_StopLocalServer(curClass->RpcRegistration);
1656 * Release the reference to the class object.
1658 IUnknown_Release(curClass->classObject);
1660 if (curClass->pMarshaledData)
1662 LARGE_INTEGER zero;
1663 memset(&zero, 0, sizeof(zero));
1664 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
1665 CoReleaseMarshalData(curClass->pMarshaledData);
1669 * Free the memory used by the chain node.
1671 HeapFree(GetProcessHeap(), 0, curClass);
1673 hr = S_OK;
1674 break;
1678 LeaveCriticalSection( &csRegisteredClassList );
1680 return hr;
1683 /***********************************************************************
1684 * COM_RegReadPath [internal]
1686 * Reads a registry value and expands it when necessary
1688 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1690 DWORD ret;
1691 HKEY key;
1692 DWORD keytype;
1693 WCHAR src[MAX_PATH];
1694 DWORD dwLength = dstlen * sizeof(WCHAR);
1696 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1697 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1698 if (keytype == REG_EXPAND_SZ) {
1699 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1700 } else {
1701 lstrcpynW(dst, src, dstlen);
1704 RegCloseKey (key);
1706 return ret;
1709 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
1711 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
1712 DWORD keytype;
1713 DWORD ret;
1714 DWORD dwLength = len * sizeof(WCHAR);
1716 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
1717 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
1718 value[0] = '\0';
1721 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1723 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
1724 static const WCHAR wszFree[] = {'F','r','e','e',0};
1725 static const WCHAR wszBoth[] = {'B','o','t','h',0};
1726 HINSTANCE hLibrary;
1727 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1728 DllGetClassObjectFunc DllGetClassObject;
1729 WCHAR dllpath[MAX_PATH+1];
1730 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
1731 HRESULT hr;
1733 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
1734 /* "Apartment" */
1735 if (!strcmpiW(threading_model, wszApartment))
1737 APARTMENT *apt = COM_CurrentApt();
1738 if (apt->multi_threaded)
1740 /* try to find an STA */
1741 APARTMENT *host_apt = apartment_findfromtype(FALSE, FALSE);
1742 if (!host_apt)
1743 FIXME("create a host apartment for apartment-threaded object %s\n", debugstr_guid(rclsid));
1744 if (host_apt)
1746 struct host_object_params params;
1747 HWND hwnd = apartment_getwindow(host_apt);
1749 params.hkeydll = hkeydll;
1750 params.clsid = *rclsid;
1751 params.iid = *riid;
1752 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1753 if (FAILED(hr))
1754 return hr;
1755 hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1756 if (SUCCEEDED(hr))
1757 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1758 IStream_Release(params.stream);
1759 return hr;
1763 /* "Free" */
1764 else if (!strcmpiW(threading_model, wszFree))
1766 APARTMENT *apt = COM_CurrentApt();
1767 if (!apt->multi_threaded)
1769 FIXME("should create object %s in multi-threaded apartment\n",
1770 debugstr_guid(rclsid));
1773 /* everything except "Apartment", "Free" and "Both" */
1774 else if (strcmpiW(threading_model, wszBoth))
1776 APARTMENT *apt = COM_CurrentApt();
1778 /* everything else is main-threaded */
1779 if (threading_model[0])
1780 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
1781 debugstr_w(threading_model), debugstr_guid(rclsid));
1783 if (apt->multi_threaded || !apt->main)
1785 /* try to find an STA */
1786 APARTMENT *host_apt = apartment_findfromtype(FALSE, TRUE);
1787 if (!host_apt)
1788 FIXME("create a host apartment for main-threaded object %s\n", debugstr_guid(rclsid));
1789 if (host_apt)
1791 struct host_object_params params;
1792 HWND hwnd = apartment_getwindow(host_apt);
1794 params.hkeydll = hkeydll;
1795 params.clsid = *rclsid;
1796 params.iid = *riid;
1797 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1798 if (FAILED(hr))
1799 return hr;
1800 hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1801 if (SUCCEEDED(hr))
1802 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1803 IStream_Release(params.stream);
1804 return hr;
1809 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1811 /* failure: CLSID is not found in registry */
1812 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1813 return REGDB_E_CLASSNOTREG;
1816 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1818 /* failure: DLL could not be loaded */
1819 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1820 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1823 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1825 /* failure: the dll did not export DllGetClassObject */
1826 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1827 FreeLibrary( hLibrary );
1828 return CO_E_DLLNOTFOUND;
1831 /* OK: get the ClassObject */
1832 COMPOBJ_DLLList_Add( hLibrary );
1833 hr = DllGetClassObject(rclsid, riid, ppv);
1835 if (hr != S_OK)
1836 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1838 return hr;
1841 /***********************************************************************
1842 * CoGetClassObject [OLE32.@]
1844 * FIXME. If request allows of several options and there is a failure
1845 * with one (other than not being registered) do we try the
1846 * others or return failure? (E.g. inprocess is registered but
1847 * the DLL is not found but the server version works)
1849 HRESULT WINAPI CoGetClassObject(
1850 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1851 REFIID iid, LPVOID *ppv)
1853 LPUNKNOWN regClassObject;
1854 HRESULT hres = E_UNEXPECTED;
1856 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1858 if (!ppv)
1859 return E_INVALIDARG;
1861 *ppv = NULL;
1863 if (!COM_CurrentApt())
1865 ERR("apartment not initialised\n");
1866 return CO_E_NOTINITIALIZED;
1869 if (pServerInfo) {
1870 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1871 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1875 * First, try and see if we can't match the class ID with one of the
1876 * registered classes.
1878 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1880 /* Get the required interface from the retrieved pointer. */
1881 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1884 * Since QI got another reference on the pointer, we want to release the
1885 * one we already have. If QI was unsuccessful, this will release the object. This
1886 * is good since we are not returning it in the "out" parameter.
1888 IUnknown_Release(regClassObject);
1890 return hres;
1893 /* First try in-process server */
1894 if (CLSCTX_INPROC_SERVER & dwClsContext)
1896 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1897 HKEY hkey;
1899 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
1900 return FTMarshalCF_Create(iid, ppv);
1902 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1903 if (FAILED(hres))
1905 if (hres == REGDB_E_CLASSNOTREG)
1906 ERR("class %s not registered\n", debugstr_guid(rclsid));
1907 else
1908 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1911 if (SUCCEEDED(hres))
1913 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1914 RegCloseKey(hkey);
1917 /* return if we got a class, otherwise fall through to one of the
1918 * other types */
1919 if (SUCCEEDED(hres))
1920 return hres;
1923 /* Next try in-process handler */
1924 if (CLSCTX_INPROC_HANDLER & dwClsContext)
1926 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1927 HKEY hkey;
1929 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1930 if (FAILED(hres))
1932 if (hres == REGDB_E_CLASSNOTREG)
1933 ERR("class %s not registered\n", debugstr_guid(rclsid));
1934 else
1935 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1938 if (SUCCEEDED(hres))
1940 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1941 RegCloseKey(hkey);
1944 /* return if we got a class, otherwise fall through to one of the
1945 * other types */
1946 if (SUCCEEDED(hres))
1947 return hres;
1950 /* Next try out of process */
1951 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1953 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
1954 if (SUCCEEDED(hres))
1955 return hres;
1958 /* Finally try remote: this requires networked DCOM (a lot of work) */
1959 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1961 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1962 hres = E_NOINTERFACE;
1965 if (FAILED(hres))
1966 ERR("no class object %s could be created for context 0x%x\n",
1967 debugstr_guid(rclsid), dwClsContext);
1968 return hres;
1971 /***********************************************************************
1972 * CoResumeClassObjects (OLE32.@)
1974 * Resumes all class objects registered with REGCLS_SUSPENDED.
1976 * RETURNS
1977 * Success: S_OK.
1978 * Failure: HRESULT code.
1980 HRESULT WINAPI CoResumeClassObjects(void)
1982 FIXME("stub\n");
1983 return S_OK;
1986 /***********************************************************************
1987 * GetClassFile (OLE32.@)
1989 * This function supplies the CLSID associated with the given filename.
1991 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1993 IStorage *pstg=0;
1994 HRESULT res;
1995 int nbElm, length, i;
1996 LONG sizeProgId;
1997 LPOLESTR *pathDec=0,absFile=0,progId=0;
1998 LPWSTR extension;
1999 static const WCHAR bkslashW[] = {'\\',0};
2000 static const WCHAR dotW[] = {'.',0};
2002 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
2004 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
2005 if((StgIsStorageFile(filePathName))==S_OK){
2007 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
2009 if (SUCCEEDED(res))
2010 res=ReadClassStg(pstg,pclsid);
2012 IStorage_Release(pstg);
2014 return res;
2016 /* if the file is not a storage object then attemps to match various bits in the file against a
2017 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
2018 this case
2020 for(i=0;i<nFileTypes;i++)
2022 for(i=0;j<nPatternsForType;j++){
2024 PATTERN pat;
2025 HANDLE hFile;
2027 pat=ReadPatternFromRegistry(i,j);
2028 hFile=CreateFileW(filePathName,,,,,,hFile);
2029 SetFilePosition(hFile,pat.offset);
2030 ReadFile(hFile,buf,pat.size,&r,NULL);
2031 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
2033 *pclsid=ReadCLSIDFromRegistry(i);
2034 return S_OK;
2039 /* if the above strategies fail then search for the extension key in the registry */
2041 /* get the last element (absolute file) in the path name */
2042 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
2043 absFile=pathDec[nbElm-1];
2045 /* failed if the path represente a directory and not an absolute file name*/
2046 if (!lstrcmpW(absFile, bkslashW))
2047 return MK_E_INVALIDEXTENSION;
2049 /* get the extension of the file */
2050 extension = NULL;
2051 length=lstrlenW(absFile);
2052 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
2053 /* nothing */;
2055 if (!extension || !lstrcmpW(extension, dotW))
2056 return MK_E_INVALIDEXTENSION;
2058 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
2060 /* get the progId associated to the extension */
2061 progId = CoTaskMemAlloc(sizeProgId);
2062 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
2064 if (res==ERROR_SUCCESS)
2065 /* return the clsid associated to the progId */
2066 res= CLSIDFromProgID(progId,pclsid);
2068 for(i=0; pathDec[i]!=NULL;i++)
2069 CoTaskMemFree(pathDec[i]);
2070 CoTaskMemFree(pathDec);
2072 CoTaskMemFree(progId);
2074 if (res==ERROR_SUCCESS)
2075 return res;
2077 return MK_E_INVALIDEXTENSION;
2080 /***********************************************************************
2081 * CoCreateInstance [OLE32.@]
2083 * Creates an instance of the specified class.
2085 * PARAMS
2086 * rclsid [I] Class ID to create an instance of.
2087 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2088 * dwClsContext [I] Flags to restrict the location of the created instance.
2089 * iid [I] The ID of the interface of the instance to return.
2090 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2092 * RETURNS
2093 * Success: S_OK
2094 * Failure: HRESULT code.
2096 * NOTES
2097 * The dwClsContext parameter can be one or more of the following:
2098 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2099 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2100 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2101 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2103 * Aggregation is the concept of deferring the IUnknown of an object to another
2104 * object. This allows a separate object to behave as though it was part of
2105 * the object and to allow this the pUnkOuter parameter can be set. Note that
2106 * not all objects support having an outer of unknown.
2108 * SEE ALSO
2109 * CoGetClassObject()
2111 HRESULT WINAPI CoCreateInstance(
2112 REFCLSID rclsid,
2113 LPUNKNOWN pUnkOuter,
2114 DWORD dwClsContext,
2115 REFIID iid,
2116 LPVOID *ppv)
2118 HRESULT hres;
2119 LPCLASSFACTORY lpclf = 0;
2121 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2122 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2125 * Sanity check
2127 if (ppv==0)
2128 return E_POINTER;
2131 * Initialize the "out" parameter
2133 *ppv = 0;
2135 if (!COM_CurrentApt())
2137 ERR("apartment not initialised\n");
2138 return CO_E_NOTINITIALIZED;
2142 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2143 * Rather than create a class factory, we can just check for it here
2145 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2146 if (StdGlobalInterfaceTableInstance == NULL)
2147 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2148 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2149 if (hres) return hres;
2151 TRACE("Retrieved GIT (%p)\n", *ppv);
2152 return S_OK;
2156 * Get a class factory to construct the object we want.
2158 hres = CoGetClassObject(rclsid,
2159 dwClsContext,
2160 NULL,
2161 &IID_IClassFactory,
2162 (LPVOID)&lpclf);
2164 if (FAILED(hres))
2165 return hres;
2168 * Create the object and don't forget to release the factory
2170 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2171 IClassFactory_Release(lpclf);
2172 if(FAILED(hres))
2173 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2174 debugstr_guid(iid), debugstr_guid(rclsid),hres);
2176 return hres;
2179 /***********************************************************************
2180 * CoCreateInstanceEx [OLE32.@]
2182 HRESULT WINAPI CoCreateInstanceEx(
2183 REFCLSID rclsid,
2184 LPUNKNOWN pUnkOuter,
2185 DWORD dwClsContext,
2186 COSERVERINFO* pServerInfo,
2187 ULONG cmq,
2188 MULTI_QI* pResults)
2190 IUnknown* pUnk = NULL;
2191 HRESULT hr;
2192 ULONG index;
2193 ULONG successCount = 0;
2196 * Sanity check
2198 if ( (cmq==0) || (pResults==NULL))
2199 return E_INVALIDARG;
2201 if (pServerInfo!=NULL)
2202 FIXME("() non-NULL pServerInfo not supported!\n");
2205 * Initialize all the "out" parameters.
2207 for (index = 0; index < cmq; index++)
2209 pResults[index].pItf = NULL;
2210 pResults[index].hr = E_NOINTERFACE;
2214 * Get the object and get its IUnknown pointer.
2216 hr = CoCreateInstance(rclsid,
2217 pUnkOuter,
2218 dwClsContext,
2219 &IID_IUnknown,
2220 (VOID**)&pUnk);
2222 if (hr)
2223 return hr;
2226 * Then, query for all the interfaces requested.
2228 for (index = 0; index < cmq; index++)
2230 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2231 pResults[index].pIID,
2232 (VOID**)&(pResults[index].pItf));
2234 if (pResults[index].hr == S_OK)
2235 successCount++;
2239 * Release our temporary unknown pointer.
2241 IUnknown_Release(pUnk);
2243 if (successCount == 0)
2244 return E_NOINTERFACE;
2246 if (successCount!=cmq)
2247 return CO_S_NOTALLINTERFACES;
2249 return S_OK;
2252 /***********************************************************************
2253 * CoLoadLibrary (OLE32.@)
2255 * Loads a library.
2257 * PARAMS
2258 * lpszLibName [I] Path to library.
2259 * bAutoFree [I] Whether the library should automatically be freed.
2261 * RETURNS
2262 * Success: Handle to loaded library.
2263 * Failure: NULL.
2265 * SEE ALSO
2266 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2268 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2270 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2272 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2275 /***********************************************************************
2276 * CoFreeLibrary [OLE32.@]
2278 * Unloads a library from memory.
2280 * PARAMS
2281 * hLibrary [I] Handle to library to unload.
2283 * RETURNS
2284 * Nothing
2286 * SEE ALSO
2287 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2289 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2291 FreeLibrary(hLibrary);
2295 /***********************************************************************
2296 * CoFreeAllLibraries [OLE32.@]
2298 * Function for backwards compatibility only. Does nothing.
2300 * RETURNS
2301 * Nothing.
2303 * SEE ALSO
2304 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2306 void WINAPI CoFreeAllLibraries(void)
2308 /* NOP */
2312 /***********************************************************************
2313 * CoFreeUnusedLibraries [OLE32.@]
2314 * CoFreeUnusedLibraries [COMPOBJ.17]
2316 * Frees any unused libraries. Unused are identified as those that return
2317 * S_OK from their DllCanUnloadNow function.
2319 * RETURNS
2320 * Nothing.
2322 * SEE ALSO
2323 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2325 void WINAPI CoFreeUnusedLibraries(void)
2327 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2328 * through the main apartment's thread to call DllCanUnloadNow */
2329 COMPOBJ_DllList_FreeUnused(0);
2332 /***********************************************************************
2333 * CoFileTimeNow [OLE32.@]
2334 * CoFileTimeNow [COMPOBJ.82]
2336 * Retrieves the current time in FILETIME format.
2338 * PARAMS
2339 * lpFileTime [O] The current time.
2341 * RETURNS
2342 * S_OK.
2344 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2346 GetSystemTimeAsFileTime( lpFileTime );
2347 return S_OK;
2350 static void COM_RevokeAllClasses(void)
2352 EnterCriticalSection( &csRegisteredClassList );
2354 while (list_head(&RegisteredClassList))
2356 RegisteredClass *curClass = LIST_ENTRY(list_head(&RegisteredClassList),
2357 RegisteredClass, entry);
2358 CoRevokeClassObject(curClass->dwCookie);
2361 LeaveCriticalSection( &csRegisteredClassList );
2364 /******************************************************************************
2365 * CoLockObjectExternal [OLE32.@]
2367 * Increments or decrements the external reference count of a stub object.
2369 * PARAMS
2370 * pUnk [I] Stub object.
2371 * fLock [I] If TRUE then increments the external ref-count,
2372 * otherwise decrements.
2373 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2374 * calling CoDisconnectObject.
2376 * RETURNS
2377 * Success: S_OK.
2378 * Failure: HRESULT code.
2380 * NOTES
2381 * If fLock is TRUE and an object is passed in that doesn't have a stub
2382 * manager then a new stub manager is created for the object.
2384 HRESULT WINAPI CoLockObjectExternal(
2385 LPUNKNOWN pUnk,
2386 BOOL fLock,
2387 BOOL fLastUnlockReleases)
2389 struct stub_manager *stubmgr;
2390 struct apartment *apt;
2392 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2393 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2395 apt = COM_CurrentApt();
2396 if (!apt) return CO_E_NOTINITIALIZED;
2398 stubmgr = get_stub_manager_from_object(apt, pUnk);
2400 if (stubmgr)
2402 if (fLock)
2403 stub_manager_ext_addref(stubmgr, 1);
2404 else
2405 stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases);
2407 stub_manager_int_release(stubmgr);
2409 return S_OK;
2411 else if (fLock)
2413 stubmgr = new_stub_manager(apt, pUnk);
2415 if (stubmgr)
2417 stub_manager_ext_addref(stubmgr, 1);
2418 stub_manager_int_release(stubmgr);
2421 return S_OK;
2423 else
2425 WARN("stub object not found %p\n", pUnk);
2426 /* Note: native is pretty broken here because it just silently
2427 * fails, without returning an appropriate error code, making apps
2428 * think that the object was disconnected, when it actually wasn't */
2429 return S_OK;
2433 /***********************************************************************
2434 * CoInitializeWOW (OLE32.@)
2436 * WOW equivalent of CoInitialize?
2438 * PARAMS
2439 * x [I] Unknown.
2440 * y [I] Unknown.
2442 * RETURNS
2443 * Unknown.
2445 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2447 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2448 return 0;
2451 /***********************************************************************
2452 * CoGetState [OLE32.@]
2454 * Retrieves the thread state object previously stored by CoSetState().
2456 * PARAMS
2457 * ppv [I] Address where pointer to object will be stored.
2459 * RETURNS
2460 * Success: S_OK.
2461 * Failure: E_OUTOFMEMORY.
2463 * NOTES
2464 * Crashes on all invalid ppv addresses, including NULL.
2465 * If the function returns a non-NULL object then the caller must release its
2466 * reference on the object when the object is no longer required.
2468 * SEE ALSO
2469 * CoSetState().
2471 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2473 struct oletls *info = COM_CurrentInfo();
2474 if (!info) return E_OUTOFMEMORY;
2476 *ppv = NULL;
2478 if (info->state)
2480 IUnknown_AddRef(info->state);
2481 *ppv = info->state;
2482 TRACE("apt->state=%p\n", info->state);
2485 return S_OK;
2488 /***********************************************************************
2489 * CoSetState [OLE32.@]
2491 * Sets the thread state object.
2493 * PARAMS
2494 * pv [I] Pointer to state object to be stored.
2496 * NOTES
2497 * The system keeps a reference on the object while the object stored.
2499 * RETURNS
2500 * Success: S_OK.
2501 * Failure: E_OUTOFMEMORY.
2503 HRESULT WINAPI CoSetState(IUnknown * pv)
2505 struct oletls *info = COM_CurrentInfo();
2506 if (!info) return E_OUTOFMEMORY;
2508 if (pv) IUnknown_AddRef(pv);
2510 if (info->state)
2512 TRACE("-- release %p now\n", info->state);
2513 IUnknown_Release(info->state);
2516 info->state = pv;
2518 return S_OK;
2522 /******************************************************************************
2523 * CoTreatAsClass [OLE32.@]
2525 * Sets the TreatAs value of a class.
2527 * PARAMS
2528 * clsidOld [I] Class to set TreatAs value on.
2529 * clsidNew [I] The class the clsidOld should be treated as.
2531 * RETURNS
2532 * Success: S_OK.
2533 * Failure: HRESULT code.
2535 * SEE ALSO
2536 * CoGetTreatAsClass
2538 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2540 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2541 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2542 HKEY hkey = NULL;
2543 WCHAR szClsidNew[CHARS_IN_GUID];
2544 HRESULT res = S_OK;
2545 WCHAR auto_treat_as[CHARS_IN_GUID];
2546 LONG auto_treat_as_size = sizeof(auto_treat_as);
2547 CLSID id;
2549 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2550 if (FAILED(res))
2551 goto done;
2552 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2554 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2555 !CLSIDFromString(auto_treat_as, &id))
2557 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2559 res = REGDB_E_WRITEREGDB;
2560 goto done;
2563 else
2565 RegDeleteKeyW(hkey, wszTreatAs);
2566 goto done;
2569 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2570 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2572 res = REGDB_E_WRITEREGDB;
2573 goto done;
2576 done:
2577 if (hkey) RegCloseKey(hkey);
2578 return res;
2581 /******************************************************************************
2582 * CoGetTreatAsClass [OLE32.@]
2584 * Gets the TreatAs value of a class.
2586 * PARAMS
2587 * clsidOld [I] Class to get the TreatAs value of.
2588 * clsidNew [I] The class the clsidOld should be treated as.
2590 * RETURNS
2591 * Success: S_OK.
2592 * Failure: HRESULT code.
2594 * SEE ALSO
2595 * CoSetTreatAsClass
2597 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2599 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2600 HKEY hkey = NULL;
2601 WCHAR szClsidNew[CHARS_IN_GUID];
2602 HRESULT res = S_OK;
2603 LONG len = sizeof(szClsidNew);
2605 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2606 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2608 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2609 if (FAILED(res))
2610 goto done;
2611 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2613 res = S_FALSE;
2614 goto done;
2616 res = CLSIDFromString(szClsidNew,clsidNew);
2617 if (FAILED(res))
2618 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2619 done:
2620 if (hkey) RegCloseKey(hkey);
2621 return res;
2624 /******************************************************************************
2625 * CoGetCurrentProcess [OLE32.@]
2626 * CoGetCurrentProcess [COMPOBJ.34]
2628 * Gets the current process ID.
2630 * RETURNS
2631 * The current process ID.
2633 * NOTES
2634 * Is DWORD really the correct return type for this function?
2636 DWORD WINAPI CoGetCurrentProcess(void)
2638 return GetCurrentProcessId();
2641 /******************************************************************************
2642 * CoRegisterMessageFilter [OLE32.@]
2644 * Registers a message filter.
2646 * PARAMS
2647 * lpMessageFilter [I] Pointer to interface.
2648 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2650 * RETURNS
2651 * Success: S_OK.
2652 * Failure: HRESULT code.
2654 * NOTES
2655 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2656 * lpMessageFilter removes the message filter.
2658 * If lplpMessageFilter is not NULL the previous message filter will be
2659 * returned in the memory pointer to this parameter and the caller is
2660 * responsible for releasing the object.
2662 * The current thread be in an apartment otherwise the function will crash.
2664 HRESULT WINAPI CoRegisterMessageFilter(
2665 LPMESSAGEFILTER lpMessageFilter,
2666 LPMESSAGEFILTER *lplpMessageFilter)
2668 struct apartment *apt;
2669 IMessageFilter *lpOldMessageFilter;
2671 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2673 apt = COM_CurrentApt();
2675 /* can't set a message filter in a multi-threaded apartment */
2676 if (!apt || apt->multi_threaded)
2678 WARN("can't set message filter in MTA or uninitialized apt\n");
2679 return CO_E_NOT_SUPPORTED;
2682 if (lpMessageFilter)
2683 IMessageFilter_AddRef(lpMessageFilter);
2685 EnterCriticalSection(&apt->cs);
2687 lpOldMessageFilter = apt->filter;
2688 apt->filter = lpMessageFilter;
2690 LeaveCriticalSection(&apt->cs);
2692 if (lplpMessageFilter)
2693 *lplpMessageFilter = lpOldMessageFilter;
2694 else if (lpOldMessageFilter)
2695 IMessageFilter_Release(lpOldMessageFilter);
2697 return S_OK;
2700 /***********************************************************************
2701 * CoIsOle1Class [OLE32.@]
2703 * Determines whether the specified class an OLE v1 class.
2705 * PARAMS
2706 * clsid [I] Class to test.
2708 * RETURNS
2709 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2711 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2713 FIXME("%s\n", debugstr_guid(clsid));
2714 return FALSE;
2717 /***********************************************************************
2718 * IsEqualGUID [OLE32.@]
2720 * Compares two Unique Identifiers.
2722 * PARAMS
2723 * rguid1 [I] The first GUID to compare.
2724 * rguid2 [I] The other GUID to compare.
2726 * RETURNS
2727 * TRUE if equal
2729 #undef IsEqualGUID
2730 BOOL WINAPI IsEqualGUID(
2731 REFGUID rguid1,
2732 REFGUID rguid2)
2734 return !memcmp(rguid1,rguid2,sizeof(GUID));
2737 /***********************************************************************
2738 * CoInitializeSecurity [OLE32.@]
2740 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2741 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2742 void* pReserved1, DWORD dwAuthnLevel,
2743 DWORD dwImpLevel, void* pReserved2,
2744 DWORD dwCapabilities, void* pReserved3)
2746 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
2747 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2748 dwCapabilities, pReserved3);
2749 return S_OK;
2752 /***********************************************************************
2753 * CoSuspendClassObjects [OLE32.@]
2755 * Suspends all registered class objects to prevent further requests coming in
2756 * for those objects.
2758 * RETURNS
2759 * Success: S_OK.
2760 * Failure: HRESULT code.
2762 HRESULT WINAPI CoSuspendClassObjects(void)
2764 FIXME("\n");
2765 return S_OK;
2768 /***********************************************************************
2769 * CoAddRefServerProcess [OLE32.@]
2771 * Helper function for incrementing the reference count of a local-server
2772 * process.
2774 * RETURNS
2775 * New reference count.
2777 * SEE ALSO
2778 * CoReleaseServerProcess().
2780 ULONG WINAPI CoAddRefServerProcess(void)
2782 ULONG refs;
2784 TRACE("\n");
2786 EnterCriticalSection(&csRegisteredClassList);
2787 refs = ++s_COMServerProcessReferences;
2788 LeaveCriticalSection(&csRegisteredClassList);
2790 TRACE("refs before: %d\n", refs - 1);
2792 return refs;
2795 /***********************************************************************
2796 * CoReleaseServerProcess [OLE32.@]
2798 * Helper function for decrementing the reference count of a local-server
2799 * process.
2801 * RETURNS
2802 * New reference count.
2804 * NOTES
2805 * When reference count reaches 0, this function suspends all registered
2806 * classes so no new connections are accepted.
2808 * SEE ALSO
2809 * CoAddRefServerProcess(), CoSuspendClassObjects().
2811 ULONG WINAPI CoReleaseServerProcess(void)
2813 ULONG refs;
2815 TRACE("\n");
2817 EnterCriticalSection(&csRegisteredClassList);
2819 refs = --s_COMServerProcessReferences;
2820 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
2822 LeaveCriticalSection(&csRegisteredClassList);
2824 TRACE("refs after: %d\n", refs);
2826 return refs;
2829 /***********************************************************************
2830 * CoIsHandlerConnected [OLE32.@]
2832 * Determines whether a proxy is connected to a remote stub.
2834 * PARAMS
2835 * pUnk [I] Pointer to object that may or may not be connected.
2837 * RETURNS
2838 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2839 * FALSE otherwise.
2841 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2843 FIXME("%p\n", pUnk);
2845 return TRUE;
2848 /***********************************************************************
2849 * CoAllowSetForegroundWindow [OLE32.@]
2852 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2854 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2855 return S_OK;
2858 /***********************************************************************
2859 * CoQueryProxyBlanket [OLE32.@]
2861 * Retrieves the security settings being used by a proxy.
2863 * PARAMS
2864 * pProxy [I] Pointer to the proxy object.
2865 * pAuthnSvc [O] The type of authentication service.
2866 * pAuthzSvc [O] The type of authorization service.
2867 * ppServerPrincName [O] Optional. The server prinicple name.
2868 * pAuthnLevel [O] The authentication level.
2869 * pImpLevel [O] The impersonation level.
2870 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2871 * pCapabilities [O] Flags affecting the security behaviour.
2873 * RETURNS
2874 * Success: S_OK.
2875 * Failure: HRESULT code.
2877 * SEE ALSO
2878 * CoCopyProxy, CoSetProxyBlanket.
2880 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2881 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2882 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2884 IClientSecurity *pCliSec;
2885 HRESULT hr;
2887 TRACE("%p\n", pProxy);
2889 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2890 if (SUCCEEDED(hr))
2892 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2893 pAuthzSvc, ppServerPrincName,
2894 pAuthnLevel, pImpLevel, ppAuthInfo,
2895 pCapabilities);
2896 IClientSecurity_Release(pCliSec);
2899 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
2900 return hr;
2903 /***********************************************************************
2904 * CoSetProxyBlanket [OLE32.@]
2906 * Sets the security settings for a proxy.
2908 * PARAMS
2909 * pProxy [I] Pointer to the proxy object.
2910 * AuthnSvc [I] The type of authentication service.
2911 * AuthzSvc [I] The type of authorization service.
2912 * pServerPrincName [I] The server prinicple name.
2913 * AuthnLevel [I] The authentication level.
2914 * ImpLevel [I] The impersonation level.
2915 * pAuthInfo [I] Information specific to the authorization/authentication service.
2916 * Capabilities [I] Flags affecting the security behaviour.
2918 * RETURNS
2919 * Success: S_OK.
2920 * Failure: HRESULT code.
2922 * SEE ALSO
2923 * CoQueryProxyBlanket, CoCopyProxy.
2925 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2926 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2927 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2929 IClientSecurity *pCliSec;
2930 HRESULT hr;
2932 TRACE("%p\n", pProxy);
2934 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2935 if (SUCCEEDED(hr))
2937 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2938 AuthzSvc, pServerPrincName,
2939 AuthnLevel, ImpLevel, pAuthInfo,
2940 Capabilities);
2941 IClientSecurity_Release(pCliSec);
2944 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
2945 return hr;
2948 /***********************************************************************
2949 * CoCopyProxy [OLE32.@]
2951 * Copies a proxy.
2953 * PARAMS
2954 * pProxy [I] Pointer to the proxy object.
2955 * ppCopy [O] Copy of the proxy.
2957 * RETURNS
2958 * Success: S_OK.
2959 * Failure: HRESULT code.
2961 * SEE ALSO
2962 * CoQueryProxyBlanket, CoSetProxyBlanket.
2964 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2966 IClientSecurity *pCliSec;
2967 HRESULT hr;
2969 TRACE("%p\n", pProxy);
2971 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2972 if (SUCCEEDED(hr))
2974 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2975 IClientSecurity_Release(pCliSec);
2978 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
2979 return hr;
2983 /***********************************************************************
2984 * CoGetCallContext [OLE32.@]
2986 * Gets the context of the currently executing server call in the current
2987 * thread.
2989 * PARAMS
2990 * riid [I] Context interface to return.
2991 * ppv [O] Pointer to memory that will receive the context on return.
2993 * RETURNS
2994 * Success: S_OK.
2995 * Failure: HRESULT code.
2997 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
2999 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
3001 *ppv = NULL;
3002 return E_NOINTERFACE;
3005 /***********************************************************************
3006 * CoQueryClientBlanket [OLE32.@]
3008 * Retrieves the authentication information about the client of the currently
3009 * executing server call in the current thread.
3011 * PARAMS
3012 * pAuthnSvc [O] Optional. The type of authentication service.
3013 * pAuthzSvc [O] Optional. The type of authorization service.
3014 * pServerPrincName [O] Optional. The server prinicple name.
3015 * pAuthnLevel [O] Optional. The authentication level.
3016 * pImpLevel [O] Optional. The impersonation level.
3017 * pPrivs [O] Optional. Information about the privileges of the client.
3018 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3020 * RETURNS
3021 * Success: S_OK.
3022 * Failure: HRESULT code.
3024 * SEE ALSO
3025 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3027 HRESULT WINAPI CoQueryClientBlanket(
3028 DWORD *pAuthnSvc,
3029 DWORD *pAuthzSvc,
3030 OLECHAR **pServerPrincName,
3031 DWORD *pAuthnLevel,
3032 DWORD *pImpLevel,
3033 RPC_AUTHZ_HANDLE *pPrivs,
3034 DWORD *pCapabilities)
3036 IServerSecurity *pSrvSec;
3037 HRESULT hr;
3039 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3040 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3041 pPrivs, pCapabilities);
3043 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3044 if (SUCCEEDED(hr))
3046 hr = IServerSecurity_QueryBlanket(
3047 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3048 pImpLevel, pPrivs, pCapabilities);
3049 IServerSecurity_Release(pSrvSec);
3052 return hr;
3055 /***********************************************************************
3056 * CoImpersonateClient [OLE32.@]
3058 * Impersonates the client of the currently executing server call in the
3059 * current thread.
3061 * PARAMS
3062 * None.
3064 * RETURNS
3065 * Success: S_OK.
3066 * Failure: HRESULT code.
3068 * NOTES
3069 * If this function fails then the current thread will not be impersonating
3070 * the client and all actions will take place on behalf of the server.
3071 * Therefore, it is important to check the return value from this function.
3073 * SEE ALSO
3074 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3076 HRESULT WINAPI CoImpersonateClient(void)
3078 IServerSecurity *pSrvSec;
3079 HRESULT hr;
3081 TRACE("\n");
3083 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3084 if (SUCCEEDED(hr))
3086 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3087 IServerSecurity_Release(pSrvSec);
3090 return hr;
3093 /***********************************************************************
3094 * CoRevertToSelf [OLE32.@]
3096 * Ends the impersonation of the client of the currently executing server
3097 * call in the current thread.
3099 * PARAMS
3100 * None.
3102 * RETURNS
3103 * Success: S_OK.
3104 * Failure: HRESULT code.
3106 * SEE ALSO
3107 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3109 HRESULT WINAPI CoRevertToSelf(void)
3111 IServerSecurity *pSrvSec;
3112 HRESULT hr;
3114 TRACE("\n");
3116 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3117 if (SUCCEEDED(hr))
3119 hr = IServerSecurity_RevertToSelf(pSrvSec);
3120 IServerSecurity_Release(pSrvSec);
3123 return hr;
3126 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3128 /* first try to retrieve messages for incoming COM calls to the apartment window */
3129 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3130 /* next retrieve other messages necessary for the app to remain responsive */
3131 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
3134 /***********************************************************************
3135 * CoWaitForMultipleHandles [OLE32.@]
3137 * Waits for one or more handles to become signaled.
3139 * PARAMS
3140 * dwFlags [I] Flags. See notes.
3141 * dwTimeout [I] Timeout in milliseconds.
3142 * cHandles [I] Number of handles pointed to by pHandles.
3143 * pHandles [I] Handles to wait for.
3144 * lpdwindex [O] Index of handle that was signaled.
3146 * RETURNS
3147 * Success: S_OK.
3148 * Failure: RPC_S_CALLPENDING on timeout.
3150 * NOTES
3152 * The dwFlags parameter can be zero or more of the following:
3153 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3154 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3156 * SEE ALSO
3157 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3159 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3160 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3162 HRESULT hr = S_OK;
3163 DWORD start_time = GetTickCount();
3164 APARTMENT *apt = COM_CurrentApt();
3165 BOOL message_loop = apt && !apt->multi_threaded;
3167 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3168 pHandles, lpdwindex);
3170 while (TRUE)
3172 DWORD now = GetTickCount();
3173 DWORD res;
3175 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
3177 hr = RPC_S_CALLPENDING;
3178 break;
3181 if (message_loop)
3183 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
3184 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
3186 TRACE("waiting for rpc completion or window message\n");
3188 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3189 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3190 QS_ALLINPUT, wait_flags);
3192 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3194 MSG msg;
3196 /* call message filter */
3198 if (COM_CurrentApt()->filter)
3200 PENDINGTYPE pendingtype =
3201 COM_CurrentInfo()->pending_call_count_server ?
3202 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3203 DWORD be_handled = IMessageFilter_MessagePending(
3204 COM_CurrentApt()->filter, 0 /* FIXME */,
3205 now - start_time, pendingtype);
3206 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3207 switch (be_handled)
3209 case PENDINGMSG_CANCELCALL:
3210 WARN("call canceled\n");
3211 hr = RPC_E_CALL_CANCELED;
3212 break;
3213 case PENDINGMSG_WAITNOPROCESS:
3214 case PENDINGMSG_WAITDEFPROCESS:
3215 default:
3216 /* FIXME: MSDN is very vague about the difference
3217 * between WAITNOPROCESS and WAITDEFPROCESS - there
3218 * appears to be none, so it is possibly a left-over
3219 * from the 16-bit world. */
3220 break;
3224 /* note: using "if" here instead of "while" might seem less
3225 * efficient, but only if we are optimising for quick delivery
3226 * of pending messages, rather than quick completion of the
3227 * COM call */
3228 if (COM_PeekMessage(apt, &msg))
3230 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3231 TranslateMessage(&msg);
3232 DispatchMessageW(&msg);
3233 if (msg.message == WM_QUIT)
3235 TRACE("resending WM_QUIT to outer message loop\n");
3236 PostQuitMessage(msg.wParam);
3237 /* no longer need to process messages */
3238 message_loop = FALSE;
3241 continue;
3244 else
3246 TRACE("waiting for rpc completion\n");
3248 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3249 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3250 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3251 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3254 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
3256 /* handle signaled, store index */
3257 *lpdwindex = (res - WAIT_OBJECT_0);
3258 break;
3260 else if (res == WAIT_TIMEOUT)
3262 hr = RPC_S_CALLPENDING;
3263 break;
3265 else
3267 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3268 hr = E_UNEXPECTED;
3269 break;
3272 TRACE("-- 0x%08x\n", hr);
3273 return hr;
3277 /***********************************************************************
3278 * CoGetObject [OLE32.@]
3280 * Gets the object named by coverting the name to a moniker and binding to it.
3282 * PARAMS
3283 * pszName [I] String representing the object.
3284 * pBindOptions [I] Parameters affecting the binding to the named object.
3285 * riid [I] Interface to bind to on the objecct.
3286 * ppv [O] On output, the interface riid of the object represented
3287 * by pszName.
3289 * RETURNS
3290 * Success: S_OK.
3291 * Failure: HRESULT code.
3293 * SEE ALSO
3294 * MkParseDisplayName.
3296 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3297 REFIID riid, void **ppv)
3299 IBindCtx *pbc;
3300 HRESULT hr;
3302 *ppv = NULL;
3304 hr = CreateBindCtx(0, &pbc);
3305 if (SUCCEEDED(hr))
3307 if (pBindOptions)
3308 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3310 if (SUCCEEDED(hr))
3312 ULONG chEaten;
3313 IMoniker *pmk;
3315 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3316 if (SUCCEEDED(hr))
3318 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3319 IMoniker_Release(pmk);
3323 IBindCtx_Release(pbc);
3325 return hr;
3328 /***********************************************************************
3329 * CoRegisterChannelHook [OLE32.@]
3331 * Registers a process-wide hook that is called during ORPC calls.
3333 * PARAMS
3334 * guidExtension [I] GUID of the channel hook to register.
3335 * pChannelHook [I] Channel hook object to register.
3337 * RETURNS
3338 * Success: S_OK.
3339 * Failure: HRESULT code.
3341 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3343 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3345 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3348 /***********************************************************************
3349 * DllMain (OLE32.@)
3351 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3353 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3355 switch(fdwReason) {
3356 case DLL_PROCESS_ATTACH:
3357 OLE32_hInstance = hinstDLL;
3358 COMPOBJ_InitProcess();
3359 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3360 break;
3362 case DLL_PROCESS_DETACH:
3363 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3364 COMPOBJ_UninitProcess();
3365 RPC_UnregisterAllChannelHooks();
3366 OLE32_hInstance = 0;
3367 break;
3369 case DLL_THREAD_DETACH:
3370 COM_TlsDestroy();
3371 break;
3373 return TRUE;
3376 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */