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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 * - Pump the message loop during RPC calls.
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);
86 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
88 APARTMENT *MTA; /* protected by csApartment */
89 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
91 static CRITICAL_SECTION csApartment;
92 static CRITICAL_SECTION_DEBUG critsect_debug =
95 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
96 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
98 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
101 * This lock count counts the number of times CoInitialize is called. It is
102 * decreased every time CoUninitialize is called. When it hits 0, the COM
103 * libraries are freed
105 static LONG s_COMLockCount = 0;
108 * This linked list contains the list of registered class objects. These
109 * are mostly used to register the factories for out-of-proc servers of OLE
112 * TODO: Make this data structure aware of inter-process communication. This
113 * means that parts of this will be exported to the Wine Server.
115 typedef struct tagRegisteredClass
117 CLSID classIdentifier;
118 LPUNKNOWN classObject;
122 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
123 struct tagRegisteredClass* nextClass;
126 static RegisteredClass* firstRegisteredClass = NULL;
128 static CRITICAL_SECTION csRegisteredClassList;
129 static CRITICAL_SECTION_DEBUG class_cs_debug =
131 0, 0, &csRegisteredClassList,
132 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
133 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
135 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
137 /*****************************************************************************
138 * This section contains OpenDllList definitions
140 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
141 * other functions that do LoadLibrary _without_ giving back a HMODULE.
142 * Without this list these handles would never be freed.
144 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
145 * next unload-call but not before 600 sec.
148 typedef struct tagOpenDll {
150 struct tagOpenDll *next;
153 static OpenDll *openDllList = NULL; /* linked list of open dlls */
155 static CRITICAL_SECTION csOpenDllList;
156 static CRITICAL_SECTION_DEBUG dll_cs_debug =
158 0, 0, &csOpenDllList,
159 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
160 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
162 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
164 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',' ',
165 '0','x','#','#','#','#','#','#','#','#',' ',0};
166 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
168 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
169 static void COMPOBJ_DllList_FreeUnused(int Timeout);
171 static void COMPOBJ_InitProcess( void )
175 /* Dispatching to the correct thread in an apartment is done through
176 * window messages rather than RPC transports. When an interface is
177 * marshalled into another apartment in the same process, a window of the
178 * following class is created. The *caller* of CoMarshalInterface (ie the
179 * application) is responsible for pumping the message loop in that thread.
180 * The WM_USER messages which point to the RPCs are then dispatched to
181 * COM_AptWndProc by the user's code from the apartment in which the interface
184 memset(&wclass, 0, sizeof(wclass));
185 wclass.lpfnWndProc = apartment_wndproc;
186 wclass.hInstance = OLE32_hInstance;
187 wclass.lpszClassName = wszAptWinClass;
188 RegisterClassW(&wclass);
191 static void COMPOBJ_UninitProcess( void )
193 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
196 static void COM_TlsDestroy(void)
198 struct oletls *info = NtCurrentTeb()->ReservedForOle;
201 if (info->apt) apartment_release(info->apt);
202 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
203 if (info->state) IUnknown_Release(info->state);
204 HeapFree(GetProcessHeap(), 0, info);
205 NtCurrentTeb()->ReservedForOle = NULL;
209 /******************************************************************************
213 /* allocates memory and fills in the necessary fields for a new apartment
215 static APARTMENT *apartment_construct(DWORD model)
219 TRACE("creating new apartment, model=%ld\n", model);
221 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
222 apt->tid = GetCurrentThreadId();
224 list_init(&apt->proxies);
225 list_init(&apt->stubmgrs);
228 apt->remunk_exported = FALSE;
230 InitializeCriticalSection(&apt->cs);
231 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
235 if (model & COINIT_APARTMENTTHREADED)
237 /* FIXME: should be randomly generated by in an RPC call to rpcss */
238 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
239 apt->win = CreateWindowW(wszAptWinClass, NULL, 0,
241 0, 0, OLE32_hInstance, NULL);
245 /* FIXME: should be randomly generated by in an RPC call to rpcss */
246 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
249 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
251 /* the locking here is not currently needed for the MTA case, but it
252 * doesn't hurt and makes the code simpler */
253 EnterCriticalSection(&csApartment);
254 list_add_head(&apts, &apt->entry);
255 LeaveCriticalSection(&csApartment);
260 /* gets and existing apartment if one exists or otherwise creates an apartment
261 * structure which stores OLE apartment-local information and stores a pointer
262 * to it in the thread-local storage */
263 static APARTMENT *apartment_get_or_create(DWORD model)
265 APARTMENT *apt = COM_CurrentApt();
269 if (model & COINIT_APARTMENTTHREADED)
271 apt = apartment_construct(model);
272 COM_CurrentInfo()->apt = apt;
276 EnterCriticalSection(&csApartment);
278 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
279 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
283 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
284 apartment_addref(MTA);
287 MTA = apartment_construct(model);
290 COM_CurrentInfo()->apt = apt;
292 LeaveCriticalSection(&csApartment);
299 DWORD apartment_addref(struct apartment *apt)
301 DWORD refs = InterlockedIncrement(&apt->refs);
302 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
306 DWORD apartment_release(struct apartment *apt)
310 EnterCriticalSection(&csApartment);
312 ret = InterlockedDecrement(&apt->refs);
313 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
314 /* destruction stuff that needs to happen under csApartment CS */
317 if (apt == MTA) MTA = NULL;
318 list_remove(&apt->entry);
321 LeaveCriticalSection(&csApartment);
325 struct list *cursor, *cursor2;
327 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
329 /* no locking is needed for this apartment, because no other thread
330 * can access it at this point */
332 apartment_disconnectproxies(apt);
334 if (apt->win) DestroyWindow(apt->win);
336 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
338 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
339 /* release the implicit reference given by the fact that the
340 * stub has external references (it must do since it is in the
341 * stub manager list in the apartment and all non-apartment users
342 * must have a ref on the apartment and so it cannot be destroyed).
344 stub_manager_int_release(stubmgr);
347 /* if this assert fires, then another thread took a reference to a
348 * stub manager without taking a reference to the containing
349 * apartment, which it must do. */
350 assert(list_empty(&apt->stubmgrs));
352 if (apt->filter) IUnknown_Release(apt->filter);
354 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
355 DeleteCriticalSection(&apt->cs);
357 HeapFree(GetProcessHeap(), 0, apt);
363 /* The given OXID must be local to this process:
365 * The ref parameter is here mostly to ensure people remember that
366 * they get one, you should normally take a ref for thread safety.
368 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
370 APARTMENT *result = NULL;
373 EnterCriticalSection(&csApartment);
374 LIST_FOR_EACH( cursor, &apts )
376 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
377 if (apt->oxid == oxid)
380 if (ref) apartment_addref(result);
384 LeaveCriticalSection(&csApartment);
389 /* gets the apartment which has a given creator thread ID. The caller must
390 * release the reference from the apartment as soon as the apartment pointer
391 * is no longer required. */
392 APARTMENT *apartment_findfromtid(DWORD tid)
394 APARTMENT *result = NULL;
397 EnterCriticalSection(&csApartment);
398 LIST_FOR_EACH( cursor, &apts )
400 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
404 apartment_addref(result);
408 LeaveCriticalSection(&csApartment);
413 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
418 RPC_ExecuteCall((struct dispatch_params *)lParam);
421 return DefWindowProcW(hWnd, msg, wParam, lParam);
425 void apartment_joinmta(void)
427 apartment_addref(MTA);
428 COM_CurrentInfo()->apt = MTA;
431 /*****************************************************************************
432 * This section contains OpenDllList implemantation
435 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
442 EnterCriticalSection( &csOpenDllList );
444 if (openDllList == NULL) {
445 /* empty list -- add first node */
446 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
447 openDllList->hLibrary=hLibrary;
448 openDllList->next = NULL;
450 /* search for this dll */
452 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
453 if (ptr->hLibrary == hLibrary) {
459 /* dll not found, add it */
461 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
462 openDllList->hLibrary = hLibrary;
463 openDllList->next = tmp;
467 LeaveCriticalSection( &csOpenDllList );
470 static void COMPOBJ_DllList_FreeUnused(int Timeout)
472 OpenDll *curr, *next, *prev = NULL;
473 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
474 DllCanUnloadNowFunc DllCanUnloadNow;
478 EnterCriticalSection( &csOpenDllList );
480 for (curr = openDllList; curr != NULL; ) {
481 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
483 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
486 TRACE("freeing %p\n", curr->hLibrary);
487 FreeLibrary(curr->hLibrary);
489 HeapFree(GetProcessHeap(), 0, curr);
490 if (curr == openDllList) {
503 LeaveCriticalSection( &csOpenDllList );
506 /******************************************************************************
507 * CoBuildVersion [OLE32.@]
508 * CoBuildVersion [COMPOBJ.1]
510 * Gets the build version of the DLL.
515 * Current build version, hiword is majornumber, loword is minornumber
517 DWORD WINAPI CoBuildVersion(void)
519 TRACE("Returning version %d, build %d.\n", rmm, rup);
520 return (rmm<<16)+rup;
523 /******************************************************************************
524 * CoInitialize [OLE32.@]
526 * Initializes the COM libraries by calling CoInitializeEx with
527 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
530 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
533 * Success: S_OK if not already initialized, S_FALSE otherwise.
534 * Failure: HRESULT code.
539 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
542 * Just delegate to the newer method.
544 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
547 /******************************************************************************
548 * CoInitializeEx [OLE32.@]
550 * Initializes the COM libraries.
553 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
554 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
557 * S_OK if successful,
558 * S_FALSE if this function was called already.
559 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
564 * The behavior used to set the IMalloc used for memory management is
566 * The dwCoInit parameter must specify of of the following apartment
568 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
569 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
570 * The parameter may also specify zero or more of the following flags:
571 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
572 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
577 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
582 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
584 if (lpReserved!=NULL)
586 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
590 * Check the lock count. If this is the first time going through the initialize
591 * process, we have to initialize the libraries.
593 * And crank-up that lock count.
595 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
598 * Initialize the various COM libraries and data structures.
600 TRACE("() - Initializing the COM libraries\n");
602 /* we may need to defer this until after apartment initialisation */
603 RunningObjectTableImpl_Initialize();
606 if (!(apt = COM_CurrentInfo()->apt))
608 apt = apartment_get_or_create(dwCoInit);
609 if (!apt) return E_OUTOFMEMORY;
611 else if (dwCoInit != apt->model)
613 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
614 code then we are probably using the wrong threading model to implement that API. */
615 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
616 return RPC_E_CHANGED_MODE;
621 COM_CurrentInfo()->inits++;
626 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
627 pending RPCs are ignored. Non-COM messages are discarded at this point.
629 static void COM_FlushMessageQueue(void)
632 APARTMENT *apt = COM_CurrentApt();
634 if (!apt || !apt->win) return;
636 TRACE("Flushing STA message queue\n");
638 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
640 if (message.hwnd != apt->win)
642 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
646 TranslateMessage(&message);
647 DispatchMessageA(&message);
651 /***********************************************************************
652 * CoUninitialize [OLE32.@]
654 * This method will decrement the refcount on the current apartment, freeing
655 * the resources associated with it if it is the last thread in the apartment.
656 * If the last apartment is freed, the function will additionally release
657 * any COM resources associated with the process.
667 void WINAPI CoUninitialize(void)
669 struct oletls * info = COM_CurrentInfo();
674 /* will only happen on OOM */
680 ERR("Mismatched CoUninitialize\n");
686 apartment_release(info->apt);
691 * Decrease the reference count.
692 * If we are back to 0 locks on the COM library, make sure we free
693 * all the associated data structures.
695 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
698 TRACE("() - Releasing the COM libraries\n");
700 RunningObjectTableImpl_UnInitialize();
702 /* Release the references to the registered class objects */
703 COM_RevokeAllClasses();
705 /* This will free the loaded COM Dlls */
706 CoFreeAllLibraries();
708 /* This ensures we deal with any pending RPCs */
709 COM_FlushMessageQueue();
711 else if (lCOMRefCnt<1) {
712 ERR( "CoUninitialize() - not CoInitialized.\n" );
713 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
717 /******************************************************************************
718 * CoDisconnectObject [OLE32.@]
719 * CoDisconnectObject [COMPOBJ.15]
721 * Disconnects all connections to this object from remote processes. Dispatches
722 * pending RPCs while blocking new RPCs from occurring, and then calls
723 * IMarshal::DisconnectObject on the given object.
725 * Typically called when the object server is forced to shut down, for instance by
729 * lpUnk [I] The object whose stub should be disconnected.
730 * reserved [I] Reserved. Should be set to 0.
734 * Failure: HRESULT code.
737 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
739 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
745 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
747 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
750 hr = IMarshal_DisconnectObject(marshal, reserved);
751 IMarshal_Release(marshal);
755 apt = COM_CurrentApt();
757 return CO_E_NOTINITIALIZED;
759 apartment_disconnectobject(apt, lpUnk);
761 /* Note: native is pretty broken here because it just silently
762 * fails, without returning an appropriate error code if the object was
763 * not found, making apps think that the object was disconnected, when
764 * it actually wasn't */
769 /******************************************************************************
770 * CoCreateGuid [OLE32.@]
772 * Simply forwards to UuidCreate in RPCRT4.
775 * pguid [O] Points to the GUID to initialize.
779 * Failure: HRESULT code.
784 HRESULT WINAPI CoCreateGuid(GUID *pguid)
786 return UuidCreate(pguid);
789 /******************************************************************************
790 * CLSIDFromString [OLE32.@]
791 * IIDFromString [OLE32.@]
793 * Converts a unique identifier from its string representation into
797 * idstr [I] The string representation of the GUID.
798 * id [O] GUID converted from the string.
802 * CO_E_CLASSSTRING if idstr is not a valid CLSID
807 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
813 memset( id, 0, sizeof (CLSID) );
817 /* validate the CLSID string */
818 if (strlenW(s) != 38)
819 return CO_E_CLASSSTRING;
821 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
822 return CO_E_CLASSSTRING;
824 for (i=1; i<37; i++) {
825 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
826 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
827 ((s[i] >= 'a') && (s[i] <= 'f')) ||
828 ((s[i] >= 'A') && (s[i] <= 'F'))))
829 return CO_E_CLASSSTRING;
832 TRACE("%s -> %p\n", debugstr_w(s), id);
834 /* quick lookup table */
835 memset(table, 0, 256);
837 for (i = 0; i < 10; i++) {
840 for (i = 0; i < 6; i++) {
841 table['A' + i] = i+10;
842 table['a' + i] = i+10;
845 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
847 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
848 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
849 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
850 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
852 /* these are just sequential bytes */
853 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
854 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
855 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
856 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
857 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
858 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
859 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
860 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
865 /*****************************************************************************/
867 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
871 ret = __CLSIDFromString(idstr, id);
872 if(ret != S_OK) { /* It appears a ProgID is also valid */
873 ret = CLSIDFromProgID(idstr, id);
878 /* Converts a GUID into the respective string representation. */
879 HRESULT WINE_StringFromCLSID(
880 const CLSID *id, /* [in] GUID to be converted */
881 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
883 static const char *hex = "0123456789ABCDEF";
888 { ERR("called with id=Null\n");
893 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
894 id->Data1, id->Data2, id->Data3,
895 id->Data4[0], id->Data4[1]);
899 for (i = 2; i < 8; i++) {
900 *s++ = hex[id->Data4[i]>>4];
901 *s++ = hex[id->Data4[i] & 0xf];
907 TRACE("%p->%s\n", id, idstr);
913 /******************************************************************************
914 * StringFromCLSID [OLE32.@]
915 * StringFromIID [OLE32.@]
917 * Converts a GUID into the respective string representation.
918 * The target string is allocated using the OLE IMalloc.
921 * id [I] the GUID to be converted.
922 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
929 * StringFromGUID2, CLSIDFromString
931 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
937 if ((ret = CoGetMalloc(0,&mllc)))
940 ret=WINE_StringFromCLSID(id,buf);
942 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
943 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
944 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
949 /******************************************************************************
950 * StringFromGUID2 [OLE32.@]
951 * StringFromGUID2 [COMPOBJ.76]
953 * Modified version of StringFromCLSID that allows you to specify max
957 * id [I] GUID to convert to string.
958 * str [O] Buffer where the result will be stored.
959 * cmax [I] Size of the buffer in characters.
962 * Success: The length of the resulting string in characters.
965 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
969 if (WINE_StringFromCLSID(id,xguid))
971 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
974 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
975 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
977 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
978 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
982 strcpyW(path, wszCLSIDSlash);
983 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
984 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
985 if (res == ERROR_FILE_NOT_FOUND)
986 return REGDB_E_CLASSNOTREG;
987 else if (res != ERROR_SUCCESS)
988 return REGDB_E_READREGDB;
996 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
998 if (res == ERROR_FILE_NOT_FOUND)
999 return REGDB_E_KEYMISSING;
1000 else if (res != ERROR_SUCCESS)
1001 return REGDB_E_READREGDB;
1006 /******************************************************************************
1007 * ProgIDFromCLSID [OLE32.@]
1009 * Converts a class id into the respective program ID.
1012 * clsid [I] Class ID, as found in registry.
1013 * lplpszProgID [O] Associated ProgID.
1018 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1020 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1022 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1027 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1031 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1032 ret = REGDB_E_CLASSNOTREG;
1036 *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1039 if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen))
1040 ret = REGDB_E_CLASSNOTREG;
1043 ret = E_OUTOFMEMORY;
1050 /******************************************************************************
1051 * CLSIDFromProgID [OLE32.@]
1053 * Converts a program id into the respective GUID.
1056 * progid [I] Unicode program ID, as found in registry.
1057 * riid [O] Associated CLSID.
1061 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1063 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1065 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1066 WCHAR buf2[CHARS_IN_GUID];
1067 LONG buf2len = sizeof(buf2);
1070 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1071 strcpyW( buf, progid );
1072 strcatW( buf, clsidW );
1073 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1075 HeapFree(GetProcessHeap(),0,buf);
1076 return CO_E_CLASSSTRING;
1078 HeapFree(GetProcessHeap(),0,buf);
1080 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1083 return CO_E_CLASSSTRING;
1086 return CLSIDFromString(buf2,riid);
1090 /*****************************************************************************
1091 * CoGetPSClsid [OLE32.@]
1093 * Retrieves the CLSID of the proxy/stub factory that implements
1094 * IPSFactoryBuffer for the specified interface.
1097 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1098 * pclsid [O] Where to store returned proxy/stub CLSID.
1103 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1107 * The standard marshaller activates the object with the CLSID
1108 * returned and uses the CreateProxy and CreateStub methods on its
1109 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1112 * CoGetPSClsid determines this CLSID by searching the
1113 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1114 * in the registry and any interface id registered by
1115 * CoRegisterPSClsid within the current process.
1119 * We only search the registry, not ids registered with
1120 * CoRegisterPSClsid.
1121 * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1122 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1123 * considered a bug in native unless an application depends on this (unlikely).
1125 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1127 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1128 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1129 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1130 WCHAR value[CHARS_IN_GUID];
1134 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1136 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1137 strcpyW(path, wszInterface);
1138 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1139 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1141 /* Open the key.. */
1142 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1144 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1145 return REGDB_E_IIDNOTREG;
1148 /* ... Once we have the key, query the registry to get the
1149 value of CLSID as a string, and convert it into a
1150 proper CLSID structure to be passed back to the app */
1151 len = sizeof(value);
1152 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1155 return REGDB_E_IIDNOTREG;
1159 /* We have the CLSid we want back from the registry as a string, so
1160 lets convert it into a CLSID structure */
1161 if (CLSIDFromString(value, pclsid) != NOERROR)
1162 return REGDB_E_IIDNOTREG;
1164 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1170 /***********************************************************************
1171 * WriteClassStm (OLE32.@)
1173 * Writes a CLSID to a stream.
1176 * pStm [I] Stream to write to.
1177 * rclsid [I] CLSID to write.
1181 * Failure: HRESULT code.
1183 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1185 TRACE("(%p,%p)\n",pStm,rclsid);
1188 return E_INVALIDARG;
1190 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1193 /***********************************************************************
1194 * ReadClassStm (OLE32.@)
1196 * Reads a CLSID from a stream.
1199 * pStm [I] Stream to read from.
1200 * rclsid [O] CLSID to read.
1204 * Failure: HRESULT code.
1206 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1211 TRACE("(%p,%p)\n",pStm,pclsid);
1214 return E_INVALIDARG;
1216 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1221 if (nbByte != sizeof(CLSID))
1229 * COM_GetRegisteredClassObject
1231 * This internal method is used to scan the registered class list to
1232 * find a class object.
1235 * rclsid Class ID of the class to find.
1236 * dwClsContext Class context to match.
1237 * ppv [out] returns a pointer to the class object. Complying
1238 * to normal COM usage, this method will increase the
1239 * reference count on this object.
1241 static HRESULT COM_GetRegisteredClassObject(
1246 HRESULT hr = S_FALSE;
1247 RegisteredClass* curClass;
1249 EnterCriticalSection( &csRegisteredClassList );
1257 * Iterate through the whole list and try to match the class ID.
1259 curClass = firstRegisteredClass;
1261 while (curClass != 0)
1264 * Check if we have a match on the class ID.
1266 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1269 * Since we don't do out-of process or DCOM just right away, let's ignore the
1274 * We have a match, return the pointer to the class object.
1276 *ppUnk = curClass->classObject;
1278 IUnknown_AddRef(curClass->classObject);
1285 * Step to the next class in the list.
1287 curClass = curClass->nextClass;
1291 LeaveCriticalSection( &csRegisteredClassList );
1293 * If we get to here, we haven't found our class.
1298 /******************************************************************************
1299 * CoRegisterClassObject [OLE32.@]
1301 * Registers the class object for a given class ID. Servers housed in EXE
1302 * files use this method instead of exporting DllGetClassObject to allow
1303 * other code to connect to their objects.
1306 * rclsid [I] CLSID of the object to register.
1307 * pUnk [I] IUnknown of the object.
1308 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1309 * flags [I] REGCLS flags indicating how connections are made.
1310 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1314 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1315 * CO_E_OBJISREG if the object is already registered. We should not return this.
1318 * CoRevokeClassObject, CoGetClassObject
1321 * MSDN claims that multiple interface registrations are legal, but we
1322 * can't do that with our current implementation.
1324 HRESULT WINAPI CoRegisterClassObject(
1329 LPDWORD lpdwRegister)
1331 RegisteredClass* newClass;
1332 LPUNKNOWN foundObject;
1335 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1336 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1338 if ( (lpdwRegister==0) || (pUnk==0) )
1339 return E_INVALIDARG;
1341 if (!COM_CurrentApt())
1343 ERR("COM was not initialized\n");
1344 return CO_E_NOTINITIALIZED;
1350 * First, check if the class is already registered.
1351 * If it is, this should cause an error.
1353 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1355 if (flags & REGCLS_MULTIPLEUSE) {
1356 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1357 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1358 IUnknown_Release(foundObject);
1361 IUnknown_Release(foundObject);
1362 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1363 return CO_E_OBJISREG;
1366 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1367 if ( newClass == NULL )
1368 return E_OUTOFMEMORY;
1370 EnterCriticalSection( &csRegisteredClassList );
1372 newClass->classIdentifier = *rclsid;
1373 newClass->runContext = dwClsContext;
1374 newClass->connectFlags = flags;
1375 newClass->pMarshaledData = NULL;
1378 * Use the address of the chain node as the cookie since we are sure it's
1379 * unique. FIXME: not on 64-bit platforms.
1381 newClass->dwCookie = (DWORD)newClass;
1382 newClass->nextClass = firstRegisteredClass;
1385 * Since we're making a copy of the object pointer, we have to increase its
1388 newClass->classObject = pUnk;
1389 IUnknown_AddRef(newClass->classObject);
1391 firstRegisteredClass = newClass;
1392 LeaveCriticalSection( &csRegisteredClassList );
1394 *lpdwRegister = newClass->dwCookie;
1396 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1397 IClassFactory *classfac;
1399 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1400 (LPVOID*)&classfac);
1403 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1405 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1406 IUnknown_Release(classfac);
1409 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1410 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1411 MSHLFLAGS_TABLESTRONG);
1413 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1414 IUnknown_Release(classfac);
1418 IUnknown_Release(classfac);
1420 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1425 /***********************************************************************
1426 * CoRevokeClassObject [OLE32.@]
1428 * Removes a class object from the class registry.
1431 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1435 * Failure: HRESULT code.
1438 * CoRegisterClassObject
1440 HRESULT WINAPI CoRevokeClassObject(
1443 HRESULT hr = E_INVALIDARG;
1444 RegisteredClass** prevClassLink;
1445 RegisteredClass* curClass;
1447 TRACE("(%08lx)\n",dwRegister);
1449 EnterCriticalSection( &csRegisteredClassList );
1452 * Iterate through the whole list and try to match the cookie.
1454 curClass = firstRegisteredClass;
1455 prevClassLink = &firstRegisteredClass;
1457 while (curClass != 0)
1460 * Check if we have a match on the cookie.
1462 if (curClass->dwCookie == dwRegister)
1465 * Remove the class from the chain.
1467 *prevClassLink = curClass->nextClass;
1470 * Release the reference to the class object.
1472 IUnknown_Release(curClass->classObject);
1474 if (curClass->pMarshaledData)
1477 memset(&zero, 0, sizeof(zero));
1478 /* FIXME: stop local server thread */
1479 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1480 CoReleaseMarshalData(curClass->pMarshaledData);
1484 * Free the memory used by the chain node.
1486 HeapFree(GetProcessHeap(), 0, curClass);
1493 * Step to the next class in the list.
1495 prevClassLink = &(curClass->nextClass);
1496 curClass = curClass->nextClass;
1500 LeaveCriticalSection( &csRegisteredClassList );
1502 * If we get to here, we haven't found our class.
1507 /***********************************************************************
1508 * COM_RegReadPath [internal]
1510 * Reads a registry value and expands it when necessary
1512 HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1517 WCHAR src[MAX_PATH];
1518 DWORD dwLength = dstlen * sizeof(WCHAR);
1520 if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1521 if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1522 if (keytype == REG_EXPAND_SZ) {
1523 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1525 lstrcpynW(dst, src, dstlen);
1533 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1536 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1537 DllGetClassObjectFunc DllGetClassObject;
1538 WCHAR dllpath[MAX_PATH+1];
1540 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1542 /* failure: CLSID is not found in registry */
1543 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1544 return REGDB_E_CLASSNOTREG;
1547 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1549 /* failure: DLL could not be loaded */
1550 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1551 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1554 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1556 /* failure: the dll did not export DllGetClassObject */
1557 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1558 FreeLibrary( hLibrary );
1559 return CO_E_DLLNOTFOUND;
1562 /* OK: get the ClassObject */
1563 COMPOBJ_DLLList_Add( hLibrary );
1564 return DllGetClassObject(rclsid, riid, ppv);
1567 /***********************************************************************
1568 * CoGetClassObject [OLE32.@]
1570 * FIXME. If request allows of several options and there is a failure
1571 * with one (other than not being registered) do we try the
1572 * others or return failure? (E.g. inprocess is registered but
1573 * the DLL is not found but the server version works)
1575 HRESULT WINAPI CoGetClassObject(
1576 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1577 REFIID iid, LPVOID *ppv)
1579 LPUNKNOWN regClassObject;
1580 HRESULT hres = E_UNEXPECTED;
1582 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1585 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1586 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1590 * First, try and see if we can't match the class ID with one of the
1591 * registered classes.
1593 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1595 /* Get the required interface from the retrieved pointer. */
1596 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1599 * Since QI got another reference on the pointer, we want to release the
1600 * one we already have. If QI was unsuccessful, this will release the object. This
1601 * is good since we are not returning it in the "out" parameter.
1603 IUnknown_Release(regClassObject);
1608 /* First try in-process server */
1609 if (CLSCTX_INPROC_SERVER & dwClsContext)
1611 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1614 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1617 if (hres == REGDB_E_CLASSNOTREG)
1618 ERR("class %s not registered\n", debugstr_guid(rclsid));
1620 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1623 if (SUCCEEDED(hres))
1625 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1629 /* return if we got a class, otherwise fall through to one of the
1631 if (SUCCEEDED(hres))
1635 /* Next try in-process handler */
1636 if (CLSCTX_INPROC_HANDLER & dwClsContext)
1638 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1641 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1644 if (hres == REGDB_E_CLASSNOTREG)
1645 ERR("class %s not registered\n", debugstr_guid(rclsid));
1647 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1650 if (SUCCEEDED(hres))
1652 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1656 /* return if we got a class, otherwise fall through to one of the
1658 if (SUCCEEDED(hres))
1662 /* Next try out of process */
1663 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1665 return RPC_GetLocalClassObject(rclsid,iid,ppv);
1668 /* Finally try remote: this requires networked DCOM (a lot of work) */
1669 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1671 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1672 hres = E_NOINTERFACE;
1676 ERR("no class object %s could be created for for context 0x%lx\n",
1677 debugstr_guid(rclsid), dwClsContext);
1681 /***********************************************************************
1682 * CoResumeClassObjects (OLE32.@)
1684 * Resumes all class objects registered with REGCLS_SUSPENDED.
1688 * Failure: HRESULT code.
1690 HRESULT WINAPI CoResumeClassObjects(void)
1696 /***********************************************************************
1697 * GetClassFile (OLE32.@)
1699 * This function supplies the CLSID associated with the given filename.
1701 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1705 int nbElm, length, i;
1707 LPOLESTR *pathDec=0,absFile=0,progId=0;
1709 static const WCHAR bkslashW[] = {'\\',0};
1710 static const WCHAR dotW[] = {'.',0};
1712 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1714 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1715 if((StgIsStorageFile(filePathName))==S_OK){
1717 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1720 res=ReadClassStg(pstg,pclsid);
1722 IStorage_Release(pstg);
1726 /* if the file is not a storage object then attemps to match various bits in the file against a
1727 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1730 for(i=0;i<nFileTypes;i++)
1732 for(i=0;j<nPatternsForType;j++){
1737 pat=ReadPatternFromRegistry(i,j);
1738 hFile=CreateFileW(filePathName,,,,,,hFile);
1739 SetFilePosition(hFile,pat.offset);
1740 ReadFile(hFile,buf,pat.size,&r,NULL);
1741 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1743 *pclsid=ReadCLSIDFromRegistry(i);
1749 /* if the above strategies fail then search for the extension key in the registry */
1751 /* get the last element (absolute file) in the path name */
1752 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1753 absFile=pathDec[nbElm-1];
1755 /* failed if the path represente a directory and not an absolute file name*/
1756 if (!lstrcmpW(absFile, bkslashW))
1757 return MK_E_INVALIDEXTENSION;
1759 /* get the extension of the file */
1761 length=lstrlenW(absFile);
1762 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1765 if (!extension || !lstrcmpW(extension, dotW))
1766 return MK_E_INVALIDEXTENSION;
1768 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1770 /* get the progId associated to the extension */
1771 progId = CoTaskMemAlloc(sizeProgId);
1772 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1774 if (res==ERROR_SUCCESS)
1775 /* return the clsid associated to the progId */
1776 res= CLSIDFromProgID(progId,pclsid);
1778 for(i=0; pathDec[i]!=NULL;i++)
1779 CoTaskMemFree(pathDec[i]);
1780 CoTaskMemFree(pathDec);
1782 CoTaskMemFree(progId);
1784 if (res==ERROR_SUCCESS)
1787 return MK_E_INVALIDEXTENSION;
1790 /***********************************************************************
1791 * CoCreateInstance [OLE32.@]
1793 HRESULT WINAPI CoCreateInstance(
1795 LPUNKNOWN pUnkOuter,
1801 LPCLASSFACTORY lpclf = 0;
1803 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
1804 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
1806 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1815 * Initialize the "out" parameter
1820 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1821 * Rather than create a class factory, we can just check for it here
1823 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1824 if (StdGlobalInterfaceTableInstance == NULL)
1825 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1826 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1827 if (hres) return hres;
1829 TRACE("Retrieved GIT (%p)\n", *ppv);
1834 * Get a class factory to construct the object we want.
1836 hres = CoGetClassObject(rclsid,
1843 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1844 debugstr_guid(rclsid),hres);
1849 * Create the object and don't forget to release the factory
1851 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1852 IClassFactory_Release(lpclf);
1854 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1855 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1860 /***********************************************************************
1861 * CoCreateInstanceEx [OLE32.@]
1863 HRESULT WINAPI CoCreateInstanceEx(
1865 LPUNKNOWN pUnkOuter,
1867 COSERVERINFO* pServerInfo,
1871 IUnknown* pUnk = NULL;
1874 ULONG successCount = 0;
1879 if ( (cmq==0) || (pResults==NULL))
1880 return E_INVALIDARG;
1882 if (pServerInfo!=NULL)
1883 FIXME("() non-NULL pServerInfo not supported!\n");
1886 * Initialize all the "out" parameters.
1888 for (index = 0; index < cmq; index++)
1890 pResults[index].pItf = NULL;
1891 pResults[index].hr = E_NOINTERFACE;
1895 * Get the object and get its IUnknown pointer.
1897 hr = CoCreateInstance(rclsid,
1907 * Then, query for all the interfaces requested.
1909 for (index = 0; index < cmq; index++)
1911 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1912 pResults[index].pIID,
1913 (VOID**)&(pResults[index].pItf));
1915 if (pResults[index].hr == S_OK)
1920 * Release our temporary unknown pointer.
1922 IUnknown_Release(pUnk);
1924 if (successCount == 0)
1925 return E_NOINTERFACE;
1927 if (successCount!=cmq)
1928 return CO_S_NOTALLINTERFACES;
1933 /***********************************************************************
1934 * CoLoadLibrary (OLE32.@)
1939 * lpszLibName [I] Path to library.
1940 * bAutoFree [I] Whether the library should automatically be freed.
1943 * Success: Handle to loaded library.
1947 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1949 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1951 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1953 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1956 /***********************************************************************
1957 * CoFreeLibrary [OLE32.@]
1959 * Unloads a library from memory.
1962 * hLibrary [I] Handle to library to unload.
1968 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1970 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1972 FreeLibrary(hLibrary);
1976 /***********************************************************************
1977 * CoFreeAllLibraries [OLE32.@]
1979 * Function for backwards compatibility only. Does nothing.
1985 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1987 void WINAPI CoFreeAllLibraries(void)
1993 /***********************************************************************
1994 * CoFreeUnusedLibraries [OLE32.@]
1995 * CoFreeUnusedLibraries [COMPOBJ.17]
1997 * Frees any unused libraries. Unused are identified as those that return
1998 * S_OK from their DllCanUnloadNow function.
2004 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2006 void WINAPI CoFreeUnusedLibraries(void)
2008 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2009 * through the main apartment's thread to call DllCanUnloadNow */
2010 COMPOBJ_DllList_FreeUnused(0);
2013 /***********************************************************************
2014 * CoFileTimeNow [OLE32.@]
2015 * CoFileTimeNow [COMPOBJ.82]
2017 * Retrieves the current time in FILETIME format.
2020 * lpFileTime [O] The current time.
2025 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2027 GetSystemTimeAsFileTime( lpFileTime );
2031 static void COM_RevokeAllClasses()
2033 EnterCriticalSection( &csRegisteredClassList );
2035 while (firstRegisteredClass!=0)
2037 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2040 LeaveCriticalSection( &csRegisteredClassList );
2043 /******************************************************************************
2044 * CoLockObjectExternal [OLE32.@]
2046 * Increments or decrements the external reference count of a stub object.
2049 * pUnk [I] Stub object.
2050 * fLock [I] If TRUE then increments the external ref-count,
2051 * otherwise decrements.
2052 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2053 * calling CoDisconnectObject.
2057 * Failure: HRESULT code.
2059 HRESULT WINAPI CoLockObjectExternal(
2062 BOOL fLastUnlockReleases)
2064 struct stub_manager *stubmgr;
2065 struct apartment *apt;
2067 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2068 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2070 apt = COM_CurrentApt();
2071 if (!apt) return CO_E_NOTINITIALIZED;
2073 stubmgr = get_stub_manager_from_object(apt, pUnk);
2078 stub_manager_ext_addref(stubmgr, 1);
2080 stub_manager_ext_release(stubmgr, 1);
2082 stub_manager_int_release(stubmgr);
2088 WARN("stub object not found %p\n", pUnk);
2089 /* Note: native is pretty broken here because it just silently
2090 * fails, without returning an appropriate error code, making apps
2091 * think that the object was disconnected, when it actually wasn't */
2096 /***********************************************************************
2097 * CoInitializeWOW (OLE32.@)
2099 * WOW equivalent of CoInitialize?
2108 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2110 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2114 /***********************************************************************
2115 * CoGetState [OLE32.@]
2117 * Retrieves the thread state object previously stored by CoSetState().
2120 * ppv [I] Address where pointer to object will be stored.
2124 * Failure: E_OUTOFMEMORY.
2127 * Crashes on all invalid ppv addresses, including NULL.
2128 * If the function returns a non-NULL object then the caller must release its
2129 * reference on the object when the object is no longer required.
2134 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2136 struct oletls *info = COM_CurrentInfo();
2137 if (!info) return E_OUTOFMEMORY;
2143 IUnknown_AddRef(info->state);
2145 TRACE("apt->state=%p\n", info->state);
2151 /***********************************************************************
2152 * CoSetState [OLE32.@]
2154 * Sets the thread state object.
2157 * pv [I] Pointer to state object to be stored.
2160 * The system keeps a reference on the object while the object stored.
2164 * Failure: E_OUTOFMEMORY.
2166 HRESULT WINAPI CoSetState(IUnknown * pv)
2168 struct oletls *info = COM_CurrentInfo();
2169 if (!info) return E_OUTOFMEMORY;
2171 if (pv) IUnknown_AddRef(pv);
2175 TRACE("-- release %p now\n", info->state);
2176 IUnknown_Release(info->state);
2185 /******************************************************************************
2186 * OleGetAutoConvert [OLE32.@]
2188 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2190 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2192 WCHAR buf[CHARS_IN_GUID];
2196 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2201 if (RegQueryValueW(hkey, NULL, buf, &len))
2203 res = REGDB_E_KEYMISSING;
2206 res = CLSIDFromString(buf, pClsidNew);
2208 if (hkey) RegCloseKey(hkey);
2212 /******************************************************************************
2213 * CoTreatAsClass [OLE32.@]
2215 * Sets the TreatAs value of a class.
2218 * clsidOld [I] Class to set TreatAs value on.
2219 * clsidNew [I] The class the clsidOld should be treated as.
2223 * Failure: HRESULT code.
2228 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2230 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2231 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2233 WCHAR szClsidNew[CHARS_IN_GUID];
2235 WCHAR auto_treat_as[CHARS_IN_GUID];
2236 LONG auto_treat_as_size = sizeof(auto_treat_as);
2239 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2242 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2244 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2245 !CLSIDFromString(auto_treat_as, &id))
2247 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2249 res = REGDB_E_WRITEREGDB;
2255 RegDeleteKeyW(hkey, wszTreatAs);
2259 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2260 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2262 res = REGDB_E_WRITEREGDB;
2267 if (hkey) RegCloseKey(hkey);
2271 /******************************************************************************
2272 * CoGetTreatAsClass [OLE32.@]
2274 * Gets the TreatAs value of a class.
2277 * clsidOld [I] Class to get the TreatAs value of.
2278 * clsidNew [I] The class the clsidOld should be treated as.
2282 * Failure: HRESULT code.
2287 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2289 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2291 WCHAR szClsidNew[CHARS_IN_GUID];
2293 LONG len = sizeof(szClsidNew);
2295 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2296 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2298 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2301 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2306 res = CLSIDFromString(szClsidNew,clsidNew);
2308 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2310 if (hkey) RegCloseKey(hkey);
2314 /******************************************************************************
2315 * CoGetCurrentProcess [OLE32.@]
2316 * CoGetCurrentProcess [COMPOBJ.34]
2318 * Gets the current process ID.
2321 * The current process ID.
2324 * Is DWORD really the correct return type for this function?
2326 DWORD WINAPI CoGetCurrentProcess(void)
2328 return GetCurrentProcessId();
2331 /******************************************************************************
2332 * CoRegisterMessageFilter [OLE32.@]
2334 * Registers a message filter.
2337 * lpMessageFilter [I] Pointer to interface.
2338 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2342 * Failure: HRESULT code.
2344 HRESULT WINAPI CoRegisterMessageFilter(
2345 LPMESSAGEFILTER lpMessageFilter,
2346 LPMESSAGEFILTER *lplpMessageFilter)
2349 if (lplpMessageFilter) {
2350 *lplpMessageFilter = NULL;
2355 /***********************************************************************
2356 * CoIsOle1Class [OLE32.@]
2358 * Determines whether the specified class an OLE v1 class.
2361 * clsid [I] Class to test.
2364 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2366 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2368 FIXME("%s\n", debugstr_guid(clsid));
2372 /***********************************************************************
2373 * IsEqualGUID [OLE32.@]
2375 * Compares two Unique Identifiers.
2378 * rguid1 [I] The first GUID to compare.
2379 * rguid2 [I] The other GUID to compare.
2385 BOOL WINAPI IsEqualGUID(
2389 return !memcmp(rguid1,rguid2,sizeof(GUID));
2392 /***********************************************************************
2393 * CoInitializeSecurity [OLE32.@]
2395 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2396 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2397 void* pReserved1, DWORD dwAuthnLevel,
2398 DWORD dwImpLevel, void* pReserved2,
2399 DWORD dwCapabilities, void* pReserved3)
2401 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2402 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2403 dwCapabilities, pReserved3);
2407 /***********************************************************************
2408 * CoSuspendClassObjects [OLE32.@]
2410 * Suspends all registered class objects to prevent further requests coming in
2411 * for those objects.
2415 * Failure: HRESULT code.
2417 HRESULT WINAPI CoSuspendClassObjects(void)
2423 /***********************************************************************
2424 * CoAddRefServerProcess [OLE32.@]
2426 * Helper function for incrementing the reference count of a local-server
2430 * New reference count.
2432 ULONG WINAPI CoAddRefServerProcess(void)
2438 /***********************************************************************
2439 * CoReleaseServerProcess [OLE32.@]
2441 * Helper function for decrementing the reference count of a local-server
2445 * New reference count.
2447 ULONG WINAPI CoReleaseServerProcess(void)
2453 /***********************************************************************
2454 * CoIsHandlerConnected [OLE32.@]
2456 * Determines whether a proxy is connected to a remote stub.
2459 * pUnk [I] Pointer to object that may or may not be connected.
2462 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2465 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2467 FIXME("%p\n", pUnk);
2472 /***********************************************************************
2473 * CoAllowSetForegroundWindow [OLE32.@]
2476 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2478 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2482 /***********************************************************************
2483 * CoQueryProxyBlanket [OLE32.@]
2485 * Retrieves the security settings being used by a proxy.
2488 * pProxy [I] Pointer to the proxy object.
2489 * pAuthnSvc [O] The type of authentication service.
2490 * pAuthzSvc [O] The type of authorization service.
2491 * ppServerPrincName [O] Optional. The server prinicple name.
2492 * pAuthnLevel [O] The authentication level.
2493 * pImpLevel [O] The impersonation level.
2494 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2495 * pCapabilities [O] Flags affecting the security behaviour.
2499 * Failure: HRESULT code.
2502 * CoCopyProxy, CoSetProxyBlanket.
2504 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2505 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2506 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2508 IClientSecurity *pCliSec;
2511 TRACE("%p\n", pProxy);
2513 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2516 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2517 pAuthzSvc, ppServerPrincName,
2518 pAuthnLevel, pImpLevel, ppAuthInfo,
2520 IClientSecurity_Release(pCliSec);
2523 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2527 /***********************************************************************
2528 * CoSetProxyBlanket [OLE32.@]
2530 * Sets the security settings for a proxy.
2533 * pProxy [I] Pointer to the proxy object.
2534 * AuthnSvc [I] The type of authentication service.
2535 * AuthzSvc [I] The type of authorization service.
2536 * pServerPrincName [I] The server prinicple name.
2537 * AuthnLevel [I] The authentication level.
2538 * ImpLevel [I] The impersonation level.
2539 * pAuthInfo [I] Information specific to the authorization/authentication service.
2540 * Capabilities [I] Flags affecting the security behaviour.
2544 * Failure: HRESULT code.
2547 * CoQueryProxyBlanket, CoCopyProxy.
2549 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2550 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2551 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2553 IClientSecurity *pCliSec;
2556 TRACE("%p\n", pProxy);
2558 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2561 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2562 AuthzSvc, pServerPrincName,
2563 AuthnLevel, ImpLevel, pAuthInfo,
2565 IClientSecurity_Release(pCliSec);
2568 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2572 /***********************************************************************
2573 * CoCopyProxy [OLE32.@]
2578 * pProxy [I] Pointer to the proxy object.
2579 * ppCopy [O] Copy of the proxy.
2583 * Failure: HRESULT code.
2586 * CoQueryProxyBlanket, CoSetProxyBlanket.
2588 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2590 IClientSecurity *pCliSec;
2593 TRACE("%p\n", pProxy);
2595 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2598 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2599 IClientSecurity_Release(pCliSec);
2602 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2607 /***********************************************************************
2608 * CoWaitForMultipleHandles [OLE32.@]
2610 * Waits for one or more handles to become signaled.
2613 * dwFlags [I] Flags. See notes.
2614 * dwTimeout [I] Timeout in milliseconds.
2615 * cHandles [I] Number of handles pointed to by pHandles.
2616 * pHandles [I] Handles to wait for.
2617 * lpdwindex [O] Index of handle that was signaled.
2621 * Failure: RPC_S_CALLPENDING on timeout.
2625 * The dwFlags parameter can be zero or more of the following:
2626 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2627 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2630 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2632 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2633 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2636 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2637 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2638 DWORD start_time = GetTickCount();
2640 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2641 pHandles, lpdwindex);
2645 DWORD now = GetTickCount();
2648 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2650 hr = RPC_S_CALLPENDING;
2654 TRACE("waiting for rpc completion or window message\n");
2656 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2657 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2658 QS_ALLINPUT, wait_flags);
2660 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2663 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2665 /* FIXME: filter the messages here */
2666 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2667 TranslateMessage(&msg);
2668 DispatchMessageW(&msg);
2669 if (msg.message == WM_QUIT)
2671 TRACE("resending WM_QUIT to outer message loop\n");
2672 PostQuitMessage(msg.wParam);
2677 else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2679 /* handle signaled, store index */
2680 *lpdwindex = (res - WAIT_OBJECT_0);
2683 else if (res == WAIT_TIMEOUT)
2685 hr = RPC_S_CALLPENDING;
2690 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2696 TRACE("-- 0x%08lx\n", hr);
2700 /***********************************************************************
2703 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2705 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2708 case DLL_PROCESS_ATTACH:
2709 OLE32_hInstance = hinstDLL;
2710 COMPOBJ_InitProcess();
2711 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2714 case DLL_PROCESS_DETACH:
2715 if (TRACE_ON(ole)) CoRevokeMallocSpy();
2716 COMPOBJ_UninitProcess();
2717 OLE32_hInstance = 0;
2720 case DLL_THREAD_DETACH:
2727 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */