4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
37 * - Call IMessageFilter functions.
39 * - Make all ole interface marshaling use NDR to be wire compatible with
41 * - Use & interpret ORPCTHIS & ORPCTHAT.
54 #define NONAMELESSUNION
55 #define NONAMELESSSTRUCT
66 #include "compobj_private.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole);
73 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
75 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
77 /****************************************************************************
78 * This section defines variables internal to the COM module.
80 * TODO: Most of these things will have to be made thread-safe.
83 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
84 static void COM_RevokeAllClasses(void);
85 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv);
87 static APARTMENT *MTA; /* protected by csApartment */
88 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
90 static CRITICAL_SECTION csApartment;
91 static CRITICAL_SECTION_DEBUG critsect_debug =
94 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
95 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
97 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
99 struct registered_psclsid
107 * This lock count counts the number of times CoInitialize is called. It is
108 * decreased every time CoUninitialize is called. When it hits 0, the COM
109 * libraries are freed
111 static LONG s_COMLockCount = 0;
114 * This linked list contains the list of registered class objects. These
115 * are mostly used to register the factories for out-of-proc servers of OLE
118 * TODO: Make this data structure aware of inter-process communication. This
119 * means that parts of this will be exported to the Wine Server.
121 typedef struct tagRegisteredClass
123 CLSID classIdentifier;
124 LPUNKNOWN classObject;
128 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
129 struct tagRegisteredClass* nextClass;
132 static RegisteredClass* firstRegisteredClass = NULL;
134 static CRITICAL_SECTION csRegisteredClassList;
135 static CRITICAL_SECTION_DEBUG class_cs_debug =
137 0, 0, &csRegisteredClassList,
138 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
139 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
141 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
143 /*****************************************************************************
144 * This section contains OpenDllList definitions
146 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
147 * other functions that do LoadLibrary _without_ giving back a HMODULE.
148 * Without this list these handles would never be freed.
150 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
151 * next unload-call but not before 600 sec.
154 typedef struct tagOpenDll {
156 struct tagOpenDll *next;
159 static OpenDll *openDllList = NULL; /* linked list of open dlls */
161 static CRITICAL_SECTION csOpenDllList;
162 static CRITICAL_SECTION_DEBUG dll_cs_debug =
164 0, 0, &csOpenDllList,
165 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
166 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
168 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
170 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
171 '0','x','#','#','#','#','#','#','#','#',' ',0};
172 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
174 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
175 static void COMPOBJ_DllList_FreeUnused(int Timeout);
177 static void COMPOBJ_InitProcess( void )
181 /* Dispatching to the correct thread in an apartment is done through
182 * window messages rather than RPC transports. When an interface is
183 * marshalled into another apartment in the same process, a window of the
184 * following class is created. The *caller* of CoMarshalInterface (ie the
185 * application) is responsible for pumping the message loop in that thread.
186 * The WM_USER messages which point to the RPCs are then dispatched to
187 * COM_AptWndProc by the user's code from the apartment in which the interface
190 memset(&wclass, 0, sizeof(wclass));
191 wclass.lpfnWndProc = apartment_wndproc;
192 wclass.hInstance = OLE32_hInstance;
193 wclass.lpszClassName = wszAptWinClass;
194 RegisterClassW(&wclass);
197 static void COMPOBJ_UninitProcess( void )
199 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
202 static void COM_TlsDestroy(void)
204 struct oletls *info = NtCurrentTeb()->ReservedForOle;
207 if (info->apt) apartment_release(info->apt);
208 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
209 if (info->state) IUnknown_Release(info->state);
210 HeapFree(GetProcessHeap(), 0, info);
211 NtCurrentTeb()->ReservedForOle = NULL;
215 /******************************************************************************
219 /* allocates memory and fills in the necessary fields for a new apartment
221 static APARTMENT *apartment_construct(DWORD model)
225 TRACE("creating new apartment, model=%ld\n", model);
227 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
228 apt->tid = GetCurrentThreadId();
230 list_init(&apt->proxies);
231 list_init(&apt->stubmgrs);
232 list_init(&apt->psclsids);
235 apt->remunk_exported = FALSE;
237 InitializeCriticalSection(&apt->cs);
238 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
240 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
242 if (apt->multi_threaded)
244 /* FIXME: should be randomly generated by in an RPC call to rpcss */
245 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
249 /* FIXME: should be randomly generated by in an RPC call to rpcss */
250 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
253 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
255 /* the locking here is not currently needed for the MTA case, but it
256 * doesn't hurt and makes the code simpler */
257 EnterCriticalSection(&csApartment);
258 list_add_head(&apts, &apt->entry);
259 LeaveCriticalSection(&csApartment);
264 /* gets and existing apartment if one exists or otherwise creates an apartment
265 * structure which stores OLE apartment-local information and stores a pointer
266 * to it in the thread-local storage */
267 static APARTMENT *apartment_get_or_create(DWORD model)
269 APARTMENT *apt = COM_CurrentApt();
273 if (model & COINIT_APARTMENTTHREADED)
275 apt = apartment_construct(model);
276 COM_CurrentInfo()->apt = apt;
280 EnterCriticalSection(&csApartment);
282 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
283 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
287 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
288 apartment_addref(MTA);
291 MTA = apartment_construct(model);
294 COM_CurrentInfo()->apt = apt;
296 LeaveCriticalSection(&csApartment);
303 static inline BOOL apartment_is_model(APARTMENT *apt, DWORD model)
305 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
308 DWORD apartment_addref(struct apartment *apt)
310 DWORD refs = InterlockedIncrement(&apt->refs);
311 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
315 DWORD apartment_release(struct apartment *apt)
319 EnterCriticalSection(&csApartment);
321 ret = InterlockedDecrement(&apt->refs);
322 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
323 /* destruction stuff that needs to happen under csApartment CS */
326 if (apt == MTA) MTA = NULL;
327 list_remove(&apt->entry);
330 LeaveCriticalSection(&csApartment);
334 struct list *cursor, *cursor2;
336 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
338 /* no locking is needed for this apartment, because no other thread
339 * can access it at this point */
341 apartment_disconnectproxies(apt);
343 if (apt->win) DestroyWindow(apt->win);
345 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
347 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
348 /* release the implicit reference given by the fact that the
349 * stub has external references (it must do since it is in the
350 * stub manager list in the apartment and all non-apartment users
351 * must have a ref on the apartment and so it cannot be destroyed).
353 stub_manager_int_release(stubmgr);
356 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
358 struct registered_psclsid *registered_psclsid =
359 LIST_ENTRY(cursor, struct registered_psclsid, entry);
361 HeapFree(GetProcessHeap(), 0, registered_psclsid);
362 list_remove(®istered_psclsid->entry);
365 /* if this assert fires, then another thread took a reference to a
366 * stub manager without taking a reference to the containing
367 * apartment, which it must do. */
368 assert(list_empty(&apt->stubmgrs));
370 if (apt->filter) IUnknown_Release(apt->filter);
372 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
373 DeleteCriticalSection(&apt->cs);
375 HeapFree(GetProcessHeap(), 0, apt);
381 /* The given OXID must be local to this process:
383 * The ref parameter is here mostly to ensure people remember that
384 * they get one, you should normally take a ref for thread safety.
386 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
388 APARTMENT *result = NULL;
391 EnterCriticalSection(&csApartment);
392 LIST_FOR_EACH( cursor, &apts )
394 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
395 if (apt->oxid == oxid)
398 if (ref) apartment_addref(result);
402 LeaveCriticalSection(&csApartment);
407 /* gets the apartment which has a given creator thread ID. The caller must
408 * release the reference from the apartment as soon as the apartment pointer
409 * is no longer required. */
410 APARTMENT *apartment_findfromtid(DWORD tid)
412 APARTMENT *result = NULL;
415 EnterCriticalSection(&csApartment);
416 LIST_FOR_EACH( cursor, &apts )
418 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
422 apartment_addref(result);
426 LeaveCriticalSection(&csApartment);
431 /* gets an apartment which has a given type. The caller must
432 * release the reference from the apartment as soon as the apartment pointer
433 * is no longer required. */
434 static APARTMENT *apartment_findfromtype(BOOL multi_threaded)
436 APARTMENT *result = NULL;
437 struct apartment *apt;
439 EnterCriticalSection(&csApartment);
440 LIST_FOR_EACH_ENTRY( apt, &apts, struct apartment, entry )
442 if (apt->multi_threaded == multi_threaded)
445 apartment_addref(result);
449 LeaveCriticalSection(&csApartment);
454 struct host_object_params
457 CLSID clsid; /* clsid of object to marshal */
458 IID iid; /* interface to marshal */
459 IStream *stream; /* stream that the object will be marshaled into */
462 static HRESULT apartment_hostobject(const struct host_object_params *params)
466 static const LARGE_INTEGER llZero;
470 hr = get_inproc_class_object(params->hkeydll, ¶ms->clsid, ¶ms->iid, (void **)&object);
474 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
476 IUnknown_Release(object);
477 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
482 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
487 RPC_ExecuteCall((struct dispatch_params *)lParam);
490 return apartment_hostobject((const struct host_object_params *)lParam);
492 return DefWindowProcW(hWnd, msg, wParam, lParam);
496 HRESULT apartment_createwindowifneeded(struct apartment *apt)
498 if (apt->multi_threaded)
503 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
505 0, 0, OLE32_hInstance, NULL);
508 ERR("CreateWindow failed with error %ld\n", GetLastError());
509 return HRESULT_FROM_WIN32(GetLastError());
511 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
512 /* someone beat us to it */
519 HWND apartment_getwindow(struct apartment *apt)
521 assert(!apt->multi_threaded);
525 void apartment_joinmta(void)
527 apartment_addref(MTA);
528 COM_CurrentInfo()->apt = MTA;
531 /*****************************************************************************
532 * This section contains OpenDllList implementation
535 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
542 EnterCriticalSection( &csOpenDllList );
544 if (openDllList == NULL) {
545 /* empty list -- add first node */
546 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
547 openDllList->hLibrary=hLibrary;
548 openDllList->next = NULL;
550 /* search for this dll */
552 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
553 if (ptr->hLibrary == hLibrary) {
559 /* dll not found, add it */
561 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
562 openDllList->hLibrary = hLibrary;
563 openDllList->next = tmp;
567 LeaveCriticalSection( &csOpenDllList );
570 static void COMPOBJ_DllList_FreeUnused(int Timeout)
572 OpenDll *curr, *next, *prev = NULL;
573 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
574 DllCanUnloadNowFunc DllCanUnloadNow;
578 EnterCriticalSection( &csOpenDllList );
580 for (curr = openDllList; curr != NULL; ) {
581 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
583 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
586 TRACE("freeing %p\n", curr->hLibrary);
587 FreeLibrary(curr->hLibrary);
589 HeapFree(GetProcessHeap(), 0, curr);
590 if (curr == openDllList) {
603 LeaveCriticalSection( &csOpenDllList );
606 /******************************************************************************
607 * CoBuildVersion [OLE32.@]
608 * CoBuildVersion [COMPOBJ.1]
610 * Gets the build version of the DLL.
615 * Current build version, hiword is majornumber, loword is minornumber
617 DWORD WINAPI CoBuildVersion(void)
619 TRACE("Returning version %d, build %d.\n", rmm, rup);
620 return (rmm<<16)+rup;
623 /******************************************************************************
624 * CoInitialize [OLE32.@]
626 * Initializes the COM libraries by calling CoInitializeEx with
627 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
630 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
633 * Success: S_OK if not already initialized, S_FALSE otherwise.
634 * Failure: HRESULT code.
639 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
642 * Just delegate to the newer method.
644 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
647 /******************************************************************************
648 * CoInitializeEx [OLE32.@]
650 * Initializes the COM libraries.
653 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
654 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
657 * S_OK if successful,
658 * S_FALSE if this function was called already.
659 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
664 * The behavior used to set the IMalloc used for memory management is
666 * The dwCoInit parameter must specify of of the following apartment
668 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
669 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
670 * The parameter may also specify zero or more of the following flags:
671 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
672 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
677 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
682 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
684 if (lpReserved!=NULL)
686 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
690 * Check the lock count. If this is the first time going through the initialize
691 * process, we have to initialize the libraries.
693 * And crank-up that lock count.
695 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
698 * Initialize the various COM libraries and data structures.
700 TRACE("() - Initializing the COM libraries\n");
702 /* we may need to defer this until after apartment initialisation */
703 RunningObjectTableImpl_Initialize();
706 if (!(apt = COM_CurrentInfo()->apt))
708 apt = apartment_get_or_create(dwCoInit);
709 if (!apt) return E_OUTOFMEMORY;
711 else if (!apartment_is_model(apt, dwCoInit))
713 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
714 code then we are probably using the wrong threading model to implement that API. */
715 ERR("Attempt to change threading model of this apartment from %s to %s\n",
716 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
717 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
718 return RPC_E_CHANGED_MODE;
723 COM_CurrentInfo()->inits++;
728 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
729 pending RPCs are ignored. Non-COM messages are discarded at this point.
731 static void COM_FlushMessageQueue(void)
734 APARTMENT *apt = COM_CurrentApt();
736 if (!apt || !apt->win) return;
738 TRACE("Flushing STA message queue\n");
740 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
742 if (message.hwnd != apt->win)
744 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
748 TranslateMessage(&message);
749 DispatchMessageA(&message);
753 /***********************************************************************
754 * CoUninitialize [OLE32.@]
756 * This method will decrement the refcount on the current apartment, freeing
757 * the resources associated with it if it is the last thread in the apartment.
758 * If the last apartment is freed, the function will additionally release
759 * any COM resources associated with the process.
769 void WINAPI CoUninitialize(void)
771 struct oletls * info = COM_CurrentInfo();
776 /* will only happen on OOM */
782 ERR("Mismatched CoUninitialize\n");
788 apartment_release(info->apt);
793 * Decrease the reference count.
794 * If we are back to 0 locks on the COM library, make sure we free
795 * all the associated data structures.
797 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
800 TRACE("() - Releasing the COM libraries\n");
802 RunningObjectTableImpl_UnInitialize();
804 /* Release the references to the registered class objects */
805 COM_RevokeAllClasses();
807 /* This will free the loaded COM Dlls */
808 CoFreeAllLibraries();
810 /* This ensures we deal with any pending RPCs */
811 COM_FlushMessageQueue();
813 else if (lCOMRefCnt<1) {
814 ERR( "CoUninitialize() - not CoInitialized.\n" );
815 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
819 /******************************************************************************
820 * CoDisconnectObject [OLE32.@]
821 * CoDisconnectObject [COMPOBJ.15]
823 * Disconnects all connections to this object from remote processes. Dispatches
824 * pending RPCs while blocking new RPCs from occurring, and then calls
825 * IMarshal::DisconnectObject on the given object.
827 * Typically called when the object server is forced to shut down, for instance by
831 * lpUnk [I] The object whose stub should be disconnected.
832 * reserved [I] Reserved. Should be set to 0.
836 * Failure: HRESULT code.
839 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
841 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
847 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
849 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
852 hr = IMarshal_DisconnectObject(marshal, reserved);
853 IMarshal_Release(marshal);
857 apt = COM_CurrentApt();
859 return CO_E_NOTINITIALIZED;
861 apartment_disconnectobject(apt, lpUnk);
863 /* Note: native is pretty broken here because it just silently
864 * fails, without returning an appropriate error code if the object was
865 * not found, making apps think that the object was disconnected, when
866 * it actually wasn't */
871 /******************************************************************************
872 * CoCreateGuid [OLE32.@]
874 * Simply forwards to UuidCreate in RPCRT4.
877 * pguid [O] Points to the GUID to initialize.
881 * Failure: HRESULT code.
886 HRESULT WINAPI CoCreateGuid(GUID *pguid)
888 return UuidCreate(pguid);
891 /******************************************************************************
892 * CLSIDFromString [OLE32.@]
893 * IIDFromString [OLE32.@]
895 * Converts a unique identifier from its string representation into
899 * idstr [I] The string representation of the GUID.
900 * id [O] GUID converted from the string.
904 * CO_E_CLASSSTRING if idstr is not a valid CLSID
909 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
915 memset( id, 0, sizeof (CLSID) );
919 /* validate the CLSID string */
920 if (strlenW(s) != 38)
921 return CO_E_CLASSSTRING;
923 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
924 return CO_E_CLASSSTRING;
926 for (i=1; i<37; i++) {
927 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
928 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
929 ((s[i] >= 'a') && (s[i] <= 'f')) ||
930 ((s[i] >= 'A') && (s[i] <= 'F'))))
931 return CO_E_CLASSSTRING;
934 TRACE("%s -> %p\n", debugstr_w(s), id);
936 /* quick lookup table */
937 memset(table, 0, 256);
939 for (i = 0; i < 10; i++) {
942 for (i = 0; i < 6; i++) {
943 table['A' + i] = i+10;
944 table['a' + i] = i+10;
947 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
949 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
950 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
951 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
952 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
954 /* these are just sequential bytes */
955 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
956 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
957 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
958 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
959 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
960 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
961 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
962 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
967 /*****************************************************************************/
969 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
976 ret = __CLSIDFromString(idstr, id);
977 if(ret != S_OK) { /* It appears a ProgID is also valid */
978 ret = CLSIDFromProgID(idstr, id);
983 /* Converts a GUID into the respective string representation. */
984 HRESULT WINE_StringFromCLSID(
985 const CLSID *id, /* [in] GUID to be converted */
986 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
988 static const char *hex = "0123456789ABCDEF";
993 { ERR("called with id=Null\n");
998 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
999 id->Data1, id->Data2, id->Data3,
1000 id->Data4[0], id->Data4[1]);
1004 for (i = 2; i < 8; i++) {
1005 *s++ = hex[id->Data4[i]>>4];
1006 *s++ = hex[id->Data4[i] & 0xf];
1012 TRACE("%p->%s\n", id, idstr);
1018 /******************************************************************************
1019 * StringFromCLSID [OLE32.@]
1020 * StringFromIID [OLE32.@]
1022 * Converts a GUID into the respective string representation.
1023 * The target string is allocated using the OLE IMalloc.
1026 * id [I] the GUID to be converted.
1027 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1034 * StringFromGUID2, CLSIDFromString
1036 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1042 if ((ret = CoGetMalloc(0,&mllc)))
1045 ret=WINE_StringFromCLSID(id,buf);
1047 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1048 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1049 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1054 /******************************************************************************
1055 * StringFromGUID2 [OLE32.@]
1056 * StringFromGUID2 [COMPOBJ.76]
1058 * Modified version of StringFromCLSID that allows you to specify max
1062 * id [I] GUID to convert to string.
1063 * str [O] Buffer where the result will be stored.
1064 * cmax [I] Size of the buffer in characters.
1067 * Success: The length of the resulting string in characters.
1070 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1074 if (WINE_StringFromCLSID(id,xguid))
1076 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1079 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1080 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1082 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1083 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1087 strcpyW(path, wszCLSIDSlash);
1088 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1089 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1090 if (res == ERROR_FILE_NOT_FOUND)
1091 return REGDB_E_CLASSNOTREG;
1092 else if (res != ERROR_SUCCESS)
1093 return REGDB_E_READREGDB;
1101 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1103 if (res == ERROR_FILE_NOT_FOUND)
1104 return REGDB_E_KEYMISSING;
1105 else if (res != ERROR_SUCCESS)
1106 return REGDB_E_READREGDB;
1111 /******************************************************************************
1112 * ProgIDFromCLSID [OLE32.@]
1114 * Converts a class id into the respective program ID.
1117 * clsid [I] Class ID, as found in registry.
1118 * ppszProgID [O] Associated ProgID.
1123 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1125 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1127 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1134 ERR("ppszProgId isn't optional\n");
1135 return E_INVALIDARG;
1139 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1143 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1144 ret = REGDB_E_CLASSNOTREG;
1148 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1151 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1152 ret = REGDB_E_CLASSNOTREG;
1155 ret = E_OUTOFMEMORY;
1162 /******************************************************************************
1163 * CLSIDFromProgID [OLE32.@]
1165 * Converts a program id into the respective GUID.
1168 * progid [I] Unicode program ID, as found in registry.
1169 * clsid [O] Associated CLSID.
1173 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1175 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1177 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1178 WCHAR buf2[CHARS_IN_GUID];
1179 LONG buf2len = sizeof(buf2);
1183 if (!progid || !clsid)
1185 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1186 return E_INVALIDARG;
1189 /* initialise clsid in case of failure */
1190 memset(clsid, 0, sizeof(*clsid));
1192 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1193 strcpyW( buf, progid );
1194 strcatW( buf, clsidW );
1195 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1197 HeapFree(GetProcessHeap(),0,buf);
1198 return CO_E_CLASSSTRING;
1200 HeapFree(GetProcessHeap(),0,buf);
1202 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1205 return CO_E_CLASSSTRING;
1208 return CLSIDFromString(buf2,clsid);
1212 /*****************************************************************************
1213 * CoGetPSClsid [OLE32.@]
1215 * Retrieves the CLSID of the proxy/stub factory that implements
1216 * IPSFactoryBuffer for the specified interface.
1219 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1220 * pclsid [O] Where to store returned proxy/stub CLSID.
1225 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1229 * The standard marshaller activates the object with the CLSID
1230 * returned and uses the CreateProxy and CreateStub methods on its
1231 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1234 * CoGetPSClsid determines this CLSID by searching the
1235 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1236 * in the registry and any interface id registered by
1237 * CoRegisterPSClsid within the current process.
1241 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1242 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1243 * considered a bug in native unless an application depends on this (unlikely).
1246 * CoRegisterPSClsid.
1248 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1250 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1251 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1252 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1253 WCHAR value[CHARS_IN_GUID];
1256 APARTMENT *apt = COM_CurrentApt();
1257 struct registered_psclsid *registered_psclsid;
1259 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1263 ERR("apartment not initialised\n");
1264 return CO_E_NOTINITIALIZED;
1269 ERR("pclsid isn't optional\n");
1270 return E_INVALIDARG;
1273 EnterCriticalSection(&apt->cs);
1275 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1276 if (IsEqualIID(®istered_psclsid->iid, riid))
1278 *pclsid = registered_psclsid->clsid;
1279 LeaveCriticalSection(&apt->cs);
1283 LeaveCriticalSection(&apt->cs);
1285 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1286 strcpyW(path, wszInterface);
1287 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1288 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1290 /* Open the key.. */
1291 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1293 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1294 return REGDB_E_IIDNOTREG;
1297 /* ... Once we have the key, query the registry to get the
1298 value of CLSID as a string, and convert it into a
1299 proper CLSID structure to be passed back to the app */
1300 len = sizeof(value);
1301 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1304 return REGDB_E_IIDNOTREG;
1308 /* We have the CLSid we want back from the registry as a string, so
1309 lets convert it into a CLSID structure */
1310 if (CLSIDFromString(value, pclsid) != NOERROR)
1311 return REGDB_E_IIDNOTREG;
1313 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1317 /*****************************************************************************
1318 * CoRegisterPSClsid [OLE32.@]
1320 * Register a proxy/stub CLSID for the given interface in the current process
1324 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1325 * rclsid [I] CLSID of the proxy/stub.
1329 * Failure: E_OUTOFMEMORY
1333 * This function does not add anything to the registry and the effects are
1334 * limited to the lifetime of the current process.
1339 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1341 APARTMENT *apt = COM_CurrentApt();
1342 struct registered_psclsid *registered_psclsid;
1344 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1348 ERR("apartment not initialised\n");
1349 return CO_E_NOTINITIALIZED;
1352 EnterCriticalSection(&apt->cs);
1354 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1355 if (IsEqualIID(®istered_psclsid->iid, riid))
1357 registered_psclsid->clsid = *rclsid;
1358 LeaveCriticalSection(&apt->cs);
1362 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1363 if (!registered_psclsid)
1365 LeaveCriticalSection(&apt->cs);
1366 return E_OUTOFMEMORY;
1369 registered_psclsid->iid = *riid;
1370 registered_psclsid->clsid = *rclsid;
1371 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
1373 LeaveCriticalSection(&apt->cs);
1380 * COM_GetRegisteredClassObject
1382 * This internal method is used to scan the registered class list to
1383 * find a class object.
1386 * rclsid Class ID of the class to find.
1387 * dwClsContext Class context to match.
1388 * ppv [out] returns a pointer to the class object. Complying
1389 * to normal COM usage, this method will increase the
1390 * reference count on this object.
1392 static HRESULT COM_GetRegisteredClassObject(
1397 HRESULT hr = S_FALSE;
1398 RegisteredClass* curClass;
1400 EnterCriticalSection( &csRegisteredClassList );
1408 * Iterate through the whole list and try to match the class ID.
1410 curClass = firstRegisteredClass;
1412 while (curClass != 0)
1415 * Check if we have a match on the class ID.
1417 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1420 * Since we don't do out-of process or DCOM just right away, let's ignore the
1425 * We have a match, return the pointer to the class object.
1427 *ppUnk = curClass->classObject;
1429 IUnknown_AddRef(curClass->classObject);
1436 * Step to the next class in the list.
1438 curClass = curClass->nextClass;
1442 LeaveCriticalSection( &csRegisteredClassList );
1444 * If we get to here, we haven't found our class.
1449 /******************************************************************************
1450 * CoRegisterClassObject [OLE32.@]
1452 * Registers the class object for a given class ID. Servers housed in EXE
1453 * files use this method instead of exporting DllGetClassObject to allow
1454 * other code to connect to their objects.
1457 * rclsid [I] CLSID of the object to register.
1458 * pUnk [I] IUnknown of the object.
1459 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1460 * flags [I] REGCLS flags indicating how connections are made.
1461 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1465 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1466 * CO_E_OBJISREG if the object is already registered. We should not return this.
1469 * CoRevokeClassObject, CoGetClassObject
1472 * MSDN claims that multiple interface registrations are legal, but we
1473 * can't do that with our current implementation.
1475 HRESULT WINAPI CoRegisterClassObject(
1480 LPDWORD lpdwRegister)
1482 RegisteredClass* newClass;
1483 LPUNKNOWN foundObject;
1486 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1487 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1489 if ( (lpdwRegister==0) || (pUnk==0) )
1490 return E_INVALIDARG;
1492 if (!COM_CurrentApt())
1494 ERR("COM was not initialized\n");
1495 return CO_E_NOTINITIALIZED;
1501 * First, check if the class is already registered.
1502 * If it is, this should cause an error.
1504 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1506 if (flags & REGCLS_MULTIPLEUSE) {
1507 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1508 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1509 IUnknown_Release(foundObject);
1512 IUnknown_Release(foundObject);
1513 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1514 return CO_E_OBJISREG;
1517 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1518 if ( newClass == NULL )
1519 return E_OUTOFMEMORY;
1521 EnterCriticalSection( &csRegisteredClassList );
1523 newClass->classIdentifier = *rclsid;
1524 newClass->runContext = dwClsContext;
1525 newClass->connectFlags = flags;
1526 newClass->pMarshaledData = NULL;
1529 * Use the address of the chain node as the cookie since we are sure it's
1530 * unique. FIXME: not on 64-bit platforms.
1532 newClass->dwCookie = (DWORD)newClass;
1533 newClass->nextClass = firstRegisteredClass;
1536 * Since we're making a copy of the object pointer, we have to increase its
1539 newClass->classObject = pUnk;
1540 IUnknown_AddRef(newClass->classObject);
1542 firstRegisteredClass = newClass;
1543 LeaveCriticalSection( &csRegisteredClassList );
1545 *lpdwRegister = newClass->dwCookie;
1547 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1548 IClassFactory *classfac;
1550 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1551 (LPVOID*)&classfac);
1554 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1556 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1557 IUnknown_Release(classfac);
1560 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1561 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1562 MSHLFLAGS_TABLESTRONG);
1564 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1565 IUnknown_Release(classfac);
1569 IUnknown_Release(classfac);
1571 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1576 /***********************************************************************
1577 * CoRevokeClassObject [OLE32.@]
1579 * Removes a class object from the class registry.
1582 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1586 * Failure: HRESULT code.
1589 * CoRegisterClassObject
1591 HRESULT WINAPI CoRevokeClassObject(
1594 HRESULT hr = E_INVALIDARG;
1595 RegisteredClass** prevClassLink;
1596 RegisteredClass* curClass;
1598 TRACE("(%08lx)\n",dwRegister);
1600 EnterCriticalSection( &csRegisteredClassList );
1603 * Iterate through the whole list and try to match the cookie.
1605 curClass = firstRegisteredClass;
1606 prevClassLink = &firstRegisteredClass;
1608 while (curClass != 0)
1611 * Check if we have a match on the cookie.
1613 if (curClass->dwCookie == dwRegister)
1616 * Remove the class from the chain.
1618 *prevClassLink = curClass->nextClass;
1621 * Release the reference to the class object.
1623 IUnknown_Release(curClass->classObject);
1625 if (curClass->pMarshaledData)
1628 memset(&zero, 0, sizeof(zero));
1629 /* FIXME: stop local server thread */
1630 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1631 CoReleaseMarshalData(curClass->pMarshaledData);
1635 * Free the memory used by the chain node.
1637 HeapFree(GetProcessHeap(), 0, curClass);
1644 * Step to the next class in the list.
1646 prevClassLink = &(curClass->nextClass);
1647 curClass = curClass->nextClass;
1651 LeaveCriticalSection( &csRegisteredClassList );
1653 * If we get to here, we haven't found our class.
1658 /***********************************************************************
1659 * COM_RegReadPath [internal]
1661 * Reads a registry value and expands it when necessary
1663 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1668 WCHAR src[MAX_PATH];
1669 DWORD dwLength = dstlen * sizeof(WCHAR);
1671 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1672 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1673 if (keytype == REG_EXPAND_SZ) {
1674 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1676 lstrcpynW(dst, src, dstlen);
1684 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
1686 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
1689 DWORD dwLength = len * sizeof(WCHAR);
1691 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
1692 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
1696 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1698 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
1699 static const WCHAR wszFree[] = {'F','r','e','e',0};
1700 static const WCHAR wszBoth[] = {'B','o','t','h',0};
1702 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1703 DllGetClassObjectFunc DllGetClassObject;
1704 WCHAR dllpath[MAX_PATH+1];
1705 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
1708 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
1710 if (!strcmpiW(threading_model, wszApartment))
1712 APARTMENT *apt = COM_CurrentApt();
1713 if (apt->multi_threaded)
1715 /* try to find an STA */
1716 APARTMENT *host_apt = apartment_findfromtype(FALSE);
1718 FIXME("create a host apartment for apartment-threaded object %s\n", debugstr_guid(rclsid));
1721 struct host_object_params params;
1722 HWND hwnd = apartment_getwindow(host_apt);
1724 params.hkeydll = hkeydll;
1725 params.clsid = *rclsid;
1727 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
1730 hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
1732 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1733 IStream_Release(params.stream);
1739 else if (!strcmpiW(threading_model, wszFree))
1741 APARTMENT *apt = COM_CurrentApt();
1742 if (!apt->multi_threaded)
1744 FIXME("should create object %s in multi-threaded apartment\n",
1745 debugstr_guid(rclsid));
1748 /* everything except "Apartment", "Free" and "Both" */
1749 else if (strcmpiW(threading_model, wszBoth))
1751 /* everything else is main-threaded */
1752 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
1753 debugstr_w(threading_model), debugstr_guid(rclsid));
1756 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1758 /* failure: CLSID is not found in registry */
1759 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1760 return REGDB_E_CLASSNOTREG;
1763 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1765 /* failure: DLL could not be loaded */
1766 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1767 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1770 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1772 /* failure: the dll did not export DllGetClassObject */
1773 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1774 FreeLibrary( hLibrary );
1775 return CO_E_DLLNOTFOUND;
1778 /* OK: get the ClassObject */
1779 COMPOBJ_DLLList_Add( hLibrary );
1780 hr = DllGetClassObject(rclsid, riid, ppv);
1783 ERR("DllGetClassObject returned error 0x%08lx\n", hr);
1788 /***********************************************************************
1789 * CoGetClassObject [OLE32.@]
1791 * FIXME. If request allows of several options and there is a failure
1792 * with one (other than not being registered) do we try the
1793 * others or return failure? (E.g. inprocess is registered but
1794 * the DLL is not found but the server version works)
1796 HRESULT WINAPI CoGetClassObject(
1797 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1798 REFIID iid, LPVOID *ppv)
1800 LPUNKNOWN regClassObject;
1801 HRESULT hres = E_UNEXPECTED;
1803 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1806 return E_INVALIDARG;
1810 if (!COM_CurrentApt())
1812 ERR("apartment not initialised\n");
1813 return CO_E_NOTINITIALIZED;
1817 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1818 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1822 * First, try and see if we can't match the class ID with one of the
1823 * registered classes.
1825 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1827 /* Get the required interface from the retrieved pointer. */
1828 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1831 * Since QI got another reference on the pointer, we want to release the
1832 * one we already have. If QI was unsuccessful, this will release the object. This
1833 * is good since we are not returning it in the "out" parameter.
1835 IUnknown_Release(regClassObject);
1840 /* First try in-process server */
1841 if (CLSCTX_INPROC_SERVER & dwClsContext)
1843 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1846 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
1847 return FTMarshalCF_Create(iid, ppv);
1849 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1852 if (hres == REGDB_E_CLASSNOTREG)
1853 ERR("class %s not registered\n", debugstr_guid(rclsid));
1855 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1858 if (SUCCEEDED(hres))
1860 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1864 /* return if we got a class, otherwise fall through to one of the
1866 if (SUCCEEDED(hres))
1870 /* Next try in-process handler */
1871 if (CLSCTX_INPROC_HANDLER & dwClsContext)
1873 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1876 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1879 if (hres == REGDB_E_CLASSNOTREG)
1880 ERR("class %s not registered\n", debugstr_guid(rclsid));
1882 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1885 if (SUCCEEDED(hres))
1887 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1891 /* return if we got a class, otherwise fall through to one of the
1893 if (SUCCEEDED(hres))
1897 /* Next try out of process */
1898 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1900 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
1901 if (SUCCEEDED(hres))
1905 /* Finally try remote: this requires networked DCOM (a lot of work) */
1906 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1908 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1909 hres = E_NOINTERFACE;
1913 ERR("no class object %s could be created for context 0x%lx\n",
1914 debugstr_guid(rclsid), dwClsContext);
1918 /***********************************************************************
1919 * CoResumeClassObjects (OLE32.@)
1921 * Resumes all class objects registered with REGCLS_SUSPENDED.
1925 * Failure: HRESULT code.
1927 HRESULT WINAPI CoResumeClassObjects(void)
1933 /***********************************************************************
1934 * GetClassFile (OLE32.@)
1936 * This function supplies the CLSID associated with the given filename.
1938 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1942 int nbElm, length, i;
1944 LPOLESTR *pathDec=0,absFile=0,progId=0;
1946 static const WCHAR bkslashW[] = {'\\',0};
1947 static const WCHAR dotW[] = {'.',0};
1949 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1951 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1952 if((StgIsStorageFile(filePathName))==S_OK){
1954 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1957 res=ReadClassStg(pstg,pclsid);
1959 IStorage_Release(pstg);
1963 /* if the file is not a storage object then attemps to match various bits in the file against a
1964 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1967 for(i=0;i<nFileTypes;i++)
1969 for(i=0;j<nPatternsForType;j++){
1974 pat=ReadPatternFromRegistry(i,j);
1975 hFile=CreateFileW(filePathName,,,,,,hFile);
1976 SetFilePosition(hFile,pat.offset);
1977 ReadFile(hFile,buf,pat.size,&r,NULL);
1978 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1980 *pclsid=ReadCLSIDFromRegistry(i);
1986 /* if the above strategies fail then search for the extension key in the registry */
1988 /* get the last element (absolute file) in the path name */
1989 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1990 absFile=pathDec[nbElm-1];
1992 /* failed if the path represente a directory and not an absolute file name*/
1993 if (!lstrcmpW(absFile, bkslashW))
1994 return MK_E_INVALIDEXTENSION;
1996 /* get the extension of the file */
1998 length=lstrlenW(absFile);
1999 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
2002 if (!extension || !lstrcmpW(extension, dotW))
2003 return MK_E_INVALIDEXTENSION;
2005 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
2007 /* get the progId associated to the extension */
2008 progId = CoTaskMemAlloc(sizeProgId);
2009 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
2011 if (res==ERROR_SUCCESS)
2012 /* return the clsid associated to the progId */
2013 res= CLSIDFromProgID(progId,pclsid);
2015 for(i=0; pathDec[i]!=NULL;i++)
2016 CoTaskMemFree(pathDec[i]);
2017 CoTaskMemFree(pathDec);
2019 CoTaskMemFree(progId);
2021 if (res==ERROR_SUCCESS)
2024 return MK_E_INVALIDEXTENSION;
2027 /***********************************************************************
2028 * CoCreateInstance [OLE32.@]
2030 HRESULT WINAPI CoCreateInstance(
2032 LPUNKNOWN pUnkOuter,
2038 LPCLASSFACTORY lpclf = 0;
2040 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2041 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2050 * Initialize the "out" parameter
2054 if (!COM_CurrentApt())
2056 ERR("apartment not initialised\n");
2057 return CO_E_NOTINITIALIZED;
2061 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2062 * Rather than create a class factory, we can just check for it here
2064 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2065 if (StdGlobalInterfaceTableInstance == NULL)
2066 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2067 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2068 if (hres) return hres;
2070 TRACE("Retrieved GIT (%p)\n", *ppv);
2075 * Get a class factory to construct the object we want.
2077 hres = CoGetClassObject(rclsid,
2087 * Create the object and don't forget to release the factory
2089 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2090 IClassFactory_Release(lpclf);
2092 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
2093 debugstr_guid(iid), debugstr_guid(rclsid),hres);
2098 /***********************************************************************
2099 * CoCreateInstanceEx [OLE32.@]
2101 HRESULT WINAPI CoCreateInstanceEx(
2103 LPUNKNOWN pUnkOuter,
2105 COSERVERINFO* pServerInfo,
2109 IUnknown* pUnk = NULL;
2112 ULONG successCount = 0;
2117 if ( (cmq==0) || (pResults==NULL))
2118 return E_INVALIDARG;
2120 if (pServerInfo!=NULL)
2121 FIXME("() non-NULL pServerInfo not supported!\n");
2124 * Initialize all the "out" parameters.
2126 for (index = 0; index < cmq; index++)
2128 pResults[index].pItf = NULL;
2129 pResults[index].hr = E_NOINTERFACE;
2133 * Get the object and get its IUnknown pointer.
2135 hr = CoCreateInstance(rclsid,
2145 * Then, query for all the interfaces requested.
2147 for (index = 0; index < cmq; index++)
2149 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2150 pResults[index].pIID,
2151 (VOID**)&(pResults[index].pItf));
2153 if (pResults[index].hr == S_OK)
2158 * Release our temporary unknown pointer.
2160 IUnknown_Release(pUnk);
2162 if (successCount == 0)
2163 return E_NOINTERFACE;
2165 if (successCount!=cmq)
2166 return CO_S_NOTALLINTERFACES;
2171 /***********************************************************************
2172 * CoLoadLibrary (OLE32.@)
2177 * lpszLibName [I] Path to library.
2178 * bAutoFree [I] Whether the library should automatically be freed.
2181 * Success: Handle to loaded library.
2185 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2187 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2189 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2191 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2194 /***********************************************************************
2195 * CoFreeLibrary [OLE32.@]
2197 * Unloads a library from memory.
2200 * hLibrary [I] Handle to library to unload.
2206 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2208 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2210 FreeLibrary(hLibrary);
2214 /***********************************************************************
2215 * CoFreeAllLibraries [OLE32.@]
2217 * Function for backwards compatibility only. Does nothing.
2223 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2225 void WINAPI CoFreeAllLibraries(void)
2231 /***********************************************************************
2232 * CoFreeUnusedLibraries [OLE32.@]
2233 * CoFreeUnusedLibraries [COMPOBJ.17]
2235 * Frees any unused libraries. Unused are identified as those that return
2236 * S_OK from their DllCanUnloadNow function.
2242 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2244 void WINAPI CoFreeUnusedLibraries(void)
2246 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2247 * through the main apartment's thread to call DllCanUnloadNow */
2248 COMPOBJ_DllList_FreeUnused(0);
2251 /***********************************************************************
2252 * CoFileTimeNow [OLE32.@]
2253 * CoFileTimeNow [COMPOBJ.82]
2255 * Retrieves the current time in FILETIME format.
2258 * lpFileTime [O] The current time.
2263 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2265 GetSystemTimeAsFileTime( lpFileTime );
2269 static void COM_RevokeAllClasses()
2271 EnterCriticalSection( &csRegisteredClassList );
2273 while (firstRegisteredClass!=0)
2275 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2278 LeaveCriticalSection( &csRegisteredClassList );
2281 /******************************************************************************
2282 * CoLockObjectExternal [OLE32.@]
2284 * Increments or decrements the external reference count of a stub object.
2287 * pUnk [I] Stub object.
2288 * fLock [I] If TRUE then increments the external ref-count,
2289 * otherwise decrements.
2290 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2291 * calling CoDisconnectObject.
2295 * Failure: HRESULT code.
2298 * If fLock is TRUE and an object is passed in that doesn't have a stub
2299 * manager then a new stub manager is created for the object.
2301 HRESULT WINAPI CoLockObjectExternal(
2304 BOOL fLastUnlockReleases)
2306 struct stub_manager *stubmgr;
2307 struct apartment *apt;
2309 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2310 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2312 apt = COM_CurrentApt();
2313 if (!apt) return CO_E_NOTINITIALIZED;
2315 stubmgr = get_stub_manager_from_object(apt, pUnk);
2320 stub_manager_ext_addref(stubmgr, 1);
2322 stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases);
2324 stub_manager_int_release(stubmgr);
2330 stubmgr = new_stub_manager(apt, pUnk);
2334 stub_manager_ext_addref(stubmgr, 1);
2335 stub_manager_int_release(stubmgr);
2342 WARN("stub object not found %p\n", pUnk);
2343 /* Note: native is pretty broken here because it just silently
2344 * fails, without returning an appropriate error code, making apps
2345 * think that the object was disconnected, when it actually wasn't */
2350 /***********************************************************************
2351 * CoInitializeWOW (OLE32.@)
2353 * WOW equivalent of CoInitialize?
2362 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2364 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2368 /***********************************************************************
2369 * CoGetState [OLE32.@]
2371 * Retrieves the thread state object previously stored by CoSetState().
2374 * ppv [I] Address where pointer to object will be stored.
2378 * Failure: E_OUTOFMEMORY.
2381 * Crashes on all invalid ppv addresses, including NULL.
2382 * If the function returns a non-NULL object then the caller must release its
2383 * reference on the object when the object is no longer required.
2388 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2390 struct oletls *info = COM_CurrentInfo();
2391 if (!info) return E_OUTOFMEMORY;
2397 IUnknown_AddRef(info->state);
2399 TRACE("apt->state=%p\n", info->state);
2405 /***********************************************************************
2406 * CoSetState [OLE32.@]
2408 * Sets the thread state object.
2411 * pv [I] Pointer to state object to be stored.
2414 * The system keeps a reference on the object while the object stored.
2418 * Failure: E_OUTOFMEMORY.
2420 HRESULT WINAPI CoSetState(IUnknown * pv)
2422 struct oletls *info = COM_CurrentInfo();
2423 if (!info) return E_OUTOFMEMORY;
2425 if (pv) IUnknown_AddRef(pv);
2429 TRACE("-- release %p now\n", info->state);
2430 IUnknown_Release(info->state);
2439 /******************************************************************************
2440 * CoTreatAsClass [OLE32.@]
2442 * Sets the TreatAs value of a class.
2445 * clsidOld [I] Class to set TreatAs value on.
2446 * clsidNew [I] The class the clsidOld should be treated as.
2450 * Failure: HRESULT code.
2455 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2457 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2458 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2460 WCHAR szClsidNew[CHARS_IN_GUID];
2462 WCHAR auto_treat_as[CHARS_IN_GUID];
2463 LONG auto_treat_as_size = sizeof(auto_treat_as);
2466 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2469 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2471 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2472 !CLSIDFromString(auto_treat_as, &id))
2474 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2476 res = REGDB_E_WRITEREGDB;
2482 RegDeleteKeyW(hkey, wszTreatAs);
2486 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2487 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2489 res = REGDB_E_WRITEREGDB;
2494 if (hkey) RegCloseKey(hkey);
2498 /******************************************************************************
2499 * CoGetTreatAsClass [OLE32.@]
2501 * Gets the TreatAs value of a class.
2504 * clsidOld [I] Class to get the TreatAs value of.
2505 * clsidNew [I] The class the clsidOld should be treated as.
2509 * Failure: HRESULT code.
2514 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2516 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2518 WCHAR szClsidNew[CHARS_IN_GUID];
2520 LONG len = sizeof(szClsidNew);
2522 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2523 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2525 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2528 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2533 res = CLSIDFromString(szClsidNew,clsidNew);
2535 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2537 if (hkey) RegCloseKey(hkey);
2541 /******************************************************************************
2542 * CoGetCurrentProcess [OLE32.@]
2543 * CoGetCurrentProcess [COMPOBJ.34]
2545 * Gets the current process ID.
2548 * The current process ID.
2551 * Is DWORD really the correct return type for this function?
2553 DWORD WINAPI CoGetCurrentProcess(void)
2555 return GetCurrentProcessId();
2558 /******************************************************************************
2559 * CoRegisterMessageFilter [OLE32.@]
2561 * Registers a message filter.
2564 * lpMessageFilter [I] Pointer to interface.
2565 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2569 * Failure: HRESULT code.
2572 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2573 * lpMessageFilter removes the message filter.
2575 * If lplpMessageFilter is not NULL the previous message filter will be
2576 * returned in the memory pointer to this parameter and the caller is
2577 * responsible for releasing the object.
2579 * The current thread be in an apartment otherwise the function will crash.
2581 HRESULT WINAPI CoRegisterMessageFilter(
2582 LPMESSAGEFILTER lpMessageFilter,
2583 LPMESSAGEFILTER *lplpMessageFilter)
2585 struct apartment *apt;
2586 IMessageFilter *lpOldMessageFilter;
2588 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2590 apt = COM_CurrentApt();
2592 /* can't set a message filter in a multi-threaded apartment */
2593 if (apt->multi_threaded)
2595 ERR("can't set message filter in MTA\n");
2596 return CO_E_NOT_SUPPORTED;
2599 if (lpMessageFilter)
2600 IMessageFilter_AddRef(lpMessageFilter);
2602 EnterCriticalSection(&apt->cs);
2604 lpOldMessageFilter = apt->filter;
2605 apt->filter = lpMessageFilter;
2607 LeaveCriticalSection(&apt->cs);
2609 if (lplpMessageFilter)
2610 *lplpMessageFilter = lpOldMessageFilter;
2611 else if (lpOldMessageFilter)
2612 IMessageFilter_Release(lpOldMessageFilter);
2614 if (lpMessageFilter)
2615 FIXME("message filter has been registered, but will not be used\n");
2620 /***********************************************************************
2621 * CoIsOle1Class [OLE32.@]
2623 * Determines whether the specified class an OLE v1 class.
2626 * clsid [I] Class to test.
2629 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2631 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2633 FIXME("%s\n", debugstr_guid(clsid));
2637 /***********************************************************************
2638 * IsEqualGUID [OLE32.@]
2640 * Compares two Unique Identifiers.
2643 * rguid1 [I] The first GUID to compare.
2644 * rguid2 [I] The other GUID to compare.
2650 BOOL WINAPI IsEqualGUID(
2654 return !memcmp(rguid1,rguid2,sizeof(GUID));
2657 /***********************************************************************
2658 * CoInitializeSecurity [OLE32.@]
2660 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2661 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2662 void* pReserved1, DWORD dwAuthnLevel,
2663 DWORD dwImpLevel, void* pReserved2,
2664 DWORD dwCapabilities, void* pReserved3)
2666 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2667 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2668 dwCapabilities, pReserved3);
2672 /***********************************************************************
2673 * CoSuspendClassObjects [OLE32.@]
2675 * Suspends all registered class objects to prevent further requests coming in
2676 * for those objects.
2680 * Failure: HRESULT code.
2682 HRESULT WINAPI CoSuspendClassObjects(void)
2688 /***********************************************************************
2689 * CoAddRefServerProcess [OLE32.@]
2691 * Helper function for incrementing the reference count of a local-server
2695 * New reference count.
2697 ULONG WINAPI CoAddRefServerProcess(void)
2703 /***********************************************************************
2704 * CoReleaseServerProcess [OLE32.@]
2706 * Helper function for decrementing the reference count of a local-server
2710 * New reference count.
2712 ULONG WINAPI CoReleaseServerProcess(void)
2718 /***********************************************************************
2719 * CoIsHandlerConnected [OLE32.@]
2721 * Determines whether a proxy is connected to a remote stub.
2724 * pUnk [I] Pointer to object that may or may not be connected.
2727 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2730 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2732 FIXME("%p\n", pUnk);
2737 /***********************************************************************
2738 * CoAllowSetForegroundWindow [OLE32.@]
2741 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2743 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2747 /***********************************************************************
2748 * CoQueryProxyBlanket [OLE32.@]
2750 * Retrieves the security settings being used by a proxy.
2753 * pProxy [I] Pointer to the proxy object.
2754 * pAuthnSvc [O] The type of authentication service.
2755 * pAuthzSvc [O] The type of authorization service.
2756 * ppServerPrincName [O] Optional. The server prinicple name.
2757 * pAuthnLevel [O] The authentication level.
2758 * pImpLevel [O] The impersonation level.
2759 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2760 * pCapabilities [O] Flags affecting the security behaviour.
2764 * Failure: HRESULT code.
2767 * CoCopyProxy, CoSetProxyBlanket.
2769 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2770 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2771 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2773 IClientSecurity *pCliSec;
2776 TRACE("%p\n", pProxy);
2778 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2781 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2782 pAuthzSvc, ppServerPrincName,
2783 pAuthnLevel, pImpLevel, ppAuthInfo,
2785 IClientSecurity_Release(pCliSec);
2788 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2792 /***********************************************************************
2793 * CoSetProxyBlanket [OLE32.@]
2795 * Sets the security settings for a proxy.
2798 * pProxy [I] Pointer to the proxy object.
2799 * AuthnSvc [I] The type of authentication service.
2800 * AuthzSvc [I] The type of authorization service.
2801 * pServerPrincName [I] The server prinicple name.
2802 * AuthnLevel [I] The authentication level.
2803 * ImpLevel [I] The impersonation level.
2804 * pAuthInfo [I] Information specific to the authorization/authentication service.
2805 * Capabilities [I] Flags affecting the security behaviour.
2809 * Failure: HRESULT code.
2812 * CoQueryProxyBlanket, CoCopyProxy.
2814 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2815 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2816 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2818 IClientSecurity *pCliSec;
2821 TRACE("%p\n", pProxy);
2823 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2826 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2827 AuthzSvc, pServerPrincName,
2828 AuthnLevel, ImpLevel, pAuthInfo,
2830 IClientSecurity_Release(pCliSec);
2833 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2837 /***********************************************************************
2838 * CoCopyProxy [OLE32.@]
2843 * pProxy [I] Pointer to the proxy object.
2844 * ppCopy [O] Copy of the proxy.
2848 * Failure: HRESULT code.
2851 * CoQueryProxyBlanket, CoSetProxyBlanket.
2853 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2855 IClientSecurity *pCliSec;
2858 TRACE("%p\n", pProxy);
2860 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2863 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2864 IClientSecurity_Release(pCliSec);
2867 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2872 /***********************************************************************
2873 * CoGetCallContext [OLE32.@]
2875 * Gets the context of the currently executing server call in the current
2879 * riid [I] Context interface to return.
2880 * ppv [O] Pointer to memory that will receive the context on return.
2884 * Failure: HRESULT code.
2886 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
2888 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
2891 return E_NOINTERFACE;
2894 /***********************************************************************
2895 * CoQueryClientBlanket [OLE32.@]
2897 * Retrieves the authentication information about the client of the currently
2898 * executing server call in the current thread.
2901 * pAuthnSvc [O] Optional. The type of authentication service.
2902 * pAuthzSvc [O] Optional. The type of authorization service.
2903 * pServerPrincName [O] Optional. The server prinicple name.
2904 * pAuthnLevel [O] Optional. The authentication level.
2905 * pImpLevel [O] Optional. The impersonation level.
2906 * pPrivs [O] Optional. Information about the privileges of the client.
2907 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
2911 * Failure: HRESULT code.
2914 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
2916 HRESULT WINAPI CoQueryClientBlanket(
2919 OLECHAR **pServerPrincName,
2922 RPC_AUTHZ_HANDLE *pPrivs,
2923 DWORD *pCapabilities)
2925 IServerSecurity *pSrvSec;
2928 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
2929 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
2930 pPrivs, pCapabilities);
2932 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2935 hr = IServerSecurity_QueryBlanket(
2936 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
2937 pImpLevel, pPrivs, pCapabilities);
2938 IServerSecurity_Release(pSrvSec);
2944 /***********************************************************************
2945 * CoImpersonateClient [OLE32.@]
2947 * Impersonates the client of the currently executing server call in the
2955 * Failure: HRESULT code.
2958 * If this function fails then the current thread will not be impersonating
2959 * the client and all actions will take place on behalf of the server.
2960 * Therefore, it is important to check the return value from this function.
2963 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
2965 HRESULT WINAPI CoImpersonateClient(void)
2967 IServerSecurity *pSrvSec;
2972 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2975 hr = IServerSecurity_ImpersonateClient(pSrvSec);
2976 IServerSecurity_Release(pSrvSec);
2982 /***********************************************************************
2983 * CoRevertToSelf [OLE32.@]
2985 * Ends the impersonation of the client of the currently executing server
2986 * call in the current thread.
2993 * Failure: HRESULT code.
2996 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
2998 HRESULT WINAPI CoRevertToSelf(void)
3000 IServerSecurity *pSrvSec;
3005 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3008 hr = IServerSecurity_RevertToSelf(pSrvSec);
3009 IServerSecurity_Release(pSrvSec);
3015 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3017 /* first try to retrieve messages for incoming COM calls to the apartment window */
3018 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3019 /* next retrieve other messages necessary for the app to remain responsive */
3020 PeekMessageW(msg, NULL, 0, WM_USER - 1, PM_REMOVE|PM_NOYIELD);
3023 /***********************************************************************
3024 * CoWaitForMultipleHandles [OLE32.@]
3026 * Waits for one or more handles to become signaled.
3029 * dwFlags [I] Flags. See notes.
3030 * dwTimeout [I] Timeout in milliseconds.
3031 * cHandles [I] Number of handles pointed to by pHandles.
3032 * pHandles [I] Handles to wait for.
3033 * lpdwindex [O] Index of handle that was signaled.
3037 * Failure: RPC_S_CALLPENDING on timeout.
3041 * The dwFlags parameter can be zero or more of the following:
3042 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3043 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3046 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3048 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3049 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
3052 DWORD start_time = GetTickCount();
3053 APARTMENT *apt = COM_CurrentApt();
3054 BOOL message_loop = apt && !apt->multi_threaded;
3056 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3057 pHandles, lpdwindex);
3061 DWORD now = GetTickCount();
3064 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
3066 hr = RPC_S_CALLPENDING;
3072 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
3073 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
3075 TRACE("waiting for rpc completion or window message\n");
3077 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3078 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3079 QS_ALLINPUT, wait_flags);
3081 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3085 /* note: using "if" here instead of "while" might seem less
3086 * efficient, but only if we are optimising for quick delivery
3087 * of pending messages, rather than quick completion of the
3089 if (COM_PeekMessage(apt, &msg))
3091 /* FIXME: filter the messages here */
3092 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3093 TranslateMessage(&msg);
3094 DispatchMessageW(&msg);
3095 if (msg.message == WM_QUIT)
3097 TRACE("resending WM_QUIT to outer message loop\n");
3098 PostQuitMessage(msg.wParam);
3099 /* no longer need to process messages */
3100 message_loop = FALSE;
3108 TRACE("waiting for rpc completion\n");
3110 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3111 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3112 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3113 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3116 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
3118 /* handle signaled, store index */
3119 *lpdwindex = (res - WAIT_OBJECT_0);
3122 else if (res == WAIT_TIMEOUT)
3124 hr = RPC_S_CALLPENDING;
3129 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
3134 TRACE("-- 0x%08lx\n", hr);
3139 /***********************************************************************
3140 * CoGetObject [OLE32.@]
3142 * Gets the object named by coverting the name to a moniker and binding to it.
3145 * pszName [I] String representing the object.
3146 * pBindOptions [I] Parameters affecting the binding to the named object.
3147 * riid [I] Interface to bind to on the objecct.
3148 * ppv [O] On output, the interface riid of the object represented
3153 * Failure: HRESULT code.
3156 * MkParseDisplayName.
3158 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3159 REFIID riid, void **ppv)
3166 hr = CreateBindCtx(0, &pbc);
3170 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3177 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3180 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3181 IMoniker_Release(pmk);
3185 IBindCtx_Release(pbc);
3190 /***********************************************************************
3193 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3195 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
3198 case DLL_PROCESS_ATTACH:
3199 OLE32_hInstance = hinstDLL;
3200 COMPOBJ_InitProcess();
3201 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3204 case DLL_PROCESS_DETACH:
3205 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3206 COMPOBJ_UninitProcess();
3207 OLE32_hInstance = 0;
3210 case DLL_THREAD_DETACH:
3217 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */