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 };
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 implemantation
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 )
918 ret = __CLSIDFromString(idstr, id);
919 if(ret != S_OK) { /* It appears a ProgID is also valid */
920 ret = CLSIDFromProgID(idstr, id);
925 /* Converts a GUID into the respective string representation. */
926 HRESULT WINE_StringFromCLSID(
927 const CLSID *id, /* [in] GUID to be converted */
928 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
930 static const char *hex = "0123456789ABCDEF";
935 { ERR("called with id=Null\n");
940 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
941 id->Data1, id->Data2, id->Data3,
942 id->Data4[0], id->Data4[1]);
946 for (i = 2; i < 8; i++) {
947 *s++ = hex[id->Data4[i]>>4];
948 *s++ = hex[id->Data4[i] & 0xf];
954 TRACE("%p->%s\n", id, idstr);
960 /******************************************************************************
961 * StringFromCLSID [OLE32.@]
962 * StringFromIID [OLE32.@]
964 * Converts a GUID into the respective string representation.
965 * The target string is allocated using the OLE IMalloc.
968 * id [I] the GUID to be converted.
969 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
976 * StringFromGUID2, CLSIDFromString
978 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
984 if ((ret = CoGetMalloc(0,&mllc)))
987 ret=WINE_StringFromCLSID(id,buf);
989 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
990 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
991 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
996 /******************************************************************************
997 * StringFromGUID2 [OLE32.@]
998 * StringFromGUID2 [COMPOBJ.76]
1000 * Modified version of StringFromCLSID that allows you to specify max
1004 * id [I] GUID to convert to string.
1005 * str [O] Buffer where the result will be stored.
1006 * cmax [I] Size of the buffer in characters.
1009 * Success: The length of the resulting string in characters.
1012 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1016 if (WINE_StringFromCLSID(id,xguid))
1018 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1021 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1022 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1024 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1025 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1029 strcpyW(path, wszCLSIDSlash);
1030 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1031 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1032 if (res == ERROR_FILE_NOT_FOUND)
1033 return REGDB_E_CLASSNOTREG;
1034 else if (res != ERROR_SUCCESS)
1035 return REGDB_E_READREGDB;
1043 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1045 if (res == ERROR_FILE_NOT_FOUND)
1046 return REGDB_E_KEYMISSING;
1047 else if (res != ERROR_SUCCESS)
1048 return REGDB_E_READREGDB;
1053 /******************************************************************************
1054 * ProgIDFromCLSID [OLE32.@]
1056 * Converts a class id into the respective program ID.
1059 * clsid [I] Class ID, as found in registry.
1060 * lplpszProgID [O] Associated ProgID.
1065 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1067 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1069 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1074 *lplpszProgID = NULL;
1075 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1079 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1080 ret = REGDB_E_CLASSNOTREG;
1084 *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1087 if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen))
1088 ret = REGDB_E_CLASSNOTREG;
1091 ret = E_OUTOFMEMORY;
1098 /******************************************************************************
1099 * CLSIDFromProgID [OLE32.@]
1101 * Converts a program id into the respective GUID.
1104 * progid [I] Unicode program ID, as found in registry.
1105 * riid [O] Associated CLSID.
1109 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1111 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1113 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1114 WCHAR buf2[CHARS_IN_GUID];
1115 LONG buf2len = sizeof(buf2);
1118 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1119 strcpyW( buf, progid );
1120 strcatW( buf, clsidW );
1121 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1123 HeapFree(GetProcessHeap(),0,buf);
1124 return CO_E_CLASSSTRING;
1126 HeapFree(GetProcessHeap(),0,buf);
1128 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1131 return CO_E_CLASSSTRING;
1134 return CLSIDFromString(buf2,riid);
1138 /*****************************************************************************
1139 * CoGetPSClsid [OLE32.@]
1141 * Retrieves the CLSID of the proxy/stub factory that implements
1142 * IPSFactoryBuffer for the specified interface.
1145 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1146 * pclsid [O] Where to store returned proxy/stub CLSID.
1151 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1155 * The standard marshaller activates the object with the CLSID
1156 * returned and uses the CreateProxy and CreateStub methods on its
1157 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1160 * CoGetPSClsid determines this CLSID by searching the
1161 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1162 * in the registry and any interface id registered by
1163 * CoRegisterPSClsid within the current process.
1167 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1168 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1169 * considered a bug in native unless an application depends on this (unlikely).
1172 * CoRegisterPSClsid.
1174 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1176 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1177 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1178 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1179 WCHAR value[CHARS_IN_GUID];
1182 APARTMENT *apt = COM_CurrentApt();
1183 struct registered_psclsid *registered_psclsid;
1185 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1189 ERR("apartment not initialised\n");
1190 return CO_E_NOTINITIALIZED;
1193 EnterCriticalSection(&apt->cs);
1195 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1196 if (IsEqualIID(®istered_psclsid->iid, riid))
1198 *pclsid = registered_psclsid->clsid;
1199 LeaveCriticalSection(&apt->cs);
1203 LeaveCriticalSection(&apt->cs);
1205 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1206 strcpyW(path, wszInterface);
1207 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1208 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1210 /* Open the key.. */
1211 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1213 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1214 return REGDB_E_IIDNOTREG;
1217 /* ... Once we have the key, query the registry to get the
1218 value of CLSID as a string, and convert it into a
1219 proper CLSID structure to be passed back to the app */
1220 len = sizeof(value);
1221 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1224 return REGDB_E_IIDNOTREG;
1228 /* We have the CLSid we want back from the registry as a string, so
1229 lets convert it into a CLSID structure */
1230 if (CLSIDFromString(value, pclsid) != NOERROR)
1231 return REGDB_E_IIDNOTREG;
1233 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1237 /*****************************************************************************
1238 * CoRegisterPSClsid [OLE32.@]
1240 * Register a proxy/stub CLSID for the given interface in the current process
1244 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1245 * rclsid [I] CLSID of the proxy/stub.
1249 * Failure: E_OUTOFMEMORY
1253 * This function does not add anything to the registry and the effects are
1254 * limited to the lifetime of the current process.
1259 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1261 APARTMENT *apt = COM_CurrentApt();
1262 struct registered_psclsid *registered_psclsid;
1264 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1268 ERR("apartment not initialised\n");
1269 return CO_E_NOTINITIALIZED;
1272 EnterCriticalSection(&apt->cs);
1274 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1275 if (IsEqualIID(®istered_psclsid->iid, riid))
1277 registered_psclsid->clsid = *rclsid;
1278 LeaveCriticalSection(&apt->cs);
1282 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1283 if (!registered_psclsid)
1285 LeaveCriticalSection(&apt->cs);
1286 return E_OUTOFMEMORY;
1289 registered_psclsid->iid = *riid;
1290 registered_psclsid->clsid = *rclsid;
1291 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
1293 LeaveCriticalSection(&apt->cs);
1300 /***********************************************************************
1301 * WriteClassStm (OLE32.@)
1303 * Writes a CLSID to a stream.
1306 * pStm [I] Stream to write to.
1307 * rclsid [I] CLSID to write.
1311 * Failure: HRESULT code.
1313 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1315 TRACE("(%p,%p)\n",pStm,rclsid);
1318 return E_INVALIDARG;
1320 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1323 /***********************************************************************
1324 * ReadClassStm (OLE32.@)
1326 * Reads a CLSID from a stream.
1329 * pStm [I] Stream to read from.
1330 * rclsid [O] CLSID to read.
1334 * Failure: HRESULT code.
1336 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1341 TRACE("(%p,%p)\n",pStm,pclsid);
1344 return E_INVALIDARG;
1346 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1351 if (nbByte != sizeof(CLSID))
1359 * COM_GetRegisteredClassObject
1361 * This internal method is used to scan the registered class list to
1362 * find a class object.
1365 * rclsid Class ID of the class to find.
1366 * dwClsContext Class context to match.
1367 * ppv [out] returns a pointer to the class object. Complying
1368 * to normal COM usage, this method will increase the
1369 * reference count on this object.
1371 static HRESULT COM_GetRegisteredClassObject(
1376 HRESULT hr = S_FALSE;
1377 RegisteredClass* curClass;
1379 EnterCriticalSection( &csRegisteredClassList );
1387 * Iterate through the whole list and try to match the class ID.
1389 curClass = firstRegisteredClass;
1391 while (curClass != 0)
1394 * Check if we have a match on the class ID.
1396 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1399 * Since we don't do out-of process or DCOM just right away, let's ignore the
1404 * We have a match, return the pointer to the class object.
1406 *ppUnk = curClass->classObject;
1408 IUnknown_AddRef(curClass->classObject);
1415 * Step to the next class in the list.
1417 curClass = curClass->nextClass;
1421 LeaveCriticalSection( &csRegisteredClassList );
1423 * If we get to here, we haven't found our class.
1428 /******************************************************************************
1429 * CoRegisterClassObject [OLE32.@]
1431 * Registers the class object for a given class ID. Servers housed in EXE
1432 * files use this method instead of exporting DllGetClassObject to allow
1433 * other code to connect to their objects.
1436 * rclsid [I] CLSID of the object to register.
1437 * pUnk [I] IUnknown of the object.
1438 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1439 * flags [I] REGCLS flags indicating how connections are made.
1440 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1444 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1445 * CO_E_OBJISREG if the object is already registered. We should not return this.
1448 * CoRevokeClassObject, CoGetClassObject
1451 * MSDN claims that multiple interface registrations are legal, but we
1452 * can't do that with our current implementation.
1454 HRESULT WINAPI CoRegisterClassObject(
1459 LPDWORD lpdwRegister)
1461 RegisteredClass* newClass;
1462 LPUNKNOWN foundObject;
1465 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1466 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1468 if ( (lpdwRegister==0) || (pUnk==0) )
1469 return E_INVALIDARG;
1471 if (!COM_CurrentApt())
1473 ERR("COM was not initialized\n");
1474 return CO_E_NOTINITIALIZED;
1480 * First, check if the class is already registered.
1481 * If it is, this should cause an error.
1483 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1485 if (flags & REGCLS_MULTIPLEUSE) {
1486 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1487 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1488 IUnknown_Release(foundObject);
1491 IUnknown_Release(foundObject);
1492 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1493 return CO_E_OBJISREG;
1496 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1497 if ( newClass == NULL )
1498 return E_OUTOFMEMORY;
1500 EnterCriticalSection( &csRegisteredClassList );
1502 newClass->classIdentifier = *rclsid;
1503 newClass->runContext = dwClsContext;
1504 newClass->connectFlags = flags;
1505 newClass->pMarshaledData = NULL;
1508 * Use the address of the chain node as the cookie since we are sure it's
1509 * unique. FIXME: not on 64-bit platforms.
1511 newClass->dwCookie = (DWORD)newClass;
1512 newClass->nextClass = firstRegisteredClass;
1515 * Since we're making a copy of the object pointer, we have to increase its
1518 newClass->classObject = pUnk;
1519 IUnknown_AddRef(newClass->classObject);
1521 firstRegisteredClass = newClass;
1522 LeaveCriticalSection( &csRegisteredClassList );
1524 *lpdwRegister = newClass->dwCookie;
1526 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1527 IClassFactory *classfac;
1529 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1530 (LPVOID*)&classfac);
1533 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1535 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1536 IUnknown_Release(classfac);
1539 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1540 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1541 MSHLFLAGS_TABLESTRONG);
1543 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1544 IUnknown_Release(classfac);
1548 IUnknown_Release(classfac);
1550 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1555 /***********************************************************************
1556 * CoRevokeClassObject [OLE32.@]
1558 * Removes a class object from the class registry.
1561 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1565 * Failure: HRESULT code.
1568 * CoRegisterClassObject
1570 HRESULT WINAPI CoRevokeClassObject(
1573 HRESULT hr = E_INVALIDARG;
1574 RegisteredClass** prevClassLink;
1575 RegisteredClass* curClass;
1577 TRACE("(%08lx)\n",dwRegister);
1579 EnterCriticalSection( &csRegisteredClassList );
1582 * Iterate through the whole list and try to match the cookie.
1584 curClass = firstRegisteredClass;
1585 prevClassLink = &firstRegisteredClass;
1587 while (curClass != 0)
1590 * Check if we have a match on the cookie.
1592 if (curClass->dwCookie == dwRegister)
1595 * Remove the class from the chain.
1597 *prevClassLink = curClass->nextClass;
1600 * Release the reference to the class object.
1602 IUnknown_Release(curClass->classObject);
1604 if (curClass->pMarshaledData)
1607 memset(&zero, 0, sizeof(zero));
1608 /* FIXME: stop local server thread */
1609 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1610 CoReleaseMarshalData(curClass->pMarshaledData);
1614 * Free the memory used by the chain node.
1616 HeapFree(GetProcessHeap(), 0, curClass);
1623 * Step to the next class in the list.
1625 prevClassLink = &(curClass->nextClass);
1626 curClass = curClass->nextClass;
1630 LeaveCriticalSection( &csRegisteredClassList );
1632 * If we get to here, we haven't found our class.
1637 /***********************************************************************
1638 * COM_RegReadPath [internal]
1640 * Reads a registry value and expands it when necessary
1642 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1647 WCHAR src[MAX_PATH];
1648 DWORD dwLength = dstlen * sizeof(WCHAR);
1650 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1651 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1652 if (keytype == REG_EXPAND_SZ) {
1653 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1655 lstrcpynW(dst, src, dstlen);
1663 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1666 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1667 DllGetClassObjectFunc DllGetClassObject;
1668 WCHAR dllpath[MAX_PATH+1];
1671 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1673 /* failure: CLSID is not found in registry */
1674 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1675 return REGDB_E_CLASSNOTREG;
1678 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1680 /* failure: DLL could not be loaded */
1681 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1682 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1685 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1687 /* failure: the dll did not export DllGetClassObject */
1688 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1689 FreeLibrary( hLibrary );
1690 return CO_E_DLLNOTFOUND;
1693 /* OK: get the ClassObject */
1694 COMPOBJ_DLLList_Add( hLibrary );
1695 hr = DllGetClassObject(rclsid, riid, ppv);
1698 ERR("DllGetClassObject returned error 0x%08lx\n", hr);
1703 /***********************************************************************
1704 * CoGetClassObject [OLE32.@]
1706 * FIXME. If request allows of several options and there is a failure
1707 * with one (other than not being registered) do we try the
1708 * others or return failure? (E.g. inprocess is registered but
1709 * the DLL is not found but the server version works)
1711 HRESULT WINAPI CoGetClassObject(
1712 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1713 REFIID iid, LPVOID *ppv)
1715 LPUNKNOWN regClassObject;
1716 HRESULT hres = E_UNEXPECTED;
1718 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1721 return E_INVALIDARG;
1725 if (!COM_CurrentApt())
1727 ERR("apartment not initialised\n");
1728 return CO_E_NOTINITIALIZED;
1732 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1733 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1737 * First, try and see if we can't match the class ID with one of the
1738 * registered classes.
1740 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1742 /* Get the required interface from the retrieved pointer. */
1743 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1746 * Since QI got another reference on the pointer, we want to release the
1747 * one we already have. If QI was unsuccessful, this will release the object. This
1748 * is good since we are not returning it in the "out" parameter.
1750 IUnknown_Release(regClassObject);
1755 /* First try in-process server */
1756 if (CLSCTX_INPROC_SERVER & dwClsContext)
1758 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1761 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
1762 return FTMarshalCF_Create(iid, ppv);
1764 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1767 if (hres == REGDB_E_CLASSNOTREG)
1768 ERR("class %s not registered\n", debugstr_guid(rclsid));
1770 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1773 if (SUCCEEDED(hres))
1775 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1779 /* return if we got a class, otherwise fall through to one of the
1781 if (SUCCEEDED(hres))
1785 /* Next try in-process handler */
1786 if (CLSCTX_INPROC_HANDLER & dwClsContext)
1788 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1791 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1794 if (hres == REGDB_E_CLASSNOTREG)
1795 ERR("class %s not registered\n", debugstr_guid(rclsid));
1797 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1800 if (SUCCEEDED(hres))
1802 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1806 /* return if we got a class, otherwise fall through to one of the
1808 if (SUCCEEDED(hres))
1812 /* Next try out of process */
1813 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1815 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
1816 if (SUCCEEDED(hres))
1820 /* Finally try remote: this requires networked DCOM (a lot of work) */
1821 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1823 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1824 hres = E_NOINTERFACE;
1828 ERR("no class object %s could be created for context 0x%lx\n",
1829 debugstr_guid(rclsid), dwClsContext);
1833 /***********************************************************************
1834 * CoResumeClassObjects (OLE32.@)
1836 * Resumes all class objects registered with REGCLS_SUSPENDED.
1840 * Failure: HRESULT code.
1842 HRESULT WINAPI CoResumeClassObjects(void)
1848 /***********************************************************************
1849 * GetClassFile (OLE32.@)
1851 * This function supplies the CLSID associated with the given filename.
1853 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1857 int nbElm, length, i;
1859 LPOLESTR *pathDec=0,absFile=0,progId=0;
1861 static const WCHAR bkslashW[] = {'\\',0};
1862 static const WCHAR dotW[] = {'.',0};
1864 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1866 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1867 if((StgIsStorageFile(filePathName))==S_OK){
1869 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1872 res=ReadClassStg(pstg,pclsid);
1874 IStorage_Release(pstg);
1878 /* if the file is not a storage object then attemps to match various bits in the file against a
1879 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1882 for(i=0;i<nFileTypes;i++)
1884 for(i=0;j<nPatternsForType;j++){
1889 pat=ReadPatternFromRegistry(i,j);
1890 hFile=CreateFileW(filePathName,,,,,,hFile);
1891 SetFilePosition(hFile,pat.offset);
1892 ReadFile(hFile,buf,pat.size,&r,NULL);
1893 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1895 *pclsid=ReadCLSIDFromRegistry(i);
1901 /* if the above strategies fail then search for the extension key in the registry */
1903 /* get the last element (absolute file) in the path name */
1904 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1905 absFile=pathDec[nbElm-1];
1907 /* failed if the path represente a directory and not an absolute file name*/
1908 if (!lstrcmpW(absFile, bkslashW))
1909 return MK_E_INVALIDEXTENSION;
1911 /* get the extension of the file */
1913 length=lstrlenW(absFile);
1914 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1917 if (!extension || !lstrcmpW(extension, dotW))
1918 return MK_E_INVALIDEXTENSION;
1920 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1922 /* get the progId associated to the extension */
1923 progId = CoTaskMemAlloc(sizeProgId);
1924 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1926 if (res==ERROR_SUCCESS)
1927 /* return the clsid associated to the progId */
1928 res= CLSIDFromProgID(progId,pclsid);
1930 for(i=0; pathDec[i]!=NULL;i++)
1931 CoTaskMemFree(pathDec[i]);
1932 CoTaskMemFree(pathDec);
1934 CoTaskMemFree(progId);
1936 if (res==ERROR_SUCCESS)
1939 return MK_E_INVALIDEXTENSION;
1942 /***********************************************************************
1943 * CoCreateInstance [OLE32.@]
1945 HRESULT WINAPI CoCreateInstance(
1947 LPUNKNOWN pUnkOuter,
1953 LPCLASSFACTORY lpclf = 0;
1955 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
1956 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
1965 * Initialize the "out" parameter
1969 if (!COM_CurrentApt())
1971 ERR("apartment not initialised\n");
1972 return CO_E_NOTINITIALIZED;
1976 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1977 * Rather than create a class factory, we can just check for it here
1979 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1980 if (StdGlobalInterfaceTableInstance == NULL)
1981 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1982 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1983 if (hres) return hres;
1985 TRACE("Retrieved GIT (%p)\n", *ppv);
1990 * Get a class factory to construct the object we want.
1992 hres = CoGetClassObject(rclsid,
2002 * Create the object and don't forget to release the factory
2004 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2005 IClassFactory_Release(lpclf);
2007 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
2008 debugstr_guid(iid), debugstr_guid(rclsid),hres);
2013 /***********************************************************************
2014 * CoCreateInstanceEx [OLE32.@]
2016 HRESULT WINAPI CoCreateInstanceEx(
2018 LPUNKNOWN pUnkOuter,
2020 COSERVERINFO* pServerInfo,
2024 IUnknown* pUnk = NULL;
2027 ULONG successCount = 0;
2032 if ( (cmq==0) || (pResults==NULL))
2033 return E_INVALIDARG;
2035 if (pServerInfo!=NULL)
2036 FIXME("() non-NULL pServerInfo not supported!\n");
2039 * Initialize all the "out" parameters.
2041 for (index = 0; index < cmq; index++)
2043 pResults[index].pItf = NULL;
2044 pResults[index].hr = E_NOINTERFACE;
2048 * Get the object and get its IUnknown pointer.
2050 hr = CoCreateInstance(rclsid,
2060 * Then, query for all the interfaces requested.
2062 for (index = 0; index < cmq; index++)
2064 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2065 pResults[index].pIID,
2066 (VOID**)&(pResults[index].pItf));
2068 if (pResults[index].hr == S_OK)
2073 * Release our temporary unknown pointer.
2075 IUnknown_Release(pUnk);
2077 if (successCount == 0)
2078 return E_NOINTERFACE;
2080 if (successCount!=cmq)
2081 return CO_S_NOTALLINTERFACES;
2086 /***********************************************************************
2087 * CoLoadLibrary (OLE32.@)
2092 * lpszLibName [I] Path to library.
2093 * bAutoFree [I] Whether the library should automatically be freed.
2096 * Success: Handle to loaded library.
2100 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2102 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2104 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2106 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2109 /***********************************************************************
2110 * CoFreeLibrary [OLE32.@]
2112 * Unloads a library from memory.
2115 * hLibrary [I] Handle to library to unload.
2121 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2123 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2125 FreeLibrary(hLibrary);
2129 /***********************************************************************
2130 * CoFreeAllLibraries [OLE32.@]
2132 * Function for backwards compatibility only. Does nothing.
2138 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2140 void WINAPI CoFreeAllLibraries(void)
2146 /***********************************************************************
2147 * CoFreeUnusedLibraries [OLE32.@]
2148 * CoFreeUnusedLibraries [COMPOBJ.17]
2150 * Frees any unused libraries. Unused are identified as those that return
2151 * S_OK from their DllCanUnloadNow function.
2157 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2159 void WINAPI CoFreeUnusedLibraries(void)
2161 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2162 * through the main apartment's thread to call DllCanUnloadNow */
2163 COMPOBJ_DllList_FreeUnused(0);
2166 /***********************************************************************
2167 * CoFileTimeNow [OLE32.@]
2168 * CoFileTimeNow [COMPOBJ.82]
2170 * Retrieves the current time in FILETIME format.
2173 * lpFileTime [O] The current time.
2178 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2180 GetSystemTimeAsFileTime( lpFileTime );
2184 static void COM_RevokeAllClasses()
2186 EnterCriticalSection( &csRegisteredClassList );
2188 while (firstRegisteredClass!=0)
2190 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2193 LeaveCriticalSection( &csRegisteredClassList );
2196 /******************************************************************************
2197 * CoLockObjectExternal [OLE32.@]
2199 * Increments or decrements the external reference count of a stub object.
2202 * pUnk [I] Stub object.
2203 * fLock [I] If TRUE then increments the external ref-count,
2204 * otherwise decrements.
2205 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2206 * calling CoDisconnectObject.
2210 * Failure: HRESULT code.
2213 * If fLock is TRUE and an object is passed in that doesn't have a stub
2214 * manager then a new stub manager is created for the object.
2216 HRESULT WINAPI CoLockObjectExternal(
2219 BOOL fLastUnlockReleases)
2221 struct stub_manager *stubmgr;
2222 struct apartment *apt;
2224 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2225 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2227 apt = COM_CurrentApt();
2228 if (!apt) return CO_E_NOTINITIALIZED;
2230 stubmgr = get_stub_manager_from_object(apt, pUnk);
2235 stub_manager_ext_addref(stubmgr, 1);
2237 stub_manager_ext_release(stubmgr, 1);
2239 stub_manager_int_release(stubmgr);
2245 stubmgr = new_stub_manager(apt, pUnk);
2249 stub_manager_ext_addref(stubmgr, 1);
2250 stub_manager_int_release(stubmgr);
2257 WARN("stub object not found %p\n", pUnk);
2258 /* Note: native is pretty broken here because it just silently
2259 * fails, without returning an appropriate error code, making apps
2260 * think that the object was disconnected, when it actually wasn't */
2265 /***********************************************************************
2266 * CoInitializeWOW (OLE32.@)
2268 * WOW equivalent of CoInitialize?
2277 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2279 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2283 /***********************************************************************
2284 * CoGetState [OLE32.@]
2286 * Retrieves the thread state object previously stored by CoSetState().
2289 * ppv [I] Address where pointer to object will be stored.
2293 * Failure: E_OUTOFMEMORY.
2296 * Crashes on all invalid ppv addresses, including NULL.
2297 * If the function returns a non-NULL object then the caller must release its
2298 * reference on the object when the object is no longer required.
2303 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2305 struct oletls *info = COM_CurrentInfo();
2306 if (!info) return E_OUTOFMEMORY;
2312 IUnknown_AddRef(info->state);
2314 TRACE("apt->state=%p\n", info->state);
2320 /***********************************************************************
2321 * CoSetState [OLE32.@]
2323 * Sets the thread state object.
2326 * pv [I] Pointer to state object to be stored.
2329 * The system keeps a reference on the object while the object stored.
2333 * Failure: E_OUTOFMEMORY.
2335 HRESULT WINAPI CoSetState(IUnknown * pv)
2337 struct oletls *info = COM_CurrentInfo();
2338 if (!info) return E_OUTOFMEMORY;
2340 if (pv) IUnknown_AddRef(pv);
2344 TRACE("-- release %p now\n", info->state);
2345 IUnknown_Release(info->state);
2354 /******************************************************************************
2355 * OleGetAutoConvert [OLE32.@]
2357 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2359 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2361 WCHAR buf[CHARS_IN_GUID];
2365 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2370 if (RegQueryValueW(hkey, NULL, buf, &len))
2372 res = REGDB_E_KEYMISSING;
2375 res = CLSIDFromString(buf, pClsidNew);
2377 if (hkey) RegCloseKey(hkey);
2381 /******************************************************************************
2382 * CoTreatAsClass [OLE32.@]
2384 * Sets the TreatAs value of a class.
2387 * clsidOld [I] Class to set TreatAs value on.
2388 * clsidNew [I] The class the clsidOld should be treated as.
2392 * Failure: HRESULT code.
2397 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2399 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2400 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2402 WCHAR szClsidNew[CHARS_IN_GUID];
2404 WCHAR auto_treat_as[CHARS_IN_GUID];
2405 LONG auto_treat_as_size = sizeof(auto_treat_as);
2408 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2411 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2413 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2414 !CLSIDFromString(auto_treat_as, &id))
2416 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2418 res = REGDB_E_WRITEREGDB;
2424 RegDeleteKeyW(hkey, wszTreatAs);
2428 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2429 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2431 res = REGDB_E_WRITEREGDB;
2436 if (hkey) RegCloseKey(hkey);
2440 /******************************************************************************
2441 * CoGetTreatAsClass [OLE32.@]
2443 * Gets the TreatAs value of a class.
2446 * clsidOld [I] Class to get the TreatAs value of.
2447 * clsidNew [I] The class the clsidOld should be treated as.
2451 * Failure: HRESULT code.
2456 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2458 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2460 WCHAR szClsidNew[CHARS_IN_GUID];
2462 LONG len = sizeof(szClsidNew);
2464 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2465 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2467 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2470 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2475 res = CLSIDFromString(szClsidNew,clsidNew);
2477 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2479 if (hkey) RegCloseKey(hkey);
2483 /******************************************************************************
2484 * CoGetCurrentProcess [OLE32.@]
2485 * CoGetCurrentProcess [COMPOBJ.34]
2487 * Gets the current process ID.
2490 * The current process ID.
2493 * Is DWORD really the correct return type for this function?
2495 DWORD WINAPI CoGetCurrentProcess(void)
2497 return GetCurrentProcessId();
2500 /******************************************************************************
2501 * CoRegisterMessageFilter [OLE32.@]
2503 * Registers a message filter.
2506 * lpMessageFilter [I] Pointer to interface.
2507 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2511 * Failure: HRESULT code.
2514 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2515 * lpMessageFilter removes the message filter.
2517 * If lplpMessageFilter is not NULL the previous message filter will be
2518 * returned in the memory pointer to this parameter and the caller is
2519 * responsible for releasing the object.
2521 * The current thread be in an apartment otherwise the function will crash.
2523 HRESULT WINAPI CoRegisterMessageFilter(
2524 LPMESSAGEFILTER lpMessageFilter,
2525 LPMESSAGEFILTER *lplpMessageFilter)
2527 struct apartment *apt;
2528 IMessageFilter *lpOldMessageFilter;
2530 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2532 apt = COM_CurrentApt();
2534 /* can't set a message filter in a multi-threaded apartment */
2535 if (apt->multi_threaded)
2537 ERR("can't set message filter in MTA\n");
2538 return CO_E_NOT_SUPPORTED;
2541 if (lpMessageFilter)
2542 IMessageFilter_AddRef(lpMessageFilter);
2544 EnterCriticalSection(&apt->cs);
2546 lpOldMessageFilter = apt->filter;
2547 apt->filter = lpMessageFilter;
2549 LeaveCriticalSection(&apt->cs);
2551 if (lplpMessageFilter)
2552 *lplpMessageFilter = lpOldMessageFilter;
2553 else if (lpOldMessageFilter)
2554 IMessageFilter_Release(lpOldMessageFilter);
2556 if (lpMessageFilter)
2557 FIXME("message filter has been registered, but will not be used\n");
2562 /***********************************************************************
2563 * CoIsOle1Class [OLE32.@]
2565 * Determines whether the specified class an OLE v1 class.
2568 * clsid [I] Class to test.
2571 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2573 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2575 FIXME("%s\n", debugstr_guid(clsid));
2579 /***********************************************************************
2580 * IsEqualGUID [OLE32.@]
2582 * Compares two Unique Identifiers.
2585 * rguid1 [I] The first GUID to compare.
2586 * rguid2 [I] The other GUID to compare.
2592 BOOL WINAPI IsEqualGUID(
2596 return !memcmp(rguid1,rguid2,sizeof(GUID));
2599 /***********************************************************************
2600 * CoInitializeSecurity [OLE32.@]
2602 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2603 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2604 void* pReserved1, DWORD dwAuthnLevel,
2605 DWORD dwImpLevel, void* pReserved2,
2606 DWORD dwCapabilities, void* pReserved3)
2608 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2609 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2610 dwCapabilities, pReserved3);
2614 /***********************************************************************
2615 * CoSuspendClassObjects [OLE32.@]
2617 * Suspends all registered class objects to prevent further requests coming in
2618 * for those objects.
2622 * Failure: HRESULT code.
2624 HRESULT WINAPI CoSuspendClassObjects(void)
2630 /***********************************************************************
2631 * CoAddRefServerProcess [OLE32.@]
2633 * Helper function for incrementing the reference count of a local-server
2637 * New reference count.
2639 ULONG WINAPI CoAddRefServerProcess(void)
2645 /***********************************************************************
2646 * CoReleaseServerProcess [OLE32.@]
2648 * Helper function for decrementing the reference count of a local-server
2652 * New reference count.
2654 ULONG WINAPI CoReleaseServerProcess(void)
2660 /***********************************************************************
2661 * CoIsHandlerConnected [OLE32.@]
2663 * Determines whether a proxy is connected to a remote stub.
2666 * pUnk [I] Pointer to object that may or may not be connected.
2669 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2672 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2674 FIXME("%p\n", pUnk);
2679 /***********************************************************************
2680 * CoAllowSetForegroundWindow [OLE32.@]
2683 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2685 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2689 /***********************************************************************
2690 * CoQueryProxyBlanket [OLE32.@]
2692 * Retrieves the security settings being used by a proxy.
2695 * pProxy [I] Pointer to the proxy object.
2696 * pAuthnSvc [O] The type of authentication service.
2697 * pAuthzSvc [O] The type of authorization service.
2698 * ppServerPrincName [O] Optional. The server prinicple name.
2699 * pAuthnLevel [O] The authentication level.
2700 * pImpLevel [O] The impersonation level.
2701 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2702 * pCapabilities [O] Flags affecting the security behaviour.
2706 * Failure: HRESULT code.
2709 * CoCopyProxy, CoSetProxyBlanket.
2711 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2712 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2713 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2715 IClientSecurity *pCliSec;
2718 TRACE("%p\n", pProxy);
2720 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2723 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2724 pAuthzSvc, ppServerPrincName,
2725 pAuthnLevel, pImpLevel, ppAuthInfo,
2727 IClientSecurity_Release(pCliSec);
2730 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2734 /***********************************************************************
2735 * CoSetProxyBlanket [OLE32.@]
2737 * Sets the security settings for a proxy.
2740 * pProxy [I] Pointer to the proxy object.
2741 * AuthnSvc [I] The type of authentication service.
2742 * AuthzSvc [I] The type of authorization service.
2743 * pServerPrincName [I] The server prinicple name.
2744 * AuthnLevel [I] The authentication level.
2745 * ImpLevel [I] The impersonation level.
2746 * pAuthInfo [I] Information specific to the authorization/authentication service.
2747 * Capabilities [I] Flags affecting the security behaviour.
2751 * Failure: HRESULT code.
2754 * CoQueryProxyBlanket, CoCopyProxy.
2756 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2757 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2758 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2760 IClientSecurity *pCliSec;
2763 TRACE("%p\n", pProxy);
2765 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2768 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2769 AuthzSvc, pServerPrincName,
2770 AuthnLevel, ImpLevel, pAuthInfo,
2772 IClientSecurity_Release(pCliSec);
2775 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2779 /***********************************************************************
2780 * CoCopyProxy [OLE32.@]
2785 * pProxy [I] Pointer to the proxy object.
2786 * ppCopy [O] Copy of the proxy.
2790 * Failure: HRESULT code.
2793 * CoQueryProxyBlanket, CoSetProxyBlanket.
2795 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2797 IClientSecurity *pCliSec;
2800 TRACE("%p\n", pProxy);
2802 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2805 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2806 IClientSecurity_Release(pCliSec);
2809 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2814 /***********************************************************************
2815 * CoGetCallContext [OLE32.@]
2817 * Gets the context of the currently executing server call in the current
2821 * riid [I] Context interface to return.
2822 * ppv [O] Pointer to memory that will receive the context on return.
2826 * Failure: HRESULT code.
2828 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
2830 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
2833 return E_NOINTERFACE;
2836 /***********************************************************************
2837 * CoQueryClientBlanket [OLE32.@]
2839 * Retrieves the authentication information about the client of the currently
2840 * executing server call in the current thread.
2843 * pAuthnSvc [O] Optional. The type of authentication service.
2844 * pAuthzSvc [O] Optional. The type of authorization service.
2845 * pServerPrincName [O] Optional. The server prinicple name.
2846 * pAuthnLevel [O] Optional. The authentication level.
2847 * pImpLevel [O] Optional. The impersonation level.
2848 * pPrivs [O] Optional. Information about the privileges of the client.
2849 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
2853 * Failure: HRESULT code.
2856 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
2858 HRESULT WINAPI CoQueryClientBlanket(
2861 OLECHAR **pServerPrincName,
2864 RPC_AUTHZ_HANDLE *pPrivs,
2865 DWORD *pCapabilities)
2867 IServerSecurity *pSrvSec;
2870 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
2871 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
2872 pPrivs, pCapabilities);
2874 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2877 hr = IServerSecurity_QueryBlanket(
2878 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
2879 pImpLevel, pPrivs, pCapabilities);
2880 IServerSecurity_Release(pSrvSec);
2886 /***********************************************************************
2887 * CoImpersonateClient [OLE32.@]
2889 * Impersonates the client of the currently executing server call in the
2897 * Failure: HRESULT code.
2900 * If this function fails then the current thread will not be impersonating
2901 * the client and all actions will take place on behalf of the server.
2902 * Therefore, it is important to check the return value from this function.
2905 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
2907 HRESULT WINAPI CoImpersonateClient(void)
2909 IServerSecurity *pSrvSec;
2914 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2917 hr = IServerSecurity_ImpersonateClient(pSrvSec);
2918 IServerSecurity_Release(pSrvSec);
2924 /***********************************************************************
2925 * CoRevertToSelf [OLE32.@]
2927 * Ends the impersonation of the client of the currently executing server
2928 * call in the current thread.
2935 * Failure: HRESULT code.
2938 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
2940 HRESULT WINAPI CoRevertToSelf(void)
2942 IServerSecurity *pSrvSec;
2947 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2950 hr = IServerSecurity_RevertToSelf(pSrvSec);
2951 IServerSecurity_Release(pSrvSec);
2957 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
2959 /* first try to retrieve messages for incoming COM calls to the apartment window */
2960 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
2961 /* next retrieve other messages necessary for the app to remain responsive */
2962 PeekMessageW(msg, NULL, 0, WM_USER - 1, PM_REMOVE|PM_NOYIELD);
2965 /***********************************************************************
2966 * CoWaitForMultipleHandles [OLE32.@]
2968 * Waits for one or more handles to become signaled.
2971 * dwFlags [I] Flags. See notes.
2972 * dwTimeout [I] Timeout in milliseconds.
2973 * cHandles [I] Number of handles pointed to by pHandles.
2974 * pHandles [I] Handles to wait for.
2975 * lpdwindex [O] Index of handle that was signaled.
2979 * Failure: RPC_S_CALLPENDING on timeout.
2983 * The dwFlags parameter can be zero or more of the following:
2984 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2985 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2988 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2990 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2991 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2994 DWORD start_time = GetTickCount();
2995 APARTMENT *apt = COM_CurrentApt();
2996 BOOL message_loop = apt && !apt->multi_threaded;
2998 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2999 pHandles, lpdwindex);
3003 DWORD now = GetTickCount();
3006 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
3008 hr = RPC_S_CALLPENDING;
3014 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
3015 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
3017 TRACE("waiting for rpc completion or window message\n");
3019 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3020 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3021 QS_ALLINPUT, wait_flags);
3023 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3027 /* note: using "if" here instead of "while" might seem less
3028 * efficient, but only if we are optimising for quick delivery
3029 * of pending messages, rather than quick completion of the
3031 if (COM_PeekMessage(apt, &msg))
3033 /* FIXME: filter the messages here */
3034 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3035 TranslateMessage(&msg);
3036 DispatchMessageW(&msg);
3037 if (msg.message == WM_QUIT)
3039 TRACE("resending WM_QUIT to outer message loop\n");
3040 PostQuitMessage(msg.wParam);
3041 /* no longer need to process messages */
3042 message_loop = FALSE;
3050 TRACE("waiting for rpc completion\n");
3052 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3053 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3054 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3055 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3058 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
3060 /* handle signaled, store index */
3061 *lpdwindex = (res - WAIT_OBJECT_0);
3064 else if (res == WAIT_TIMEOUT)
3066 hr = RPC_S_CALLPENDING;
3071 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
3076 TRACE("-- 0x%08lx\n", hr);
3081 /***********************************************************************
3082 * CoGetObject [OLE32.@]
3084 * Gets the object named by coverting the name to a moniker and binding to it.
3087 * pszName [I] String representing the object.
3088 * pBindOptions [I] Parameters affecting the binding to the named object.
3089 * riid [I] Interface to bind to on the objecct.
3090 * ppv [O] On output, the interface riid of the object represented
3095 * Failure: HRESULT code.
3098 * MkParseDisplayName.
3100 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3101 REFIID riid, void **ppv)
3108 hr = CreateBindCtx(0, &pbc);
3112 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3119 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3122 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3123 IMoniker_Release(pmk);
3127 IBindCtx_Release(pbc);
3132 /***********************************************************************
3135 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3137 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
3140 case DLL_PROCESS_ATTACH:
3141 OLE32_hInstance = hinstDLL;
3142 COMPOBJ_InitProcess();
3143 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3146 case DLL_PROCESS_DETACH:
3147 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3148 COMPOBJ_UninitProcess();
3149 OLE32_hInstance = 0;
3152 case DLL_THREAD_DETACH:
3159 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */