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
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
27 * Therefore do not test against COINIT_MULTITHREADED
29 * TODO list: (items bunched together depend on each other)
31 * - Implement the service control manager (in rpcss) to keep track
32 * of registered class objects: ISCM::ServerRegisterClsid et al
33 * - Implement the OXID resolver so we don't need magic endpoint names for
34 * clients and servers to meet up
36 * - Call IMessageFilter functions.
38 * - Make all ole interface marshaling use NDR to be wire compatible with
40 * - Use & interpret ORPCTHIS & ORPCTHAT.
53 #define NONAMELESSUNION
54 #define NONAMELESSSTRUCT
65 #include "compobj_private.h"
67 #include "wine/unicode.h"
68 #include "wine/debug.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(ole);
72 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
74 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
76 /****************************************************************************
77 * This section defines variables internal to the COM module.
79 * TODO: Most of these things will have to be made thread-safe.
82 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
83 static void COM_RevokeAllClasses(void);
85 APARTMENT *MTA; /* protected by csApartment */
86 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
88 static CRITICAL_SECTION csApartment;
89 static CRITICAL_SECTION_DEBUG critsect_debug =
92 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
93 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
95 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
98 * This lock count counts the number of times CoInitialize is called. It is
99 * decreased every time CoUninitialize is called. When it hits 0, the COM
100 * libraries are freed
102 static LONG s_COMLockCount = 0;
105 * This linked list contains the list of registered class objects. These
106 * are mostly used to register the factories for out-of-proc servers of OLE
109 * TODO: Make this data structure aware of inter-process communication. This
110 * means that parts of this will be exported to the Wine Server.
112 typedef struct tagRegisteredClass
114 CLSID classIdentifier;
115 LPUNKNOWN classObject;
119 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
120 struct tagRegisteredClass* nextClass;
123 static RegisteredClass* firstRegisteredClass = NULL;
125 static CRITICAL_SECTION csRegisteredClassList;
126 static CRITICAL_SECTION_DEBUG class_cs_debug =
128 0, 0, &csRegisteredClassList,
129 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
130 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
132 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
134 /*****************************************************************************
135 * This section contains OpenDllList definitions
137 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
138 * other functions that do LoadLibrary _without_ giving back a HMODULE.
139 * Without this list these handles would never be freed.
141 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
142 * next unload-call but not before 600 sec.
145 typedef struct tagOpenDll {
147 struct tagOpenDll *next;
150 static OpenDll *openDllList = NULL; /* linked list of open dlls */
152 static CRITICAL_SECTION csOpenDllList;
153 static CRITICAL_SECTION_DEBUG dll_cs_debug =
155 0, 0, &csOpenDllList,
156 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
157 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
159 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
161 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',' ',
162 '0','x','#','#','#','#','#','#','#','#',' ',0};
163 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
165 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
166 static void COMPOBJ_DllList_FreeUnused(int Timeout);
168 static void COMPOBJ_InitProcess( void )
172 /* Dispatching to the correct thread in an apartment is done through
173 * window messages rather than RPC transports. When an interface is
174 * marshalled into another apartment in the same process, a window of the
175 * following class is created. The *caller* of CoMarshalInterface (ie the
176 * application) is responsible for pumping the message loop in that thread.
177 * The WM_USER messages which point to the RPCs are then dispatched to
178 * COM_AptWndProc by the user's code from the apartment in which the interface
181 memset(&wclass, 0, sizeof(wclass));
182 wclass.lpfnWndProc = apartment_wndproc;
183 wclass.hInstance = OLE32_hInstance;
184 wclass.lpszClassName = wszAptWinClass;
185 RegisterClassW(&wclass);
188 static void COMPOBJ_UninitProcess( void )
190 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
193 static void COM_TlsDestroy(void)
195 struct oletls *info = NtCurrentTeb()->ReservedForOle;
198 if (info->apt) apartment_release(info->apt);
199 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
200 if (info->state) IUnknown_Release(info->state);
201 HeapFree(GetProcessHeap(), 0, info);
202 NtCurrentTeb()->ReservedForOle = NULL;
206 /******************************************************************************
210 /* allocates memory and fills in the necessary fields for a new apartment
212 static APARTMENT *apartment_construct(DWORD model)
216 TRACE("creating new apartment, model=%ld\n", model);
218 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
219 apt->tid = GetCurrentThreadId();
221 list_init(&apt->proxies);
222 list_init(&apt->stubmgrs);
225 apt->remunk_exported = FALSE;
227 InitializeCriticalSection(&apt->cs);
228 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
230 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
232 if (apt->multi_threaded)
234 /* FIXME: should be randomly generated by in an RPC call to rpcss */
235 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
239 /* FIXME: should be randomly generated by in an RPC call to rpcss */
240 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
243 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
245 /* the locking here is not currently needed for the MTA case, but it
246 * doesn't hurt and makes the code simpler */
247 EnterCriticalSection(&csApartment);
248 list_add_head(&apts, &apt->entry);
249 LeaveCriticalSection(&csApartment);
254 /* gets and existing apartment if one exists or otherwise creates an apartment
255 * structure which stores OLE apartment-local information and stores a pointer
256 * to it in the thread-local storage */
257 static APARTMENT *apartment_get_or_create(DWORD model)
259 APARTMENT *apt = COM_CurrentApt();
263 if (model & COINIT_APARTMENTTHREADED)
265 apt = apartment_construct(model);
266 COM_CurrentInfo()->apt = apt;
270 EnterCriticalSection(&csApartment);
272 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
273 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
277 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
278 apartment_addref(MTA);
281 MTA = apartment_construct(model);
284 COM_CurrentInfo()->apt = apt;
286 LeaveCriticalSection(&csApartment);
293 static inline BOOL apartment_is_model(APARTMENT *apt, DWORD model)
295 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
298 DWORD apartment_addref(struct apartment *apt)
300 DWORD refs = InterlockedIncrement(&apt->refs);
301 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
305 DWORD apartment_release(struct apartment *apt)
309 EnterCriticalSection(&csApartment);
311 ret = InterlockedDecrement(&apt->refs);
312 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
313 /* destruction stuff that needs to happen under csApartment CS */
316 if (apt == MTA) MTA = NULL;
317 list_remove(&apt->entry);
320 LeaveCriticalSection(&csApartment);
324 struct list *cursor, *cursor2;
326 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
328 /* no locking is needed for this apartment, because no other thread
329 * can access it at this point */
331 apartment_disconnectproxies(apt);
333 if (apt->win) DestroyWindow(apt->win);
335 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
337 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
338 /* release the implicit reference given by the fact that the
339 * stub has external references (it must do since it is in the
340 * stub manager list in the apartment and all non-apartment users
341 * must have a ref on the apartment and so it cannot be destroyed).
343 stub_manager_int_release(stubmgr);
346 /* if this assert fires, then another thread took a reference to a
347 * stub manager without taking a reference to the containing
348 * apartment, which it must do. */
349 assert(list_empty(&apt->stubmgrs));
351 if (apt->filter) IUnknown_Release(apt->filter);
353 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
354 DeleteCriticalSection(&apt->cs);
356 HeapFree(GetProcessHeap(), 0, apt);
362 /* The given OXID must be local to this process:
364 * The ref parameter is here mostly to ensure people remember that
365 * they get one, you should normally take a ref for thread safety.
367 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
369 APARTMENT *result = NULL;
372 EnterCriticalSection(&csApartment);
373 LIST_FOR_EACH( cursor, &apts )
375 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
376 if (apt->oxid == oxid)
379 if (ref) apartment_addref(result);
383 LeaveCriticalSection(&csApartment);
388 /* gets the apartment which has a given creator thread ID. The caller must
389 * release the reference from the apartment as soon as the apartment pointer
390 * is no longer required. */
391 APARTMENT *apartment_findfromtid(DWORD tid)
393 APARTMENT *result = NULL;
396 EnterCriticalSection(&csApartment);
397 LIST_FOR_EACH( cursor, &apts )
399 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
403 apartment_addref(result);
407 LeaveCriticalSection(&csApartment);
412 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
417 RPC_ExecuteCall((struct dispatch_params *)lParam);
420 return DefWindowProcW(hWnd, msg, wParam, lParam);
424 HRESULT apartment_createwindowifneeded(struct apartment *apt)
426 if (apt->multi_threaded)
431 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
433 0, 0, OLE32_hInstance, NULL);
436 ERR("CreateWindow failed with error %ld\n", GetLastError());
437 return HRESULT_FROM_WIN32(GetLastError());
439 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
440 /* someone beat us to it */
447 HWND apartment_getwindow(struct apartment *apt)
449 assert(!apt->multi_threaded);
453 void apartment_joinmta(void)
455 apartment_addref(MTA);
456 COM_CurrentInfo()->apt = MTA;
459 /*****************************************************************************
460 * This section contains OpenDllList implemantation
463 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
470 EnterCriticalSection( &csOpenDllList );
472 if (openDllList == NULL) {
473 /* empty list -- add first node */
474 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
475 openDllList->hLibrary=hLibrary;
476 openDllList->next = NULL;
478 /* search for this dll */
480 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
481 if (ptr->hLibrary == hLibrary) {
487 /* dll not found, add it */
489 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
490 openDllList->hLibrary = hLibrary;
491 openDllList->next = tmp;
495 LeaveCriticalSection( &csOpenDllList );
498 static void COMPOBJ_DllList_FreeUnused(int Timeout)
500 OpenDll *curr, *next, *prev = NULL;
501 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
502 DllCanUnloadNowFunc DllCanUnloadNow;
506 EnterCriticalSection( &csOpenDllList );
508 for (curr = openDllList; curr != NULL; ) {
509 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
511 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
514 TRACE("freeing %p\n", curr->hLibrary);
515 FreeLibrary(curr->hLibrary);
517 HeapFree(GetProcessHeap(), 0, curr);
518 if (curr == openDllList) {
531 LeaveCriticalSection( &csOpenDllList );
534 /******************************************************************************
535 * CoBuildVersion [OLE32.@]
536 * CoBuildVersion [COMPOBJ.1]
538 * Gets the build version of the DLL.
543 * Current build version, hiword is majornumber, loword is minornumber
545 DWORD WINAPI CoBuildVersion(void)
547 TRACE("Returning version %d, build %d.\n", rmm, rup);
548 return (rmm<<16)+rup;
551 /******************************************************************************
552 * CoInitialize [OLE32.@]
554 * Initializes the COM libraries by calling CoInitializeEx with
555 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
558 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
561 * Success: S_OK if not already initialized, S_FALSE otherwise.
562 * Failure: HRESULT code.
567 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
570 * Just delegate to the newer method.
572 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
575 /******************************************************************************
576 * CoInitializeEx [OLE32.@]
578 * Initializes the COM libraries.
581 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
582 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
585 * S_OK if successful,
586 * S_FALSE if this function was called already.
587 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
592 * The behavior used to set the IMalloc used for memory management is
594 * The dwCoInit parameter must specify of of the following apartment
596 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
597 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
598 * The parameter may also specify zero or more of the following flags:
599 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
600 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
605 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
610 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
612 if (lpReserved!=NULL)
614 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
618 * Check the lock count. If this is the first time going through the initialize
619 * process, we have to initialize the libraries.
621 * And crank-up that lock count.
623 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
626 * Initialize the various COM libraries and data structures.
628 TRACE("() - Initializing the COM libraries\n");
630 /* we may need to defer this until after apartment initialisation */
631 RunningObjectTableImpl_Initialize();
634 if (!(apt = COM_CurrentInfo()->apt))
636 apt = apartment_get_or_create(dwCoInit);
637 if (!apt) return E_OUTOFMEMORY;
639 else if (!apartment_is_model(apt, dwCoInit))
641 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
642 code then we are probably using the wrong threading model to implement that API. */
643 ERR("Attempt to change threading model of this apartment from %s to %s\n",
644 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
645 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
646 return RPC_E_CHANGED_MODE;
651 COM_CurrentInfo()->inits++;
656 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
657 pending RPCs are ignored. Non-COM messages are discarded at this point.
659 static void COM_FlushMessageQueue(void)
662 APARTMENT *apt = COM_CurrentApt();
664 if (!apt || !apt->win) return;
666 TRACE("Flushing STA message queue\n");
668 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
670 if (message.hwnd != apt->win)
672 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
676 TranslateMessage(&message);
677 DispatchMessageA(&message);
681 /***********************************************************************
682 * CoUninitialize [OLE32.@]
684 * This method will decrement the refcount on the current apartment, freeing
685 * the resources associated with it if it is the last thread in the apartment.
686 * If the last apartment is freed, the function will additionally release
687 * any COM resources associated with the process.
697 void WINAPI CoUninitialize(void)
699 struct oletls * info = COM_CurrentInfo();
704 /* will only happen on OOM */
710 ERR("Mismatched CoUninitialize\n");
716 apartment_release(info->apt);
721 * Decrease the reference count.
722 * If we are back to 0 locks on the COM library, make sure we free
723 * all the associated data structures.
725 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
728 TRACE("() - Releasing the COM libraries\n");
730 RunningObjectTableImpl_UnInitialize();
732 /* Release the references to the registered class objects */
733 COM_RevokeAllClasses();
735 /* This will free the loaded COM Dlls */
736 CoFreeAllLibraries();
738 /* This ensures we deal with any pending RPCs */
739 COM_FlushMessageQueue();
741 else if (lCOMRefCnt<1) {
742 ERR( "CoUninitialize() - not CoInitialized.\n" );
743 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
747 /******************************************************************************
748 * CoDisconnectObject [OLE32.@]
749 * CoDisconnectObject [COMPOBJ.15]
751 * Disconnects all connections to this object from remote processes. Dispatches
752 * pending RPCs while blocking new RPCs from occurring, and then calls
753 * IMarshal::DisconnectObject on the given object.
755 * Typically called when the object server is forced to shut down, for instance by
759 * lpUnk [I] The object whose stub should be disconnected.
760 * reserved [I] Reserved. Should be set to 0.
764 * Failure: HRESULT code.
767 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
769 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
775 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
777 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
780 hr = IMarshal_DisconnectObject(marshal, reserved);
781 IMarshal_Release(marshal);
785 apt = COM_CurrentApt();
787 return CO_E_NOTINITIALIZED;
789 apartment_disconnectobject(apt, lpUnk);
791 /* Note: native is pretty broken here because it just silently
792 * fails, without returning an appropriate error code if the object was
793 * not found, making apps think that the object was disconnected, when
794 * it actually wasn't */
799 /******************************************************************************
800 * CoCreateGuid [OLE32.@]
802 * Simply forwards to UuidCreate in RPCRT4.
805 * pguid [O] Points to the GUID to initialize.
809 * Failure: HRESULT code.
814 HRESULT WINAPI CoCreateGuid(GUID *pguid)
816 return UuidCreate(pguid);
819 /******************************************************************************
820 * CLSIDFromString [OLE32.@]
821 * IIDFromString [OLE32.@]
823 * Converts a unique identifier from its string representation into
827 * idstr [I] The string representation of the GUID.
828 * id [O] GUID converted from the string.
832 * CO_E_CLASSSTRING if idstr is not a valid CLSID
837 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
843 memset( id, 0, sizeof (CLSID) );
847 /* validate the CLSID string */
848 if (strlenW(s) != 38)
849 return CO_E_CLASSSTRING;
851 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
852 return CO_E_CLASSSTRING;
854 for (i=1; i<37; i++) {
855 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
856 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
857 ((s[i] >= 'a') && (s[i] <= 'f')) ||
858 ((s[i] >= 'A') && (s[i] <= 'F'))))
859 return CO_E_CLASSSTRING;
862 TRACE("%s -> %p\n", debugstr_w(s), id);
864 /* quick lookup table */
865 memset(table, 0, 256);
867 for (i = 0; i < 10; i++) {
870 for (i = 0; i < 6; i++) {
871 table['A' + i] = i+10;
872 table['a' + i] = i+10;
875 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
877 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
878 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
879 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
880 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
882 /* these are just sequential bytes */
883 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
884 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
885 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
886 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
887 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
888 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
889 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
890 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
895 /*****************************************************************************/
897 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
901 ret = __CLSIDFromString(idstr, id);
902 if(ret != S_OK) { /* It appears a ProgID is also valid */
903 ret = CLSIDFromProgID(idstr, id);
908 /* Converts a GUID into the respective string representation. */
909 HRESULT WINE_StringFromCLSID(
910 const CLSID *id, /* [in] GUID to be converted */
911 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
913 static const char *hex = "0123456789ABCDEF";
918 { ERR("called with id=Null\n");
923 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
924 id->Data1, id->Data2, id->Data3,
925 id->Data4[0], id->Data4[1]);
929 for (i = 2; i < 8; i++) {
930 *s++ = hex[id->Data4[i]>>4];
931 *s++ = hex[id->Data4[i] & 0xf];
937 TRACE("%p->%s\n", id, idstr);
943 /******************************************************************************
944 * StringFromCLSID [OLE32.@]
945 * StringFromIID [OLE32.@]
947 * Converts a GUID into the respective string representation.
948 * The target string is allocated using the OLE IMalloc.
951 * id [I] the GUID to be converted.
952 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
959 * StringFromGUID2, CLSIDFromString
961 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
967 if ((ret = CoGetMalloc(0,&mllc)))
970 ret=WINE_StringFromCLSID(id,buf);
972 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
973 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
974 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
979 /******************************************************************************
980 * StringFromGUID2 [OLE32.@]
981 * StringFromGUID2 [COMPOBJ.76]
983 * Modified version of StringFromCLSID that allows you to specify max
987 * id [I] GUID to convert to string.
988 * str [O] Buffer where the result will be stored.
989 * cmax [I] Size of the buffer in characters.
992 * Success: The length of the resulting string in characters.
995 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
999 if (WINE_StringFromCLSID(id,xguid))
1001 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1004 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1005 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1007 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1008 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1012 strcpyW(path, wszCLSIDSlash);
1013 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1014 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1015 if (res == ERROR_FILE_NOT_FOUND)
1016 return REGDB_E_CLASSNOTREG;
1017 else if (res != ERROR_SUCCESS)
1018 return REGDB_E_READREGDB;
1026 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1028 if (res == ERROR_FILE_NOT_FOUND)
1029 return REGDB_E_KEYMISSING;
1030 else if (res != ERROR_SUCCESS)
1031 return REGDB_E_READREGDB;
1036 /******************************************************************************
1037 * ProgIDFromCLSID [OLE32.@]
1039 * Converts a class id into the respective program ID.
1042 * clsid [I] Class ID, as found in registry.
1043 * lplpszProgID [O] Associated ProgID.
1048 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1050 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1052 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1057 *lplpszProgID = NULL;
1058 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1062 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1063 ret = REGDB_E_CLASSNOTREG;
1067 *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1070 if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen))
1071 ret = REGDB_E_CLASSNOTREG;
1074 ret = E_OUTOFMEMORY;
1081 /******************************************************************************
1082 * CLSIDFromProgID [OLE32.@]
1084 * Converts a program id into the respective GUID.
1087 * progid [I] Unicode program ID, as found in registry.
1088 * riid [O] Associated CLSID.
1092 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1094 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1096 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1097 WCHAR buf2[CHARS_IN_GUID];
1098 LONG buf2len = sizeof(buf2);
1101 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1102 strcpyW( buf, progid );
1103 strcatW( buf, clsidW );
1104 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1106 HeapFree(GetProcessHeap(),0,buf);
1107 return CO_E_CLASSSTRING;
1109 HeapFree(GetProcessHeap(),0,buf);
1111 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1114 return CO_E_CLASSSTRING;
1117 return CLSIDFromString(buf2,riid);
1121 /*****************************************************************************
1122 * CoGetPSClsid [OLE32.@]
1124 * Retrieves the CLSID of the proxy/stub factory that implements
1125 * IPSFactoryBuffer for the specified interface.
1128 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1129 * pclsid [O] Where to store returned proxy/stub CLSID.
1134 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1138 * The standard marshaller activates the object with the CLSID
1139 * returned and uses the CreateProxy and CreateStub methods on its
1140 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1143 * CoGetPSClsid determines this CLSID by searching the
1144 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1145 * in the registry and any interface id registered by
1146 * CoRegisterPSClsid within the current process.
1150 * We only search the registry, not ids registered with
1151 * CoRegisterPSClsid.
1152 * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1153 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1154 * considered a bug in native unless an application depends on this (unlikely).
1156 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1158 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1159 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1160 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1161 WCHAR value[CHARS_IN_GUID];
1165 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1167 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1168 strcpyW(path, wszInterface);
1169 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1170 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1172 /* Open the key.. */
1173 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1175 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1176 return REGDB_E_IIDNOTREG;
1179 /* ... Once we have the key, query the registry to get the
1180 value of CLSID as a string, and convert it into a
1181 proper CLSID structure to be passed back to the app */
1182 len = sizeof(value);
1183 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1186 return REGDB_E_IIDNOTREG;
1190 /* We have the CLSid we want back from the registry as a string, so
1191 lets convert it into a CLSID structure */
1192 if (CLSIDFromString(value, pclsid) != NOERROR)
1193 return REGDB_E_IIDNOTREG;
1195 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1201 /***********************************************************************
1202 * WriteClassStm (OLE32.@)
1204 * Writes a CLSID to a stream.
1207 * pStm [I] Stream to write to.
1208 * rclsid [I] CLSID to write.
1212 * Failure: HRESULT code.
1214 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1216 TRACE("(%p,%p)\n",pStm,rclsid);
1219 return E_INVALIDARG;
1221 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1224 /***********************************************************************
1225 * ReadClassStm (OLE32.@)
1227 * Reads a CLSID from a stream.
1230 * pStm [I] Stream to read from.
1231 * rclsid [O] CLSID to read.
1235 * Failure: HRESULT code.
1237 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1242 TRACE("(%p,%p)\n",pStm,pclsid);
1245 return E_INVALIDARG;
1247 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1252 if (nbByte != sizeof(CLSID))
1260 * COM_GetRegisteredClassObject
1262 * This internal method is used to scan the registered class list to
1263 * find a class object.
1266 * rclsid Class ID of the class to find.
1267 * dwClsContext Class context to match.
1268 * ppv [out] returns a pointer to the class object. Complying
1269 * to normal COM usage, this method will increase the
1270 * reference count on this object.
1272 static HRESULT COM_GetRegisteredClassObject(
1277 HRESULT hr = S_FALSE;
1278 RegisteredClass* curClass;
1280 EnterCriticalSection( &csRegisteredClassList );
1288 * Iterate through the whole list and try to match the class ID.
1290 curClass = firstRegisteredClass;
1292 while (curClass != 0)
1295 * Check if we have a match on the class ID.
1297 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1300 * Since we don't do out-of process or DCOM just right away, let's ignore the
1305 * We have a match, return the pointer to the class object.
1307 *ppUnk = curClass->classObject;
1309 IUnknown_AddRef(curClass->classObject);
1316 * Step to the next class in the list.
1318 curClass = curClass->nextClass;
1322 LeaveCriticalSection( &csRegisteredClassList );
1324 * If we get to here, we haven't found our class.
1329 /******************************************************************************
1330 * CoRegisterClassObject [OLE32.@]
1332 * Registers the class object for a given class ID. Servers housed in EXE
1333 * files use this method instead of exporting DllGetClassObject to allow
1334 * other code to connect to their objects.
1337 * rclsid [I] CLSID of the object to register.
1338 * pUnk [I] IUnknown of the object.
1339 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1340 * flags [I] REGCLS flags indicating how connections are made.
1341 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1345 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1346 * CO_E_OBJISREG if the object is already registered. We should not return this.
1349 * CoRevokeClassObject, CoGetClassObject
1352 * MSDN claims that multiple interface registrations are legal, but we
1353 * can't do that with our current implementation.
1355 HRESULT WINAPI CoRegisterClassObject(
1360 LPDWORD lpdwRegister)
1362 RegisteredClass* newClass;
1363 LPUNKNOWN foundObject;
1366 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1367 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1369 if ( (lpdwRegister==0) || (pUnk==0) )
1370 return E_INVALIDARG;
1372 if (!COM_CurrentApt())
1374 ERR("COM was not initialized\n");
1375 return CO_E_NOTINITIALIZED;
1381 * First, check if the class is already registered.
1382 * If it is, this should cause an error.
1384 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1386 if (flags & REGCLS_MULTIPLEUSE) {
1387 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1388 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1389 IUnknown_Release(foundObject);
1392 IUnknown_Release(foundObject);
1393 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1394 return CO_E_OBJISREG;
1397 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1398 if ( newClass == NULL )
1399 return E_OUTOFMEMORY;
1401 EnterCriticalSection( &csRegisteredClassList );
1403 newClass->classIdentifier = *rclsid;
1404 newClass->runContext = dwClsContext;
1405 newClass->connectFlags = flags;
1406 newClass->pMarshaledData = NULL;
1409 * Use the address of the chain node as the cookie since we are sure it's
1410 * unique. FIXME: not on 64-bit platforms.
1412 newClass->dwCookie = (DWORD)newClass;
1413 newClass->nextClass = firstRegisteredClass;
1416 * Since we're making a copy of the object pointer, we have to increase its
1419 newClass->classObject = pUnk;
1420 IUnknown_AddRef(newClass->classObject);
1422 firstRegisteredClass = newClass;
1423 LeaveCriticalSection( &csRegisteredClassList );
1425 *lpdwRegister = newClass->dwCookie;
1427 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1428 IClassFactory *classfac;
1430 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1431 (LPVOID*)&classfac);
1434 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1436 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1437 IUnknown_Release(classfac);
1440 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1441 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1442 MSHLFLAGS_TABLESTRONG);
1444 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1445 IUnknown_Release(classfac);
1449 IUnknown_Release(classfac);
1451 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1456 /***********************************************************************
1457 * CoRevokeClassObject [OLE32.@]
1459 * Removes a class object from the class registry.
1462 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1466 * Failure: HRESULT code.
1469 * CoRegisterClassObject
1471 HRESULT WINAPI CoRevokeClassObject(
1474 HRESULT hr = E_INVALIDARG;
1475 RegisteredClass** prevClassLink;
1476 RegisteredClass* curClass;
1478 TRACE("(%08lx)\n",dwRegister);
1480 EnterCriticalSection( &csRegisteredClassList );
1483 * Iterate through the whole list and try to match the cookie.
1485 curClass = firstRegisteredClass;
1486 prevClassLink = &firstRegisteredClass;
1488 while (curClass != 0)
1491 * Check if we have a match on the cookie.
1493 if (curClass->dwCookie == dwRegister)
1496 * Remove the class from the chain.
1498 *prevClassLink = curClass->nextClass;
1501 * Release the reference to the class object.
1503 IUnknown_Release(curClass->classObject);
1505 if (curClass->pMarshaledData)
1508 memset(&zero, 0, sizeof(zero));
1509 /* FIXME: stop local server thread */
1510 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1511 CoReleaseMarshalData(curClass->pMarshaledData);
1515 * Free the memory used by the chain node.
1517 HeapFree(GetProcessHeap(), 0, curClass);
1524 * Step to the next class in the list.
1526 prevClassLink = &(curClass->nextClass);
1527 curClass = curClass->nextClass;
1531 LeaveCriticalSection( &csRegisteredClassList );
1533 * If we get to here, we haven't found our class.
1538 /***********************************************************************
1539 * COM_RegReadPath [internal]
1541 * Reads a registry value and expands it when necessary
1543 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1548 WCHAR src[MAX_PATH];
1549 DWORD dwLength = dstlen * sizeof(WCHAR);
1551 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1552 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1553 if (keytype == REG_EXPAND_SZ) {
1554 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1556 lstrcpynW(dst, src, dstlen);
1564 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1567 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1568 DllGetClassObjectFunc DllGetClassObject;
1569 WCHAR dllpath[MAX_PATH+1];
1572 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1574 /* failure: CLSID is not found in registry */
1575 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1576 return REGDB_E_CLASSNOTREG;
1579 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1581 /* failure: DLL could not be loaded */
1582 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1583 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1586 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1588 /* failure: the dll did not export DllGetClassObject */
1589 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1590 FreeLibrary( hLibrary );
1591 return CO_E_DLLNOTFOUND;
1594 /* OK: get the ClassObject */
1595 COMPOBJ_DLLList_Add( hLibrary );
1596 hr = DllGetClassObject(rclsid, riid, ppv);
1599 ERR("DllGetClassObject returned error 0x%08lx\n", hr);
1604 /***********************************************************************
1605 * CoGetClassObject [OLE32.@]
1607 * FIXME. If request allows of several options and there is a failure
1608 * with one (other than not being registered) do we try the
1609 * others or return failure? (E.g. inprocess is registered but
1610 * the DLL is not found but the server version works)
1612 HRESULT WINAPI CoGetClassObject(
1613 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1614 REFIID iid, LPVOID *ppv)
1616 LPUNKNOWN regClassObject;
1617 HRESULT hres = E_UNEXPECTED;
1619 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1622 return E_INVALIDARG;
1626 if (!COM_CurrentApt())
1628 ERR("apartment not initialised\n");
1629 return CO_E_NOTINITIALIZED;
1633 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1634 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1638 * First, try and see if we can't match the class ID with one of the
1639 * registered classes.
1641 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1643 /* Get the required interface from the retrieved pointer. */
1644 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1647 * Since QI got another reference on the pointer, we want to release the
1648 * one we already have. If QI was unsuccessful, this will release the object. This
1649 * is good since we are not returning it in the "out" parameter.
1651 IUnknown_Release(regClassObject);
1656 /* First try in-process server */
1657 if (CLSCTX_INPROC_SERVER & dwClsContext)
1659 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1662 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
1663 return FTMarshalCF_Create(iid, ppv);
1665 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1668 if (hres == REGDB_E_CLASSNOTREG)
1669 ERR("class %s not registered\n", debugstr_guid(rclsid));
1671 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1674 if (SUCCEEDED(hres))
1676 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1680 /* return if we got a class, otherwise fall through to one of the
1682 if (SUCCEEDED(hres))
1686 /* Next try in-process handler */
1687 if (CLSCTX_INPROC_HANDLER & dwClsContext)
1689 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1692 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1695 if (hres == REGDB_E_CLASSNOTREG)
1696 ERR("class %s not registered\n", debugstr_guid(rclsid));
1698 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1701 if (SUCCEEDED(hres))
1703 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1707 /* return if we got a class, otherwise fall through to one of the
1709 if (SUCCEEDED(hres))
1713 /* Next try out of process */
1714 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1716 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
1717 if (SUCCEEDED(hres))
1721 /* Finally try remote: this requires networked DCOM (a lot of work) */
1722 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1724 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1725 hres = E_NOINTERFACE;
1729 ERR("no class object %s could be created for context 0x%lx\n",
1730 debugstr_guid(rclsid), dwClsContext);
1734 /***********************************************************************
1735 * CoResumeClassObjects (OLE32.@)
1737 * Resumes all class objects registered with REGCLS_SUSPENDED.
1741 * Failure: HRESULT code.
1743 HRESULT WINAPI CoResumeClassObjects(void)
1749 /***********************************************************************
1750 * GetClassFile (OLE32.@)
1752 * This function supplies the CLSID associated with the given filename.
1754 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1758 int nbElm, length, i;
1760 LPOLESTR *pathDec=0,absFile=0,progId=0;
1762 static const WCHAR bkslashW[] = {'\\',0};
1763 static const WCHAR dotW[] = {'.',0};
1765 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1767 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1768 if((StgIsStorageFile(filePathName))==S_OK){
1770 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1773 res=ReadClassStg(pstg,pclsid);
1775 IStorage_Release(pstg);
1779 /* if the file is not a storage object then attemps to match various bits in the file against a
1780 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1783 for(i=0;i<nFileTypes;i++)
1785 for(i=0;j<nPatternsForType;j++){
1790 pat=ReadPatternFromRegistry(i,j);
1791 hFile=CreateFileW(filePathName,,,,,,hFile);
1792 SetFilePosition(hFile,pat.offset);
1793 ReadFile(hFile,buf,pat.size,&r,NULL);
1794 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1796 *pclsid=ReadCLSIDFromRegistry(i);
1802 /* if the above strategies fail then search for the extension key in the registry */
1804 /* get the last element (absolute file) in the path name */
1805 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1806 absFile=pathDec[nbElm-1];
1808 /* failed if the path represente a directory and not an absolute file name*/
1809 if (!lstrcmpW(absFile, bkslashW))
1810 return MK_E_INVALIDEXTENSION;
1812 /* get the extension of the file */
1814 length=lstrlenW(absFile);
1815 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1818 if (!extension || !lstrcmpW(extension, dotW))
1819 return MK_E_INVALIDEXTENSION;
1821 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1823 /* get the progId associated to the extension */
1824 progId = CoTaskMemAlloc(sizeProgId);
1825 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1827 if (res==ERROR_SUCCESS)
1828 /* return the clsid associated to the progId */
1829 res= CLSIDFromProgID(progId,pclsid);
1831 for(i=0; pathDec[i]!=NULL;i++)
1832 CoTaskMemFree(pathDec[i]);
1833 CoTaskMemFree(pathDec);
1835 CoTaskMemFree(progId);
1837 if (res==ERROR_SUCCESS)
1840 return MK_E_INVALIDEXTENSION;
1843 /***********************************************************************
1844 * CoCreateInstance [OLE32.@]
1846 HRESULT WINAPI CoCreateInstance(
1848 LPUNKNOWN pUnkOuter,
1854 LPCLASSFACTORY lpclf = 0;
1856 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
1857 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
1866 * Initialize the "out" parameter
1870 if (!COM_CurrentApt())
1872 ERR("apartment not initialised\n");
1873 return CO_E_NOTINITIALIZED;
1877 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1878 * Rather than create a class factory, we can just check for it here
1880 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1881 if (StdGlobalInterfaceTableInstance == NULL)
1882 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1883 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1884 if (hres) return hres;
1886 TRACE("Retrieved GIT (%p)\n", *ppv);
1891 * Get a class factory to construct the object we want.
1893 hres = CoGetClassObject(rclsid,
1903 * Create the object and don't forget to release the factory
1905 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1906 IClassFactory_Release(lpclf);
1908 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1909 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1914 /***********************************************************************
1915 * CoCreateInstanceEx [OLE32.@]
1917 HRESULT WINAPI CoCreateInstanceEx(
1919 LPUNKNOWN pUnkOuter,
1921 COSERVERINFO* pServerInfo,
1925 IUnknown* pUnk = NULL;
1928 ULONG successCount = 0;
1933 if ( (cmq==0) || (pResults==NULL))
1934 return E_INVALIDARG;
1936 if (pServerInfo!=NULL)
1937 FIXME("() non-NULL pServerInfo not supported!\n");
1940 * Initialize all the "out" parameters.
1942 for (index = 0; index < cmq; index++)
1944 pResults[index].pItf = NULL;
1945 pResults[index].hr = E_NOINTERFACE;
1949 * Get the object and get its IUnknown pointer.
1951 hr = CoCreateInstance(rclsid,
1961 * Then, query for all the interfaces requested.
1963 for (index = 0; index < cmq; index++)
1965 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1966 pResults[index].pIID,
1967 (VOID**)&(pResults[index].pItf));
1969 if (pResults[index].hr == S_OK)
1974 * Release our temporary unknown pointer.
1976 IUnknown_Release(pUnk);
1978 if (successCount == 0)
1979 return E_NOINTERFACE;
1981 if (successCount!=cmq)
1982 return CO_S_NOTALLINTERFACES;
1987 /***********************************************************************
1988 * CoLoadLibrary (OLE32.@)
1993 * lpszLibName [I] Path to library.
1994 * bAutoFree [I] Whether the library should automatically be freed.
1997 * Success: Handle to loaded library.
2001 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2003 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2005 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2007 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2010 /***********************************************************************
2011 * CoFreeLibrary [OLE32.@]
2013 * Unloads a library from memory.
2016 * hLibrary [I] Handle to library to unload.
2022 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2024 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2026 FreeLibrary(hLibrary);
2030 /***********************************************************************
2031 * CoFreeAllLibraries [OLE32.@]
2033 * Function for backwards compatibility only. Does nothing.
2039 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2041 void WINAPI CoFreeAllLibraries(void)
2047 /***********************************************************************
2048 * CoFreeUnusedLibraries [OLE32.@]
2049 * CoFreeUnusedLibraries [COMPOBJ.17]
2051 * Frees any unused libraries. Unused are identified as those that return
2052 * S_OK from their DllCanUnloadNow function.
2058 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2060 void WINAPI CoFreeUnusedLibraries(void)
2062 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2063 * through the main apartment's thread to call DllCanUnloadNow */
2064 COMPOBJ_DllList_FreeUnused(0);
2067 /***********************************************************************
2068 * CoFileTimeNow [OLE32.@]
2069 * CoFileTimeNow [COMPOBJ.82]
2071 * Retrieves the current time in FILETIME format.
2074 * lpFileTime [O] The current time.
2079 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2081 GetSystemTimeAsFileTime( lpFileTime );
2085 static void COM_RevokeAllClasses()
2087 EnterCriticalSection( &csRegisteredClassList );
2089 while (firstRegisteredClass!=0)
2091 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2094 LeaveCriticalSection( &csRegisteredClassList );
2097 /******************************************************************************
2098 * CoLockObjectExternal [OLE32.@]
2100 * Increments or decrements the external reference count of a stub object.
2103 * pUnk [I] Stub object.
2104 * fLock [I] If TRUE then increments the external ref-count,
2105 * otherwise decrements.
2106 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2107 * calling CoDisconnectObject.
2111 * Failure: HRESULT code.
2114 * If fLock is TRUE and an object is passed in that doesn't have a stub
2115 * manager then a new stub manager is created for the object.
2117 HRESULT WINAPI CoLockObjectExternal(
2120 BOOL fLastUnlockReleases)
2122 struct stub_manager *stubmgr;
2123 struct apartment *apt;
2125 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2126 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2128 apt = COM_CurrentApt();
2129 if (!apt) return CO_E_NOTINITIALIZED;
2131 stubmgr = get_stub_manager_from_object(apt, pUnk);
2136 stub_manager_ext_addref(stubmgr, 1);
2138 stub_manager_ext_release(stubmgr, 1);
2140 stub_manager_int_release(stubmgr);
2146 stubmgr = new_stub_manager(apt, pUnk);
2150 stub_manager_ext_addref(stubmgr, 1);
2151 stub_manager_int_release(stubmgr);
2158 WARN("stub object not found %p\n", pUnk);
2159 /* Note: native is pretty broken here because it just silently
2160 * fails, without returning an appropriate error code, making apps
2161 * think that the object was disconnected, when it actually wasn't */
2166 /***********************************************************************
2167 * CoInitializeWOW (OLE32.@)
2169 * WOW equivalent of CoInitialize?
2178 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2180 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2184 /***********************************************************************
2185 * CoGetState [OLE32.@]
2187 * Retrieves the thread state object previously stored by CoSetState().
2190 * ppv [I] Address where pointer to object will be stored.
2194 * Failure: E_OUTOFMEMORY.
2197 * Crashes on all invalid ppv addresses, including NULL.
2198 * If the function returns a non-NULL object then the caller must release its
2199 * reference on the object when the object is no longer required.
2204 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2206 struct oletls *info = COM_CurrentInfo();
2207 if (!info) return E_OUTOFMEMORY;
2213 IUnknown_AddRef(info->state);
2215 TRACE("apt->state=%p\n", info->state);
2221 /***********************************************************************
2222 * CoSetState [OLE32.@]
2224 * Sets the thread state object.
2227 * pv [I] Pointer to state object to be stored.
2230 * The system keeps a reference on the object while the object stored.
2234 * Failure: E_OUTOFMEMORY.
2236 HRESULT WINAPI CoSetState(IUnknown * pv)
2238 struct oletls *info = COM_CurrentInfo();
2239 if (!info) return E_OUTOFMEMORY;
2241 if (pv) IUnknown_AddRef(pv);
2245 TRACE("-- release %p now\n", info->state);
2246 IUnknown_Release(info->state);
2255 /******************************************************************************
2256 * OleGetAutoConvert [OLE32.@]
2258 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2260 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2262 WCHAR buf[CHARS_IN_GUID];
2266 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2271 if (RegQueryValueW(hkey, NULL, buf, &len))
2273 res = REGDB_E_KEYMISSING;
2276 res = CLSIDFromString(buf, pClsidNew);
2278 if (hkey) RegCloseKey(hkey);
2282 /******************************************************************************
2283 * CoTreatAsClass [OLE32.@]
2285 * Sets the TreatAs value of a class.
2288 * clsidOld [I] Class to set TreatAs value on.
2289 * clsidNew [I] The class the clsidOld should be treated as.
2293 * Failure: HRESULT code.
2298 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2300 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2301 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2303 WCHAR szClsidNew[CHARS_IN_GUID];
2305 WCHAR auto_treat_as[CHARS_IN_GUID];
2306 LONG auto_treat_as_size = sizeof(auto_treat_as);
2309 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2312 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2314 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2315 !CLSIDFromString(auto_treat_as, &id))
2317 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2319 res = REGDB_E_WRITEREGDB;
2325 RegDeleteKeyW(hkey, wszTreatAs);
2329 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2330 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2332 res = REGDB_E_WRITEREGDB;
2337 if (hkey) RegCloseKey(hkey);
2341 /******************************************************************************
2342 * CoGetTreatAsClass [OLE32.@]
2344 * Gets the TreatAs value of a class.
2347 * clsidOld [I] Class to get the TreatAs value of.
2348 * clsidNew [I] The class the clsidOld should be treated as.
2352 * Failure: HRESULT code.
2357 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2359 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2361 WCHAR szClsidNew[CHARS_IN_GUID];
2363 LONG len = sizeof(szClsidNew);
2365 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2366 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2368 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2371 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2376 res = CLSIDFromString(szClsidNew,clsidNew);
2378 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2380 if (hkey) RegCloseKey(hkey);
2384 /******************************************************************************
2385 * CoGetCurrentProcess [OLE32.@]
2386 * CoGetCurrentProcess [COMPOBJ.34]
2388 * Gets the current process ID.
2391 * The current process ID.
2394 * Is DWORD really the correct return type for this function?
2396 DWORD WINAPI CoGetCurrentProcess(void)
2398 return GetCurrentProcessId();
2401 /******************************************************************************
2402 * CoRegisterMessageFilter [OLE32.@]
2404 * Registers a message filter.
2407 * lpMessageFilter [I] Pointer to interface.
2408 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2412 * Failure: HRESULT code.
2415 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2416 * lpMessageFilter removes the message filter.
2418 * If lplpMessageFilter is not NULL the previous message filter will be
2419 * returned in the memory pointer to this parameter and the caller is
2420 * responsible for releasing the object.
2422 * The current thread be in an apartment otherwise the function will crash.
2424 HRESULT WINAPI CoRegisterMessageFilter(
2425 LPMESSAGEFILTER lpMessageFilter,
2426 LPMESSAGEFILTER *lplpMessageFilter)
2428 struct apartment *apt;
2429 IMessageFilter *lpOldMessageFilter;
2431 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2433 apt = COM_CurrentApt();
2435 /* can't set a message filter in a multi-threaded apartment */
2436 if (apt->multi_threaded)
2438 ERR("can't set message filter in MTA\n");
2439 return CO_E_NOT_SUPPORTED;
2442 if (lpMessageFilter)
2443 IMessageFilter_AddRef(lpMessageFilter);
2445 EnterCriticalSection(&apt->cs);
2447 lpOldMessageFilter = apt->filter;
2448 apt->filter = lpMessageFilter;
2450 LeaveCriticalSection(&apt->cs);
2452 if (lplpMessageFilter)
2453 *lplpMessageFilter = lpOldMessageFilter;
2454 else if (lpOldMessageFilter)
2455 IMessageFilter_Release(lpOldMessageFilter);
2457 if (lpMessageFilter)
2458 FIXME("message filter has been registered, but will not be used\n");
2463 /***********************************************************************
2464 * CoIsOle1Class [OLE32.@]
2466 * Determines whether the specified class an OLE v1 class.
2469 * clsid [I] Class to test.
2472 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2474 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2476 FIXME("%s\n", debugstr_guid(clsid));
2480 /***********************************************************************
2481 * IsEqualGUID [OLE32.@]
2483 * Compares two Unique Identifiers.
2486 * rguid1 [I] The first GUID to compare.
2487 * rguid2 [I] The other GUID to compare.
2493 BOOL WINAPI IsEqualGUID(
2497 return !memcmp(rguid1,rguid2,sizeof(GUID));
2500 /***********************************************************************
2501 * CoInitializeSecurity [OLE32.@]
2503 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2504 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2505 void* pReserved1, DWORD dwAuthnLevel,
2506 DWORD dwImpLevel, void* pReserved2,
2507 DWORD dwCapabilities, void* pReserved3)
2509 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2510 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2511 dwCapabilities, pReserved3);
2515 /***********************************************************************
2516 * CoSuspendClassObjects [OLE32.@]
2518 * Suspends all registered class objects to prevent further requests coming in
2519 * for those objects.
2523 * Failure: HRESULT code.
2525 HRESULT WINAPI CoSuspendClassObjects(void)
2531 /***********************************************************************
2532 * CoAddRefServerProcess [OLE32.@]
2534 * Helper function for incrementing the reference count of a local-server
2538 * New reference count.
2540 ULONG WINAPI CoAddRefServerProcess(void)
2546 /***********************************************************************
2547 * CoReleaseServerProcess [OLE32.@]
2549 * Helper function for decrementing the reference count of a local-server
2553 * New reference count.
2555 ULONG WINAPI CoReleaseServerProcess(void)
2561 /***********************************************************************
2562 * CoIsHandlerConnected [OLE32.@]
2564 * Determines whether a proxy is connected to a remote stub.
2567 * pUnk [I] Pointer to object that may or may not be connected.
2570 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2573 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2575 FIXME("%p\n", pUnk);
2580 /***********************************************************************
2581 * CoAllowSetForegroundWindow [OLE32.@]
2584 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2586 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2590 /***********************************************************************
2591 * CoQueryProxyBlanket [OLE32.@]
2593 * Retrieves the security settings being used by a proxy.
2596 * pProxy [I] Pointer to the proxy object.
2597 * pAuthnSvc [O] The type of authentication service.
2598 * pAuthzSvc [O] The type of authorization service.
2599 * ppServerPrincName [O] Optional. The server prinicple name.
2600 * pAuthnLevel [O] The authentication level.
2601 * pImpLevel [O] The impersonation level.
2602 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2603 * pCapabilities [O] Flags affecting the security behaviour.
2607 * Failure: HRESULT code.
2610 * CoCopyProxy, CoSetProxyBlanket.
2612 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2613 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2614 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2616 IClientSecurity *pCliSec;
2619 TRACE("%p\n", pProxy);
2621 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2624 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2625 pAuthzSvc, ppServerPrincName,
2626 pAuthnLevel, pImpLevel, ppAuthInfo,
2628 IClientSecurity_Release(pCliSec);
2631 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2635 /***********************************************************************
2636 * CoSetProxyBlanket [OLE32.@]
2638 * Sets the security settings for a proxy.
2641 * pProxy [I] Pointer to the proxy object.
2642 * AuthnSvc [I] The type of authentication service.
2643 * AuthzSvc [I] The type of authorization service.
2644 * pServerPrincName [I] The server prinicple name.
2645 * AuthnLevel [I] The authentication level.
2646 * ImpLevel [I] The impersonation level.
2647 * pAuthInfo [I] Information specific to the authorization/authentication service.
2648 * Capabilities [I] Flags affecting the security behaviour.
2652 * Failure: HRESULT code.
2655 * CoQueryProxyBlanket, CoCopyProxy.
2657 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2658 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2659 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2661 IClientSecurity *pCliSec;
2664 TRACE("%p\n", pProxy);
2666 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2669 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2670 AuthzSvc, pServerPrincName,
2671 AuthnLevel, ImpLevel, pAuthInfo,
2673 IClientSecurity_Release(pCliSec);
2676 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2680 /***********************************************************************
2681 * CoCopyProxy [OLE32.@]
2686 * pProxy [I] Pointer to the proxy object.
2687 * ppCopy [O] Copy of the proxy.
2691 * Failure: HRESULT code.
2694 * CoQueryProxyBlanket, CoSetProxyBlanket.
2696 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2698 IClientSecurity *pCliSec;
2701 TRACE("%p\n", pProxy);
2703 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2706 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2707 IClientSecurity_Release(pCliSec);
2710 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2715 /***********************************************************************
2716 * CoGetCallContext [OLE32.@]
2718 * Gets the context of the currently executing server call in the current
2722 * riid [I] Context interface to return.
2723 * ppv [O] Pointer to memory that will receive the context on return.
2727 * Failure: HRESULT code.
2729 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
2731 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
2734 return E_NOINTERFACE;
2737 /***********************************************************************
2738 * CoQueryClientBlanket [OLE32.@]
2740 * Retrieves the authentication information about the client of the currently
2741 * executing server call in the current thread.
2744 * pAuthnSvc [O] Optional. The type of authentication service.
2745 * pAuthzSvc [O] Optional. The type of authorization service.
2746 * pServerPrincName [O] Optional. The server prinicple name.
2747 * pAuthnLevel [O] Optional. The authentication level.
2748 * pImpLevel [O] Optional. The impersonation level.
2749 * pPrivs [O] Optional. Information about the privileges of the client.
2750 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
2754 * Failure: HRESULT code.
2757 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
2759 HRESULT WINAPI CoQueryClientBlanket(
2762 OLECHAR **pServerPrincName,
2765 RPC_AUTHZ_HANDLE *pPrivs,
2766 DWORD *pCapabilities)
2768 IServerSecurity *pSrvSec;
2771 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
2772 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
2773 pPrivs, pCapabilities);
2775 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2778 hr = IServerSecurity_QueryBlanket(
2779 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
2780 pImpLevel, pPrivs, pCapabilities);
2781 IServerSecurity_Release(pSrvSec);
2787 /***********************************************************************
2788 * CoImpersonateClient [OLE32.@]
2790 * Impersonates the client of the currently executing server call in the
2798 * Failure: HRESULT code.
2801 * If this function fails then the current thread will not be impersonating
2802 * the client and all actions will take place on behalf of the server.
2803 * Therefore, it is important to check the return value from this function.
2806 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
2808 HRESULT WINAPI CoImpersonateClient(void)
2810 IServerSecurity *pSrvSec;
2815 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2818 hr = IServerSecurity_ImpersonateClient(pSrvSec);
2819 IServerSecurity_Release(pSrvSec);
2825 /***********************************************************************
2826 * CoRevertToSelf [OLE32.@]
2828 * Ends the impersonation of the client of the currently executing server
2829 * call in the current thread.
2836 * Failure: HRESULT code.
2839 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
2841 HRESULT WINAPI CoRevertToSelf(void)
2843 IServerSecurity *pSrvSec;
2848 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2851 hr = IServerSecurity_RevertToSelf(pSrvSec);
2852 IServerSecurity_Release(pSrvSec);
2858 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
2860 /* first try to retrieve messages for incoming COM calls to the apartment window */
2861 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
2862 /* next retrieve other messages necessary for the app to remain responsive */
2863 PeekMessageW(msg, NULL, 0, WM_USER - 1, PM_REMOVE|PM_NOYIELD);
2866 /***********************************************************************
2867 * CoWaitForMultipleHandles [OLE32.@]
2869 * Waits for one or more handles to become signaled.
2872 * dwFlags [I] Flags. See notes.
2873 * dwTimeout [I] Timeout in milliseconds.
2874 * cHandles [I] Number of handles pointed to by pHandles.
2875 * pHandles [I] Handles to wait for.
2876 * lpdwindex [O] Index of handle that was signaled.
2880 * Failure: RPC_S_CALLPENDING on timeout.
2884 * The dwFlags parameter can be zero or more of the following:
2885 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2886 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2889 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2891 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2892 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2895 DWORD start_time = GetTickCount();
2896 APARTMENT *apt = COM_CurrentApt();
2897 BOOL message_loop = apt && !apt->multi_threaded;
2899 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2900 pHandles, lpdwindex);
2904 DWORD now = GetTickCount();
2907 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2909 hr = RPC_S_CALLPENDING;
2915 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2916 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2918 TRACE("waiting for rpc completion or window message\n");
2920 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2921 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2922 QS_ALLINPUT, wait_flags);
2924 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2928 /* note: using "if" here instead of "while" might seem less
2929 * efficient, but only if we are optimising for quick delivery
2930 * of pending messages, rather than quick completion of the
2932 if (COM_PeekMessage(apt, &msg))
2934 /* FIXME: filter the messages here */
2935 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2936 TranslateMessage(&msg);
2937 DispatchMessageW(&msg);
2938 if (msg.message == WM_QUIT)
2940 TRACE("resending WM_QUIT to outer message loop\n");
2941 PostQuitMessage(msg.wParam);
2942 /* no longer need to process messages */
2943 message_loop = FALSE;
2951 TRACE("waiting for rpc completion\n");
2953 res = WaitForMultipleObjectsEx(cHandles, pHandles,
2954 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
2955 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2956 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
2959 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2961 /* handle signaled, store index */
2962 *lpdwindex = (res - WAIT_OBJECT_0);
2965 else if (res == WAIT_TIMEOUT)
2967 hr = RPC_S_CALLPENDING;
2972 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2977 TRACE("-- 0x%08lx\n", hr);
2982 /***********************************************************************
2983 * CoGetObject [OLE32.@]
2985 * Gets the object named by coverting the name to a moniker and binding to it.
2988 * pszName [I] String representing the object.
2989 * pBindOptions [I] Parameters affecting the binding to the named object.
2990 * riid [I] Interface to bind to on the objecct.
2991 * ppv [O] On output, the interface riid of the object represented
2996 * Failure: HRESULT code.
2999 * MkParseDisplayName.
3001 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3002 REFIID riid, void **ppv)
3009 hr = CreateBindCtx(0, &pbc);
3013 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3020 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3023 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3024 IMoniker_Release(pmk);
3028 IBindCtx_Release(pbc);
3033 /***********************************************************************
3036 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3038 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
3041 case DLL_PROCESS_ATTACH:
3042 OLE32_hInstance = hinstDLL;
3043 COMPOBJ_InitProcess();
3044 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3047 case DLL_PROCESS_DETACH:
3048 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3049 COMPOBJ_UninitProcess();
3050 OLE32_hInstance = 0;
3053 case DLL_THREAD_DETACH:
3060 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */