ole32: Add some documentation for CoCreateInstance.
[wine/testsucceed.git] / dlls / ole32 / compobj.c
blobdcae4f8edcbcf729a379131f1920b417e8ff7448
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 * - Call IMessageFilter functions.
39 * - Make all ole interface marshaling use NDR to be wire compatible with
40 * native DCOM
41 * - Use & interpret ORPCTHIS & ORPCTHAT.
45 #include "config.h"
47 #include <stdlib.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <assert.h>
53 #define COBJMACROS
54 #define NONAMELESSUNION
55 #define NONAMELESSSTRUCT
57 #include "windef.h"
58 #include "winbase.h"
59 #include "winerror.h"
60 #include "winreg.h"
61 #include "winuser.h"
62 #include "objbase.h"
63 #include "ole2.h"
64 #include "ole2ver.h"
66 #include "compobj_private.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole);
73 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
75 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
77 /****************************************************************************
78 * This section defines variables internal to the COM module.
80 * TODO: Most of these things will have to be made thread-safe.
83 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
84 static void COM_RevokeAllClasses(void);
85 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv);
87 static APARTMENT *MTA; /* protected by csApartment */
88 static APARTMENT *MainApartment; /* the first STA apartment */
89 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
91 static CRITICAL_SECTION csApartment;
92 static CRITICAL_SECTION_DEBUG critsect_debug =
94 0, 0, &csApartment,
95 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
96 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
98 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
100 struct registered_psclsid
102 struct list entry;
103 IID iid;
104 CLSID clsid;
108 * This lock count counts the number of times CoInitialize is called. It is
109 * decreased every time CoUninitialize is called. When it hits 0, the COM
110 * libraries are freed
112 static LONG s_COMLockCount = 0;
115 * This linked list contains the list of registered class objects. These
116 * are mostly used to register the factories for out-of-proc servers of OLE
117 * objects.
119 * TODO: Make this data structure aware of inter-process communication. This
120 * means that parts of this will be exported to the Wine Server.
122 typedef struct tagRegisteredClass
124 CLSID classIdentifier;
125 LPUNKNOWN classObject;
126 DWORD runContext;
127 DWORD connectFlags;
128 DWORD dwCookie;
129 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
130 struct tagRegisteredClass* nextClass;
131 } RegisteredClass;
133 static RegisteredClass* firstRegisteredClass = NULL;
135 static CRITICAL_SECTION csRegisteredClassList;
136 static CRITICAL_SECTION_DEBUG class_cs_debug =
138 0, 0, &csRegisteredClassList,
139 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
140 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
142 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
144 /*****************************************************************************
145 * This section contains OpenDllList definitions
147 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
148 * other functions that do LoadLibrary _without_ giving back a HMODULE.
149 * Without this list these handles would never be freed.
151 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
152 * next unload-call but not before 600 sec.
155 typedef struct tagOpenDll {
156 HINSTANCE hLibrary;
157 struct tagOpenDll *next;
158 } OpenDll;
160 static OpenDll *openDllList = NULL; /* linked list of open dlls */
162 static CRITICAL_SECTION csOpenDllList;
163 static CRITICAL_SECTION_DEBUG dll_cs_debug =
165 0, 0, &csOpenDllList,
166 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
167 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
169 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
171 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',' ',
172 '0','x','#','#','#','#','#','#','#','#',' ',0};
173 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
175 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
176 static void COMPOBJ_DllList_FreeUnused(int Timeout);
178 static void COMPOBJ_InitProcess( void )
180 WNDCLASSW wclass;
182 /* Dispatching to the correct thread in an apartment is done through
183 * window messages rather than RPC transports. When an interface is
184 * marshalled into another apartment in the same process, a window of the
185 * following class is created. The *caller* of CoMarshalInterface (ie the
186 * application) is responsible for pumping the message loop in that thread.
187 * The WM_USER messages which point to the RPCs are then dispatched to
188 * COM_AptWndProc by the user's code from the apartment in which the interface
189 * was unmarshalled.
191 memset(&wclass, 0, sizeof(wclass));
192 wclass.lpfnWndProc = apartment_wndproc;
193 wclass.hInstance = OLE32_hInstance;
194 wclass.lpszClassName = wszAptWinClass;
195 RegisterClassW(&wclass);
198 static void COMPOBJ_UninitProcess( void )
200 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
203 static void COM_TlsDestroy(void)
205 struct oletls *info = NtCurrentTeb()->ReservedForOle;
206 if (info)
208 if (info->apt) apartment_release(info->apt);
209 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
210 if (info->state) IUnknown_Release(info->state);
211 HeapFree(GetProcessHeap(), 0, info);
212 NtCurrentTeb()->ReservedForOle = NULL;
216 /******************************************************************************
217 * Manage apartments.
220 /* allocates memory and fills in the necessary fields for a new apartment
221 * object. must be called inside apartment cs */
222 static APARTMENT *apartment_construct(DWORD model)
224 APARTMENT *apt;
226 TRACE("creating new apartment, model=%d\n", model);
228 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
229 apt->tid = GetCurrentThreadId();
231 list_init(&apt->proxies);
232 list_init(&apt->stubmgrs);
233 list_init(&apt->psclsids);
234 apt->ipidc = 0;
235 apt->refs = 1;
236 apt->remunk_exported = FALSE;
237 apt->oidc = 1;
238 InitializeCriticalSection(&apt->cs);
239 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
241 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
243 if (apt->multi_threaded)
245 /* FIXME: should be randomly generated by in an RPC call to rpcss */
246 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
248 else
250 /* FIXME: should be randomly generated by in an RPC call to rpcss */
251 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
254 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
256 list_add_head(&apts, &apt->entry);
258 return apt;
261 /* gets and existing apartment if one exists or otherwise creates an apartment
262 * structure which stores OLE apartment-local information and stores a pointer
263 * to it in the thread-local storage */
264 static APARTMENT *apartment_get_or_create(DWORD model)
266 APARTMENT *apt = COM_CurrentApt();
268 if (!apt)
270 if (model & COINIT_APARTMENTTHREADED)
272 EnterCriticalSection(&csApartment);
274 apt = apartment_construct(model);
275 if (!MainApartment)
277 MainApartment = apt;
278 apt->main = TRUE;
279 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
282 LeaveCriticalSection(&csApartment);
284 else
286 EnterCriticalSection(&csApartment);
288 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
289 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
290 * in a process */
291 if (MTA)
293 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
294 apartment_addref(MTA);
296 else
297 MTA = apartment_construct(model);
299 apt = MTA;
301 LeaveCriticalSection(&csApartment);
303 COM_CurrentInfo()->apt = apt;
306 return apt;
309 static inline BOOL apartment_is_model(APARTMENT *apt, DWORD model)
311 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
314 DWORD apartment_addref(struct apartment *apt)
316 DWORD refs = InterlockedIncrement(&apt->refs);
317 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
318 return refs;
321 DWORD apartment_release(struct apartment *apt)
323 DWORD ret;
325 EnterCriticalSection(&csApartment);
327 ret = InterlockedDecrement(&apt->refs);
328 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
329 /* destruction stuff that needs to happen under csApartment CS */
330 if (ret == 0)
332 if (apt == MTA) MTA = NULL;
333 else if (apt == MainApartment) MainApartment = NULL;
334 list_remove(&apt->entry);
337 LeaveCriticalSection(&csApartment);
339 if (ret == 0)
341 struct list *cursor, *cursor2;
343 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
345 /* no locking is needed for this apartment, because no other thread
346 * can access it at this point */
348 apartment_disconnectproxies(apt);
350 if (apt->win) DestroyWindow(apt->win);
352 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
354 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
355 /* release the implicit reference given by the fact that the
356 * stub has external references (it must do since it is in the
357 * stub manager list in the apartment and all non-apartment users
358 * must have a ref on the apartment and so it cannot be destroyed).
360 stub_manager_int_release(stubmgr);
363 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
365 struct registered_psclsid *registered_psclsid =
366 LIST_ENTRY(cursor, struct registered_psclsid, entry);
368 list_remove(&registered_psclsid->entry);
369 HeapFree(GetProcessHeap(), 0, registered_psclsid);
372 /* if this assert fires, then another thread took a reference to a
373 * stub manager without taking a reference to the containing
374 * apartment, which it must do. */
375 assert(list_empty(&apt->stubmgrs));
377 if (apt->filter) IUnknown_Release(apt->filter);
379 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
380 DeleteCriticalSection(&apt->cs);
382 HeapFree(GetProcessHeap(), 0, apt);
385 return ret;
388 /* The given OXID must be local to this process:
390 * The ref parameter is here mostly to ensure people remember that
391 * they get one, you should normally take a ref for thread safety.
393 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
395 APARTMENT *result = NULL;
396 struct list *cursor;
398 EnterCriticalSection(&csApartment);
399 LIST_FOR_EACH( cursor, &apts )
401 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
402 if (apt->oxid == oxid)
404 result = apt;
405 if (ref) apartment_addref(result);
406 break;
409 LeaveCriticalSection(&csApartment);
411 return result;
414 /* gets the apartment which has a given creator thread ID. The caller must
415 * release the reference from the apartment as soon as the apartment pointer
416 * is no longer required. */
417 APARTMENT *apartment_findfromtid(DWORD tid)
419 APARTMENT *result = NULL;
420 struct list *cursor;
422 EnterCriticalSection(&csApartment);
423 LIST_FOR_EACH( cursor, &apts )
425 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
426 if (apt->tid == tid)
428 result = apt;
429 apartment_addref(result);
430 break;
433 LeaveCriticalSection(&csApartment);
435 return result;
438 /* gets an apartment which has a given type. The caller must
439 * release the reference from the apartment as soon as the apartment pointer
440 * is no longer required. */
441 static APARTMENT *apartment_findfromtype(BOOL multi_threaded, BOOL main_apartment)
443 APARTMENT *result = NULL;
444 struct apartment *apt;
446 EnterCriticalSection(&csApartment);
448 if (!multi_threaded && main_apartment)
450 result = MainApartment;
451 if (result) apartment_addref(result);
452 LeaveCriticalSection(&csApartment);
453 return result;
456 LIST_FOR_EACH_ENTRY( apt, &apts, struct apartment, entry )
458 if (apt->multi_threaded == multi_threaded)
460 result = apt;
461 apartment_addref(result);
462 break;
465 LeaveCriticalSection(&csApartment);
467 return result;
470 struct host_object_params
472 HKEY hkeydll;
473 CLSID clsid; /* clsid of object to marshal */
474 IID iid; /* interface to marshal */
475 IStream *stream; /* stream that the object will be marshaled into */
478 static HRESULT apartment_hostobject(const struct host_object_params *params)
480 IUnknown *object;
481 HRESULT hr;
482 static const LARGE_INTEGER llZero;
484 TRACE("\n");
486 hr = get_inproc_class_object(params->hkeydll, &params->clsid, &params->iid, (void **)&object);
487 if (FAILED(hr))
488 return hr;
490 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
491 if (FAILED(hr))
492 IUnknown_Release(object);
493 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
495 return hr;
498 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
500 switch (msg)
502 case DM_EXECUTERPC:
503 RPC_ExecuteCall((struct dispatch_params *)lParam);
504 return 0;
505 case DM_HOSTOBJECT:
506 return apartment_hostobject((const struct host_object_params *)lParam);
507 default:
508 return DefWindowProcW(hWnd, msg, wParam, lParam);
512 HRESULT apartment_createwindowifneeded(struct apartment *apt)
514 if (apt->multi_threaded)
515 return S_OK;
517 if (!apt->win)
519 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
520 0, 0, 0, 0,
521 0, 0, OLE32_hInstance, NULL);
522 if (!hwnd)
524 ERR("CreateWindow failed with error %d\n", GetLastError());
525 return HRESULT_FROM_WIN32(GetLastError());
527 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
528 /* someone beat us to it */
529 DestroyWindow(hwnd);
532 return S_OK;
535 HWND apartment_getwindow(struct apartment *apt)
537 assert(!apt->multi_threaded);
538 return apt->win;
541 void apartment_joinmta(void)
543 apartment_addref(MTA);
544 COM_CurrentInfo()->apt = MTA;
547 /*****************************************************************************
548 * This section contains OpenDllList implementation
551 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
553 OpenDll *ptr;
554 OpenDll *tmp;
556 TRACE("\n");
558 EnterCriticalSection( &csOpenDllList );
560 if (openDllList == NULL) {
561 /* empty list -- add first node */
562 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
563 openDllList->hLibrary=hLibrary;
564 openDllList->next = NULL;
565 } else {
566 /* search for this dll */
567 int found = FALSE;
568 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
569 if (ptr->hLibrary == hLibrary) {
570 found = TRUE;
571 break;
574 if (!found) {
575 /* dll not found, add it */
576 tmp = openDllList;
577 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
578 openDllList->hLibrary = hLibrary;
579 openDllList->next = tmp;
583 LeaveCriticalSection( &csOpenDllList );
586 static void COMPOBJ_DllList_FreeUnused(int Timeout)
588 OpenDll *curr, *next, *prev = NULL;
589 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
590 DllCanUnloadNowFunc DllCanUnloadNow;
592 TRACE("\n");
594 EnterCriticalSection( &csOpenDllList );
596 for (curr = openDllList; curr != NULL; ) {
597 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
599 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
600 next = curr->next;
602 TRACE("freeing %p\n", curr->hLibrary);
603 FreeLibrary(curr->hLibrary);
605 HeapFree(GetProcessHeap(), 0, curr);
606 if (curr == openDllList) {
607 openDllList = next;
608 } else {
609 prev->next = next;
612 curr = next;
613 } else {
614 prev = curr;
615 curr = curr->next;
619 LeaveCriticalSection( &csOpenDllList );
622 /******************************************************************************
623 * CoBuildVersion [OLE32.@]
624 * CoBuildVersion [COMPOBJ.1]
626 * Gets the build version of the DLL.
628 * PARAMS
630 * RETURNS
631 * Current build version, hiword is majornumber, loword is minornumber
633 DWORD WINAPI CoBuildVersion(void)
635 TRACE("Returning version %d, build %d.\n", rmm, rup);
636 return (rmm<<16)+rup;
639 /******************************************************************************
640 * CoInitialize [OLE32.@]
642 * Initializes the COM libraries by calling CoInitializeEx with
643 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
645 * PARAMS
646 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
648 * RETURNS
649 * Success: S_OK if not already initialized, S_FALSE otherwise.
650 * Failure: HRESULT code.
652 * SEE ALSO
653 * CoInitializeEx
655 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
658 * Just delegate to the newer method.
660 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
663 /******************************************************************************
664 * CoInitializeEx [OLE32.@]
666 * Initializes the COM libraries.
668 * PARAMS
669 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
670 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
672 * RETURNS
673 * S_OK if successful,
674 * S_FALSE if this function was called already.
675 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
676 * threading model.
678 * NOTES
680 * The behavior used to set the IMalloc used for memory management is
681 * obsolete.
682 * The dwCoInit parameter must specify one of the following apartment
683 * threading models:
684 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
685 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
686 * The parameter may also specify zero or more of the following flags:
687 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
688 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
690 * SEE ALSO
691 * CoUninitialize
693 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
695 HRESULT hr = S_OK;
696 APARTMENT *apt;
698 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
700 if (lpReserved!=NULL)
702 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
706 * Check the lock count. If this is the first time going through the initialize
707 * process, we have to initialize the libraries.
709 * And crank-up that lock count.
711 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
714 * Initialize the various COM libraries and data structures.
716 TRACE("() - Initializing the COM libraries\n");
718 /* we may need to defer this until after apartment initialisation */
719 RunningObjectTableImpl_Initialize();
722 if (!(apt = COM_CurrentInfo()->apt))
724 apt = apartment_get_or_create(dwCoInit);
725 if (!apt) return E_OUTOFMEMORY;
727 else if (!apartment_is_model(apt, dwCoInit))
729 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
730 code then we are probably using the wrong threading model to implement that API. */
731 ERR("Attempt to change threading model of this apartment from %s to %s\n",
732 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
733 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
734 return RPC_E_CHANGED_MODE;
736 else
737 hr = S_FALSE;
739 COM_CurrentInfo()->inits++;
741 return hr;
744 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
745 pending RPCs are ignored. Non-COM messages are discarded at this point.
747 static void COM_FlushMessageQueue(void)
749 MSG message;
750 APARTMENT *apt = COM_CurrentApt();
752 if (!apt || !apt->win) return;
754 TRACE("Flushing STA message queue\n");
756 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
758 if (message.hwnd != apt->win)
760 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
761 continue;
764 TranslateMessage(&message);
765 DispatchMessageA(&message);
769 /***********************************************************************
770 * CoUninitialize [OLE32.@]
772 * This method will decrement the refcount on the current apartment, freeing
773 * the resources associated with it if it is the last thread in the apartment.
774 * If the last apartment is freed, the function will additionally release
775 * any COM resources associated with the process.
777 * PARAMS
779 * RETURNS
780 * Nothing.
782 * SEE ALSO
783 * CoInitializeEx
785 void WINAPI CoUninitialize(void)
787 struct oletls * info = COM_CurrentInfo();
788 LONG lCOMRefCnt;
790 TRACE("()\n");
792 /* will only happen on OOM */
793 if (!info) return;
795 /* sanity check */
796 if (!info->inits)
798 ERR("Mismatched CoUninitialize\n");
799 return;
802 if (!--info->inits)
804 apartment_release(info->apt);
805 info->apt = NULL;
809 * Decrease the reference count.
810 * If we are back to 0 locks on the COM library, make sure we free
811 * all the associated data structures.
813 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
814 if (lCOMRefCnt==1)
816 TRACE("() - Releasing the COM libraries\n");
818 RunningObjectTableImpl_UnInitialize();
820 /* Release the references to the registered class objects */
821 COM_RevokeAllClasses();
823 /* This will free the loaded COM Dlls */
824 CoFreeAllLibraries();
826 /* This ensures we deal with any pending RPCs */
827 COM_FlushMessageQueue();
829 else if (lCOMRefCnt<1) {
830 ERR( "CoUninitialize() - not CoInitialized.\n" );
831 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
835 /******************************************************************************
836 * CoDisconnectObject [OLE32.@]
837 * CoDisconnectObject [COMPOBJ.15]
839 * Disconnects all connections to this object from remote processes. Dispatches
840 * pending RPCs while blocking new RPCs from occurring, and then calls
841 * IMarshal::DisconnectObject on the given object.
843 * Typically called when the object server is forced to shut down, for instance by
844 * the user.
846 * PARAMS
847 * lpUnk [I] The object whose stub should be disconnected.
848 * reserved [I] Reserved. Should be set to 0.
850 * RETURNS
851 * Success: S_OK.
852 * Failure: HRESULT code.
854 * SEE ALSO
855 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
857 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
859 HRESULT hr;
860 IMarshal *marshal;
861 APARTMENT *apt;
863 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
865 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
866 if (hr == S_OK)
868 hr = IMarshal_DisconnectObject(marshal, reserved);
869 IMarshal_Release(marshal);
870 return hr;
873 apt = COM_CurrentApt();
874 if (!apt)
875 return CO_E_NOTINITIALIZED;
877 apartment_disconnectobject(apt, lpUnk);
879 /* Note: native is pretty broken here because it just silently
880 * fails, without returning an appropriate error code if the object was
881 * not found, making apps think that the object was disconnected, when
882 * it actually wasn't */
884 return S_OK;
887 /******************************************************************************
888 * CoCreateGuid [OLE32.@]
890 * Simply forwards to UuidCreate in RPCRT4.
892 * PARAMS
893 * pguid [O] Points to the GUID to initialize.
895 * RETURNS
896 * Success: S_OK.
897 * Failure: HRESULT code.
899 * SEE ALSO
900 * UuidCreate
902 HRESULT WINAPI CoCreateGuid(GUID *pguid)
904 return UuidCreate(pguid);
907 /******************************************************************************
908 * CLSIDFromString [OLE32.@]
909 * IIDFromString [OLE32.@]
911 * Converts a unique identifier from its string representation into
912 * the GUID struct.
914 * PARAMS
915 * idstr [I] The string representation of the GUID.
916 * id [O] GUID converted from the string.
918 * RETURNS
919 * S_OK on success
920 * CO_E_CLASSSTRING if idstr is not a valid CLSID
922 * SEE ALSO
923 * StringFromCLSID
925 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
927 int i;
928 BYTE table[256];
930 if (!s) {
931 memset( id, 0, sizeof (CLSID) );
932 return S_OK;
935 /* validate the CLSID string */
936 if (strlenW(s) != 38)
937 return CO_E_CLASSSTRING;
939 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
940 return CO_E_CLASSSTRING;
942 for (i=1; i<37; i++) {
943 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
944 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
945 ((s[i] >= 'a') && (s[i] <= 'f')) ||
946 ((s[i] >= 'A') && (s[i] <= 'F'))))
947 return CO_E_CLASSSTRING;
950 TRACE("%s -> %p\n", debugstr_w(s), id);
952 /* quick lookup table */
953 memset(table, 0, 256);
955 for (i = 0; i < 10; i++) {
956 table['0' + i] = i;
958 for (i = 0; i < 6; i++) {
959 table['A' + i] = i+10;
960 table['a' + i] = i+10;
963 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
965 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
966 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
967 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
968 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
970 /* these are just sequential bytes */
971 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
972 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
973 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
974 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
975 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
976 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
977 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
978 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
980 return S_OK;
983 /*****************************************************************************/
985 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
987 HRESULT ret;
989 if (!id)
990 return E_INVALIDARG;
992 ret = __CLSIDFromString(idstr, id);
993 if(ret != S_OK) { /* It appears a ProgID is also valid */
994 ret = CLSIDFromProgID(idstr, id);
996 return ret;
999 /* Converts a GUID into the respective string representation. */
1000 HRESULT WINE_StringFromCLSID(
1001 const CLSID *id, /* [in] GUID to be converted */
1002 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
1004 static const char hex[] = "0123456789ABCDEF";
1005 char *s;
1006 int i;
1008 if (!id)
1009 { ERR("called with id=Null\n");
1010 *idstr = 0x00;
1011 return E_FAIL;
1014 sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
1015 id->Data1, id->Data2, id->Data3,
1016 id->Data4[0], id->Data4[1]);
1017 s = &idstr[25];
1019 /* 6 hex bytes */
1020 for (i = 2; i < 8; i++) {
1021 *s++ = hex[id->Data4[i]>>4];
1022 *s++ = hex[id->Data4[i] & 0xf];
1025 *s++ = '}';
1026 *s++ = '\0';
1028 TRACE("%p->%s\n", id, idstr);
1030 return S_OK;
1034 /******************************************************************************
1035 * StringFromCLSID [OLE32.@]
1036 * StringFromIID [OLE32.@]
1038 * Converts a GUID into the respective string representation.
1039 * The target string is allocated using the OLE IMalloc.
1041 * PARAMS
1042 * id [I] the GUID to be converted.
1043 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1045 * RETURNS
1046 * S_OK
1047 * E_FAIL
1049 * SEE ALSO
1050 * StringFromGUID2, CLSIDFromString
1052 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1054 char buf[80];
1055 HRESULT ret;
1056 LPMALLOC mllc;
1058 if ((ret = CoGetMalloc(0,&mllc)))
1059 return ret;
1061 ret=WINE_StringFromCLSID(id,buf);
1062 if (!ret) {
1063 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1064 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1065 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1067 return ret;
1070 /******************************************************************************
1071 * StringFromGUID2 [OLE32.@]
1072 * StringFromGUID2 [COMPOBJ.76]
1074 * Modified version of StringFromCLSID that allows you to specify max
1075 * buffer size.
1077 * PARAMS
1078 * id [I] GUID to convert to string.
1079 * str [O] Buffer where the result will be stored.
1080 * cmax [I] Size of the buffer in characters.
1082 * RETURNS
1083 * Success: The length of the resulting string in characters.
1084 * Failure: 0.
1086 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1088 char xguid[80];
1090 if (WINE_StringFromCLSID(id,xguid))
1091 return 0;
1092 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1095 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1096 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1098 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1099 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1100 LONG res;
1101 HKEY key;
1103 strcpyW(path, wszCLSIDSlash);
1104 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1105 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1106 if (res == ERROR_FILE_NOT_FOUND)
1107 return REGDB_E_CLASSNOTREG;
1108 else if (res != ERROR_SUCCESS)
1109 return REGDB_E_READREGDB;
1111 if (!keyname)
1113 *subkey = key;
1114 return S_OK;
1117 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1118 RegCloseKey(key);
1119 if (res == ERROR_FILE_NOT_FOUND)
1120 return REGDB_E_KEYMISSING;
1121 else if (res != ERROR_SUCCESS)
1122 return REGDB_E_READREGDB;
1124 return S_OK;
1127 /* open HKCR\\AppId\\{string form of appid clsid} key */
1128 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1130 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1131 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1132 DWORD res;
1133 WCHAR buf[CHARS_IN_GUID];
1134 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1135 DWORD size;
1136 HKEY hkey;
1137 DWORD type;
1138 HRESULT hr;
1140 /* read the AppID value under the class's key */
1141 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1142 if (FAILED(hr))
1143 return hr;
1145 size = sizeof(buf);
1146 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1147 RegCloseKey(hkey);
1148 if (res == ERROR_FILE_NOT_FOUND)
1149 return REGDB_E_KEYMISSING;
1150 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1151 return REGDB_E_READREGDB;
1153 strcpyW(keyname, szAppIdKey);
1154 strcatW(keyname, buf);
1155 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1156 if (res == ERROR_FILE_NOT_FOUND)
1157 return REGDB_E_KEYMISSING;
1158 else if (res != ERROR_SUCCESS)
1159 return REGDB_E_READREGDB;
1161 return S_OK;
1164 /******************************************************************************
1165 * ProgIDFromCLSID [OLE32.@]
1167 * Converts a class id into the respective program ID.
1169 * PARAMS
1170 * clsid [I] Class ID, as found in registry.
1171 * ppszProgID [O] Associated ProgID.
1173 * RETURNS
1174 * S_OK
1175 * E_OUTOFMEMORY
1176 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1178 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1180 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1181 HKEY hkey;
1182 HRESULT ret;
1183 LONG progidlen = 0;
1185 if (!ppszProgID)
1187 ERR("ppszProgId isn't optional\n");
1188 return E_INVALIDARG;
1191 *ppszProgID = NULL;
1192 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1193 if (FAILED(ret))
1194 return ret;
1196 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1197 ret = REGDB_E_CLASSNOTREG;
1199 if (ret == S_OK)
1201 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1202 if (*ppszProgID)
1204 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1205 ret = REGDB_E_CLASSNOTREG;
1207 else
1208 ret = E_OUTOFMEMORY;
1211 RegCloseKey(hkey);
1212 return ret;
1215 /******************************************************************************
1216 * CLSIDFromProgID [OLE32.@]
1218 * Converts a program id into the respective GUID.
1220 * PARAMS
1221 * progid [I] Unicode program ID, as found in registry.
1222 * clsid [O] Associated CLSID.
1224 * RETURNS
1225 * Success: S_OK
1226 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1228 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1230 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1231 WCHAR buf2[CHARS_IN_GUID];
1232 LONG buf2len = sizeof(buf2);
1233 HKEY xhkey;
1234 WCHAR *buf;
1236 if (!progid || !clsid)
1238 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1239 return E_INVALIDARG;
1242 /* initialise clsid in case of failure */
1243 memset(clsid, 0, sizeof(*clsid));
1245 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1246 strcpyW( buf, progid );
1247 strcatW( buf, clsidW );
1248 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1250 HeapFree(GetProcessHeap(),0,buf);
1251 return CO_E_CLASSSTRING;
1253 HeapFree(GetProcessHeap(),0,buf);
1255 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1257 RegCloseKey(xhkey);
1258 return CO_E_CLASSSTRING;
1260 RegCloseKey(xhkey);
1261 return CLSIDFromString(buf2,clsid);
1265 /*****************************************************************************
1266 * CoGetPSClsid [OLE32.@]
1268 * Retrieves the CLSID of the proxy/stub factory that implements
1269 * IPSFactoryBuffer for the specified interface.
1271 * PARAMS
1272 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1273 * pclsid [O] Where to store returned proxy/stub CLSID.
1275 * RETURNS
1276 * S_OK
1277 * E_OUTOFMEMORY
1278 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1280 * NOTES
1282 * The standard marshaller activates the object with the CLSID
1283 * returned and uses the CreateProxy and CreateStub methods on its
1284 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1285 * given object.
1287 * CoGetPSClsid determines this CLSID by searching the
1288 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1289 * in the registry and any interface id registered by
1290 * CoRegisterPSClsid within the current process.
1292 * BUGS
1294 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1295 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1296 * considered a bug in native unless an application depends on this (unlikely).
1298 * SEE ALSO
1299 * CoRegisterPSClsid.
1301 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1303 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1304 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1305 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1306 WCHAR value[CHARS_IN_GUID];
1307 LONG len;
1308 HKEY hkey;
1309 APARTMENT *apt = COM_CurrentApt();
1310 struct registered_psclsid *registered_psclsid;
1312 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1314 if (!apt)
1316 ERR("apartment not initialised\n");
1317 return CO_E_NOTINITIALIZED;
1320 if (!pclsid)
1322 ERR("pclsid isn't optional\n");
1323 return E_INVALIDARG;
1326 EnterCriticalSection(&apt->cs);
1328 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1329 if (IsEqualIID(&registered_psclsid->iid, riid))
1331 *pclsid = registered_psclsid->clsid;
1332 LeaveCriticalSection(&apt->cs);
1333 return S_OK;
1336 LeaveCriticalSection(&apt->cs);
1338 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1339 strcpyW(path, wszInterface);
1340 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1341 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1343 /* Open the key.. */
1344 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1346 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1347 return REGDB_E_IIDNOTREG;
1350 /* ... Once we have the key, query the registry to get the
1351 value of CLSID as a string, and convert it into a
1352 proper CLSID structure to be passed back to the app */
1353 len = sizeof(value);
1354 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1356 RegCloseKey(hkey);
1357 return REGDB_E_IIDNOTREG;
1359 RegCloseKey(hkey);
1361 /* We have the CLSid we want back from the registry as a string, so
1362 lets convert it into a CLSID structure */
1363 if (CLSIDFromString(value, pclsid) != NOERROR)
1364 return REGDB_E_IIDNOTREG;
1366 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1367 return S_OK;
1370 /*****************************************************************************
1371 * CoRegisterPSClsid [OLE32.@]
1373 * Register a proxy/stub CLSID for the given interface in the current process
1374 * only.
1376 * PARAMS
1377 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1378 * rclsid [I] CLSID of the proxy/stub.
1380 * RETURNS
1381 * Success: S_OK
1382 * Failure: E_OUTOFMEMORY
1384 * NOTES
1386 * This function does not add anything to the registry and the effects are
1387 * limited to the lifetime of the current process.
1389 * SEE ALSO
1390 * CoGetPSClsid.
1392 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1394 APARTMENT *apt = COM_CurrentApt();
1395 struct registered_psclsid *registered_psclsid;
1397 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1399 if (!apt)
1401 ERR("apartment not initialised\n");
1402 return CO_E_NOTINITIALIZED;
1405 EnterCriticalSection(&apt->cs);
1407 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1408 if (IsEqualIID(&registered_psclsid->iid, riid))
1410 registered_psclsid->clsid = *rclsid;
1411 LeaveCriticalSection(&apt->cs);
1412 return S_OK;
1415 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1416 if (!registered_psclsid)
1418 LeaveCriticalSection(&apt->cs);
1419 return E_OUTOFMEMORY;
1422 registered_psclsid->iid = *riid;
1423 registered_psclsid->clsid = *rclsid;
1424 list_add_head(&apt->psclsids, &registered_psclsid->entry);
1426 LeaveCriticalSection(&apt->cs);
1428 return S_OK;
1432 /***
1433 * COM_GetRegisteredClassObject
1435 * This internal method is used to scan the registered class list to
1436 * find a class object.
1438 * Params:
1439 * rclsid Class ID of the class to find.
1440 * dwClsContext Class context to match.
1441 * ppv [out] returns a pointer to the class object. Complying
1442 * to normal COM usage, this method will increase the
1443 * reference count on this object.
1445 static HRESULT COM_GetRegisteredClassObject(
1446 REFCLSID rclsid,
1447 DWORD dwClsContext,
1448 LPUNKNOWN* ppUnk)
1450 HRESULT hr = S_FALSE;
1451 RegisteredClass* curClass;
1453 EnterCriticalSection( &csRegisteredClassList );
1456 * Sanity check
1458 assert(ppUnk!=0);
1461 * Iterate through the whole list and try to match the class ID.
1463 curClass = firstRegisteredClass;
1465 while (curClass != 0)
1468 * Check if we have a match on the class ID.
1470 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1473 * Since we don't do out-of process or DCOM just right away, let's ignore the
1474 * class context.
1478 * We have a match, return the pointer to the class object.
1480 *ppUnk = curClass->classObject;
1482 IUnknown_AddRef(curClass->classObject);
1484 hr = S_OK;
1485 goto end;
1489 * Step to the next class in the list.
1491 curClass = curClass->nextClass;
1494 end:
1495 LeaveCriticalSection( &csRegisteredClassList );
1497 * If we get to here, we haven't found our class.
1499 return hr;
1502 /******************************************************************************
1503 * CoRegisterClassObject [OLE32.@]
1505 * Registers the class object for a given class ID. Servers housed in EXE
1506 * files use this method instead of exporting DllGetClassObject to allow
1507 * other code to connect to their objects.
1509 * PARAMS
1510 * rclsid [I] CLSID of the object to register.
1511 * pUnk [I] IUnknown of the object.
1512 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1513 * flags [I] REGCLS flags indicating how connections are made.
1514 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1516 * RETURNS
1517 * S_OK on success,
1518 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1519 * CO_E_OBJISREG if the object is already registered. We should not return this.
1521 * SEE ALSO
1522 * CoRevokeClassObject, CoGetClassObject
1524 * BUGS
1525 * MSDN claims that multiple interface registrations are legal, but we
1526 * can't do that with our current implementation.
1528 HRESULT WINAPI CoRegisterClassObject(
1529 REFCLSID rclsid,
1530 LPUNKNOWN pUnk,
1531 DWORD dwClsContext,
1532 DWORD flags,
1533 LPDWORD lpdwRegister)
1535 RegisteredClass* newClass;
1536 LPUNKNOWN foundObject;
1537 HRESULT hr;
1539 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1540 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1542 if ( (lpdwRegister==0) || (pUnk==0) )
1543 return E_INVALIDARG;
1545 if (!COM_CurrentApt())
1547 ERR("COM was not initialized\n");
1548 return CO_E_NOTINITIALIZED;
1551 *lpdwRegister = 0;
1554 * First, check if the class is already registered.
1555 * If it is, this should cause an error.
1557 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1558 if (hr == S_OK) {
1559 if (flags & REGCLS_MULTIPLEUSE) {
1560 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1561 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1562 IUnknown_Release(foundObject);
1563 return hr;
1565 IUnknown_Release(foundObject);
1566 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1567 return CO_E_OBJISREG;
1570 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1571 if ( newClass == NULL )
1572 return E_OUTOFMEMORY;
1574 EnterCriticalSection( &csRegisteredClassList );
1576 newClass->classIdentifier = *rclsid;
1577 newClass->runContext = dwClsContext;
1578 newClass->connectFlags = flags;
1579 newClass->pMarshaledData = NULL;
1582 * Use the address of the chain node as the cookie since we are sure it's
1583 * unique. FIXME: not on 64-bit platforms.
1585 newClass->dwCookie = (DWORD)newClass;
1586 newClass->nextClass = firstRegisteredClass;
1589 * Since we're making a copy of the object pointer, we have to increase its
1590 * reference count.
1592 newClass->classObject = pUnk;
1593 IUnknown_AddRef(newClass->classObject);
1595 firstRegisteredClass = newClass;
1596 LeaveCriticalSection( &csRegisteredClassList );
1598 *lpdwRegister = newClass->dwCookie;
1600 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1601 IClassFactory *classfac;
1603 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1604 (LPVOID*)&classfac);
1605 if (hr) return hr;
1607 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1608 if (hr) {
1609 FIXME("Failed to create stream on hglobal, %x\n", hr);
1610 IUnknown_Release(classfac);
1611 return hr;
1613 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1614 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1615 MSHLFLAGS_TABLESTRONG);
1616 if (hr) {
1617 FIXME("CoMarshalInterface failed, %x!\n",hr);
1618 IUnknown_Release(classfac);
1619 return hr;
1622 IUnknown_Release(classfac);
1624 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1626 return S_OK;
1629 /***********************************************************************
1630 * CoRevokeClassObject [OLE32.@]
1632 * Removes a class object from the class registry.
1634 * PARAMS
1635 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1637 * RETURNS
1638 * Success: S_OK.
1639 * Failure: HRESULT code.
1641 * SEE ALSO
1642 * CoRegisterClassObject
1644 HRESULT WINAPI CoRevokeClassObject(
1645 DWORD dwRegister)
1647 HRESULT hr = E_INVALIDARG;
1648 RegisteredClass** prevClassLink;
1649 RegisteredClass* curClass;
1651 TRACE("(%08x)\n",dwRegister);
1653 EnterCriticalSection( &csRegisteredClassList );
1656 * Iterate through the whole list and try to match the cookie.
1658 curClass = firstRegisteredClass;
1659 prevClassLink = &firstRegisteredClass;
1661 while (curClass != 0)
1664 * Check if we have a match on the cookie.
1666 if (curClass->dwCookie == dwRegister)
1669 * Remove the class from the chain.
1671 *prevClassLink = curClass->nextClass;
1674 * Release the reference to the class object.
1676 IUnknown_Release(curClass->classObject);
1678 if (curClass->pMarshaledData)
1680 LARGE_INTEGER zero;
1681 memset(&zero, 0, sizeof(zero));
1682 /* FIXME: stop local server thread */
1683 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1684 CoReleaseMarshalData(curClass->pMarshaledData);
1688 * Free the memory used by the chain node.
1690 HeapFree(GetProcessHeap(), 0, curClass);
1692 hr = S_OK;
1693 goto end;
1697 * Step to the next class in the list.
1699 prevClassLink = &(curClass->nextClass);
1700 curClass = curClass->nextClass;
1703 end:
1704 LeaveCriticalSection( &csRegisteredClassList );
1706 * If we get to here, we haven't found our class.
1708 return hr;
1711 /***********************************************************************
1712 * COM_RegReadPath [internal]
1714 * Reads a registry value and expands it when necessary
1716 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1718 DWORD ret;
1719 HKEY key;
1720 DWORD keytype;
1721 WCHAR src[MAX_PATH];
1722 DWORD dwLength = dstlen * sizeof(WCHAR);
1724 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1725 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1726 if (keytype == REG_EXPAND_SZ) {
1727 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1728 } else {
1729 lstrcpynW(dst, src, dstlen);
1732 RegCloseKey (key);
1734 return ret;
1737 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
1739 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
1740 DWORD keytype;
1741 DWORD ret;
1742 DWORD dwLength = len * sizeof(WCHAR);
1744 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
1745 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
1746 value[0] = '\0';
1749 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1751 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
1752 static const WCHAR wszFree[] = {'F','r','e','e',0};
1753 static const WCHAR wszBoth[] = {'B','o','t','h',0};
1754 HINSTANCE hLibrary;
1755 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1756 DllGetClassObjectFunc DllGetClassObject;
1757 WCHAR dllpath[MAX_PATH+1];
1758 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
1759 HRESULT hr;
1761 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
1762 /* "Apartment" */
1763 if (!strcmpiW(threading_model, wszApartment))
1765 APARTMENT *apt = COM_CurrentApt();
1766 if (apt->multi_threaded)
1768 /* try to find an STA */
1769 APARTMENT *host_apt = apartment_findfromtype(FALSE, FALSE);
1770 if (!host_apt)
1771 FIXME("create a host apartment for apartment-threaded object %s\n", debugstr_guid(rclsid));
1772 if (host_apt)
1774 struct host_object_params params;
1775 HWND hwnd = apartment_getwindow(host_apt);
1777 params.hkeydll = hkeydll;
1778 params.clsid = *rclsid;
1779 params.iid = *riid;
1780 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1781 if (FAILED(hr))
1782 return hr;
1783 hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1784 if (SUCCEEDED(hr))
1785 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1786 IStream_Release(params.stream);
1787 return hr;
1791 /* "Free" */
1792 else if (!strcmpiW(threading_model, wszFree))
1794 APARTMENT *apt = COM_CurrentApt();
1795 if (!apt->multi_threaded)
1797 FIXME("should create object %s in multi-threaded apartment\n",
1798 debugstr_guid(rclsid));
1801 /* everything except "Apartment", "Free" and "Both" */
1802 else if (strcmpiW(threading_model, wszBoth))
1804 APARTMENT *apt = COM_CurrentApt();
1806 /* everything else is main-threaded */
1807 if (threading_model[0])
1808 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
1809 debugstr_w(threading_model), debugstr_guid(rclsid));
1811 if (apt->multi_threaded || !apt->main)
1813 /* try to find an STA */
1814 APARTMENT *host_apt = apartment_findfromtype(FALSE, TRUE);
1815 if (!host_apt)
1816 FIXME("create a host apartment for main-threaded object %s\n", debugstr_guid(rclsid));
1817 if (host_apt)
1819 struct host_object_params params;
1820 HWND hwnd = apartment_getwindow(host_apt);
1822 params.hkeydll = hkeydll;
1823 params.clsid = *rclsid;
1824 params.iid = *riid;
1825 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1826 if (FAILED(hr))
1827 return hr;
1828 hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1829 if (SUCCEEDED(hr))
1830 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1831 IStream_Release(params.stream);
1832 return hr;
1837 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1839 /* failure: CLSID is not found in registry */
1840 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1841 return REGDB_E_CLASSNOTREG;
1844 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1846 /* failure: DLL could not be loaded */
1847 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1848 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1851 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1853 /* failure: the dll did not export DllGetClassObject */
1854 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1855 FreeLibrary( hLibrary );
1856 return CO_E_DLLNOTFOUND;
1859 /* OK: get the ClassObject */
1860 COMPOBJ_DLLList_Add( hLibrary );
1861 hr = DllGetClassObject(rclsid, riid, ppv);
1863 if (hr != S_OK)
1864 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1866 return hr;
1869 /***********************************************************************
1870 * CoGetClassObject [OLE32.@]
1872 * FIXME. If request allows of several options and there is a failure
1873 * with one (other than not being registered) do we try the
1874 * others or return failure? (E.g. inprocess is registered but
1875 * the DLL is not found but the server version works)
1877 HRESULT WINAPI CoGetClassObject(
1878 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1879 REFIID iid, LPVOID *ppv)
1881 LPUNKNOWN regClassObject;
1882 HRESULT hres = E_UNEXPECTED;
1884 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1886 if (!ppv)
1887 return E_INVALIDARG;
1889 *ppv = NULL;
1891 if (!COM_CurrentApt())
1893 ERR("apartment not initialised\n");
1894 return CO_E_NOTINITIALIZED;
1897 if (pServerInfo) {
1898 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1899 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1903 * First, try and see if we can't match the class ID with one of the
1904 * registered classes.
1906 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1908 /* Get the required interface from the retrieved pointer. */
1909 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1912 * Since QI got another reference on the pointer, we want to release the
1913 * one we already have. If QI was unsuccessful, this will release the object. This
1914 * is good since we are not returning it in the "out" parameter.
1916 IUnknown_Release(regClassObject);
1918 return hres;
1921 /* First try in-process server */
1922 if (CLSCTX_INPROC_SERVER & dwClsContext)
1924 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1925 HKEY hkey;
1927 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
1928 return FTMarshalCF_Create(iid, ppv);
1930 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1931 if (FAILED(hres))
1933 if (hres == REGDB_E_CLASSNOTREG)
1934 ERR("class %s not registered\n", debugstr_guid(rclsid));
1935 else
1936 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1939 if (SUCCEEDED(hres))
1941 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1942 RegCloseKey(hkey);
1945 /* return if we got a class, otherwise fall through to one of the
1946 * other types */
1947 if (SUCCEEDED(hres))
1948 return hres;
1951 /* Next try in-process handler */
1952 if (CLSCTX_INPROC_HANDLER & dwClsContext)
1954 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1955 HKEY hkey;
1957 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1958 if (FAILED(hres))
1960 if (hres == REGDB_E_CLASSNOTREG)
1961 ERR("class %s not registered\n", debugstr_guid(rclsid));
1962 else
1963 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1966 if (SUCCEEDED(hres))
1968 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1969 RegCloseKey(hkey);
1972 /* return if we got a class, otherwise fall through to one of the
1973 * other types */
1974 if (SUCCEEDED(hres))
1975 return hres;
1978 /* Next try out of process */
1979 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1981 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
1982 if (SUCCEEDED(hres))
1983 return hres;
1986 /* Finally try remote: this requires networked DCOM (a lot of work) */
1987 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1989 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1990 hres = E_NOINTERFACE;
1993 if (FAILED(hres))
1994 ERR("no class object %s could be created for context 0x%x\n",
1995 debugstr_guid(rclsid), dwClsContext);
1996 return hres;
1999 /***********************************************************************
2000 * CoResumeClassObjects (OLE32.@)
2002 * Resumes all class objects registered with REGCLS_SUSPENDED.
2004 * RETURNS
2005 * Success: S_OK.
2006 * Failure: HRESULT code.
2008 HRESULT WINAPI CoResumeClassObjects(void)
2010 FIXME("stub\n");
2011 return S_OK;
2014 /***********************************************************************
2015 * GetClassFile (OLE32.@)
2017 * This function supplies the CLSID associated with the given filename.
2019 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
2021 IStorage *pstg=0;
2022 HRESULT res;
2023 int nbElm, length, i;
2024 LONG sizeProgId;
2025 LPOLESTR *pathDec=0,absFile=0,progId=0;
2026 LPWSTR extension;
2027 static const WCHAR bkslashW[] = {'\\',0};
2028 static const WCHAR dotW[] = {'.',0};
2030 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
2032 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
2033 if((StgIsStorageFile(filePathName))==S_OK){
2035 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
2037 if (SUCCEEDED(res))
2038 res=ReadClassStg(pstg,pclsid);
2040 IStorage_Release(pstg);
2042 return res;
2044 /* if the file is not a storage object then attemps to match various bits in the file against a
2045 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
2046 this case
2048 for(i=0;i<nFileTypes;i++)
2050 for(i=0;j<nPatternsForType;j++){
2052 PATTERN pat;
2053 HANDLE hFile;
2055 pat=ReadPatternFromRegistry(i,j);
2056 hFile=CreateFileW(filePathName,,,,,,hFile);
2057 SetFilePosition(hFile,pat.offset);
2058 ReadFile(hFile,buf,pat.size,&r,NULL);
2059 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
2061 *pclsid=ReadCLSIDFromRegistry(i);
2062 return S_OK;
2067 /* if the above strategies fail then search for the extension key in the registry */
2069 /* get the last element (absolute file) in the path name */
2070 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
2071 absFile=pathDec[nbElm-1];
2073 /* failed if the path represente a directory and not an absolute file name*/
2074 if (!lstrcmpW(absFile, bkslashW))
2075 return MK_E_INVALIDEXTENSION;
2077 /* get the extension of the file */
2078 extension = NULL;
2079 length=lstrlenW(absFile);
2080 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
2081 /* nothing */;
2083 if (!extension || !lstrcmpW(extension, dotW))
2084 return MK_E_INVALIDEXTENSION;
2086 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
2088 /* get the progId associated to the extension */
2089 progId = CoTaskMemAlloc(sizeProgId);
2090 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
2092 if (res==ERROR_SUCCESS)
2093 /* return the clsid associated to the progId */
2094 res= CLSIDFromProgID(progId,pclsid);
2096 for(i=0; pathDec[i]!=NULL;i++)
2097 CoTaskMemFree(pathDec[i]);
2098 CoTaskMemFree(pathDec);
2100 CoTaskMemFree(progId);
2102 if (res==ERROR_SUCCESS)
2103 return res;
2105 return MK_E_INVALIDEXTENSION;
2108 /***********************************************************************
2109 * CoCreateInstance [OLE32.@]
2111 * Creates an instance of the specified class.
2113 * PARAMS
2114 * rclsid [I] Class ID to create an instance of.
2115 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2116 * dwClsContext [I] Flags to restrict the location of the created instance.
2117 * iid [I] The ID of the interface of the instance to return.
2118 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2120 * RETURNS
2121 * Success: S_OK
2122 * Failure: HRESULT code.
2124 * NOTES
2125 * The dwClsContext parameter can be one or more of the following:
2126 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2127 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2128 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2129 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2131 * Aggregation is the concept of deferring the IUnknown of an object to another
2132 * object. This allows a separate object to behave as though it was part of
2133 * the object and to allow this the pUnkOuter parameter can be set. Note that
2134 * not all objects support having an outer of unknown.
2136 * SEE ALSO
2137 * CoGetClassObject()
2139 HRESULT WINAPI CoCreateInstance(
2140 REFCLSID rclsid,
2141 LPUNKNOWN pUnkOuter,
2142 DWORD dwClsContext,
2143 REFIID iid,
2144 LPVOID *ppv)
2146 HRESULT hres;
2147 LPCLASSFACTORY lpclf = 0;
2149 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2150 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2153 * Sanity check
2155 if (ppv==0)
2156 return E_POINTER;
2159 * Initialize the "out" parameter
2161 *ppv = 0;
2163 if (!COM_CurrentApt())
2165 ERR("apartment not initialised\n");
2166 return CO_E_NOTINITIALIZED;
2170 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2171 * Rather than create a class factory, we can just check for it here
2173 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2174 if (StdGlobalInterfaceTableInstance == NULL)
2175 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2176 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2177 if (hres) return hres;
2179 TRACE("Retrieved GIT (%p)\n", *ppv);
2180 return S_OK;
2184 * Get a class factory to construct the object we want.
2186 hres = CoGetClassObject(rclsid,
2187 dwClsContext,
2188 NULL,
2189 &IID_IClassFactory,
2190 (LPVOID)&lpclf);
2192 if (FAILED(hres))
2193 return hres;
2196 * Create the object and don't forget to release the factory
2198 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2199 IClassFactory_Release(lpclf);
2200 if(FAILED(hres))
2201 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2202 debugstr_guid(iid), debugstr_guid(rclsid),hres);
2204 return hres;
2207 /***********************************************************************
2208 * CoCreateInstanceEx [OLE32.@]
2210 HRESULT WINAPI CoCreateInstanceEx(
2211 REFCLSID rclsid,
2212 LPUNKNOWN pUnkOuter,
2213 DWORD dwClsContext,
2214 COSERVERINFO* pServerInfo,
2215 ULONG cmq,
2216 MULTI_QI* pResults)
2218 IUnknown* pUnk = NULL;
2219 HRESULT hr;
2220 ULONG index;
2221 ULONG successCount = 0;
2224 * Sanity check
2226 if ( (cmq==0) || (pResults==NULL))
2227 return E_INVALIDARG;
2229 if (pServerInfo!=NULL)
2230 FIXME("() non-NULL pServerInfo not supported!\n");
2233 * Initialize all the "out" parameters.
2235 for (index = 0; index < cmq; index++)
2237 pResults[index].pItf = NULL;
2238 pResults[index].hr = E_NOINTERFACE;
2242 * Get the object and get its IUnknown pointer.
2244 hr = CoCreateInstance(rclsid,
2245 pUnkOuter,
2246 dwClsContext,
2247 &IID_IUnknown,
2248 (VOID**)&pUnk);
2250 if (hr)
2251 return hr;
2254 * Then, query for all the interfaces requested.
2256 for (index = 0; index < cmq; index++)
2258 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2259 pResults[index].pIID,
2260 (VOID**)&(pResults[index].pItf));
2262 if (pResults[index].hr == S_OK)
2263 successCount++;
2267 * Release our temporary unknown pointer.
2269 IUnknown_Release(pUnk);
2271 if (successCount == 0)
2272 return E_NOINTERFACE;
2274 if (successCount!=cmq)
2275 return CO_S_NOTALLINTERFACES;
2277 return S_OK;
2280 /***********************************************************************
2281 * CoLoadLibrary (OLE32.@)
2283 * Loads a library.
2285 * PARAMS
2286 * lpszLibName [I] Path to library.
2287 * bAutoFree [I] Whether the library should automatically be freed.
2289 * RETURNS
2290 * Success: Handle to loaded library.
2291 * Failure: NULL.
2293 * SEE ALSO
2294 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2296 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2298 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2300 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2303 /***********************************************************************
2304 * CoFreeLibrary [OLE32.@]
2306 * Unloads a library from memory.
2308 * PARAMS
2309 * hLibrary [I] Handle to library to unload.
2311 * RETURNS
2312 * Nothing
2314 * SEE ALSO
2315 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2317 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2319 FreeLibrary(hLibrary);
2323 /***********************************************************************
2324 * CoFreeAllLibraries [OLE32.@]
2326 * Function for backwards compatibility only. Does nothing.
2328 * RETURNS
2329 * Nothing.
2331 * SEE ALSO
2332 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2334 void WINAPI CoFreeAllLibraries(void)
2336 /* NOP */
2340 /***********************************************************************
2341 * CoFreeUnusedLibraries [OLE32.@]
2342 * CoFreeUnusedLibraries [COMPOBJ.17]
2344 * Frees any unused libraries. Unused are identified as those that return
2345 * S_OK from their DllCanUnloadNow function.
2347 * RETURNS
2348 * Nothing.
2350 * SEE ALSO
2351 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2353 void WINAPI CoFreeUnusedLibraries(void)
2355 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2356 * through the main apartment's thread to call DllCanUnloadNow */
2357 COMPOBJ_DllList_FreeUnused(0);
2360 /***********************************************************************
2361 * CoFileTimeNow [OLE32.@]
2362 * CoFileTimeNow [COMPOBJ.82]
2364 * Retrieves the current time in FILETIME format.
2366 * PARAMS
2367 * lpFileTime [O] The current time.
2369 * RETURNS
2370 * S_OK.
2372 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2374 GetSystemTimeAsFileTime( lpFileTime );
2375 return S_OK;
2378 static void COM_RevokeAllClasses(void)
2380 EnterCriticalSection( &csRegisteredClassList );
2382 while (firstRegisteredClass!=0)
2384 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2387 LeaveCriticalSection( &csRegisteredClassList );
2390 /******************************************************************************
2391 * CoLockObjectExternal [OLE32.@]
2393 * Increments or decrements the external reference count of a stub object.
2395 * PARAMS
2396 * pUnk [I] Stub object.
2397 * fLock [I] If TRUE then increments the external ref-count,
2398 * otherwise decrements.
2399 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2400 * calling CoDisconnectObject.
2402 * RETURNS
2403 * Success: S_OK.
2404 * Failure: HRESULT code.
2406 * NOTES
2407 * If fLock is TRUE and an object is passed in that doesn't have a stub
2408 * manager then a new stub manager is created for the object.
2410 HRESULT WINAPI CoLockObjectExternal(
2411 LPUNKNOWN pUnk,
2412 BOOL fLock,
2413 BOOL fLastUnlockReleases)
2415 struct stub_manager *stubmgr;
2416 struct apartment *apt;
2418 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2419 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2421 apt = COM_CurrentApt();
2422 if (!apt) return CO_E_NOTINITIALIZED;
2424 stubmgr = get_stub_manager_from_object(apt, pUnk);
2426 if (stubmgr)
2428 if (fLock)
2429 stub_manager_ext_addref(stubmgr, 1);
2430 else
2431 stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases);
2433 stub_manager_int_release(stubmgr);
2435 return S_OK;
2437 else if (fLock)
2439 stubmgr = new_stub_manager(apt, pUnk);
2441 if (stubmgr)
2443 stub_manager_ext_addref(stubmgr, 1);
2444 stub_manager_int_release(stubmgr);
2447 return S_OK;
2449 else
2451 WARN("stub object not found %p\n", pUnk);
2452 /* Note: native is pretty broken here because it just silently
2453 * fails, without returning an appropriate error code, making apps
2454 * think that the object was disconnected, when it actually wasn't */
2455 return S_OK;
2459 /***********************************************************************
2460 * CoInitializeWOW (OLE32.@)
2462 * WOW equivalent of CoInitialize?
2464 * PARAMS
2465 * x [I] Unknown.
2466 * y [I] Unknown.
2468 * RETURNS
2469 * Unknown.
2471 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2473 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2474 return 0;
2477 /***********************************************************************
2478 * CoGetState [OLE32.@]
2480 * Retrieves the thread state object previously stored by CoSetState().
2482 * PARAMS
2483 * ppv [I] Address where pointer to object will be stored.
2485 * RETURNS
2486 * Success: S_OK.
2487 * Failure: E_OUTOFMEMORY.
2489 * NOTES
2490 * Crashes on all invalid ppv addresses, including NULL.
2491 * If the function returns a non-NULL object then the caller must release its
2492 * reference on the object when the object is no longer required.
2494 * SEE ALSO
2495 * CoSetState().
2497 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2499 struct oletls *info = COM_CurrentInfo();
2500 if (!info) return E_OUTOFMEMORY;
2502 *ppv = NULL;
2504 if (info->state)
2506 IUnknown_AddRef(info->state);
2507 *ppv = info->state;
2508 TRACE("apt->state=%p\n", info->state);
2511 return S_OK;
2514 /***********************************************************************
2515 * CoSetState [OLE32.@]
2517 * Sets the thread state object.
2519 * PARAMS
2520 * pv [I] Pointer to state object to be stored.
2522 * NOTES
2523 * The system keeps a reference on the object while the object stored.
2525 * RETURNS
2526 * Success: S_OK.
2527 * Failure: E_OUTOFMEMORY.
2529 HRESULT WINAPI CoSetState(IUnknown * pv)
2531 struct oletls *info = COM_CurrentInfo();
2532 if (!info) return E_OUTOFMEMORY;
2534 if (pv) IUnknown_AddRef(pv);
2536 if (info->state)
2538 TRACE("-- release %p now\n", info->state);
2539 IUnknown_Release(info->state);
2542 info->state = pv;
2544 return S_OK;
2548 /******************************************************************************
2549 * CoTreatAsClass [OLE32.@]
2551 * Sets the TreatAs value of a class.
2553 * PARAMS
2554 * clsidOld [I] Class to set TreatAs value on.
2555 * clsidNew [I] The class the clsidOld should be treated as.
2557 * RETURNS
2558 * Success: S_OK.
2559 * Failure: HRESULT code.
2561 * SEE ALSO
2562 * CoGetTreatAsClass
2564 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2566 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2567 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2568 HKEY hkey = NULL;
2569 WCHAR szClsidNew[CHARS_IN_GUID];
2570 HRESULT res = S_OK;
2571 WCHAR auto_treat_as[CHARS_IN_GUID];
2572 LONG auto_treat_as_size = sizeof(auto_treat_as);
2573 CLSID id;
2575 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2576 if (FAILED(res))
2577 goto done;
2578 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2580 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2581 !CLSIDFromString(auto_treat_as, &id))
2583 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2585 res = REGDB_E_WRITEREGDB;
2586 goto done;
2589 else
2591 RegDeleteKeyW(hkey, wszTreatAs);
2592 goto done;
2595 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2596 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2598 res = REGDB_E_WRITEREGDB;
2599 goto done;
2602 done:
2603 if (hkey) RegCloseKey(hkey);
2604 return res;
2607 /******************************************************************************
2608 * CoGetTreatAsClass [OLE32.@]
2610 * Gets the TreatAs value of a class.
2612 * PARAMS
2613 * clsidOld [I] Class to get the TreatAs value of.
2614 * clsidNew [I] The class the clsidOld should be treated as.
2616 * RETURNS
2617 * Success: S_OK.
2618 * Failure: HRESULT code.
2620 * SEE ALSO
2621 * CoSetTreatAsClass
2623 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2625 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2626 HKEY hkey = NULL;
2627 WCHAR szClsidNew[CHARS_IN_GUID];
2628 HRESULT res = S_OK;
2629 LONG len = sizeof(szClsidNew);
2631 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2632 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2634 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2635 if (FAILED(res))
2636 goto done;
2637 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2639 res = S_FALSE;
2640 goto done;
2642 res = CLSIDFromString(szClsidNew,clsidNew);
2643 if (FAILED(res))
2644 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2645 done:
2646 if (hkey) RegCloseKey(hkey);
2647 return res;
2650 /******************************************************************************
2651 * CoGetCurrentProcess [OLE32.@]
2652 * CoGetCurrentProcess [COMPOBJ.34]
2654 * Gets the current process ID.
2656 * RETURNS
2657 * The current process ID.
2659 * NOTES
2660 * Is DWORD really the correct return type for this function?
2662 DWORD WINAPI CoGetCurrentProcess(void)
2664 return GetCurrentProcessId();
2667 /******************************************************************************
2668 * CoRegisterMessageFilter [OLE32.@]
2670 * Registers a message filter.
2672 * PARAMS
2673 * lpMessageFilter [I] Pointer to interface.
2674 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2676 * RETURNS
2677 * Success: S_OK.
2678 * Failure: HRESULT code.
2680 * NOTES
2681 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2682 * lpMessageFilter removes the message filter.
2684 * If lplpMessageFilter is not NULL the previous message filter will be
2685 * returned in the memory pointer to this parameter and the caller is
2686 * responsible for releasing the object.
2688 * The current thread be in an apartment otherwise the function will crash.
2690 HRESULT WINAPI CoRegisterMessageFilter(
2691 LPMESSAGEFILTER lpMessageFilter,
2692 LPMESSAGEFILTER *lplpMessageFilter)
2694 struct apartment *apt;
2695 IMessageFilter *lpOldMessageFilter;
2697 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2699 apt = COM_CurrentApt();
2701 /* can't set a message filter in a multi-threaded apartment */
2702 if (!apt || apt->multi_threaded)
2704 WARN("can't set message filter in MTA or uninitialized apt\n");
2705 return CO_E_NOT_SUPPORTED;
2708 if (lpMessageFilter)
2709 IMessageFilter_AddRef(lpMessageFilter);
2711 EnterCriticalSection(&apt->cs);
2713 lpOldMessageFilter = apt->filter;
2714 apt->filter = lpMessageFilter;
2716 LeaveCriticalSection(&apt->cs);
2718 if (lplpMessageFilter)
2719 *lplpMessageFilter = lpOldMessageFilter;
2720 else if (lpOldMessageFilter)
2721 IMessageFilter_Release(lpOldMessageFilter);
2723 if (lpMessageFilter)
2724 FIXME("message filter has been registered, but will not be used\n");
2726 return S_OK;
2729 /***********************************************************************
2730 * CoIsOle1Class [OLE32.@]
2732 * Determines whether the specified class an OLE v1 class.
2734 * PARAMS
2735 * clsid [I] Class to test.
2737 * RETURNS
2738 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2740 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2742 FIXME("%s\n", debugstr_guid(clsid));
2743 return FALSE;
2746 /***********************************************************************
2747 * IsEqualGUID [OLE32.@]
2749 * Compares two Unique Identifiers.
2751 * PARAMS
2752 * rguid1 [I] The first GUID to compare.
2753 * rguid2 [I] The other GUID to compare.
2755 * RETURNS
2756 * TRUE if equal
2758 #undef IsEqualGUID
2759 BOOL WINAPI IsEqualGUID(
2760 REFGUID rguid1,
2761 REFGUID rguid2)
2763 return !memcmp(rguid1,rguid2,sizeof(GUID));
2766 /***********************************************************************
2767 * CoInitializeSecurity [OLE32.@]
2769 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2770 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2771 void* pReserved1, DWORD dwAuthnLevel,
2772 DWORD dwImpLevel, void* pReserved2,
2773 DWORD dwCapabilities, void* pReserved3)
2775 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
2776 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2777 dwCapabilities, pReserved3);
2778 return S_OK;
2781 /***********************************************************************
2782 * CoSuspendClassObjects [OLE32.@]
2784 * Suspends all registered class objects to prevent further requests coming in
2785 * for those objects.
2787 * RETURNS
2788 * Success: S_OK.
2789 * Failure: HRESULT code.
2791 HRESULT WINAPI CoSuspendClassObjects(void)
2793 FIXME("\n");
2794 return S_OK;
2797 /***********************************************************************
2798 * CoAddRefServerProcess [OLE32.@]
2800 * Helper function for incrementing the reference count of a local-server
2801 * process.
2803 * RETURNS
2804 * New reference count.
2806 ULONG WINAPI CoAddRefServerProcess(void)
2808 FIXME("\n");
2809 return 2;
2812 /***********************************************************************
2813 * CoReleaseServerProcess [OLE32.@]
2815 * Helper function for decrementing the reference count of a local-server
2816 * process.
2818 * RETURNS
2819 * New reference count.
2821 ULONG WINAPI CoReleaseServerProcess(void)
2823 FIXME("\n");
2824 return 1;
2827 /***********************************************************************
2828 * CoIsHandlerConnected [OLE32.@]
2830 * Determines whether a proxy is connected to a remote stub.
2832 * PARAMS
2833 * pUnk [I] Pointer to object that may or may not be connected.
2835 * RETURNS
2836 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2837 * FALSE otherwise.
2839 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2841 FIXME("%p\n", pUnk);
2843 return TRUE;
2846 /***********************************************************************
2847 * CoAllowSetForegroundWindow [OLE32.@]
2850 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2852 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2853 return S_OK;
2856 /***********************************************************************
2857 * CoQueryProxyBlanket [OLE32.@]
2859 * Retrieves the security settings being used by a proxy.
2861 * PARAMS
2862 * pProxy [I] Pointer to the proxy object.
2863 * pAuthnSvc [O] The type of authentication service.
2864 * pAuthzSvc [O] The type of authorization service.
2865 * ppServerPrincName [O] Optional. The server prinicple name.
2866 * pAuthnLevel [O] The authentication level.
2867 * pImpLevel [O] The impersonation level.
2868 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2869 * pCapabilities [O] Flags affecting the security behaviour.
2871 * RETURNS
2872 * Success: S_OK.
2873 * Failure: HRESULT code.
2875 * SEE ALSO
2876 * CoCopyProxy, CoSetProxyBlanket.
2878 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2879 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2880 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2882 IClientSecurity *pCliSec;
2883 HRESULT hr;
2885 TRACE("%p\n", pProxy);
2887 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2888 if (SUCCEEDED(hr))
2890 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2891 pAuthzSvc, ppServerPrincName,
2892 pAuthnLevel, pImpLevel, ppAuthInfo,
2893 pCapabilities);
2894 IClientSecurity_Release(pCliSec);
2897 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
2898 return hr;
2901 /***********************************************************************
2902 * CoSetProxyBlanket [OLE32.@]
2904 * Sets the security settings for a proxy.
2906 * PARAMS
2907 * pProxy [I] Pointer to the proxy object.
2908 * AuthnSvc [I] The type of authentication service.
2909 * AuthzSvc [I] The type of authorization service.
2910 * pServerPrincName [I] The server prinicple name.
2911 * AuthnLevel [I] The authentication level.
2912 * ImpLevel [I] The impersonation level.
2913 * pAuthInfo [I] Information specific to the authorization/authentication service.
2914 * Capabilities [I] Flags affecting the security behaviour.
2916 * RETURNS
2917 * Success: S_OK.
2918 * Failure: HRESULT code.
2920 * SEE ALSO
2921 * CoQueryProxyBlanket, CoCopyProxy.
2923 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2924 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2925 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2927 IClientSecurity *pCliSec;
2928 HRESULT hr;
2930 TRACE("%p\n", pProxy);
2932 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2933 if (SUCCEEDED(hr))
2935 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2936 AuthzSvc, pServerPrincName,
2937 AuthnLevel, ImpLevel, pAuthInfo,
2938 Capabilities);
2939 IClientSecurity_Release(pCliSec);
2942 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
2943 return hr;
2946 /***********************************************************************
2947 * CoCopyProxy [OLE32.@]
2949 * Copies a proxy.
2951 * PARAMS
2952 * pProxy [I] Pointer to the proxy object.
2953 * ppCopy [O] Copy of the proxy.
2955 * RETURNS
2956 * Success: S_OK.
2957 * Failure: HRESULT code.
2959 * SEE ALSO
2960 * CoQueryProxyBlanket, CoSetProxyBlanket.
2962 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2964 IClientSecurity *pCliSec;
2965 HRESULT hr;
2967 TRACE("%p\n", pProxy);
2969 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2970 if (SUCCEEDED(hr))
2972 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2973 IClientSecurity_Release(pCliSec);
2976 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
2977 return hr;
2981 /***********************************************************************
2982 * CoGetCallContext [OLE32.@]
2984 * Gets the context of the currently executing server call in the current
2985 * thread.
2987 * PARAMS
2988 * riid [I] Context interface to return.
2989 * ppv [O] Pointer to memory that will receive the context on return.
2991 * RETURNS
2992 * Success: S_OK.
2993 * Failure: HRESULT code.
2995 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
2997 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
2999 *ppv = NULL;
3000 return E_NOINTERFACE;
3003 /***********************************************************************
3004 * CoQueryClientBlanket [OLE32.@]
3006 * Retrieves the authentication information about the client of the currently
3007 * executing server call in the current thread.
3009 * PARAMS
3010 * pAuthnSvc [O] Optional. The type of authentication service.
3011 * pAuthzSvc [O] Optional. The type of authorization service.
3012 * pServerPrincName [O] Optional. The server prinicple name.
3013 * pAuthnLevel [O] Optional. The authentication level.
3014 * pImpLevel [O] Optional. The impersonation level.
3015 * pPrivs [O] Optional. Information about the privileges of the client.
3016 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3018 * RETURNS
3019 * Success: S_OK.
3020 * Failure: HRESULT code.
3022 * SEE ALSO
3023 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3025 HRESULT WINAPI CoQueryClientBlanket(
3026 DWORD *pAuthnSvc,
3027 DWORD *pAuthzSvc,
3028 OLECHAR **pServerPrincName,
3029 DWORD *pAuthnLevel,
3030 DWORD *pImpLevel,
3031 RPC_AUTHZ_HANDLE *pPrivs,
3032 DWORD *pCapabilities)
3034 IServerSecurity *pSrvSec;
3035 HRESULT hr;
3037 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3038 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3039 pPrivs, pCapabilities);
3041 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3042 if (SUCCEEDED(hr))
3044 hr = IServerSecurity_QueryBlanket(
3045 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3046 pImpLevel, pPrivs, pCapabilities);
3047 IServerSecurity_Release(pSrvSec);
3050 return hr;
3053 /***********************************************************************
3054 * CoImpersonateClient [OLE32.@]
3056 * Impersonates the client of the currently executing server call in the
3057 * current thread.
3059 * PARAMS
3060 * None.
3062 * RETURNS
3063 * Success: S_OK.
3064 * Failure: HRESULT code.
3066 * NOTES
3067 * If this function fails then the current thread will not be impersonating
3068 * the client and all actions will take place on behalf of the server.
3069 * Therefore, it is important to check the return value from this function.
3071 * SEE ALSO
3072 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3074 HRESULT WINAPI CoImpersonateClient(void)
3076 IServerSecurity *pSrvSec;
3077 HRESULT hr;
3079 TRACE("\n");
3081 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3082 if (SUCCEEDED(hr))
3084 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3085 IServerSecurity_Release(pSrvSec);
3088 return hr;
3091 /***********************************************************************
3092 * CoRevertToSelf [OLE32.@]
3094 * Ends the impersonation of the client of the currently executing server
3095 * call in the current thread.
3097 * PARAMS
3098 * None.
3100 * RETURNS
3101 * Success: S_OK.
3102 * Failure: HRESULT code.
3104 * SEE ALSO
3105 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3107 HRESULT WINAPI CoRevertToSelf(void)
3109 IServerSecurity *pSrvSec;
3110 HRESULT hr;
3112 TRACE("\n");
3114 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3115 if (SUCCEEDED(hr))
3117 hr = IServerSecurity_RevertToSelf(pSrvSec);
3118 IServerSecurity_Release(pSrvSec);
3121 return hr;
3124 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3126 /* first try to retrieve messages for incoming COM calls to the apartment window */
3127 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3128 /* next retrieve other messages necessary for the app to remain responsive */
3129 PeekMessageW(msg, NULL, 0, WM_USER - 1, PM_REMOVE|PM_NOYIELD);
3132 /***********************************************************************
3133 * CoWaitForMultipleHandles [OLE32.@]
3135 * Waits for one or more handles to become signaled.
3137 * PARAMS
3138 * dwFlags [I] Flags. See notes.
3139 * dwTimeout [I] Timeout in milliseconds.
3140 * cHandles [I] Number of handles pointed to by pHandles.
3141 * pHandles [I] Handles to wait for.
3142 * lpdwindex [O] Index of handle that was signaled.
3144 * RETURNS
3145 * Success: S_OK.
3146 * Failure: RPC_S_CALLPENDING on timeout.
3148 * NOTES
3150 * The dwFlags parameter can be zero or more of the following:
3151 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3152 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3154 * SEE ALSO
3155 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3157 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3158 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
3160 HRESULT hr = S_OK;
3161 DWORD start_time = GetTickCount();
3162 APARTMENT *apt = COM_CurrentApt();
3163 BOOL message_loop = apt && !apt->multi_threaded;
3165 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3166 pHandles, lpdwindex);
3168 while (TRUE)
3170 DWORD now = GetTickCount();
3171 DWORD res;
3173 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
3175 hr = RPC_S_CALLPENDING;
3176 break;
3179 if (message_loop)
3181 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
3182 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
3184 TRACE("waiting for rpc completion or window message\n");
3186 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3187 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3188 QS_ALLINPUT, wait_flags);
3190 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3192 MSG msg;
3194 /* note: using "if" here instead of "while" might seem less
3195 * efficient, but only if we are optimising for quick delivery
3196 * of pending messages, rather than quick completion of the
3197 * COM call */
3198 if (COM_PeekMessage(apt, &msg))
3200 /* FIXME: filter the messages here */
3201 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3202 TranslateMessage(&msg);
3203 DispatchMessageW(&msg);
3204 if (msg.message == WM_QUIT)
3206 TRACE("resending WM_QUIT to outer message loop\n");
3207 PostQuitMessage(msg.wParam);
3208 /* no longer need to process messages */
3209 message_loop = FALSE;
3212 continue;
3215 else
3217 TRACE("waiting for rpc completion\n");
3219 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3220 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3221 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3222 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3225 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
3227 /* handle signaled, store index */
3228 *lpdwindex = (res - WAIT_OBJECT_0);
3229 break;
3231 else if (res == WAIT_TIMEOUT)
3233 hr = RPC_S_CALLPENDING;
3234 break;
3236 else
3238 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3239 hr = E_UNEXPECTED;
3240 break;
3243 TRACE("-- 0x%08x\n", hr);
3244 return hr;
3248 /***********************************************************************
3249 * CoGetObject [OLE32.@]
3251 * Gets the object named by coverting the name to a moniker and binding to it.
3253 * PARAMS
3254 * pszName [I] String representing the object.
3255 * pBindOptions [I] Parameters affecting the binding to the named object.
3256 * riid [I] Interface to bind to on the objecct.
3257 * ppv [O] On output, the interface riid of the object represented
3258 * by pszName.
3260 * RETURNS
3261 * Success: S_OK.
3262 * Failure: HRESULT code.
3264 * SEE ALSO
3265 * MkParseDisplayName.
3267 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3268 REFIID riid, void **ppv)
3270 IBindCtx *pbc;
3271 HRESULT hr;
3273 *ppv = NULL;
3275 hr = CreateBindCtx(0, &pbc);
3276 if (SUCCEEDED(hr))
3278 if (pBindOptions)
3279 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3281 if (SUCCEEDED(hr))
3283 ULONG chEaten;
3284 IMoniker *pmk;
3286 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3287 if (SUCCEEDED(hr))
3289 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3290 IMoniker_Release(pmk);
3294 IBindCtx_Release(pbc);
3296 return hr;
3299 /***********************************************************************
3300 * DllMain (OLE32.@)
3302 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3304 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3306 switch(fdwReason) {
3307 case DLL_PROCESS_ATTACH:
3308 OLE32_hInstance = hinstDLL;
3309 COMPOBJ_InitProcess();
3310 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3311 break;
3313 case DLL_PROCESS_DETACH:
3314 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3315 COMPOBJ_UninitProcess();
3316 OLE32_hInstance = 0;
3317 break;
3319 case DLL_THREAD_DETACH:
3320 COM_TlsDestroy();
3321 break;
3323 return TRUE;
3326 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */