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 static 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 };
97 struct registered_psclsid
105 * This lock count counts the number of times CoInitialize is called. It is
106 * decreased every time CoUninitialize is called. When it hits 0, the COM
107 * libraries are freed
109 static LONG s_COMLockCount = 0;
112 * This linked list contains the list of registered class objects. These
113 * are mostly used to register the factories for out-of-proc servers of OLE
116 * TODO: Make this data structure aware of inter-process communication. This
117 * means that parts of this will be exported to the Wine Server.
119 typedef struct tagRegisteredClass
121 CLSID classIdentifier;
122 LPUNKNOWN classObject;
126 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
127 struct tagRegisteredClass* nextClass;
130 static RegisteredClass* firstRegisteredClass = NULL;
132 static CRITICAL_SECTION csRegisteredClassList;
133 static CRITICAL_SECTION_DEBUG class_cs_debug =
135 0, 0, &csRegisteredClassList,
136 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
137 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
139 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
141 /*****************************************************************************
142 * This section contains OpenDllList definitions
144 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
145 * other functions that do LoadLibrary _without_ giving back a HMODULE.
146 * Without this list these handles would never be freed.
148 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
149 * next unload-call but not before 600 sec.
152 typedef struct tagOpenDll {
154 struct tagOpenDll *next;
157 static OpenDll *openDllList = NULL; /* linked list of open dlls */
159 static CRITICAL_SECTION csOpenDllList;
160 static CRITICAL_SECTION_DEBUG dll_cs_debug =
162 0, 0, &csOpenDllList,
163 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
164 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
166 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
168 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',' ',
169 '0','x','#','#','#','#','#','#','#','#',' ',0};
170 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
172 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
173 static void COMPOBJ_DllList_FreeUnused(int Timeout);
175 static void COMPOBJ_InitProcess( void )
179 /* Dispatching to the correct thread in an apartment is done through
180 * window messages rather than RPC transports. When an interface is
181 * marshalled into another apartment in the same process, a window of the
182 * following class is created. The *caller* of CoMarshalInterface (ie the
183 * application) is responsible for pumping the message loop in that thread.
184 * The WM_USER messages which point to the RPCs are then dispatched to
185 * COM_AptWndProc by the user's code from the apartment in which the interface
188 memset(&wclass, 0, sizeof(wclass));
189 wclass.lpfnWndProc = apartment_wndproc;
190 wclass.hInstance = OLE32_hInstance;
191 wclass.lpszClassName = wszAptWinClass;
192 RegisterClassW(&wclass);
195 static void COMPOBJ_UninitProcess( void )
197 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
200 static void COM_TlsDestroy(void)
202 struct oletls *info = NtCurrentTeb()->ReservedForOle;
205 if (info->apt) apartment_release(info->apt);
206 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
207 if (info->state) IUnknown_Release(info->state);
208 HeapFree(GetProcessHeap(), 0, info);
209 NtCurrentTeb()->ReservedForOle = NULL;
213 /******************************************************************************
217 /* allocates memory and fills in the necessary fields for a new apartment
219 static APARTMENT *apartment_construct(DWORD model)
223 TRACE("creating new apartment, model=%ld\n", model);
225 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
226 apt->tid = GetCurrentThreadId();
228 list_init(&apt->proxies);
229 list_init(&apt->stubmgrs);
230 list_init(&apt->psclsids);
233 apt->remunk_exported = FALSE;
235 InitializeCriticalSection(&apt->cs);
236 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
238 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
240 if (apt->multi_threaded)
242 /* FIXME: should be randomly generated by in an RPC call to rpcss */
243 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
247 /* FIXME: should be randomly generated by in an RPC call to rpcss */
248 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
251 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
253 /* the locking here is not currently needed for the MTA case, but it
254 * doesn't hurt and makes the code simpler */
255 EnterCriticalSection(&csApartment);
256 list_add_head(&apts, &apt->entry);
257 LeaveCriticalSection(&csApartment);
262 /* gets and existing apartment if one exists or otherwise creates an apartment
263 * structure which stores OLE apartment-local information and stores a pointer
264 * to it in the thread-local storage */
265 static APARTMENT *apartment_get_or_create(DWORD model)
267 APARTMENT *apt = COM_CurrentApt();
271 if (model & COINIT_APARTMENTTHREADED)
273 apt = apartment_construct(model);
274 COM_CurrentInfo()->apt = apt;
278 EnterCriticalSection(&csApartment);
280 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
281 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
285 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
286 apartment_addref(MTA);
289 MTA = apartment_construct(model);
292 COM_CurrentInfo()->apt = apt;
294 LeaveCriticalSection(&csApartment);
301 static inline BOOL apartment_is_model(APARTMENT *apt, DWORD model)
303 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
306 DWORD apartment_addref(struct apartment *apt)
308 DWORD refs = InterlockedIncrement(&apt->refs);
309 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
313 DWORD apartment_release(struct apartment *apt)
317 EnterCriticalSection(&csApartment);
319 ret = InterlockedDecrement(&apt->refs);
320 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
321 /* destruction stuff that needs to happen under csApartment CS */
324 if (apt == MTA) MTA = NULL;
325 list_remove(&apt->entry);
328 LeaveCriticalSection(&csApartment);
332 struct list *cursor, *cursor2;
334 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
336 /* no locking is needed for this apartment, because no other thread
337 * can access it at this point */
339 apartment_disconnectproxies(apt);
341 if (apt->win) DestroyWindow(apt->win);
343 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
345 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
346 /* release the implicit reference given by the fact that the
347 * stub has external references (it must do since it is in the
348 * stub manager list in the apartment and all non-apartment users
349 * must have a ref on the apartment and so it cannot be destroyed).
351 stub_manager_int_release(stubmgr);
354 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
356 struct registered_psclsid *registered_psclsid =
357 LIST_ENTRY(cursor, struct registered_psclsid, entry);
359 HeapFree(GetProcessHeap(), 0, registered_psclsid);
360 list_remove(®istered_psclsid->entry);
363 /* if this assert fires, then another thread took a reference to a
364 * stub manager without taking a reference to the containing
365 * apartment, which it must do. */
366 assert(list_empty(&apt->stubmgrs));
368 if (apt->filter) IUnknown_Release(apt->filter);
370 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
371 DeleteCriticalSection(&apt->cs);
373 HeapFree(GetProcessHeap(), 0, apt);
379 /* The given OXID must be local to this process:
381 * The ref parameter is here mostly to ensure people remember that
382 * they get one, you should normally take a ref for thread safety.
384 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
386 APARTMENT *result = NULL;
389 EnterCriticalSection(&csApartment);
390 LIST_FOR_EACH( cursor, &apts )
392 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
393 if (apt->oxid == oxid)
396 if (ref) apartment_addref(result);
400 LeaveCriticalSection(&csApartment);
405 /* gets the apartment which has a given creator thread ID. The caller must
406 * release the reference from the apartment as soon as the apartment pointer
407 * is no longer required. */
408 APARTMENT *apartment_findfromtid(DWORD tid)
410 APARTMENT *result = NULL;
413 EnterCriticalSection(&csApartment);
414 LIST_FOR_EACH( cursor, &apts )
416 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
420 apartment_addref(result);
424 LeaveCriticalSection(&csApartment);
429 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
434 RPC_ExecuteCall((struct dispatch_params *)lParam);
437 return DefWindowProcW(hWnd, msg, wParam, lParam);
441 HRESULT apartment_createwindowifneeded(struct apartment *apt)
443 if (apt->multi_threaded)
448 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
450 0, 0, OLE32_hInstance, NULL);
453 ERR("CreateWindow failed with error %ld\n", GetLastError());
454 return HRESULT_FROM_WIN32(GetLastError());
456 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
457 /* someone beat us to it */
464 HWND apartment_getwindow(struct apartment *apt)
466 assert(!apt->multi_threaded);
470 void apartment_joinmta(void)
472 apartment_addref(MTA);
473 COM_CurrentInfo()->apt = MTA;
476 /*****************************************************************************
477 * This section contains OpenDllList implementation
480 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
487 EnterCriticalSection( &csOpenDllList );
489 if (openDllList == NULL) {
490 /* empty list -- add first node */
491 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
492 openDllList->hLibrary=hLibrary;
493 openDllList->next = NULL;
495 /* search for this dll */
497 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
498 if (ptr->hLibrary == hLibrary) {
504 /* dll not found, add it */
506 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
507 openDllList->hLibrary = hLibrary;
508 openDllList->next = tmp;
512 LeaveCriticalSection( &csOpenDllList );
515 static void COMPOBJ_DllList_FreeUnused(int Timeout)
517 OpenDll *curr, *next, *prev = NULL;
518 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
519 DllCanUnloadNowFunc DllCanUnloadNow;
523 EnterCriticalSection( &csOpenDllList );
525 for (curr = openDllList; curr != NULL; ) {
526 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
528 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
531 TRACE("freeing %p\n", curr->hLibrary);
532 FreeLibrary(curr->hLibrary);
534 HeapFree(GetProcessHeap(), 0, curr);
535 if (curr == openDllList) {
548 LeaveCriticalSection( &csOpenDllList );
551 /******************************************************************************
552 * CoBuildVersion [OLE32.@]
553 * CoBuildVersion [COMPOBJ.1]
555 * Gets the build version of the DLL.
560 * Current build version, hiword is majornumber, loword is minornumber
562 DWORD WINAPI CoBuildVersion(void)
564 TRACE("Returning version %d, build %d.\n", rmm, rup);
565 return (rmm<<16)+rup;
568 /******************************************************************************
569 * CoInitialize [OLE32.@]
571 * Initializes the COM libraries by calling CoInitializeEx with
572 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
575 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
578 * Success: S_OK if not already initialized, S_FALSE otherwise.
579 * Failure: HRESULT code.
584 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
587 * Just delegate to the newer method.
589 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
592 /******************************************************************************
593 * CoInitializeEx [OLE32.@]
595 * Initializes the COM libraries.
598 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
599 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
602 * S_OK if successful,
603 * S_FALSE if this function was called already.
604 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
609 * The behavior used to set the IMalloc used for memory management is
611 * The dwCoInit parameter must specify of of the following apartment
613 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
614 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
615 * The parameter may also specify zero or more of the following flags:
616 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
617 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
622 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
627 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
629 if (lpReserved!=NULL)
631 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
635 * Check the lock count. If this is the first time going through the initialize
636 * process, we have to initialize the libraries.
638 * And crank-up that lock count.
640 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
643 * Initialize the various COM libraries and data structures.
645 TRACE("() - Initializing the COM libraries\n");
647 /* we may need to defer this until after apartment initialisation */
648 RunningObjectTableImpl_Initialize();
651 if (!(apt = COM_CurrentInfo()->apt))
653 apt = apartment_get_or_create(dwCoInit);
654 if (!apt) return E_OUTOFMEMORY;
656 else if (!apartment_is_model(apt, dwCoInit))
658 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
659 code then we are probably using the wrong threading model to implement that API. */
660 ERR("Attempt to change threading model of this apartment from %s to %s\n",
661 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
662 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
663 return RPC_E_CHANGED_MODE;
668 COM_CurrentInfo()->inits++;
673 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
674 pending RPCs are ignored. Non-COM messages are discarded at this point.
676 static void COM_FlushMessageQueue(void)
679 APARTMENT *apt = COM_CurrentApt();
681 if (!apt || !apt->win) return;
683 TRACE("Flushing STA message queue\n");
685 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
687 if (message.hwnd != apt->win)
689 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
693 TranslateMessage(&message);
694 DispatchMessageA(&message);
698 /***********************************************************************
699 * CoUninitialize [OLE32.@]
701 * This method will decrement the refcount on the current apartment, freeing
702 * the resources associated with it if it is the last thread in the apartment.
703 * If the last apartment is freed, the function will additionally release
704 * any COM resources associated with the process.
714 void WINAPI CoUninitialize(void)
716 struct oletls * info = COM_CurrentInfo();
721 /* will only happen on OOM */
727 ERR("Mismatched CoUninitialize\n");
733 apartment_release(info->apt);
738 * Decrease the reference count.
739 * If we are back to 0 locks on the COM library, make sure we free
740 * all the associated data structures.
742 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
745 TRACE("() - Releasing the COM libraries\n");
747 RunningObjectTableImpl_UnInitialize();
749 /* Release the references to the registered class objects */
750 COM_RevokeAllClasses();
752 /* This will free the loaded COM Dlls */
753 CoFreeAllLibraries();
755 /* This ensures we deal with any pending RPCs */
756 COM_FlushMessageQueue();
758 else if (lCOMRefCnt<1) {
759 ERR( "CoUninitialize() - not CoInitialized.\n" );
760 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
764 /******************************************************************************
765 * CoDisconnectObject [OLE32.@]
766 * CoDisconnectObject [COMPOBJ.15]
768 * Disconnects all connections to this object from remote processes. Dispatches
769 * pending RPCs while blocking new RPCs from occurring, and then calls
770 * IMarshal::DisconnectObject on the given object.
772 * Typically called when the object server is forced to shut down, for instance by
776 * lpUnk [I] The object whose stub should be disconnected.
777 * reserved [I] Reserved. Should be set to 0.
781 * Failure: HRESULT code.
784 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
786 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
792 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
794 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
797 hr = IMarshal_DisconnectObject(marshal, reserved);
798 IMarshal_Release(marshal);
802 apt = COM_CurrentApt();
804 return CO_E_NOTINITIALIZED;
806 apartment_disconnectobject(apt, lpUnk);
808 /* Note: native is pretty broken here because it just silently
809 * fails, without returning an appropriate error code if the object was
810 * not found, making apps think that the object was disconnected, when
811 * it actually wasn't */
816 /******************************************************************************
817 * CoCreateGuid [OLE32.@]
819 * Simply forwards to UuidCreate in RPCRT4.
822 * pguid [O] Points to the GUID to initialize.
826 * Failure: HRESULT code.
831 HRESULT WINAPI CoCreateGuid(GUID *pguid)
833 return UuidCreate(pguid);
836 /******************************************************************************
837 * CLSIDFromString [OLE32.@]
838 * IIDFromString [OLE32.@]
840 * Converts a unique identifier from its string representation into
844 * idstr [I] The string representation of the GUID.
845 * id [O] GUID converted from the string.
849 * CO_E_CLASSSTRING if idstr is not a valid CLSID
854 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
860 memset( id, 0, sizeof (CLSID) );
864 /* validate the CLSID string */
865 if (strlenW(s) != 38)
866 return CO_E_CLASSSTRING;
868 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
869 return CO_E_CLASSSTRING;
871 for (i=1; i<37; i++) {
872 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
873 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
874 ((s[i] >= 'a') && (s[i] <= 'f')) ||
875 ((s[i] >= 'A') && (s[i] <= 'F'))))
876 return CO_E_CLASSSTRING;
879 TRACE("%s -> %p\n", debugstr_w(s), id);
881 /* quick lookup table */
882 memset(table, 0, 256);
884 for (i = 0; i < 10; i++) {
887 for (i = 0; i < 6; i++) {
888 table['A' + i] = i+10;
889 table['a' + i] = i+10;
892 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
894 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
895 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
896 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
897 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
899 /* these are just sequential bytes */
900 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
901 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
902 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
903 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
904 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
905 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
906 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
907 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
912 /*****************************************************************************/
914 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
921 ret = __CLSIDFromString(idstr, id);
922 if(ret != S_OK) { /* It appears a ProgID is also valid */
923 ret = CLSIDFromProgID(idstr, id);
928 /* Converts a GUID into the respective string representation. */
929 HRESULT WINE_StringFromCLSID(
930 const CLSID *id, /* [in] GUID to be converted */
931 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
933 static const char *hex = "0123456789ABCDEF";
938 { ERR("called with id=Null\n");
943 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
944 id->Data1, id->Data2, id->Data3,
945 id->Data4[0], id->Data4[1]);
949 for (i = 2; i < 8; i++) {
950 *s++ = hex[id->Data4[i]>>4];
951 *s++ = hex[id->Data4[i] & 0xf];
957 TRACE("%p->%s\n", id, idstr);
963 /******************************************************************************
964 * StringFromCLSID [OLE32.@]
965 * StringFromIID [OLE32.@]
967 * Converts a GUID into the respective string representation.
968 * The target string is allocated using the OLE IMalloc.
971 * id [I] the GUID to be converted.
972 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
979 * StringFromGUID2, CLSIDFromString
981 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
987 if ((ret = CoGetMalloc(0,&mllc)))
990 ret=WINE_StringFromCLSID(id,buf);
992 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
993 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
994 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
999 /******************************************************************************
1000 * StringFromGUID2 [OLE32.@]
1001 * StringFromGUID2 [COMPOBJ.76]
1003 * Modified version of StringFromCLSID that allows you to specify max
1007 * id [I] GUID to convert to string.
1008 * str [O] Buffer where the result will be stored.
1009 * cmax [I] Size of the buffer in characters.
1012 * Success: The length of the resulting string in characters.
1015 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1019 if (WINE_StringFromCLSID(id,xguid))
1021 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1024 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1025 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1027 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1028 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1032 strcpyW(path, wszCLSIDSlash);
1033 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1034 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1035 if (res == ERROR_FILE_NOT_FOUND)
1036 return REGDB_E_CLASSNOTREG;
1037 else if (res != ERROR_SUCCESS)
1038 return REGDB_E_READREGDB;
1046 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1048 if (res == ERROR_FILE_NOT_FOUND)
1049 return REGDB_E_KEYMISSING;
1050 else if (res != ERROR_SUCCESS)
1051 return REGDB_E_READREGDB;
1056 /******************************************************************************
1057 * ProgIDFromCLSID [OLE32.@]
1059 * Converts a class id into the respective program ID.
1062 * clsid [I] Class ID, as found in registry.
1063 * ppszProgID [O] Associated ProgID.
1068 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1070 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1072 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1079 ERR("ppszProgId isn't optional\n");
1080 return E_INVALIDARG;
1084 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1088 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1089 ret = REGDB_E_CLASSNOTREG;
1093 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1096 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1097 ret = REGDB_E_CLASSNOTREG;
1100 ret = E_OUTOFMEMORY;
1107 /******************************************************************************
1108 * CLSIDFromProgID [OLE32.@]
1110 * Converts a program id into the respective GUID.
1113 * progid [I] Unicode program ID, as found in registry.
1114 * clsid [O] Associated CLSID.
1118 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1120 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1122 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1123 WCHAR buf2[CHARS_IN_GUID];
1124 LONG buf2len = sizeof(buf2);
1128 if (!progid || !clsid)
1130 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1131 return E_INVALIDARG;
1134 /* initialise clsid in case of failure */
1135 memset(clsid, 0, sizeof(*clsid));
1137 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1138 strcpyW( buf, progid );
1139 strcatW( buf, clsidW );
1140 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1142 HeapFree(GetProcessHeap(),0,buf);
1143 return CO_E_CLASSSTRING;
1145 HeapFree(GetProcessHeap(),0,buf);
1147 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1150 return CO_E_CLASSSTRING;
1153 return CLSIDFromString(buf2,clsid);
1157 /*****************************************************************************
1158 * CoGetPSClsid [OLE32.@]
1160 * Retrieves the CLSID of the proxy/stub factory that implements
1161 * IPSFactoryBuffer for the specified interface.
1164 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1165 * pclsid [O] Where to store returned proxy/stub CLSID.
1170 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1174 * The standard marshaller activates the object with the CLSID
1175 * returned and uses the CreateProxy and CreateStub methods on its
1176 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1179 * CoGetPSClsid determines this CLSID by searching the
1180 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1181 * in the registry and any interface id registered by
1182 * CoRegisterPSClsid within the current process.
1186 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1187 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1188 * considered a bug in native unless an application depends on this (unlikely).
1191 * CoRegisterPSClsid.
1193 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1195 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1196 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1197 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1198 WCHAR value[CHARS_IN_GUID];
1201 APARTMENT *apt = COM_CurrentApt();
1202 struct registered_psclsid *registered_psclsid;
1204 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1208 ERR("apartment not initialised\n");
1209 return CO_E_NOTINITIALIZED;
1214 ERR("pclsid isn't optional\n");
1215 return E_INVALIDARG;
1218 EnterCriticalSection(&apt->cs);
1220 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1221 if (IsEqualIID(®istered_psclsid->iid, riid))
1223 *pclsid = registered_psclsid->clsid;
1224 LeaveCriticalSection(&apt->cs);
1228 LeaveCriticalSection(&apt->cs);
1230 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1231 strcpyW(path, wszInterface);
1232 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1233 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1235 /* Open the key.. */
1236 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1238 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1239 return REGDB_E_IIDNOTREG;
1242 /* ... Once we have the key, query the registry to get the
1243 value of CLSID as a string, and convert it into a
1244 proper CLSID structure to be passed back to the app */
1245 len = sizeof(value);
1246 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1249 return REGDB_E_IIDNOTREG;
1253 /* We have the CLSid we want back from the registry as a string, so
1254 lets convert it into a CLSID structure */
1255 if (CLSIDFromString(value, pclsid) != NOERROR)
1256 return REGDB_E_IIDNOTREG;
1258 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1262 /*****************************************************************************
1263 * CoRegisterPSClsid [OLE32.@]
1265 * Register a proxy/stub CLSID for the given interface in the current process
1269 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1270 * rclsid [I] CLSID of the proxy/stub.
1274 * Failure: E_OUTOFMEMORY
1278 * This function does not add anything to the registry and the effects are
1279 * limited to the lifetime of the current process.
1284 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1286 APARTMENT *apt = COM_CurrentApt();
1287 struct registered_psclsid *registered_psclsid;
1289 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1293 ERR("apartment not initialised\n");
1294 return CO_E_NOTINITIALIZED;
1297 EnterCriticalSection(&apt->cs);
1299 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1300 if (IsEqualIID(®istered_psclsid->iid, riid))
1302 registered_psclsid->clsid = *rclsid;
1303 LeaveCriticalSection(&apt->cs);
1307 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1308 if (!registered_psclsid)
1310 LeaveCriticalSection(&apt->cs);
1311 return E_OUTOFMEMORY;
1314 registered_psclsid->iid = *riid;
1315 registered_psclsid->clsid = *rclsid;
1316 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
1318 LeaveCriticalSection(&apt->cs);
1325 /***********************************************************************
1326 * WriteClassStm (OLE32.@)
1328 * Writes a CLSID to a stream.
1331 * pStm [I] Stream to write to.
1332 * rclsid [I] CLSID to write.
1336 * Failure: HRESULT code.
1338 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1340 TRACE("(%p,%p)\n",pStm,rclsid);
1343 return E_INVALIDARG;
1345 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1348 /***********************************************************************
1349 * ReadClassStm (OLE32.@)
1351 * Reads a CLSID from a stream.
1354 * pStm [I] Stream to read from.
1355 * rclsid [O] CLSID to read.
1359 * Failure: HRESULT code.
1361 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1366 TRACE("(%p,%p)\n",pStm,pclsid);
1369 return E_INVALIDARG;
1371 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1376 if (nbByte != sizeof(CLSID))
1384 * COM_GetRegisteredClassObject
1386 * This internal method is used to scan the registered class list to
1387 * find a class object.
1390 * rclsid Class ID of the class to find.
1391 * dwClsContext Class context to match.
1392 * ppv [out] returns a pointer to the class object. Complying
1393 * to normal COM usage, this method will increase the
1394 * reference count on this object.
1396 static HRESULT COM_GetRegisteredClassObject(
1401 HRESULT hr = S_FALSE;
1402 RegisteredClass* curClass;
1404 EnterCriticalSection( &csRegisteredClassList );
1412 * Iterate through the whole list and try to match the class ID.
1414 curClass = firstRegisteredClass;
1416 while (curClass != 0)
1419 * Check if we have a match on the class ID.
1421 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1424 * Since we don't do out-of process or DCOM just right away, let's ignore the
1429 * We have a match, return the pointer to the class object.
1431 *ppUnk = curClass->classObject;
1433 IUnknown_AddRef(curClass->classObject);
1440 * Step to the next class in the list.
1442 curClass = curClass->nextClass;
1446 LeaveCriticalSection( &csRegisteredClassList );
1448 * If we get to here, we haven't found our class.
1453 /******************************************************************************
1454 * CoRegisterClassObject [OLE32.@]
1456 * Registers the class object for a given class ID. Servers housed in EXE
1457 * files use this method instead of exporting DllGetClassObject to allow
1458 * other code to connect to their objects.
1461 * rclsid [I] CLSID of the object to register.
1462 * pUnk [I] IUnknown of the object.
1463 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1464 * flags [I] REGCLS flags indicating how connections are made.
1465 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1469 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1470 * CO_E_OBJISREG if the object is already registered. We should not return this.
1473 * CoRevokeClassObject, CoGetClassObject
1476 * MSDN claims that multiple interface registrations are legal, but we
1477 * can't do that with our current implementation.
1479 HRESULT WINAPI CoRegisterClassObject(
1484 LPDWORD lpdwRegister)
1486 RegisteredClass* newClass;
1487 LPUNKNOWN foundObject;
1490 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1491 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1493 if ( (lpdwRegister==0) || (pUnk==0) )
1494 return E_INVALIDARG;
1496 if (!COM_CurrentApt())
1498 ERR("COM was not initialized\n");
1499 return CO_E_NOTINITIALIZED;
1505 * First, check if the class is already registered.
1506 * If it is, this should cause an error.
1508 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1510 if (flags & REGCLS_MULTIPLEUSE) {
1511 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1512 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1513 IUnknown_Release(foundObject);
1516 IUnknown_Release(foundObject);
1517 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1518 return CO_E_OBJISREG;
1521 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1522 if ( newClass == NULL )
1523 return E_OUTOFMEMORY;
1525 EnterCriticalSection( &csRegisteredClassList );
1527 newClass->classIdentifier = *rclsid;
1528 newClass->runContext = dwClsContext;
1529 newClass->connectFlags = flags;
1530 newClass->pMarshaledData = NULL;
1533 * Use the address of the chain node as the cookie since we are sure it's
1534 * unique. FIXME: not on 64-bit platforms.
1536 newClass->dwCookie = (DWORD)newClass;
1537 newClass->nextClass = firstRegisteredClass;
1540 * Since we're making a copy of the object pointer, we have to increase its
1543 newClass->classObject = pUnk;
1544 IUnknown_AddRef(newClass->classObject);
1546 firstRegisteredClass = newClass;
1547 LeaveCriticalSection( &csRegisteredClassList );
1549 *lpdwRegister = newClass->dwCookie;
1551 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1552 IClassFactory *classfac;
1554 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1555 (LPVOID*)&classfac);
1558 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1560 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1561 IUnknown_Release(classfac);
1564 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1565 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1566 MSHLFLAGS_TABLESTRONG);
1568 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1569 IUnknown_Release(classfac);
1573 IUnknown_Release(classfac);
1575 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1580 /***********************************************************************
1581 * CoRevokeClassObject [OLE32.@]
1583 * Removes a class object from the class registry.
1586 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1590 * Failure: HRESULT code.
1593 * CoRegisterClassObject
1595 HRESULT WINAPI CoRevokeClassObject(
1598 HRESULT hr = E_INVALIDARG;
1599 RegisteredClass** prevClassLink;
1600 RegisteredClass* curClass;
1602 TRACE("(%08lx)\n",dwRegister);
1604 EnterCriticalSection( &csRegisteredClassList );
1607 * Iterate through the whole list and try to match the cookie.
1609 curClass = firstRegisteredClass;
1610 prevClassLink = &firstRegisteredClass;
1612 while (curClass != 0)
1615 * Check if we have a match on the cookie.
1617 if (curClass->dwCookie == dwRegister)
1620 * Remove the class from the chain.
1622 *prevClassLink = curClass->nextClass;
1625 * Release the reference to the class object.
1627 IUnknown_Release(curClass->classObject);
1629 if (curClass->pMarshaledData)
1632 memset(&zero, 0, sizeof(zero));
1633 /* FIXME: stop local server thread */
1634 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1635 CoReleaseMarshalData(curClass->pMarshaledData);
1639 * Free the memory used by the chain node.
1641 HeapFree(GetProcessHeap(), 0, curClass);
1648 * Step to the next class in the list.
1650 prevClassLink = &(curClass->nextClass);
1651 curClass = curClass->nextClass;
1655 LeaveCriticalSection( &csRegisteredClassList );
1657 * If we get to here, we haven't found our class.
1662 /***********************************************************************
1663 * COM_RegReadPath [internal]
1665 * Reads a registry value and expands it when necessary
1667 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1672 WCHAR src[MAX_PATH];
1673 DWORD dwLength = dstlen * sizeof(WCHAR);
1675 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1676 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1677 if (keytype == REG_EXPAND_SZ) {
1678 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1680 lstrcpynW(dst, src, dstlen);
1688 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1691 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1692 DllGetClassObjectFunc DllGetClassObject;
1693 WCHAR dllpath[MAX_PATH+1];
1696 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1698 /* failure: CLSID is not found in registry */
1699 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1700 return REGDB_E_CLASSNOTREG;
1703 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1705 /* failure: DLL could not be loaded */
1706 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1707 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1710 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1712 /* failure: the dll did not export DllGetClassObject */
1713 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1714 FreeLibrary( hLibrary );
1715 return CO_E_DLLNOTFOUND;
1718 /* OK: get the ClassObject */
1719 COMPOBJ_DLLList_Add( hLibrary );
1720 hr = DllGetClassObject(rclsid, riid, ppv);
1723 ERR("DllGetClassObject returned error 0x%08lx\n", hr);
1728 /***********************************************************************
1729 * CoGetClassObject [OLE32.@]
1731 * FIXME. If request allows of several options and there is a failure
1732 * with one (other than not being registered) do we try the
1733 * others or return failure? (E.g. inprocess is registered but
1734 * the DLL is not found but the server version works)
1736 HRESULT WINAPI CoGetClassObject(
1737 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1738 REFIID iid, LPVOID *ppv)
1740 LPUNKNOWN regClassObject;
1741 HRESULT hres = E_UNEXPECTED;
1743 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1746 return E_INVALIDARG;
1750 if (!COM_CurrentApt())
1752 ERR("apartment not initialised\n");
1753 return CO_E_NOTINITIALIZED;
1757 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1758 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1762 * First, try and see if we can't match the class ID with one of the
1763 * registered classes.
1765 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1767 /* Get the required interface from the retrieved pointer. */
1768 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1771 * Since QI got another reference on the pointer, we want to release the
1772 * one we already have. If QI was unsuccessful, this will release the object. This
1773 * is good since we are not returning it in the "out" parameter.
1775 IUnknown_Release(regClassObject);
1780 /* First try in-process server */
1781 if (CLSCTX_INPROC_SERVER & dwClsContext)
1783 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1786 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
1787 return FTMarshalCF_Create(iid, ppv);
1789 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1792 if (hres == REGDB_E_CLASSNOTREG)
1793 ERR("class %s not registered\n", debugstr_guid(rclsid));
1795 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1798 if (SUCCEEDED(hres))
1800 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1804 /* return if we got a class, otherwise fall through to one of the
1806 if (SUCCEEDED(hres))
1810 /* Next try in-process handler */
1811 if (CLSCTX_INPROC_HANDLER & dwClsContext)
1813 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1816 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1819 if (hres == REGDB_E_CLASSNOTREG)
1820 ERR("class %s not registered\n", debugstr_guid(rclsid));
1822 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1825 if (SUCCEEDED(hres))
1827 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1831 /* return if we got a class, otherwise fall through to one of the
1833 if (SUCCEEDED(hres))
1837 /* Next try out of process */
1838 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1840 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
1841 if (SUCCEEDED(hres))
1845 /* Finally try remote: this requires networked DCOM (a lot of work) */
1846 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1848 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1849 hres = E_NOINTERFACE;
1853 ERR("no class object %s could be created for context 0x%lx\n",
1854 debugstr_guid(rclsid), dwClsContext);
1858 /***********************************************************************
1859 * CoResumeClassObjects (OLE32.@)
1861 * Resumes all class objects registered with REGCLS_SUSPENDED.
1865 * Failure: HRESULT code.
1867 HRESULT WINAPI CoResumeClassObjects(void)
1873 /***********************************************************************
1874 * GetClassFile (OLE32.@)
1876 * This function supplies the CLSID associated with the given filename.
1878 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1882 int nbElm, length, i;
1884 LPOLESTR *pathDec=0,absFile=0,progId=0;
1886 static const WCHAR bkslashW[] = {'\\',0};
1887 static const WCHAR dotW[] = {'.',0};
1889 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1891 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1892 if((StgIsStorageFile(filePathName))==S_OK){
1894 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1897 res=ReadClassStg(pstg,pclsid);
1899 IStorage_Release(pstg);
1903 /* if the file is not a storage object then attemps to match various bits in the file against a
1904 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1907 for(i=0;i<nFileTypes;i++)
1909 for(i=0;j<nPatternsForType;j++){
1914 pat=ReadPatternFromRegistry(i,j);
1915 hFile=CreateFileW(filePathName,,,,,,hFile);
1916 SetFilePosition(hFile,pat.offset);
1917 ReadFile(hFile,buf,pat.size,&r,NULL);
1918 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1920 *pclsid=ReadCLSIDFromRegistry(i);
1926 /* if the above strategies fail then search for the extension key in the registry */
1928 /* get the last element (absolute file) in the path name */
1929 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1930 absFile=pathDec[nbElm-1];
1932 /* failed if the path represente a directory and not an absolute file name*/
1933 if (!lstrcmpW(absFile, bkslashW))
1934 return MK_E_INVALIDEXTENSION;
1936 /* get the extension of the file */
1938 length=lstrlenW(absFile);
1939 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1942 if (!extension || !lstrcmpW(extension, dotW))
1943 return MK_E_INVALIDEXTENSION;
1945 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1947 /* get the progId associated to the extension */
1948 progId = CoTaskMemAlloc(sizeProgId);
1949 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1951 if (res==ERROR_SUCCESS)
1952 /* return the clsid associated to the progId */
1953 res= CLSIDFromProgID(progId,pclsid);
1955 for(i=0; pathDec[i]!=NULL;i++)
1956 CoTaskMemFree(pathDec[i]);
1957 CoTaskMemFree(pathDec);
1959 CoTaskMemFree(progId);
1961 if (res==ERROR_SUCCESS)
1964 return MK_E_INVALIDEXTENSION;
1967 /***********************************************************************
1968 * CoCreateInstance [OLE32.@]
1970 HRESULT WINAPI CoCreateInstance(
1972 LPUNKNOWN pUnkOuter,
1978 LPCLASSFACTORY lpclf = 0;
1980 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
1981 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
1990 * Initialize the "out" parameter
1994 if (!COM_CurrentApt())
1996 ERR("apartment not initialised\n");
1997 return CO_E_NOTINITIALIZED;
2001 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2002 * Rather than create a class factory, we can just check for it here
2004 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2005 if (StdGlobalInterfaceTableInstance == NULL)
2006 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2007 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2008 if (hres) return hres;
2010 TRACE("Retrieved GIT (%p)\n", *ppv);
2015 * Get a class factory to construct the object we want.
2017 hres = CoGetClassObject(rclsid,
2027 * Create the object and don't forget to release the factory
2029 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2030 IClassFactory_Release(lpclf);
2032 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
2033 debugstr_guid(iid), debugstr_guid(rclsid),hres);
2038 /***********************************************************************
2039 * CoCreateInstanceEx [OLE32.@]
2041 HRESULT WINAPI CoCreateInstanceEx(
2043 LPUNKNOWN pUnkOuter,
2045 COSERVERINFO* pServerInfo,
2049 IUnknown* pUnk = NULL;
2052 ULONG successCount = 0;
2057 if ( (cmq==0) || (pResults==NULL))
2058 return E_INVALIDARG;
2060 if (pServerInfo!=NULL)
2061 FIXME("() non-NULL pServerInfo not supported!\n");
2064 * Initialize all the "out" parameters.
2066 for (index = 0; index < cmq; index++)
2068 pResults[index].pItf = NULL;
2069 pResults[index].hr = E_NOINTERFACE;
2073 * Get the object and get its IUnknown pointer.
2075 hr = CoCreateInstance(rclsid,
2085 * Then, query for all the interfaces requested.
2087 for (index = 0; index < cmq; index++)
2089 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2090 pResults[index].pIID,
2091 (VOID**)&(pResults[index].pItf));
2093 if (pResults[index].hr == S_OK)
2098 * Release our temporary unknown pointer.
2100 IUnknown_Release(pUnk);
2102 if (successCount == 0)
2103 return E_NOINTERFACE;
2105 if (successCount!=cmq)
2106 return CO_S_NOTALLINTERFACES;
2111 /***********************************************************************
2112 * CoLoadLibrary (OLE32.@)
2117 * lpszLibName [I] Path to library.
2118 * bAutoFree [I] Whether the library should automatically be freed.
2121 * Success: Handle to loaded library.
2125 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2127 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2129 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2131 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2134 /***********************************************************************
2135 * CoFreeLibrary [OLE32.@]
2137 * Unloads a library from memory.
2140 * hLibrary [I] Handle to library to unload.
2146 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2148 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2150 FreeLibrary(hLibrary);
2154 /***********************************************************************
2155 * CoFreeAllLibraries [OLE32.@]
2157 * Function for backwards compatibility only. Does nothing.
2163 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2165 void WINAPI CoFreeAllLibraries(void)
2171 /***********************************************************************
2172 * CoFreeUnusedLibraries [OLE32.@]
2173 * CoFreeUnusedLibraries [COMPOBJ.17]
2175 * Frees any unused libraries. Unused are identified as those that return
2176 * S_OK from their DllCanUnloadNow function.
2182 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2184 void WINAPI CoFreeUnusedLibraries(void)
2186 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2187 * through the main apartment's thread to call DllCanUnloadNow */
2188 COMPOBJ_DllList_FreeUnused(0);
2191 /***********************************************************************
2192 * CoFileTimeNow [OLE32.@]
2193 * CoFileTimeNow [COMPOBJ.82]
2195 * Retrieves the current time in FILETIME format.
2198 * lpFileTime [O] The current time.
2203 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2205 GetSystemTimeAsFileTime( lpFileTime );
2209 static void COM_RevokeAllClasses()
2211 EnterCriticalSection( &csRegisteredClassList );
2213 while (firstRegisteredClass!=0)
2215 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2218 LeaveCriticalSection( &csRegisteredClassList );
2221 /******************************************************************************
2222 * CoLockObjectExternal [OLE32.@]
2224 * Increments or decrements the external reference count of a stub object.
2227 * pUnk [I] Stub object.
2228 * fLock [I] If TRUE then increments the external ref-count,
2229 * otherwise decrements.
2230 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2231 * calling CoDisconnectObject.
2235 * Failure: HRESULT code.
2238 * If fLock is TRUE and an object is passed in that doesn't have a stub
2239 * manager then a new stub manager is created for the object.
2241 HRESULT WINAPI CoLockObjectExternal(
2244 BOOL fLastUnlockReleases)
2246 struct stub_manager *stubmgr;
2247 struct apartment *apt;
2249 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2250 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2252 apt = COM_CurrentApt();
2253 if (!apt) return CO_E_NOTINITIALIZED;
2255 stubmgr = get_stub_manager_from_object(apt, pUnk);
2260 stub_manager_ext_addref(stubmgr, 1);
2262 stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases);
2264 stub_manager_int_release(stubmgr);
2270 stubmgr = new_stub_manager(apt, pUnk);
2274 stub_manager_ext_addref(stubmgr, 1);
2275 stub_manager_int_release(stubmgr);
2282 WARN("stub object not found %p\n", pUnk);
2283 /* Note: native is pretty broken here because it just silently
2284 * fails, without returning an appropriate error code, making apps
2285 * think that the object was disconnected, when it actually wasn't */
2290 /***********************************************************************
2291 * CoInitializeWOW (OLE32.@)
2293 * WOW equivalent of CoInitialize?
2302 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2304 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2308 /***********************************************************************
2309 * CoGetState [OLE32.@]
2311 * Retrieves the thread state object previously stored by CoSetState().
2314 * ppv [I] Address where pointer to object will be stored.
2318 * Failure: E_OUTOFMEMORY.
2321 * Crashes on all invalid ppv addresses, including NULL.
2322 * If the function returns a non-NULL object then the caller must release its
2323 * reference on the object when the object is no longer required.
2328 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2330 struct oletls *info = COM_CurrentInfo();
2331 if (!info) return E_OUTOFMEMORY;
2337 IUnknown_AddRef(info->state);
2339 TRACE("apt->state=%p\n", info->state);
2345 /***********************************************************************
2346 * CoSetState [OLE32.@]
2348 * Sets the thread state object.
2351 * pv [I] Pointer to state object to be stored.
2354 * The system keeps a reference on the object while the object stored.
2358 * Failure: E_OUTOFMEMORY.
2360 HRESULT WINAPI CoSetState(IUnknown * pv)
2362 struct oletls *info = COM_CurrentInfo();
2363 if (!info) return E_OUTOFMEMORY;
2365 if (pv) IUnknown_AddRef(pv);
2369 TRACE("-- release %p now\n", info->state);
2370 IUnknown_Release(info->state);
2379 /******************************************************************************
2380 * OleGetAutoConvert [OLE32.@]
2382 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2384 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2386 WCHAR buf[CHARS_IN_GUID];
2390 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2395 if (RegQueryValueW(hkey, NULL, buf, &len))
2397 res = REGDB_E_KEYMISSING;
2400 res = CLSIDFromString(buf, pClsidNew);
2402 if (hkey) RegCloseKey(hkey);
2406 /******************************************************************************
2407 * CoTreatAsClass [OLE32.@]
2409 * Sets the TreatAs value of a class.
2412 * clsidOld [I] Class to set TreatAs value on.
2413 * clsidNew [I] The class the clsidOld should be treated as.
2417 * Failure: HRESULT code.
2422 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2424 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2425 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2427 WCHAR szClsidNew[CHARS_IN_GUID];
2429 WCHAR auto_treat_as[CHARS_IN_GUID];
2430 LONG auto_treat_as_size = sizeof(auto_treat_as);
2433 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2436 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2438 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2439 !CLSIDFromString(auto_treat_as, &id))
2441 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2443 res = REGDB_E_WRITEREGDB;
2449 RegDeleteKeyW(hkey, wszTreatAs);
2453 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2454 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2456 res = REGDB_E_WRITEREGDB;
2461 if (hkey) RegCloseKey(hkey);
2465 /******************************************************************************
2466 * CoGetTreatAsClass [OLE32.@]
2468 * Gets the TreatAs value of a class.
2471 * clsidOld [I] Class to get the TreatAs value of.
2472 * clsidNew [I] The class the clsidOld should be treated as.
2476 * Failure: HRESULT code.
2481 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2483 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2485 WCHAR szClsidNew[CHARS_IN_GUID];
2487 LONG len = sizeof(szClsidNew);
2489 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2490 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2492 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2495 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2500 res = CLSIDFromString(szClsidNew,clsidNew);
2502 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2504 if (hkey) RegCloseKey(hkey);
2508 /******************************************************************************
2509 * CoGetCurrentProcess [OLE32.@]
2510 * CoGetCurrentProcess [COMPOBJ.34]
2512 * Gets the current process ID.
2515 * The current process ID.
2518 * Is DWORD really the correct return type for this function?
2520 DWORD WINAPI CoGetCurrentProcess(void)
2522 return GetCurrentProcessId();
2525 /******************************************************************************
2526 * CoRegisterMessageFilter [OLE32.@]
2528 * Registers a message filter.
2531 * lpMessageFilter [I] Pointer to interface.
2532 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2536 * Failure: HRESULT code.
2539 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2540 * lpMessageFilter removes the message filter.
2542 * If lplpMessageFilter is not NULL the previous message filter will be
2543 * returned in the memory pointer to this parameter and the caller is
2544 * responsible for releasing the object.
2546 * The current thread be in an apartment otherwise the function will crash.
2548 HRESULT WINAPI CoRegisterMessageFilter(
2549 LPMESSAGEFILTER lpMessageFilter,
2550 LPMESSAGEFILTER *lplpMessageFilter)
2552 struct apartment *apt;
2553 IMessageFilter *lpOldMessageFilter;
2555 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2557 apt = COM_CurrentApt();
2559 /* can't set a message filter in a multi-threaded apartment */
2560 if (apt->multi_threaded)
2562 ERR("can't set message filter in MTA\n");
2563 return CO_E_NOT_SUPPORTED;
2566 if (lpMessageFilter)
2567 IMessageFilter_AddRef(lpMessageFilter);
2569 EnterCriticalSection(&apt->cs);
2571 lpOldMessageFilter = apt->filter;
2572 apt->filter = lpMessageFilter;
2574 LeaveCriticalSection(&apt->cs);
2576 if (lplpMessageFilter)
2577 *lplpMessageFilter = lpOldMessageFilter;
2578 else if (lpOldMessageFilter)
2579 IMessageFilter_Release(lpOldMessageFilter);
2581 if (lpMessageFilter)
2582 FIXME("message filter has been registered, but will not be used\n");
2587 /***********************************************************************
2588 * CoIsOle1Class [OLE32.@]
2590 * Determines whether the specified class an OLE v1 class.
2593 * clsid [I] Class to test.
2596 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2598 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2600 FIXME("%s\n", debugstr_guid(clsid));
2604 /***********************************************************************
2605 * IsEqualGUID [OLE32.@]
2607 * Compares two Unique Identifiers.
2610 * rguid1 [I] The first GUID to compare.
2611 * rguid2 [I] The other GUID to compare.
2617 BOOL WINAPI IsEqualGUID(
2621 return !memcmp(rguid1,rguid2,sizeof(GUID));
2624 /***********************************************************************
2625 * CoInitializeSecurity [OLE32.@]
2627 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2628 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2629 void* pReserved1, DWORD dwAuthnLevel,
2630 DWORD dwImpLevel, void* pReserved2,
2631 DWORD dwCapabilities, void* pReserved3)
2633 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2634 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2635 dwCapabilities, pReserved3);
2639 /***********************************************************************
2640 * CoSuspendClassObjects [OLE32.@]
2642 * Suspends all registered class objects to prevent further requests coming in
2643 * for those objects.
2647 * Failure: HRESULT code.
2649 HRESULT WINAPI CoSuspendClassObjects(void)
2655 /***********************************************************************
2656 * CoAddRefServerProcess [OLE32.@]
2658 * Helper function for incrementing the reference count of a local-server
2662 * New reference count.
2664 ULONG WINAPI CoAddRefServerProcess(void)
2670 /***********************************************************************
2671 * CoReleaseServerProcess [OLE32.@]
2673 * Helper function for decrementing the reference count of a local-server
2677 * New reference count.
2679 ULONG WINAPI CoReleaseServerProcess(void)
2685 /***********************************************************************
2686 * CoIsHandlerConnected [OLE32.@]
2688 * Determines whether a proxy is connected to a remote stub.
2691 * pUnk [I] Pointer to object that may or may not be connected.
2694 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2697 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2699 FIXME("%p\n", pUnk);
2704 /***********************************************************************
2705 * CoAllowSetForegroundWindow [OLE32.@]
2708 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2710 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2714 /***********************************************************************
2715 * CoQueryProxyBlanket [OLE32.@]
2717 * Retrieves the security settings being used by a proxy.
2720 * pProxy [I] Pointer to the proxy object.
2721 * pAuthnSvc [O] The type of authentication service.
2722 * pAuthzSvc [O] The type of authorization service.
2723 * ppServerPrincName [O] Optional. The server prinicple name.
2724 * pAuthnLevel [O] The authentication level.
2725 * pImpLevel [O] The impersonation level.
2726 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2727 * pCapabilities [O] Flags affecting the security behaviour.
2731 * Failure: HRESULT code.
2734 * CoCopyProxy, CoSetProxyBlanket.
2736 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2737 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2738 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2740 IClientSecurity *pCliSec;
2743 TRACE("%p\n", pProxy);
2745 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2748 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2749 pAuthzSvc, ppServerPrincName,
2750 pAuthnLevel, pImpLevel, ppAuthInfo,
2752 IClientSecurity_Release(pCliSec);
2755 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2759 /***********************************************************************
2760 * CoSetProxyBlanket [OLE32.@]
2762 * Sets the security settings for a proxy.
2765 * pProxy [I] Pointer to the proxy object.
2766 * AuthnSvc [I] The type of authentication service.
2767 * AuthzSvc [I] The type of authorization service.
2768 * pServerPrincName [I] The server prinicple name.
2769 * AuthnLevel [I] The authentication level.
2770 * ImpLevel [I] The impersonation level.
2771 * pAuthInfo [I] Information specific to the authorization/authentication service.
2772 * Capabilities [I] Flags affecting the security behaviour.
2776 * Failure: HRESULT code.
2779 * CoQueryProxyBlanket, CoCopyProxy.
2781 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2782 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2783 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2785 IClientSecurity *pCliSec;
2788 TRACE("%p\n", pProxy);
2790 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2793 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2794 AuthzSvc, pServerPrincName,
2795 AuthnLevel, ImpLevel, pAuthInfo,
2797 IClientSecurity_Release(pCliSec);
2800 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2804 /***********************************************************************
2805 * CoCopyProxy [OLE32.@]
2810 * pProxy [I] Pointer to the proxy object.
2811 * ppCopy [O] Copy of the proxy.
2815 * Failure: HRESULT code.
2818 * CoQueryProxyBlanket, CoSetProxyBlanket.
2820 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2822 IClientSecurity *pCliSec;
2825 TRACE("%p\n", pProxy);
2827 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2830 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2831 IClientSecurity_Release(pCliSec);
2834 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2839 /***********************************************************************
2840 * CoGetCallContext [OLE32.@]
2842 * Gets the context of the currently executing server call in the current
2846 * riid [I] Context interface to return.
2847 * ppv [O] Pointer to memory that will receive the context on return.
2851 * Failure: HRESULT code.
2853 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
2855 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
2858 return E_NOINTERFACE;
2861 /***********************************************************************
2862 * CoQueryClientBlanket [OLE32.@]
2864 * Retrieves the authentication information about the client of the currently
2865 * executing server call in the current thread.
2868 * pAuthnSvc [O] Optional. The type of authentication service.
2869 * pAuthzSvc [O] Optional. The type of authorization service.
2870 * pServerPrincName [O] Optional. The server prinicple name.
2871 * pAuthnLevel [O] Optional. The authentication level.
2872 * pImpLevel [O] Optional. The impersonation level.
2873 * pPrivs [O] Optional. Information about the privileges of the client.
2874 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
2878 * Failure: HRESULT code.
2881 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
2883 HRESULT WINAPI CoQueryClientBlanket(
2886 OLECHAR **pServerPrincName,
2889 RPC_AUTHZ_HANDLE *pPrivs,
2890 DWORD *pCapabilities)
2892 IServerSecurity *pSrvSec;
2895 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
2896 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
2897 pPrivs, pCapabilities);
2899 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2902 hr = IServerSecurity_QueryBlanket(
2903 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
2904 pImpLevel, pPrivs, pCapabilities);
2905 IServerSecurity_Release(pSrvSec);
2911 /***********************************************************************
2912 * CoImpersonateClient [OLE32.@]
2914 * Impersonates the client of the currently executing server call in the
2922 * Failure: HRESULT code.
2925 * If this function fails then the current thread will not be impersonating
2926 * the client and all actions will take place on behalf of the server.
2927 * Therefore, it is important to check the return value from this function.
2930 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
2932 HRESULT WINAPI CoImpersonateClient(void)
2934 IServerSecurity *pSrvSec;
2939 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2942 hr = IServerSecurity_ImpersonateClient(pSrvSec);
2943 IServerSecurity_Release(pSrvSec);
2949 /***********************************************************************
2950 * CoRevertToSelf [OLE32.@]
2952 * Ends the impersonation of the client of the currently executing server
2953 * call in the current thread.
2960 * Failure: HRESULT code.
2963 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
2965 HRESULT WINAPI CoRevertToSelf(void)
2967 IServerSecurity *pSrvSec;
2972 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2975 hr = IServerSecurity_RevertToSelf(pSrvSec);
2976 IServerSecurity_Release(pSrvSec);
2982 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
2984 /* first try to retrieve messages for incoming COM calls to the apartment window */
2985 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
2986 /* next retrieve other messages necessary for the app to remain responsive */
2987 PeekMessageW(msg, NULL, 0, WM_USER - 1, PM_REMOVE|PM_NOYIELD);
2990 /***********************************************************************
2991 * CoWaitForMultipleHandles [OLE32.@]
2993 * Waits for one or more handles to become signaled.
2996 * dwFlags [I] Flags. See notes.
2997 * dwTimeout [I] Timeout in milliseconds.
2998 * cHandles [I] Number of handles pointed to by pHandles.
2999 * pHandles [I] Handles to wait for.
3000 * lpdwindex [O] Index of handle that was signaled.
3004 * Failure: RPC_S_CALLPENDING on timeout.
3008 * The dwFlags parameter can be zero or more of the following:
3009 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3010 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3013 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3015 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3016 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
3019 DWORD start_time = GetTickCount();
3020 APARTMENT *apt = COM_CurrentApt();
3021 BOOL message_loop = apt && !apt->multi_threaded;
3023 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3024 pHandles, lpdwindex);
3028 DWORD now = GetTickCount();
3031 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
3033 hr = RPC_S_CALLPENDING;
3039 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
3040 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
3042 TRACE("waiting for rpc completion or window message\n");
3044 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3045 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3046 QS_ALLINPUT, wait_flags);
3048 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3052 /* note: using "if" here instead of "while" might seem less
3053 * efficient, but only if we are optimising for quick delivery
3054 * of pending messages, rather than quick completion of the
3056 if (COM_PeekMessage(apt, &msg))
3058 /* FIXME: filter the messages here */
3059 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3060 TranslateMessage(&msg);
3061 DispatchMessageW(&msg);
3062 if (msg.message == WM_QUIT)
3064 TRACE("resending WM_QUIT to outer message loop\n");
3065 PostQuitMessage(msg.wParam);
3066 /* no longer need to process messages */
3067 message_loop = FALSE;
3075 TRACE("waiting for rpc completion\n");
3077 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3078 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3079 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3080 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3083 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
3085 /* handle signaled, store index */
3086 *lpdwindex = (res - WAIT_OBJECT_0);
3089 else if (res == WAIT_TIMEOUT)
3091 hr = RPC_S_CALLPENDING;
3096 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
3101 TRACE("-- 0x%08lx\n", hr);
3106 /***********************************************************************
3107 * CoGetObject [OLE32.@]
3109 * Gets the object named by coverting the name to a moniker and binding to it.
3112 * pszName [I] String representing the object.
3113 * pBindOptions [I] Parameters affecting the binding to the named object.
3114 * riid [I] Interface to bind to on the objecct.
3115 * ppv [O] On output, the interface riid of the object represented
3120 * Failure: HRESULT code.
3123 * MkParseDisplayName.
3125 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3126 REFIID riid, void **ppv)
3133 hr = CreateBindCtx(0, &pbc);
3137 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3144 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3147 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3148 IMoniker_Release(pmk);
3152 IBindCtx_Release(pbc);
3157 /***********************************************************************
3160 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3162 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
3165 case DLL_PROCESS_ATTACH:
3166 OLE32_hInstance = hinstDLL;
3167 COMPOBJ_InitProcess();
3168 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3171 case DLL_PROCESS_DETACH:
3172 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3173 COMPOBJ_UninitProcess();
3174 OLE32_hInstance = 0;
3177 case DLL_THREAD_DETACH:
3184 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */