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
67 #include "wine/unicode.h"
69 #include "compobj_private.h"
71 #include "wine/debug.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(ole);
75 typedef LPCSTR LPCOLESTR16;
77 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
79 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
81 /****************************************************************************
82 * This section defines variables internal to the COM module.
84 * TODO: Most of these things will have to be made thread-safe.
87 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
88 static void COM_RevokeAllClasses(void);
90 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
92 APARTMENT *MTA; /* protected by csApartment */
93 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
95 static CRITICAL_SECTION csApartment;
96 static CRITICAL_SECTION_DEBUG critsect_debug =
99 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
100 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
102 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
105 * This lock count counts the number of times CoInitialize is called. It is
106 * decreased every time CoUninitialize is called. When it hits 0, the COM
107 * libraries are freed
109 static LONG s_COMLockCount = 0;
112 * This linked list contains the list of registered class objects. These
113 * are mostly used to register the factories for out-of-proc servers of OLE
116 * TODO: Make this data structure aware of inter-process communication. This
117 * means that parts of this will be exported to the Wine Server.
119 typedef struct tagRegisteredClass
121 CLSID classIdentifier;
122 LPUNKNOWN classObject;
126 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
127 struct tagRegisteredClass* nextClass;
130 static RegisteredClass* firstRegisteredClass = NULL;
132 static CRITICAL_SECTION csRegisteredClassList;
133 static CRITICAL_SECTION_DEBUG class_cs_debug =
135 0, 0, &csRegisteredClassList,
136 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
137 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
139 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
141 /*****************************************************************************
142 * This section contains OpenDllList definitions
144 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
145 * other functions that do LoadLibrary _without_ giving back a HMODULE.
146 * Without this list these handles would never be freed.
148 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
149 * next unload-call but not before 600 sec.
152 typedef struct tagOpenDll {
154 struct tagOpenDll *next;
157 static OpenDll *openDllList = NULL; /* linked list of open dlls */
159 static CRITICAL_SECTION csOpenDllList;
160 static CRITICAL_SECTION_DEBUG dll_cs_debug =
162 0, 0, &csOpenDllList,
163 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
164 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
166 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
168 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
169 '0','x','#','#','#','#','#','#','#','#',' ',0};
170 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
172 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
173 static void COMPOBJ_DllList_FreeUnused(int Timeout);
175 static void COMPOBJ_InitProcess( void )
179 /* Dispatching to the correct thread in an apartment is done through
180 * window messages rather than RPC transports. When an interface is
181 * marshalled into another apartment in the same process, a window of the
182 * following class is created. The *caller* of CoMarshalInterface (ie the
183 * application) is responsible for pumping the message loop in that thread.
184 * The WM_USER messages which point to the RPCs are then dispatched to
185 * COM_AptWndProc by the user's code from the apartment in which the interface
188 memset(&wclass, 0, sizeof(wclass));
189 wclass.lpfnWndProc = apartment_wndproc;
190 wclass.hInstance = OLE32_hInstance;
191 wclass.lpszClassName = wszAptWinClass;
192 RegisterClassW(&wclass);
195 static void COMPOBJ_UninitProcess( void )
197 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
200 static void COM_TlsDestroy(void)
202 struct oletls *info = NtCurrentTeb()->ReservedForOle;
205 if (info->apt) apartment_release(info->apt);
206 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
207 if (info->state) IUnknown_Release(info->state);
208 HeapFree(GetProcessHeap(), 0, info);
209 NtCurrentTeb()->ReservedForOle = NULL;
213 /******************************************************************************
217 /* allocates memory and fills in the necessary fields for a new apartment
219 static APARTMENT *apartment_construct(DWORD model)
223 TRACE("creating new apartment, model=%ld\n", model);
225 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
226 apt->tid = GetCurrentThreadId();
228 list_init(&apt->proxies);
229 list_init(&apt->stubmgrs);
232 apt->remunk_exported = FALSE;
234 InitializeCriticalSection(&apt->cs);
235 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
239 if (model & COINIT_APARTMENTTHREADED)
241 /* FIXME: should be randomly generated by in an RPC call to rpcss */
242 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
243 apt->win = CreateWindowW(wszAptWinClass, NULL, 0,
245 0, 0, OLE32_hInstance, NULL);
249 /* FIXME: should be randomly generated by in an RPC call to rpcss */
250 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
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 DWORD apartment_addref(struct apartment *apt)
305 DWORD refs = InterlockedIncrement(&apt->refs);
306 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
310 DWORD apartment_release(struct apartment *apt)
314 EnterCriticalSection(&csApartment);
316 ret = InterlockedDecrement(&apt->refs);
317 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
318 /* destruction stuff that needs to happen under csApartment CS */
321 if (apt == MTA) MTA = NULL;
322 list_remove(&apt->entry);
325 LeaveCriticalSection(&csApartment);
329 struct list *cursor, *cursor2;
331 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
333 /* no locking is needed for this apartment, because no other thread
334 * can access it at this point */
336 apartment_disconnectproxies(apt);
338 if (apt->win) DestroyWindow(apt->win);
340 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
342 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
343 /* release the implicit reference given by the fact that the
344 * stub has external references (it must do since it is in the
345 * stub manager list in the apartment and all non-apartment users
346 * must have a ref on the apartment and so it cannot be destroyed).
348 stub_manager_int_release(stubmgr);
351 /* if this assert fires, then another thread took a reference to a
352 * stub manager without taking a reference to the containing
353 * apartment, which it must do. */
354 assert(list_empty(&apt->stubmgrs));
356 if (apt->filter) IUnknown_Release(apt->filter);
358 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
359 DeleteCriticalSection(&apt->cs);
361 HeapFree(GetProcessHeap(), 0, apt);
367 /* The given OXID must be local to this process:
369 * The ref parameter is here mostly to ensure people remember that
370 * they get one, you should normally take a ref for thread safety.
372 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
374 APARTMENT *result = NULL;
377 EnterCriticalSection(&csApartment);
378 LIST_FOR_EACH( cursor, &apts )
380 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
381 if (apt->oxid == oxid)
384 if (ref) apartment_addref(result);
388 LeaveCriticalSection(&csApartment);
393 /* gets the apartment which has a given creator thread ID. The caller must
394 * release the reference from the apartment as soon as the apartment pointer
395 * is no longer required. */
396 APARTMENT *apartment_findfromtid(DWORD tid)
398 APARTMENT *result = NULL;
401 EnterCriticalSection(&csApartment);
402 LIST_FOR_EACH( cursor, &apts )
404 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
408 apartment_addref(result);
412 LeaveCriticalSection(&csApartment);
417 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
422 return RPC_ExecuteCall((struct dispatch_params *)lParam);
424 return DefWindowProcW(hWnd, msg, wParam, lParam);
428 /*****************************************************************************
429 * This section contains OpenDllList implemantation
432 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
439 EnterCriticalSection( &csOpenDllList );
441 if (openDllList == NULL) {
442 /* empty list -- add first node */
443 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
444 openDllList->hLibrary=hLibrary;
445 openDllList->next = NULL;
447 /* search for this dll */
449 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
450 if (ptr->hLibrary == hLibrary) {
456 /* dll not found, add it */
458 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
459 openDllList->hLibrary = hLibrary;
460 openDllList->next = tmp;
464 LeaveCriticalSection( &csOpenDllList );
467 static void COMPOBJ_DllList_FreeUnused(int Timeout)
469 OpenDll *curr, *next, *prev = NULL;
470 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
471 DllCanUnloadNowFunc DllCanUnloadNow;
475 EnterCriticalSection( &csOpenDllList );
477 for (curr = openDllList; curr != NULL; ) {
478 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
480 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
483 TRACE("freeing %p\n", curr->hLibrary);
484 FreeLibrary(curr->hLibrary);
486 HeapFree(GetProcessHeap(), 0, curr);
487 if (curr == openDllList) {
500 LeaveCriticalSection( &csOpenDllList );
503 /******************************************************************************
504 * CoBuildVersion [OLE32.@]
505 * CoBuildVersion [COMPOBJ.1]
507 * Gets the build version of the DLL.
512 * Current build version, hiword is majornumber, loword is minornumber
514 DWORD WINAPI CoBuildVersion(void)
516 TRACE("Returning version %d, build %d.\n", rmm, rup);
517 return (rmm<<16)+rup;
520 /******************************************************************************
521 * CoInitialize [OLE32.@]
523 * Initializes the COM libraries by calling CoInitializeEx with
524 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
527 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
530 * Success: S_OK if not already initialized, S_FALSE otherwise.
531 * Failure: HRESULT code.
536 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
539 * Just delegate to the newer method.
541 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
544 /******************************************************************************
545 * CoInitializeEx [OLE32.@]
547 * Initializes the COM libraries.
550 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
551 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
554 * S_OK if successful,
555 * S_FALSE if this function was called already.
556 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
561 * The behavior used to set the IMalloc used for memory management is
563 * The dwCoInit parameter must specify of of the following apartment
565 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
566 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
567 * The parameter may also specify zero or more of the following flags:
568 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
569 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
574 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
579 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
581 if (lpReserved!=NULL)
583 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
587 * Check the lock count. If this is the first time going through the initialize
588 * process, we have to initialize the libraries.
590 * And crank-up that lock count.
592 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
595 * Initialize the various COM libraries and data structures.
597 TRACE("() - Initializing the COM libraries\n");
599 /* we may need to defer this until after apartment initialisation */
600 RunningObjectTableImpl_Initialize();
603 if (!(apt = COM_CurrentInfo()->apt))
605 apt = apartment_get_or_create(dwCoInit);
606 if (!apt) return E_OUTOFMEMORY;
608 else if (dwCoInit != apt->model)
610 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
611 code then we are probably using the wrong threading model to implement that API. */
612 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
613 return RPC_E_CHANGED_MODE;
618 COM_CurrentInfo()->inits++;
623 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
624 pending RPCs are ignored. Non-COM messages are discarded at this point.
626 static void COM_FlushMessageQueue(void)
629 APARTMENT *apt = COM_CurrentApt();
631 if (!apt || !apt->win) return;
633 TRACE("Flushing STA message queue\n");
635 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
637 if (message.hwnd != apt->win)
639 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
643 TranslateMessage(&message);
644 DispatchMessageA(&message);
648 /***********************************************************************
649 * CoUninitialize [OLE32.@]
651 * This method will decrement the refcount on the current apartment, freeing
652 * the resources associated with it if it is the last thread in the apartment.
653 * If the last apartment is freed, the function will additionally release
654 * any COM resources associated with the process.
664 void WINAPI CoUninitialize(void)
666 struct oletls * info = COM_CurrentInfo();
671 /* will only happen on OOM */
677 ERR("Mismatched CoUninitialize\n");
683 apartment_release(info->apt);
688 * Decrease the reference count.
689 * If we are back to 0 locks on the COM library, make sure we free
690 * all the associated data structures.
692 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
695 TRACE("() - Releasing the COM libraries\n");
697 RunningObjectTableImpl_UnInitialize();
699 /* Release the references to the registered class objects */
700 COM_RevokeAllClasses();
702 /* This will free the loaded COM Dlls */
703 CoFreeAllLibraries();
705 /* This ensures we deal with any pending RPCs */
706 COM_FlushMessageQueue();
708 else if (lCOMRefCnt<1) {
709 ERR( "CoUninitialize() - not CoInitialized.\n" );
710 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
714 /******************************************************************************
715 * CoDisconnectObject [OLE32.@]
716 * CoDisconnectObject [COMPOBJ.15]
718 * Disconnects all connections to this object from remote processes. Dispatches
719 * pending RPCs while blocking new RPCs from occurring, and then calls
720 * IMarshal::DisconnectObject on the given object.
722 * Typically called when the object server is forced to shut down, for instance by
726 * lpUnk [I] The object whose stub should be disconnected.
727 * reserved [I] Reserved. Should be set to 0.
731 * Failure: HRESULT code.
734 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
736 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
742 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
744 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
747 hr = IMarshal_DisconnectObject(marshal, reserved);
748 IMarshal_Release(marshal);
752 apt = COM_CurrentApt();
754 return CO_E_NOTINITIALIZED;
756 apartment_disconnectobject(apt, lpUnk);
758 /* Note: native is pretty broken here because it just silently
759 * fails, without returning an appropriate error code if the object was
760 * not found, making apps think that the object was disconnected, when
761 * it actually wasn't */
766 /******************************************************************************
767 * CoCreateGuid [OLE32.@]
769 * Simply forwards to UuidCreate in RPCRT4.
772 * pguid [O] Points to the GUID to initialize.
776 * Failure: HRESULT code.
781 HRESULT WINAPI CoCreateGuid(GUID *pguid)
783 return UuidCreate(pguid);
786 /******************************************************************************
787 * CLSIDFromString [OLE32.@]
788 * IIDFromString [OLE32.@]
790 * Converts a unique identifier from its string representation into
794 * idstr [I] The string representation of the GUID.
795 * id [O] GUID converted from the string.
799 * CO_E_CLASSSTRING if idstr is not a valid CLSID
803 * In Windows, if idstr is not a valid CLSID string then it gets
804 * treated as a ProgID. Wine currently doesn't do this. If idstr is
805 * NULL it's treated as an all-zero GUID.
810 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
817 memset( id, 0, sizeof (CLSID) );
821 /* validate the CLSID string */
822 if (strlen(idstr) != 38)
823 return CO_E_CLASSSTRING;
825 s = (const BYTE *) idstr;
826 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
827 return CO_E_CLASSSTRING;
829 for (i=1; i<37; i++) {
830 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
831 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
832 ((s[i] >= 'a') && (s[i] <= 'f')) ||
833 ((s[i] >= 'A') && (s[i] <= 'F'))))
834 return CO_E_CLASSSTRING;
837 TRACE("%s -> %p\n", s, id);
839 /* quick lookup table */
840 memset(table, 0, 256);
842 for (i = 0; i < 10; i++) {
845 for (i = 0; i < 6; i++) {
846 table['A' + i] = i+10;
847 table['a' + i] = i+10;
850 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
852 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
853 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
854 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
855 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
857 /* these are just sequential bytes */
858 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
859 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
860 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
861 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
862 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
863 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
864 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
865 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
870 /*****************************************************************************/
872 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
877 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
878 return CO_E_CLASSSTRING;
881 ret = __CLSIDFromStringA(xid,id);
882 if(ret != S_OK) { /* It appears a ProgID is also valid */
883 ret = CLSIDFromProgID(idstr, id);
888 /* Converts a GUID into the respective string representation. */
889 HRESULT WINE_StringFromCLSID(
890 const CLSID *id, /* [in] GUID to be converted */
891 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
893 static const char *hex = "0123456789ABCDEF";
898 { ERR("called with id=Null\n");
903 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
904 id->Data1, id->Data2, id->Data3,
905 id->Data4[0], id->Data4[1]);
909 for (i = 2; i < 8; i++) {
910 *s++ = hex[id->Data4[i]>>4];
911 *s++ = hex[id->Data4[i] & 0xf];
917 TRACE("%p->%s\n", id, idstr);
923 /******************************************************************************
924 * StringFromCLSID [OLE32.@]
925 * StringFromIID [OLE32.@]
927 * Converts a GUID into the respective string representation.
928 * The target string is allocated using the OLE IMalloc.
931 * id [I] the GUID to be converted.
932 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
939 * StringFromGUID2, CLSIDFromString
941 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
947 if ((ret = CoGetMalloc(0,&mllc)))
950 ret=WINE_StringFromCLSID(id,buf);
952 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
953 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
954 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
959 /******************************************************************************
960 * StringFromGUID2 [OLE32.@]
961 * StringFromGUID2 [COMPOBJ.76]
963 * Modified version of StringFromCLSID that allows you to specify max
967 * id [I] GUID to convert to string.
968 * str [O] Buffer where the result will be stored.
969 * cmax [I] Size of the buffer in characters.
972 * Success: The length of the resulting string in characters.
975 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
979 if (WINE_StringFromCLSID(id,xguid))
981 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
984 /* open HKCR\\CLSID\\{string form of clsid} key */
985 DWORD COM_OpenKeyForCLSID(REFCLSID clsid, REGSAM access, HKEY *key)
987 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
988 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
989 strcpyW(path, wszCLSIDSlash);
990 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
991 return RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, access, key);
994 /******************************************************************************
995 * ProgIDFromCLSID [OLE32.@]
997 * Converts a class id into the respective program ID.
1000 * clsid [I] Class ID, as found in registry.
1001 * lplpszProgID [O] Associated ProgID.
1006 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1008 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1010 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1015 if (ERROR_SUCCESS != COM_OpenKeyForCLSID(clsid, KEY_READ, &hkey_clsid))
1016 ret = REGDB_E_CLASSNOTREG;
1020 if (RegOpenKeyExW(hkey_clsid, wszProgID, 0, KEY_READ, &hkey))
1021 ret = REGDB_E_CLASSNOTREG;
1022 RegCloseKey(hkey_clsid);
1029 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1030 ret = REGDB_E_CLASSNOTREG;
1034 *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1037 if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen))
1038 ret = REGDB_E_CLASSNOTREG;
1041 ret = E_OUTOFMEMORY;
1049 /******************************************************************************
1050 * CLSIDFromProgID [COMPOBJ.61]
1052 * Converts a program ID into the respective GUID.
1055 * progid [I] program id as found in registry
1056 * riid [O] associated CLSID
1060 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1062 HRESULT WINAPI CLSIDFromProgID16(LPCOLESTR16 progid, LPCLSID riid)
1069 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1070 sprintf(buf,"%s\\CLSID",progid);
1071 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1072 HeapFree(GetProcessHeap(),0,buf);
1073 return CO_E_CLASSSTRING;
1075 HeapFree(GetProcessHeap(),0,buf);
1076 buf2len = sizeof(buf2);
1077 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1079 return CO_E_CLASSSTRING;
1082 return __CLSIDFromStringA(buf2,riid);
1085 /******************************************************************************
1086 * CLSIDFromProgID [OLE32.@]
1088 * Converts a program id into the respective GUID.
1091 * progid [I] Unicode program ID, as found in registry.
1092 * riid [O] Associated CLSID.
1096 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1098 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1100 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1101 WCHAR buf2[CHARS_IN_GUID];
1102 LONG buf2len = sizeof(buf2);
1105 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1106 strcpyW( buf, progid );
1107 strcatW( buf, clsidW );
1108 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1110 HeapFree(GetProcessHeap(),0,buf);
1111 return CO_E_CLASSSTRING;
1113 HeapFree(GetProcessHeap(),0,buf);
1115 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1118 return CO_E_CLASSSTRING;
1121 return CLSIDFromString(buf2,riid);
1126 /*****************************************************************************
1127 * CoGetPSClsid [OLE32.@]
1129 * Retrieves the CLSID of the proxy/stub factory that implements
1130 * IPSFactoryBuffer for the specified interface.
1133 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1134 * pclsid [O] Where to store returned proxy/stub CLSID.
1139 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1143 * The standard marshaller activates the object with the CLSID
1144 * returned and uses the CreateProxy and CreateStub methods on its
1145 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1148 * CoGetPSClsid determines this CLSID by searching the
1149 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1150 * in the registry and any interface id registered by
1151 * CoRegisterPSClsid within the current process.
1155 * We only search the registry, not ids registered with
1156 * CoRegisterPSClsid.
1157 * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1158 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1159 * considered a bug in native unless an application depends on this (unlikely).
1161 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1163 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1164 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1165 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1166 WCHAR value[CHARS_IN_GUID];
1170 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1172 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1173 strcpyW(path, wszInterface);
1174 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1175 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1177 /* Open the key.. */
1178 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1180 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1181 return REGDB_E_IIDNOTREG;
1184 /* ... Once we have the key, query the registry to get the
1185 value of CLSID as a string, and convert it into a
1186 proper CLSID structure to be passed back to the app */
1187 len = sizeof(value);
1188 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1191 return REGDB_E_IIDNOTREG;
1195 /* We have the CLSid we want back from the registry as a string, so
1196 lets convert it into a CLSID structure */
1197 if (CLSIDFromString(value, pclsid) != NOERROR)
1198 return REGDB_E_IIDNOTREG;
1200 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1206 /***********************************************************************
1207 * WriteClassStm (OLE32.@)
1209 * Writes a CLSID to a stream.
1212 * pStm [I] Stream to write to.
1213 * rclsid [I] CLSID to write.
1217 * Failure: HRESULT code.
1219 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1221 TRACE("(%p,%p)\n",pStm,rclsid);
1224 return E_INVALIDARG;
1226 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1229 /***********************************************************************
1230 * ReadClassStm (OLE32.@)
1232 * Reads a CLSID from a stream.
1235 * pStm [I] Stream to read from.
1236 * rclsid [O] CLSID to read.
1240 * Failure: HRESULT code.
1242 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1247 TRACE("(%p,%p)\n",pStm,pclsid);
1250 return E_INVALIDARG;
1252 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1257 if (nbByte != sizeof(CLSID))
1265 * COM_GetRegisteredClassObject
1267 * This internal method is used to scan the registered class list to
1268 * find a class object.
1271 * rclsid Class ID of the class to find.
1272 * dwClsContext Class context to match.
1273 * ppv [out] returns a pointer to the class object. Complying
1274 * to normal COM usage, this method will increase the
1275 * reference count on this object.
1277 static HRESULT COM_GetRegisteredClassObject(
1282 HRESULT hr = S_FALSE;
1283 RegisteredClass* curClass;
1285 EnterCriticalSection( &csRegisteredClassList );
1293 * Iterate through the whole list and try to match the class ID.
1295 curClass = firstRegisteredClass;
1297 while (curClass != 0)
1300 * Check if we have a match on the class ID.
1302 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1305 * Since we don't do out-of process or DCOM just right away, let's ignore the
1310 * We have a match, return the pointer to the class object.
1312 *ppUnk = curClass->classObject;
1314 IUnknown_AddRef(curClass->classObject);
1321 * Step to the next class in the list.
1323 curClass = curClass->nextClass;
1327 LeaveCriticalSection( &csRegisteredClassList );
1329 * If we get to here, we haven't found our class.
1334 /******************************************************************************
1335 * CoRegisterClassObject [OLE32.@]
1337 * Registers the class object for a given class ID. Servers housed in EXE
1338 * files use this method instead of exporting DllGetClassObject to allow
1339 * other code to connect to their objects.
1342 * rclsid [I] CLSID of the object to register.
1343 * pUnk [I] IUnknown of the object.
1344 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1345 * flags [I] REGCLS flags indicating how connections are made.
1346 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1350 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1351 * CO_E_OBJISREG if the object is already registered. We should not return this.
1354 * CoRevokeClassObject, CoGetClassObject
1357 * MSDN claims that multiple interface registrations are legal, but we
1358 * can't do that with our current implementation.
1360 HRESULT WINAPI CoRegisterClassObject(
1365 LPDWORD lpdwRegister)
1367 RegisteredClass* newClass;
1368 LPUNKNOWN foundObject;
1371 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1372 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1374 if ( (lpdwRegister==0) || (pUnk==0) )
1375 return E_INVALIDARG;
1377 if (!COM_CurrentApt())
1379 ERR("COM was not initialized\n");
1380 return CO_E_NOTINITIALIZED;
1386 * First, check if the class is already registered.
1387 * If it is, this should cause an error.
1389 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1391 IUnknown_Release(foundObject);
1392 return CO_E_OBJISREG;
1395 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1396 if ( newClass == NULL )
1397 return E_OUTOFMEMORY;
1399 EnterCriticalSection( &csRegisteredClassList );
1401 newClass->classIdentifier = *rclsid;
1402 newClass->runContext = dwClsContext;
1403 newClass->connectFlags = flags;
1404 newClass->pMarshaledData = NULL;
1407 * Use the address of the chain node as the cookie since we are sure it's
1408 * unique. FIXME: not on 64-bit platforms.
1410 newClass->dwCookie = (DWORD)newClass;
1411 newClass->nextClass = firstRegisteredClass;
1414 * Since we're making a copy of the object pointer, we have to increase its
1417 newClass->classObject = pUnk;
1418 IUnknown_AddRef(newClass->classObject);
1420 firstRegisteredClass = newClass;
1421 LeaveCriticalSection( &csRegisteredClassList );
1423 *lpdwRegister = newClass->dwCookie;
1425 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1426 IClassFactory *classfac;
1428 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1429 (LPVOID*)&classfac);
1432 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1434 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1435 IUnknown_Release(classfac);
1438 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1439 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1440 MSHLFLAGS_TABLESTRONG);
1442 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1443 IUnknown_Release(classfac);
1447 IUnknown_Release(classfac);
1449 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1454 /***********************************************************************
1455 * CoRevokeClassObject [OLE32.@]
1457 * Removes a class object from the class registry.
1460 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1464 * Failure: HRESULT code.
1467 * CoRegisterClassObject
1469 HRESULT WINAPI CoRevokeClassObject(
1472 HRESULT hr = E_INVALIDARG;
1473 RegisteredClass** prevClassLink;
1474 RegisteredClass* curClass;
1476 TRACE("(%08lx)\n",dwRegister);
1478 EnterCriticalSection( &csRegisteredClassList );
1481 * Iterate through the whole list and try to match the cookie.
1483 curClass = firstRegisteredClass;
1484 prevClassLink = &firstRegisteredClass;
1486 while (curClass != 0)
1489 * Check if we have a match on the cookie.
1491 if (curClass->dwCookie == dwRegister)
1494 * Remove the class from the chain.
1496 *prevClassLink = curClass->nextClass;
1499 * Release the reference to the class object.
1501 IUnknown_Release(curClass->classObject);
1503 if (curClass->pMarshaledData)
1506 memset(&zero, 0, sizeof(zero));
1507 /* FIXME: stop local server thread */
1508 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1509 CoReleaseMarshalData(curClass->pMarshaledData);
1513 * Free the memory used by the chain node.
1515 HeapFree(GetProcessHeap(), 0, curClass);
1522 * Step to the next class in the list.
1524 prevClassLink = &(curClass->nextClass);
1525 curClass = curClass->nextClass;
1529 LeaveCriticalSection( &csRegisteredClassList );
1531 * If we get to here, we haven't found our class.
1536 /***********************************************************************
1537 * COM_RegReadPath [internal]
1539 * Reads a registry value and expands it when necessary
1541 HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1546 WCHAR src[MAX_PATH];
1547 DWORD dwLength = dstlen * sizeof(WCHAR);
1549 if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1550 if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1551 if (keytype == REG_EXPAND_SZ) {
1552 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1554 lstrcpynW(dst, src, dstlen);
1562 /***********************************************************************
1563 * CoGetClassObject [OLE32.@]
1565 * FIXME. If request allows of several options and there is a failure
1566 * with one (other than not being registered) do we try the
1567 * others or return failure? (E.g. inprocess is registered but
1568 * the DLL is not found but the server version works)
1570 HRESULT WINAPI CoGetClassObject(
1571 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1572 REFIID iid, LPVOID *ppv)
1574 LPUNKNOWN regClassObject;
1575 HRESULT hres = E_UNEXPECTED;
1577 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1580 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1581 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1585 * First, try and see if we can't match the class ID with one of the
1586 * registered classes.
1588 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1590 /* Get the required interface from the retrieved pointer. */
1591 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1594 * Since QI got another reference on the pointer, we want to release the
1595 * one we already have. If QI was unsuccessful, this will release the object. This
1596 * is good since we are not returning it in the "out" parameter.
1598 IUnknown_Release(regClassObject);
1603 /* first try: in-process */
1604 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext)
1606 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1608 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1609 DllGetClassObjectFunc DllGetClassObject;
1610 WCHAR dllpath[MAX_PATH+1];
1613 if (ERROR_SUCCESS != COM_OpenKeyForCLSID(rclsid, KEY_READ, &hkey))
1615 ERR("class %s not registered\n", debugstr_guid(rclsid));
1616 hres = REGDB_E_CLASSNOTREG;
1619 if (COM_RegReadPath(hkey, wszInprocServer32, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1621 /* failure: CLSID is not found in registry */
1622 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1623 hres = REGDB_E_CLASSNOTREG;
1627 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1629 /* failure: DLL could not be loaded */
1630 ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(dllpath));
1631 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1633 else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1635 /* failure: the dll did not export DllGetClassObject */
1636 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1637 FreeLibrary( hLibrary );
1638 hres = CO_E_DLLNOTFOUND;
1642 /* OK: get the ClassObject */
1643 COMPOBJ_DLLList_Add( hLibrary );
1644 return DllGetClassObject(rclsid, iid, ppv);
1649 /* Next try out of process */
1650 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1652 return RPC_GetLocalClassObject(rclsid,iid,ppv);
1655 /* Finally try remote: this requires networked DCOM (a lot of work) */
1656 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1658 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1659 hres = E_NOINTERFACE;
1665 /***********************************************************************
1666 * CoGetClassObject [COMPOBJ.7]
1669 HRESULT WINAPI CoGetClassObject16(
1670 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1671 REFIID iid, LPVOID *ppv)
1673 FIXME(", stub!\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1676 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1677 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
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 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1812 * Initialize the "out" parameter
1817 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1818 * Rather than create a class factory, we can just check for it here
1820 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1821 if (StdGlobalInterfaceTableInstance == NULL)
1822 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1823 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1824 if (hres) return hres;
1826 TRACE("Retrieved GIT (%p)\n", *ppv);
1831 * Get a class factory to construct the object we want.
1833 hres = CoGetClassObject(rclsid,
1840 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1841 debugstr_guid(rclsid),hres);
1846 * Create the object and don't forget to release the factory
1848 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1849 IClassFactory_Release(lpclf);
1851 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1852 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1857 /***********************************************************************
1858 * CoCreateInstance [COMPOBJ.13]
1860 HRESULT WINAPI CoCreateInstance16(
1862 LPUNKNOWN pUnkOuter,
1867 FIXME("(%s, %p, %lx, %s, %p), stub!\n",
1868 debugstr_guid(rclsid), pUnkOuter, dwClsContext, debugstr_guid(iid),
1874 /***********************************************************************
1875 * CoCreateInstanceEx [OLE32.@]
1877 HRESULT WINAPI CoCreateInstanceEx(
1879 LPUNKNOWN pUnkOuter,
1881 COSERVERINFO* pServerInfo,
1885 IUnknown* pUnk = NULL;
1888 ULONG successCount = 0;
1893 if ( (cmq==0) || (pResults==NULL))
1894 return E_INVALIDARG;
1896 if (pServerInfo!=NULL)
1897 FIXME("() non-NULL pServerInfo not supported!\n");
1900 * Initialize all the "out" parameters.
1902 for (index = 0; index < cmq; index++)
1904 pResults[index].pItf = NULL;
1905 pResults[index].hr = E_NOINTERFACE;
1909 * Get the object and get its IUnknown pointer.
1911 hr = CoCreateInstance(rclsid,
1921 * Then, query for all the interfaces requested.
1923 for (index = 0; index < cmq; index++)
1925 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1926 pResults[index].pIID,
1927 (VOID**)&(pResults[index].pItf));
1929 if (pResults[index].hr == S_OK)
1934 * Release our temporary unknown pointer.
1936 IUnknown_Release(pUnk);
1938 if (successCount == 0)
1939 return E_NOINTERFACE;
1941 if (successCount!=cmq)
1942 return CO_S_NOTALLINTERFACES;
1947 /***********************************************************************
1948 * CoLoadLibrary (OLE32.@)
1953 * lpszLibName [I] Path to library.
1954 * bAutoFree [I] Whether the library should automatically be freed.
1957 * Success: Handle to loaded library.
1961 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1963 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1965 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1967 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1970 /***********************************************************************
1971 * CoFreeLibrary [OLE32.@]
1973 * Unloads a library from memory.
1976 * hLibrary [I] Handle to library to unload.
1982 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1984 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1986 FreeLibrary(hLibrary);
1990 /***********************************************************************
1991 * CoFreeAllLibraries [OLE32.@]
1993 * Function for backwards compatibility only. Does nothing.
1999 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2001 void WINAPI CoFreeAllLibraries(void)
2007 /***********************************************************************
2008 * CoFreeUnusedLibraries [OLE32.@]
2009 * CoFreeUnusedLibraries [COMPOBJ.17]
2011 * Frees any unused libraries. Unused are identified as those that return
2012 * S_OK from their DllCanUnloadNow function.
2018 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2020 void WINAPI CoFreeUnusedLibraries(void)
2022 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2023 * through the main apartment's thread to call DllCanUnloadNow */
2024 COMPOBJ_DllList_FreeUnused(0);
2027 /***********************************************************************
2028 * CoFileTimeNow [OLE32.@]
2029 * CoFileTimeNow [COMPOBJ.82]
2031 * Retrieves the current time in FILETIME format.
2034 * lpFileTime [O] The current time.
2039 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2041 GetSystemTimeAsFileTime( lpFileTime );
2045 static void COM_RevokeAllClasses()
2047 EnterCriticalSection( &csRegisteredClassList );
2049 while (firstRegisteredClass!=0)
2051 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2054 LeaveCriticalSection( &csRegisteredClassList );
2057 /******************************************************************************
2058 * CoLockObjectExternal [OLE32.@]
2060 * Increments or decrements the external reference count of a stub object.
2063 * pUnk [I] Stub object.
2064 * fLock [I] If TRUE then increments the external ref-count,
2065 * otherwise decrements.
2066 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2067 * calling CoDisconnectObject.
2071 * Failure: HRESULT code.
2073 HRESULT WINAPI CoLockObjectExternal(
2076 BOOL fLastUnlockReleases)
2078 struct stub_manager *stubmgr;
2079 struct apartment *apt;
2081 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2082 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2084 apt = COM_CurrentApt();
2085 if (!apt) return CO_E_NOTINITIALIZED;
2087 stubmgr = get_stub_manager_from_object(apt, pUnk);
2092 stub_manager_ext_addref(stubmgr, 1);
2094 stub_manager_ext_release(stubmgr, 1);
2096 stub_manager_int_release(stubmgr);
2102 WARN("stub object not found %p\n", pUnk);
2103 /* Note: native is pretty broken here because it just silently
2104 * fails, without returning an appropriate error code, making apps
2105 * think that the object was disconnected, when it actually wasn't */
2110 /***********************************************************************
2111 * CoInitializeWOW (OLE32.@)
2113 * WOW equivalent of CoInitialize?
2122 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2124 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2128 /***********************************************************************
2129 * CoGetState [OLE32.@]
2131 * Retrieves the thread state object previously stored by CoSetState().
2134 * ppv [I] Address where pointer to object will be stored.
2138 * Failure: E_OUTOFMEMORY.
2141 * Crashes on all invalid ppv addresses, including NULL.
2142 * If the function returns a non-NULL object then the caller must release its
2143 * reference on the object when the object is no longer required.
2148 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2150 struct oletls *info = COM_CurrentInfo();
2151 if (!info) return E_OUTOFMEMORY;
2157 IUnknown_AddRef(info->state);
2159 TRACE("apt->state=%p\n", info->state);
2165 /***********************************************************************
2166 * CoSetState [OLE32.@]
2168 * Sets the thread state object.
2171 * pv [I] Pointer to state object to be stored.
2174 * The system keeps a reference on the object while the object stored.
2178 * Failure: E_OUTOFMEMORY.
2180 HRESULT WINAPI CoSetState(IUnknown * pv)
2182 struct oletls *info = COM_CurrentInfo();
2183 if (!info) return E_OUTOFMEMORY;
2185 if (pv) IUnknown_AddRef(pv);
2189 TRACE("-- release %p now\n", info->state);
2190 IUnknown_Release(info->state);
2199 /******************************************************************************
2200 * OleGetAutoConvert [OLE32.@]
2202 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2204 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2206 WCHAR buf[CHARS_IN_GUID];
2210 if (ERROR_SUCCESS != COM_OpenKeyForCLSID(clsidOld, KEY_READ, &hkey))
2212 res = REGDB_E_CLASSNOTREG;
2217 /* we can just query for the default value of AutoConvertTo key like that,
2218 without opening the AutoConvertTo key and querying for NULL (default) */
2219 if (RegQueryValueW(hkey, wszAutoConvertTo, buf, &len))
2221 res = REGDB_E_KEYMISSING;
2224 res = CLSIDFromString(buf, pClsidNew);
2226 if (hkey) RegCloseKey(hkey);
2230 /******************************************************************************
2231 * CoTreatAsClass [OLE32.@]
2233 * Sets the TreatAs value of a class.
2236 * clsidOld [I] Class to set TreatAs value on.
2237 * clsidNew [I] The class the clsidOld should be treated as.
2241 * Failure: HRESULT code.
2246 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2248 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2249 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2251 WCHAR szClsidNew[CHARS_IN_GUID];
2253 WCHAR auto_treat_as[CHARS_IN_GUID];
2254 LONG auto_treat_as_size = sizeof(auto_treat_as);
2257 if (ERROR_SUCCESS != COM_OpenKeyForCLSID(clsidOld, KEY_READ | KEY_WRITE, &hkey))
2259 res = REGDB_E_CLASSNOTREG;
2262 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2264 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2265 !CLSIDFromString(auto_treat_as, &id))
2267 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2269 res = REGDB_E_WRITEREGDB;
2275 RegDeleteKeyW(hkey, wszTreatAs);
2279 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2280 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2282 res = REGDB_E_WRITEREGDB;
2287 if (hkey) RegCloseKey(hkey);
2291 /******************************************************************************
2292 * CoGetTreatAsClass [OLE32.@]
2294 * Gets the TreatAs value of a class.
2297 * clsidOld [I] Class to get the TreatAs value of.
2298 * clsidNew [I] The class the clsidOld should be treated as.
2302 * Failure: HRESULT code.
2307 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2309 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2311 WCHAR szClsidNew[CHARS_IN_GUID];
2313 LONG len = sizeof(szClsidNew);
2315 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2316 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2318 if (COM_OpenKeyForCLSID(clsidOld, KEY_READ, &hkey))
2320 res = REGDB_E_CLASSNOTREG;
2323 if (RegQueryValueW(hkey, wszTreatAs, szClsidNew, &len))
2328 res = CLSIDFromString(szClsidNew,clsidNew);
2330 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2332 if (hkey) RegCloseKey(hkey);
2336 /******************************************************************************
2337 * CoGetCurrentProcess [OLE32.@]
2338 * CoGetCurrentProcess [COMPOBJ.34]
2340 * Gets the current process ID.
2343 * The current process ID.
2346 * Is DWORD really the correct return type for this function?
2348 DWORD WINAPI CoGetCurrentProcess(void)
2350 return GetCurrentProcessId();
2353 /******************************************************************************
2354 * CoRegisterMessageFilter [OLE32.@]
2356 * Registers a message filter.
2359 * lpMessageFilter [I] Pointer to interface.
2360 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2364 * Failure: HRESULT code.
2366 HRESULT WINAPI CoRegisterMessageFilter(
2367 LPMESSAGEFILTER lpMessageFilter,
2368 LPMESSAGEFILTER *lplpMessageFilter)
2371 if (lplpMessageFilter) {
2372 *lplpMessageFilter = NULL;
2377 /***********************************************************************
2378 * CoIsOle1Class [OLE32.@]
2380 * Determines whether the specified class an OLE v1 class.
2383 * clsid [I] Class to test.
2386 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2388 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2390 FIXME("%s\n", debugstr_guid(clsid));
2394 /***********************************************************************
2395 * IsEqualGUID [OLE32.@]
2397 * Compares two Unique Identifiers.
2400 * rguid1 [I] The first GUID to compare.
2401 * rguid2 [I] The other GUID to compare.
2407 BOOL WINAPI IsEqualGUID(
2411 return !memcmp(rguid1,rguid2,sizeof(GUID));
2414 /***********************************************************************
2415 * CoInitializeSecurity [OLE32.@]
2417 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2418 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2419 void* pReserved1, DWORD dwAuthnLevel,
2420 DWORD dwImpLevel, void* pReserved2,
2421 DWORD dwCapabilities, void* pReserved3)
2423 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2424 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2425 dwCapabilities, pReserved3);
2429 /***********************************************************************
2430 * CoSuspendClassObjects [OLE32.@]
2432 * Suspends all registered class objects to prevent further requests coming in
2433 * for those objects.
2437 * Failure: HRESULT code.
2439 HRESULT WINAPI CoSuspendClassObjects(void)
2445 /***********************************************************************
2446 * CoAddRefServerProcess [OLE32.@]
2448 * Helper function for incrementing the reference count of a local-server
2452 * New reference count.
2454 ULONG WINAPI CoAddRefServerProcess(void)
2460 /***********************************************************************
2461 * CoReleaseServerProcess [OLE32.@]
2463 * Helper function for decrementing the reference count of a local-server
2467 * New reference count.
2469 ULONG WINAPI CoReleaseServerProcess(void)
2475 /***********************************************************************
2476 * CoIsHandlerConnected [OLE32.@]
2478 * Determines whether a proxy is connected to a remote stub.
2481 * pUnk [I] Pointer to object that may or may not be connected.
2484 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2487 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2489 FIXME("%p\n", pUnk);
2494 /***********************************************************************
2495 * CoAllowSetForegroundWindow [OLE32.@]
2498 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2500 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2504 /***********************************************************************
2505 * CoQueryProxyBlanket [OLE32.@]
2507 * Retrieves the security settings being used by a proxy.
2510 * pProxy [I] Pointer to the proxy object.
2511 * pAuthnSvc [O] The type of authentication service.
2512 * pAuthzSvc [O] The type of authorization service.
2513 * ppServerPrincName [O] Optional. The server prinicple name.
2514 * pAuthnLevel [O] The authentication level.
2515 * pImpLevel [O] The impersonation level.
2516 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2517 * pCapabilities [O] Flags affecting the security behaviour.
2521 * Failure: HRESULT code.
2524 * CoCopyProxy, CoSetProxyBlanket.
2526 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2527 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2528 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2530 IClientSecurity *pCliSec;
2533 TRACE("%p\n", pProxy);
2535 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2538 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2539 pAuthzSvc, ppServerPrincName,
2540 pAuthnLevel, pImpLevel, ppAuthInfo,
2542 IClientSecurity_Release(pCliSec);
2545 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2549 /***********************************************************************
2550 * CoSetProxyBlanket [OLE32.@]
2552 * Sets the security settings for a proxy.
2555 * pProxy [I] Pointer to the proxy object.
2556 * AuthnSvc [I] The type of authentication service.
2557 * AuthzSvc [I] The type of authorization service.
2558 * pServerPrincName [I] The server prinicple name.
2559 * AuthnLevel [I] The authentication level.
2560 * ImpLevel [I] The impersonation level.
2561 * pAuthInfo [I] Information specific to the authorization/authentication service.
2562 * Capabilities [I] Flags affecting the security behaviour.
2566 * Failure: HRESULT code.
2569 * CoQueryProxyBlanket, CoCopyProxy.
2571 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2572 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2573 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2575 IClientSecurity *pCliSec;
2578 TRACE("%p\n", pProxy);
2580 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2583 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2584 AuthzSvc, pServerPrincName,
2585 AuthnLevel, ImpLevel, pAuthInfo,
2587 IClientSecurity_Release(pCliSec);
2590 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2594 /***********************************************************************
2595 * CoCopyProxy [OLE32.@]
2600 * pProxy [I] Pointer to the proxy object.
2601 * ppCopy [O] Copy of the proxy.
2605 * Failure: HRESULT code.
2608 * CoQueryProxyBlanket, CoSetProxyBlanket.
2610 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2612 IClientSecurity *pCliSec;
2615 TRACE("%p\n", pProxy);
2617 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2620 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2621 IClientSecurity_Release(pCliSec);
2624 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2629 /***********************************************************************
2630 * CoWaitForMultipleHandles [OLE32.@]
2632 * Waits for one or more handles to become signaled.
2635 * dwFlags [I] Flags. See notes.
2636 * dwTimeout [I] Timeout in milliseconds.
2637 * cHandles [I] Number of handles pointed to by pHandles.
2638 * pHandles [I] Handles to wait for.
2639 * lpdwindex [O] Index of handle that was signaled.
2643 * Failure: RPC_S_CALLPENDING on timeout.
2647 * The dwFlags parameter can be zero or more of the following:
2648 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2649 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2652 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2654 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2655 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2658 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2659 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2660 DWORD start_time = GetTickCount();
2662 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2663 pHandles, lpdwindex);
2667 DWORD now = GetTickCount();
2670 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2672 hr = RPC_S_CALLPENDING;
2676 TRACE("waiting for rpc completion or window message\n");
2678 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2679 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2680 QS_ALLINPUT, wait_flags);
2682 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2685 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2687 /* FIXME: filter the messages here */
2688 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2689 TranslateMessage(&msg);
2690 DispatchMessageW(&msg);
2693 else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2695 /* handle signaled, store index */
2696 *lpdwindex = (res - WAIT_OBJECT_0);
2699 else if (res == WAIT_TIMEOUT)
2701 hr = RPC_S_CALLPENDING;
2706 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2711 TRACE("-- 0x%08lx\n", hr);
2715 /***********************************************************************
2718 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2720 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2723 case DLL_PROCESS_ATTACH:
2724 OLE32_hInstance = hinstDLL;
2725 COMPOBJ_InitProcess();
2726 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2729 case DLL_PROCESS_DETACH:
2730 if (TRACE_ON(ole)) CoRevokeMallocSpy();
2731 COMPOBJ_UninitProcess();
2732 OLE32_hInstance = 0;
2735 case DLL_THREAD_DETACH:
2742 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */