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, { 0, (DWORD)(__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, { 0, (DWORD)(__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, { 0, (DWORD)(__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();
227 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
228 GetCurrentProcess(), &apt->thread,
229 THREAD_ALL_ACCESS, FALSE, 0);
231 list_init(&apt->proxies);
232 list_init(&apt->stubmgrs);
235 apt->remunk_exported = FALSE;
237 InitializeCriticalSection(&apt->cs);
238 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
242 if (model & COINIT_APARTMENTTHREADED)
244 /* FIXME: should be randomly generated by in an RPC call to rpcss */
245 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
246 apt->win = CreateWindowW(wszAptWinClass, NULL, 0,
248 0, 0, OLE32_hInstance, NULL);
252 /* FIXME: should be randomly generated by in an RPC call to rpcss */
253 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
256 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
258 /* the locking here is not currently needed for the MTA case, but it
259 * doesn't hurt and makes the code simpler */
260 EnterCriticalSection(&csApartment);
261 list_add_head(&apts, &apt->entry);
262 LeaveCriticalSection(&csApartment);
267 /* gets and existing apartment if one exists or otherwise creates an apartment
268 * structure which stores OLE apartment-local information and stores a pointer
269 * to it in the thread-local storage */
270 static APARTMENT *apartment_get_or_create(DWORD model)
272 APARTMENT *apt = COM_CurrentApt();
276 if (model & COINIT_APARTMENTTHREADED)
278 apt = apartment_construct(model);
279 COM_CurrentInfo()->apt = apt;
283 EnterCriticalSection(&csApartment);
285 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
286 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
290 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
291 apartment_addref(MTA);
294 MTA = apartment_construct(model);
297 COM_CurrentInfo()->apt = apt;
299 LeaveCriticalSection(&csApartment);
306 DWORD apartment_addref(struct apartment *apt)
308 DWORD refs = InterlockedIncrement(&apt->refs);
309 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
313 DWORD apartment_release(struct apartment *apt)
317 EnterCriticalSection(&csApartment);
319 ret = InterlockedDecrement(&apt->refs);
320 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
321 /* destruction stuff that needs to happen under csApartment CS */
324 if (apt == MTA) MTA = NULL;
325 list_remove(&apt->entry);
328 LeaveCriticalSection(&csApartment);
332 struct list *cursor, *cursor2;
334 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
336 /* no locking is needed for this apartment, because no other thread
337 * can access it at this point */
339 apartment_disconnectproxies(apt);
341 if (apt->win) DestroyWindow(apt->win);
343 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
345 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
346 /* release the implicit reference given by the fact that the
347 * stub has external references (it must do since it is in the
348 * stub manager list in the apartment and all non-apartment users
349 * must have a ref on the apartment and so it cannot be destroyed).
351 stub_manager_int_release(stubmgr);
354 /* if this assert fires, then another thread took a reference to a
355 * stub manager without taking a reference to the containing
356 * apartment, which it must do. */
357 assert(list_empty(&apt->stubmgrs));
359 if (apt->filter) IUnknown_Release(apt->filter);
361 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
362 DeleteCriticalSection(&apt->cs);
363 CloseHandle(apt->thread);
365 HeapFree(GetProcessHeap(), 0, apt);
371 /* The given OXID must be local to this process:
373 * The ref parameter is here mostly to ensure people remember that
374 * they get one, you should normally take a ref for thread safety.
376 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
378 APARTMENT *result = NULL;
381 EnterCriticalSection(&csApartment);
382 LIST_FOR_EACH( cursor, &apts )
384 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
385 if (apt->oxid == oxid)
388 if (ref) apartment_addref(result);
392 LeaveCriticalSection(&csApartment);
397 /* gets the apartment which has a given creator thread ID. The caller must
398 * release the reference from the apartment as soon as the apartment pointer
399 * is no longer required. */
400 APARTMENT *apartment_findfromtid(DWORD tid)
402 APARTMENT *result = NULL;
405 EnterCriticalSection(&csApartment);
406 LIST_FOR_EACH( cursor, &apts )
408 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
412 apartment_addref(result);
416 LeaveCriticalSection(&csApartment);
421 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
426 return RPC_ExecuteCall((struct dispatch_params *)lParam);
428 return DefWindowProcW(hWnd, msg, wParam, lParam);
432 /*****************************************************************************
433 * This section contains OpenDllList implemantation
436 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
443 EnterCriticalSection( &csOpenDllList );
445 if (openDllList == NULL) {
446 /* empty list -- add first node */
447 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
448 openDllList->hLibrary=hLibrary;
449 openDllList->next = NULL;
451 /* search for this dll */
453 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
454 if (ptr->hLibrary == hLibrary) {
460 /* dll not found, add it */
462 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
463 openDllList->hLibrary = hLibrary;
464 openDllList->next = tmp;
468 LeaveCriticalSection( &csOpenDllList );
471 static void COMPOBJ_DllList_FreeUnused(int Timeout)
473 OpenDll *curr, *next, *prev = NULL;
474 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
475 DllCanUnloadNowFunc DllCanUnloadNow;
479 EnterCriticalSection( &csOpenDllList );
481 for (curr = openDllList; curr != NULL; ) {
482 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
484 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
487 TRACE("freeing %p\n", curr->hLibrary);
488 FreeLibrary(curr->hLibrary);
490 HeapFree(GetProcessHeap(), 0, curr);
491 if (curr == openDllList) {
504 LeaveCriticalSection( &csOpenDllList );
507 /******************************************************************************
508 * CoBuildVersion [OLE32.@]
509 * CoBuildVersion [COMPOBJ.1]
511 * Gets the build version of the DLL.
516 * Current build version, hiword is majornumber, loword is minornumber
518 DWORD WINAPI CoBuildVersion(void)
520 TRACE("Returning version %d, build %d.\n", rmm, rup);
521 return (rmm<<16)+rup;
524 /******************************************************************************
525 * CoInitialize [OLE32.@]
527 * Initializes the COM libraries by calling CoInitializeEx with
528 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
531 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
534 * Success: S_OK if not already initialized, S_FALSE otherwise.
535 * Failure: HRESULT code.
540 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
543 * Just delegate to the newer method.
545 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
548 /******************************************************************************
549 * CoInitializeEx [OLE32.@]
551 * Initializes the COM libraries.
554 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
555 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
558 * S_OK if successful,
559 * S_FALSE if this function was called already.
560 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
565 * The behavior used to set the IMalloc used for memory management is
567 * The dwCoInit parameter must specify of of the following apartment
569 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
570 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
571 * The parameter may also specify zero or more of the following flags:
572 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
573 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
578 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
583 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
585 if (lpReserved!=NULL)
587 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
591 * Check the lock count. If this is the first time going through the initialize
592 * process, we have to initialize the libraries.
594 * And crank-up that lock count.
596 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
599 * Initialize the various COM libraries and data structures.
601 TRACE("() - Initializing the COM libraries\n");
603 /* we may need to defer this until after apartment initialisation */
604 RunningObjectTableImpl_Initialize();
607 if (!(apt = COM_CurrentInfo()->apt))
609 apt = apartment_get_or_create(dwCoInit);
610 if (!apt) return E_OUTOFMEMORY;
612 else if (dwCoInit != apt->model)
614 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
615 code then we are probably using the wrong threading model to implement that API. */
616 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
617 return RPC_E_CHANGED_MODE;
622 COM_CurrentInfo()->inits++;
627 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
628 pending RPCs are ignored. Non-COM messages are discarded at this point.
630 static void COM_FlushMessageQueue(void)
633 APARTMENT *apt = COM_CurrentApt();
635 if (!apt || !apt->win) return;
637 TRACE("Flushing STA message queue\n");
639 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
641 if (message.hwnd != apt->win)
643 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
647 TranslateMessage(&message);
648 DispatchMessageA(&message);
652 /***********************************************************************
653 * CoUninitialize [OLE32.@]
655 * This method will decrement the refcount on the current apartment, freeing
656 * the resources associated with it if it is the last thread in the apartment.
657 * If the last apartment is freed, the function will additionally release
658 * any COM resources associated with the process.
668 void WINAPI CoUninitialize(void)
670 struct oletls * info = COM_CurrentInfo();
675 /* will only happen on OOM */
681 ERR("Mismatched CoUninitialize\n");
687 apartment_release(info->apt);
692 * Decrease the reference count.
693 * If we are back to 0 locks on the COM library, make sure we free
694 * all the associated data structures.
696 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
699 TRACE("() - Releasing the COM libraries\n");
701 RunningObjectTableImpl_UnInitialize();
703 /* Release the references to the registered class objects */
704 COM_RevokeAllClasses();
706 /* This will free the loaded COM Dlls */
707 CoFreeAllLibraries();
709 /* This ensures we deal with any pending RPCs */
710 COM_FlushMessageQueue();
712 else if (lCOMRefCnt<1) {
713 ERR( "CoUninitialize() - not CoInitialized.\n" );
714 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
718 /******************************************************************************
719 * CoDisconnectObject [OLE32.@]
720 * CoDisconnectObject [COMPOBJ.15]
722 * Disconnects all connections to this object from remote processes. Dispatches
723 * pending RPCs while blocking new RPCs from occurring, and then calls
724 * IMarshal::DisconnectObject on the given object.
726 * Typically called when the object server is forced to shut down, for instance by
730 * lpUnk [I] The object whose stub should be disconnected.
731 * reserved [I] Reserved. Should be set to 0.
735 * Failure: HRESULT code.
738 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
740 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
746 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
748 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
751 hr = IMarshal_DisconnectObject(marshal, reserved);
752 IMarshal_Release(marshal);
756 apt = COM_CurrentApt();
758 return CO_E_NOTINITIALIZED;
760 apartment_disconnectobject(apt, lpUnk);
762 /* Note: native is pretty broken here because it just silently
763 * fails, without returning an appropriate error code if the object was
764 * not found, making apps think that the object was disconnected, when
765 * it actually wasn't */
770 /******************************************************************************
771 * CoCreateGuid [OLE32.@]
773 * Simply forwards to UuidCreate in RPCRT4.
776 * pguid [O] Points to the GUID to initialize.
780 * Failure: HRESULT code.
785 HRESULT WINAPI CoCreateGuid(GUID *pguid)
787 return UuidCreate(pguid);
790 /******************************************************************************
791 * CLSIDFromString [OLE32.@]
792 * IIDFromString [OLE32.@]
794 * Converts a unique identifier from its string representation into
798 * idstr [I] The string representation of the GUID.
799 * id [O] GUID converted from the string.
803 * CO_E_CLASSSTRING if idstr is not a valid CLSID
807 * In Windows, if idstr is not a valid CLSID string then it gets
808 * treated as a ProgID. Wine currently doesn't do this. If idstr is
809 * NULL it's treated as an all-zero GUID.
814 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
816 const BYTE *s = (const BYTE *) idstr;
821 s = "{00000000-0000-0000-0000-000000000000}";
822 else { /* validate the CLSID string */
825 return CO_E_CLASSSTRING;
827 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
828 return CO_E_CLASSSTRING;
830 for (i=1; i<37; i++) {
831 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
832 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
833 ((s[i] >= 'a') && (s[i] <= 'f')) ||
834 ((s[i] >= 'A') && (s[i] <= 'F'))))
835 return CO_E_CLASSSTRING;
839 TRACE("%s -> %p\n", s, id);
841 /* quick lookup table */
842 memset(table, 0, 256);
844 for (i = 0; i < 10; i++) {
847 for (i = 0; i < 6; i++) {
848 table['A' + i] = i+10;
849 table['a' + i] = i+10;
852 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
854 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
855 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
856 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
857 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
859 /* these are just sequential bytes */
860 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
861 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
862 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
863 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
864 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
865 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
866 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
867 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
872 /*****************************************************************************/
874 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
879 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
880 return CO_E_CLASSSTRING;
883 ret = __CLSIDFromStringA(xid,id);
884 if(ret != S_OK) { /* It appears a ProgID is also valid */
885 ret = CLSIDFromProgID(idstr, id);
890 /* Converts a GUID into the respective string representation. */
891 HRESULT WINE_StringFromCLSID(
892 const CLSID *id, /* [in] GUID to be converted */
893 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
895 static const char *hex = "0123456789ABCDEF";
900 { ERR("called with id=Null\n");
905 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
906 id->Data1, id->Data2, id->Data3,
907 id->Data4[0], id->Data4[1]);
911 for (i = 2; i < 8; i++) {
912 *s++ = hex[id->Data4[i]>>4];
913 *s++ = hex[id->Data4[i] & 0xf];
919 TRACE("%p->%s\n", id, idstr);
925 /******************************************************************************
926 * StringFromCLSID [OLE32.@]
927 * StringFromIID [OLE32.@]
929 * Converts a GUID into the respective string representation.
930 * The target string is allocated using the OLE IMalloc.
933 * id [I] the GUID to be converted.
934 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
941 * StringFromGUID2, CLSIDFromString
943 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
949 if ((ret = CoGetMalloc(0,&mllc)))
952 ret=WINE_StringFromCLSID(id,buf);
954 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
955 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
956 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
961 /******************************************************************************
962 * StringFromGUID2 [OLE32.@]
963 * StringFromGUID2 [COMPOBJ.76]
965 * Modified version of StringFromCLSID that allows you to specify max
969 * id [I] GUID to convert to string.
970 * str [O] Buffer where the result will be stored.
971 * cmax [I] Size of the buffer in characters.
974 * Success: The length of the resulting string in characters.
977 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
981 if (WINE_StringFromCLSID(id,xguid))
983 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
986 /* open HKCR\\CLSID\\{string form of clsid} key */
987 DWORD COM_OpenKeyForCLSID(REFCLSID clsid, REGSAM access, HKEY *key)
989 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
990 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
991 strcpyW(path, wszCLSIDSlash);
992 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
993 return RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, access, key);
996 /******************************************************************************
997 * ProgIDFromCLSID [OLE32.@]
999 * Converts a class id into the respective program ID.
1002 * clsid [I] Class ID, as found in registry.
1003 * lplpszProgID [O] Associated ProgID.
1008 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1010 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1012 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1017 if (ERROR_SUCCESS != COM_OpenKeyForCLSID(clsid, KEY_READ, &hkey_clsid))
1018 ret = REGDB_E_CLASSNOTREG;
1022 if (RegOpenKeyExW(hkey_clsid, wszProgID, 0, KEY_READ, &hkey))
1023 ret = REGDB_E_CLASSNOTREG;
1024 RegCloseKey(hkey_clsid);
1029 DWORD progidlen = 0;
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;
1051 /******************************************************************************
1052 * CLSIDFromProgID [COMPOBJ.61]
1054 * Converts a program ID into the respective GUID.
1057 * progid [I] program id as found in registry
1058 * riid [O] associated CLSID
1062 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1064 HRESULT WINAPI CLSIDFromProgID16(LPCOLESTR16 progid, LPCLSID riid)
1071 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1072 sprintf(buf,"%s\\CLSID",progid);
1073 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1074 HeapFree(GetProcessHeap(),0,buf);
1075 return CO_E_CLASSSTRING;
1077 HeapFree(GetProcessHeap(),0,buf);
1078 buf2len = sizeof(buf2);
1079 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1081 return CO_E_CLASSSTRING;
1084 return __CLSIDFromStringA(buf2,riid);
1087 /******************************************************************************
1088 * CLSIDFromProgID [OLE32.@]
1090 * Converts a program id into the respective GUID.
1093 * progid [I] Unicode program ID, as found in registry.
1094 * riid [O] Associated CLSID.
1098 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1100 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1102 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1103 WCHAR buf2[CHARS_IN_GUID];
1104 DWORD buf2len = sizeof(buf2);
1107 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1108 strcpyW( buf, progid );
1109 strcatW( buf, clsidW );
1110 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1112 HeapFree(GetProcessHeap(),0,buf);
1113 return CO_E_CLASSSTRING;
1115 HeapFree(GetProcessHeap(),0,buf);
1117 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1120 return CO_E_CLASSSTRING;
1123 return CLSIDFromString(buf2,riid);
1128 /*****************************************************************************
1129 * CoGetPSClsid [OLE32.@]
1131 * Retrieves the CLSID of the proxy/stub factory that implements
1132 * IPSFactoryBuffer for the specified interface.
1135 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1136 * pclsid [O] Where to store returned proxy/stub CLSID.
1141 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1145 * The standard marshaller activates the object with the CLSID
1146 * returned and uses the CreateProxy and CreateStub methods on its
1147 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1150 * CoGetPSClsid determines this CLSID by searching the
1151 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1152 * in the registry and any interface id registered by
1153 * CoRegisterPSClsid within the current process.
1157 * We only search the registry, not ids registered with
1158 * CoRegisterPSClsid.
1159 * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1160 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1161 * considered a bug in native unless an application depends on this (unlikely).
1163 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1165 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1166 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1167 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1168 WCHAR value[CHARS_IN_GUID];
1172 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1174 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1175 strcpyW(path, wszInterface);
1176 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1177 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1179 /* Open the key.. */
1180 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1182 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1183 return REGDB_E_IIDNOTREG;
1186 /* ... Once we have the key, query the registry to get the
1187 value of CLSID as a string, and convert it into a
1188 proper CLSID structure to be passed back to the app */
1189 len = sizeof(value);
1190 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1193 return REGDB_E_IIDNOTREG;
1197 /* We have the CLSid we want back from the registry as a string, so
1198 lets convert it into a CLSID structure */
1199 if (CLSIDFromString(value, pclsid) != NOERROR)
1200 return REGDB_E_IIDNOTREG;
1202 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1208 /***********************************************************************
1209 * WriteClassStm (OLE32.@)
1211 * Writes a CLSID to a stream.
1214 * pStm [I] Stream to write to.
1215 * rclsid [I] CLSID to write.
1219 * Failure: HRESULT code.
1221 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1223 TRACE("(%p,%p)\n",pStm,rclsid);
1226 return E_INVALIDARG;
1228 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1231 /***********************************************************************
1232 * ReadClassStm (OLE32.@)
1234 * Reads a CLSID from a stream.
1237 * pStm [I] Stream to read from.
1238 * rclsid [O] CLSID to read.
1242 * Failure: HRESULT code.
1244 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1249 TRACE("(%p,%p)\n",pStm,pclsid);
1252 return E_INVALIDARG;
1254 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1259 if (nbByte != sizeof(CLSID))
1267 * COM_GetRegisteredClassObject
1269 * This internal method is used to scan the registered class list to
1270 * find a class object.
1273 * rclsid Class ID of the class to find.
1274 * dwClsContext Class context to match.
1275 * ppv [out] returns a pointer to the class object. Complying
1276 * to normal COM usage, this method will increase the
1277 * reference count on this object.
1279 static HRESULT COM_GetRegisteredClassObject(
1284 HRESULT hr = S_FALSE;
1285 RegisteredClass* curClass;
1287 EnterCriticalSection( &csRegisteredClassList );
1295 * Iterate through the whole list and try to match the class ID.
1297 curClass = firstRegisteredClass;
1299 while (curClass != 0)
1302 * Check if we have a match on the class ID.
1304 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1307 * Since we don't do out-of process or DCOM just right away, let's ignore the
1312 * We have a match, return the pointer to the class object.
1314 *ppUnk = curClass->classObject;
1316 IUnknown_AddRef(curClass->classObject);
1323 * Step to the next class in the list.
1325 curClass = curClass->nextClass;
1329 LeaveCriticalSection( &csRegisteredClassList );
1331 * If we get to here, we haven't found our class.
1336 /******************************************************************************
1337 * CoRegisterClassObject [OLE32.@]
1339 * Registers the class object for a given class ID. Servers housed in EXE
1340 * files use this method instead of exporting DllGetClassObject to allow
1341 * other code to connect to their objects.
1344 * rclsid [I] CLSID of the object to register.
1345 * pUnk [I] IUnknown of the object.
1346 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1347 * flags [I] REGCLS flags indicating how connections are made.
1348 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1352 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1353 * CO_E_OBJISREG if the object is already registered. We should not return this.
1356 * CoRevokeClassObject, CoGetClassObject
1359 * MSDN claims that multiple interface registrations are legal, but we
1360 * can't do that with our current implementation.
1362 HRESULT WINAPI CoRegisterClassObject(
1367 LPDWORD lpdwRegister)
1369 RegisteredClass* newClass;
1370 LPUNKNOWN foundObject;
1373 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1374 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1376 if ( (lpdwRegister==0) || (pUnk==0) )
1377 return E_INVALIDARG;
1379 if (!COM_CurrentApt())
1381 ERR("COM was not initialized\n");
1382 return CO_E_NOTINITIALIZED;
1388 * First, check if the class is already registered.
1389 * If it is, this should cause an error.
1391 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1393 IUnknown_Release(foundObject);
1394 return CO_E_OBJISREG;
1397 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1398 if ( newClass == NULL )
1399 return E_OUTOFMEMORY;
1401 EnterCriticalSection( &csRegisteredClassList );
1403 newClass->classIdentifier = *rclsid;
1404 newClass->runContext = dwClsContext;
1405 newClass->connectFlags = flags;
1406 newClass->pMarshaledData = NULL;
1409 * Use the address of the chain node as the cookie since we are sure it's
1410 * unique. FIXME: not on 64-bit platforms.
1412 newClass->dwCookie = (DWORD)newClass;
1413 newClass->nextClass = firstRegisteredClass;
1416 * Since we're making a copy of the object pointer, we have to increase its
1419 newClass->classObject = pUnk;
1420 IUnknown_AddRef(newClass->classObject);
1422 firstRegisteredClass = newClass;
1423 LeaveCriticalSection( &csRegisteredClassList );
1425 *lpdwRegister = newClass->dwCookie;
1427 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1428 IClassFactory *classfac;
1430 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1431 (LPVOID*)&classfac);
1434 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1436 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1437 IUnknown_Release(classfac);
1440 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1441 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1442 MSHLFLAGS_TABLESTRONG);
1444 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1445 IUnknown_Release(classfac);
1449 IUnknown_Release(classfac);
1451 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1456 /***********************************************************************
1457 * CoRevokeClassObject [OLE32.@]
1459 * Removes a class object from the class registry.
1462 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1466 * Failure: HRESULT code.
1469 * CoRegisterClassObject
1471 HRESULT WINAPI CoRevokeClassObject(
1474 HRESULT hr = E_INVALIDARG;
1475 RegisteredClass** prevClassLink;
1476 RegisteredClass* curClass;
1478 TRACE("(%08lx)\n",dwRegister);
1480 EnterCriticalSection( &csRegisteredClassList );
1483 * Iterate through the whole list and try to match the cookie.
1485 curClass = firstRegisteredClass;
1486 prevClassLink = &firstRegisteredClass;
1488 while (curClass != 0)
1491 * Check if we have a match on the cookie.
1493 if (curClass->dwCookie == dwRegister)
1496 * Remove the class from the chain.
1498 *prevClassLink = curClass->nextClass;
1501 * Release the reference to the class object.
1503 IUnknown_Release(curClass->classObject);
1505 if (curClass->pMarshaledData)
1508 memset(&zero, 0, sizeof(zero));
1509 /* FIXME: stop local server thread */
1510 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1511 CoReleaseMarshalData(curClass->pMarshaledData);
1515 * Free the memory used by the chain node.
1517 HeapFree(GetProcessHeap(), 0, curClass);
1524 * Step to the next class in the list.
1526 prevClassLink = &(curClass->nextClass);
1527 curClass = curClass->nextClass;
1531 LeaveCriticalSection( &csRegisteredClassList );
1533 * If we get to here, we haven't found our class.
1538 /***********************************************************************
1539 * COM_RegReadPath [internal]
1541 * Reads a registry value and expands it when necessary
1543 HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1548 WCHAR src[MAX_PATH];
1549 DWORD dwLength = dstlen * sizeof(WCHAR);
1551 if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1552 if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1553 if (keytype == REG_EXPAND_SZ) {
1554 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1556 lstrcpynW(dst, src, dstlen);
1564 /***********************************************************************
1565 * CoGetClassObject [OLE32.@]
1567 * FIXME. If request allows of several options and there is a failure
1568 * with one (other than not being registered) do we try the
1569 * others or return failure? (E.g. inprocess is registered but
1570 * the DLL is not found but the server version works)
1572 HRESULT WINAPI CoGetClassObject(
1573 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1574 REFIID iid, LPVOID *ppv)
1576 LPUNKNOWN regClassObject;
1577 HRESULT hres = E_UNEXPECTED;
1579 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1582 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1583 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1587 * First, try and see if we can't match the class ID with one of the
1588 * registered classes.
1590 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1592 /* Get the required interface from the retrieved pointer. */
1593 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1596 * Since QI got another reference on the pointer, we want to release the
1597 * one we already have. If QI was unsuccessful, this will release the object. This
1598 * is good since we are not returning it in the "out" parameter.
1600 IUnknown_Release(regClassObject);
1605 /* first try: in-process */
1606 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext)
1608 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1610 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1611 DllGetClassObjectFunc DllGetClassObject;
1612 WCHAR dllpath[MAX_PATH+1];
1615 if (ERROR_SUCCESS != COM_OpenKeyForCLSID(rclsid, KEY_READ, &hkey))
1617 ERR("class %s not registered\n", debugstr_guid(rclsid));
1618 hres = REGDB_E_CLASSNOTREG;
1621 if (COM_RegReadPath(hkey, wszInprocServer32, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1623 /* failure: CLSID is not found in registry */
1624 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1625 hres = REGDB_E_CLASSNOTREG;
1629 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1631 /* failure: DLL could not be loaded */
1632 ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(dllpath));
1633 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1635 else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1637 /* failure: the dll did not export DllGetClassObject */
1638 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1639 FreeLibrary( hLibrary );
1640 hres = CO_E_DLLNOTFOUND;
1644 /* OK: get the ClassObject */
1645 COMPOBJ_DLLList_Add( hLibrary );
1646 return DllGetClassObject(rclsid, iid, ppv);
1651 /* Next try out of process */
1652 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1654 return RPC_GetLocalClassObject(rclsid,iid,ppv);
1657 /* Finally try remote: this requires networked DCOM (a lot of work) */
1658 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1660 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1661 hres = E_NOINTERFACE;
1667 /***********************************************************************
1668 * CoGetClassObject [COMPOBJ.7]
1671 HRESULT WINAPI CoGetClassObject16(
1672 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1673 REFIID iid, LPVOID *ppv)
1675 FIXME(", stub!\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1678 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1679 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1683 /***********************************************************************
1684 * CoResumeClassObjects (OLE32.@)
1686 * Resumes all class objects registered with REGCLS_SUSPENDED.
1690 * Failure: HRESULT code.
1692 HRESULT WINAPI CoResumeClassObjects(void)
1698 /***********************************************************************
1699 * GetClassFile (OLE32.@)
1701 * This function supplies the CLSID associated with the given filename.
1703 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1707 int nbElm, length, i;
1709 LPOLESTR *pathDec=0,absFile=0,progId=0;
1711 static const WCHAR bkslashW[] = {'\\',0};
1712 static const WCHAR dotW[] = {'.',0};
1714 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1716 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1717 if((StgIsStorageFile(filePathName))==S_OK){
1719 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1722 res=ReadClassStg(pstg,pclsid);
1724 IStorage_Release(pstg);
1728 /* if the file is not a storage object then attemps to match various bits in the file against a
1729 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1732 for(i=0;i<nFileTypes;i++)
1734 for(i=0;j<nPatternsForType;j++){
1739 pat=ReadPatternFromRegistry(i,j);
1740 hFile=CreateFileW(filePathName,,,,,,hFile);
1741 SetFilePosition(hFile,pat.offset);
1742 ReadFile(hFile,buf,pat.size,&r,NULL);
1743 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1745 *pclsid=ReadCLSIDFromRegistry(i);
1751 /* if the above strategies fail then search for the extension key in the registry */
1753 /* get the last element (absolute file) in the path name */
1754 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1755 absFile=pathDec[nbElm-1];
1757 /* failed if the path represente a directory and not an absolute file name*/
1758 if (!lstrcmpW(absFile, bkslashW))
1759 return MK_E_INVALIDEXTENSION;
1761 /* get the extension of the file */
1763 length=lstrlenW(absFile);
1764 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1767 if (!extension || !lstrcmpW(extension, dotW))
1768 return MK_E_INVALIDEXTENSION;
1770 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1772 /* get the progId associated to the extension */
1773 progId = CoTaskMemAlloc(sizeProgId);
1774 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1776 if (res==ERROR_SUCCESS)
1777 /* return the clsid associated to the progId */
1778 res= CLSIDFromProgID(progId,pclsid);
1780 for(i=0; pathDec[i]!=NULL;i++)
1781 CoTaskMemFree(pathDec[i]);
1782 CoTaskMemFree(pathDec);
1784 CoTaskMemFree(progId);
1786 if (res==ERROR_SUCCESS)
1789 return MK_E_INVALIDEXTENSION;
1792 /***********************************************************************
1793 * CoCreateInstance [OLE32.@]
1795 HRESULT WINAPI CoCreateInstance(
1797 LPUNKNOWN pUnkOuter,
1803 LPCLASSFACTORY lpclf = 0;
1805 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1814 * Initialize the "out" parameter
1819 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1820 * Rather than create a class factory, we can just check for it here
1822 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1823 if (StdGlobalInterfaceTableInstance == NULL)
1824 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1825 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1826 if (hres) return hres;
1828 TRACE("Retrieved GIT (%p)\n", *ppv);
1833 * Get a class factory to construct the object we want.
1835 hres = CoGetClassObject(rclsid,
1842 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1843 debugstr_guid(rclsid),hres);
1848 * Create the object and don't forget to release the factory
1850 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1851 IClassFactory_Release(lpclf);
1853 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1854 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1859 /***********************************************************************
1860 * CoCreateInstance [COMPOBJ.13]
1862 HRESULT WINAPI CoCreateInstance16(
1864 LPUNKNOWN pUnkOuter,
1869 FIXME("(%s, %p, %lx, %s, %p), stub!\n",
1870 debugstr_guid(rclsid), pUnkOuter, dwClsContext, debugstr_guid(iid),
1876 /***********************************************************************
1877 * CoCreateInstanceEx [OLE32.@]
1879 HRESULT WINAPI CoCreateInstanceEx(
1881 LPUNKNOWN pUnkOuter,
1883 COSERVERINFO* pServerInfo,
1887 IUnknown* pUnk = NULL;
1890 ULONG successCount = 0;
1895 if ( (cmq==0) || (pResults==NULL))
1896 return E_INVALIDARG;
1898 if (pServerInfo!=NULL)
1899 FIXME("() non-NULL pServerInfo not supported!\n");
1902 * Initialize all the "out" parameters.
1904 for (index = 0; index < cmq; index++)
1906 pResults[index].pItf = NULL;
1907 pResults[index].hr = E_NOINTERFACE;
1911 * Get the object and get its IUnknown pointer.
1913 hr = CoCreateInstance(rclsid,
1923 * Then, query for all the interfaces requested.
1925 for (index = 0; index < cmq; index++)
1927 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1928 pResults[index].pIID,
1929 (VOID**)&(pResults[index].pItf));
1931 if (pResults[index].hr == S_OK)
1936 * Release our temporary unknown pointer.
1938 IUnknown_Release(pUnk);
1940 if (successCount == 0)
1941 return E_NOINTERFACE;
1943 if (successCount!=cmq)
1944 return CO_S_NOTALLINTERFACES;
1949 /***********************************************************************
1950 * CoLoadLibrary (OLE32.@)
1955 * lpszLibName [I] Path to library.
1956 * bAutoFree [I] Whether the library should automatically be freed.
1959 * Success: Handle to loaded library.
1963 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1965 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1967 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1969 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1972 /***********************************************************************
1973 * CoFreeLibrary [OLE32.@]
1975 * Unloads a library from memory.
1978 * hLibrary [I] Handle to library to unload.
1984 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1986 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1988 FreeLibrary(hLibrary);
1992 /***********************************************************************
1993 * CoFreeAllLibraries [OLE32.@]
1995 * Function for backwards compatibility only. Does nothing.
2001 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2003 void WINAPI CoFreeAllLibraries(void)
2009 /***********************************************************************
2010 * CoFreeUnusedLibraries [OLE32.@]
2011 * CoFreeUnusedLibraries [COMPOBJ.17]
2013 * Frees any unused libraries. Unused are identified as those that return
2014 * S_OK from their DllCanUnloadNow function.
2020 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2022 void WINAPI CoFreeUnusedLibraries(void)
2024 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2025 * through the main apartment's thread to call DllCanUnloadNow */
2026 COMPOBJ_DllList_FreeUnused(0);
2029 /***********************************************************************
2030 * CoFileTimeNow [OLE32.@]
2031 * CoFileTimeNow [COMPOBJ.82]
2033 * Retrieves the current time in FILETIME format.
2036 * lpFileTime [O] The current time.
2041 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2043 GetSystemTimeAsFileTime( lpFileTime );
2047 static void COM_RevokeAllClasses()
2049 EnterCriticalSection( &csRegisteredClassList );
2051 while (firstRegisteredClass!=0)
2053 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2056 LeaveCriticalSection( &csRegisteredClassList );
2059 /******************************************************************************
2060 * CoLockObjectExternal [OLE32.@]
2062 * Increments or decrements the external reference count of a stub object.
2065 * pUnk [I] Stub object.
2066 * fLock [I] If TRUE then increments the external ref-count,
2067 * otherwise decrements.
2068 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2069 * calling CoDisconnectObject.
2073 * Failure: HRESULT code.
2075 HRESULT WINAPI CoLockObjectExternal(
2078 BOOL fLastUnlockReleases)
2080 struct stub_manager *stubmgr;
2081 struct apartment *apt;
2083 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2084 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2086 apt = COM_CurrentApt();
2087 if (!apt) return CO_E_NOTINITIALIZED;
2089 stubmgr = get_stub_manager_from_object(apt, pUnk);
2094 stub_manager_ext_addref(stubmgr, 1);
2096 stub_manager_ext_release(stubmgr, 1);
2098 stub_manager_int_release(stubmgr);
2104 WARN("stub object not found %p\n", pUnk);
2105 /* Note: native is pretty broken here because it just silently
2106 * fails, without returning an appropriate error code, making apps
2107 * think that the object was disconnected, when it actually wasn't */
2112 /***********************************************************************
2113 * CoInitializeWOW (OLE32.@)
2115 * WOW equivalent of CoInitialize?
2124 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2126 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2130 /***********************************************************************
2131 * CoGetState [OLE32.@]
2133 * Retrieves the thread state object previously stored by CoSetState().
2136 * ppv [I] Address where pointer to object will be stored.
2140 * Failure: E_OUTOFMEMORY.
2143 * Crashes on all invalid ppv addresses, including NULL.
2144 * If the function returns a non-NULL object then the caller must release its
2145 * reference on the object when the object is no longer required.
2150 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2152 struct oletls *info = COM_CurrentInfo();
2153 if (!info) return E_OUTOFMEMORY;
2159 IUnknown_AddRef(info->state);
2161 TRACE("apt->state=%p\n", info->state);
2167 /***********************************************************************
2168 * CoSetState [OLE32.@]
2170 * Sets the thread state object.
2173 * pv [I] Pointer to state object to be stored.
2176 * The system keeps a reference on the object while the object stored.
2180 * Failure: E_OUTOFMEMORY.
2182 HRESULT WINAPI CoSetState(IUnknown * pv)
2184 struct oletls *info = COM_CurrentInfo();
2185 if (!info) return E_OUTOFMEMORY;
2187 if (pv) IUnknown_AddRef(pv);
2191 TRACE("-- release %p now\n", info->state);
2192 IUnknown_Release(info->state);
2201 /******************************************************************************
2202 * OleGetAutoConvert [OLE32.@]
2204 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2206 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2208 WCHAR buf[CHARS_IN_GUID];
2212 if (ERROR_SUCCESS != COM_OpenKeyForCLSID(clsidOld, KEY_READ, &hkey))
2214 res = REGDB_E_CLASSNOTREG;
2219 /* we can just query for the default value of AutoConvertTo key like that,
2220 without opening the AutoConvertTo key and querying for NULL (default) */
2221 if (RegQueryValueW(hkey, wszAutoConvertTo, buf, &len))
2223 res = REGDB_E_KEYMISSING;
2226 res = CLSIDFromString(buf, pClsidNew);
2228 if (hkey) RegCloseKey(hkey);
2232 /******************************************************************************
2233 * CoTreatAsClass [OLE32.@]
2235 * Sets the TreatAs value of a class.
2238 * clsidOld [I] Class to set TreatAs value on.
2239 * clsidNew [I] The class the clsidOld should be treated as.
2243 * Failure: HRESULT code.
2248 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2250 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2251 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2253 WCHAR szClsidNew[CHARS_IN_GUID];
2255 WCHAR auto_treat_as[CHARS_IN_GUID];
2256 LONG auto_treat_as_size = sizeof(auto_treat_as);
2259 if (ERROR_SUCCESS != COM_OpenKeyForCLSID(clsidOld, KEY_READ | KEY_WRITE, &hkey))
2261 res = REGDB_E_CLASSNOTREG;
2264 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2266 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2267 !CLSIDFromString(auto_treat_as, &id))
2269 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2271 res = REGDB_E_WRITEREGDB;
2277 RegDeleteKeyW(hkey, wszTreatAs);
2281 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2282 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2284 res = REGDB_E_WRITEREGDB;
2289 if (hkey) RegCloseKey(hkey);
2293 /******************************************************************************
2294 * CoGetTreatAsClass [OLE32.@]
2296 * Gets the TreatAs value of a class.
2299 * clsidOld [I] Class to get the TreatAs value of.
2300 * clsidNew [I] The class the clsidOld should be treated as.
2304 * Failure: HRESULT code.
2309 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2311 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2313 WCHAR szClsidNew[CHARS_IN_GUID];
2315 LONG len = sizeof(szClsidNew);
2317 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2318 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2320 if (COM_OpenKeyForCLSID(clsidOld, KEY_READ, &hkey))
2322 res = REGDB_E_CLASSNOTREG;
2325 if (RegQueryValueW(hkey, wszTreatAs, szClsidNew, &len))
2330 res = CLSIDFromString(szClsidNew,clsidNew);
2332 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2334 if (hkey) RegCloseKey(hkey);
2338 /******************************************************************************
2339 * CoGetCurrentProcess [OLE32.@]
2340 * CoGetCurrentProcess [COMPOBJ.34]
2342 * Gets the current process ID.
2345 * The current process ID.
2348 * Is DWORD really the correct return type for this function?
2350 DWORD WINAPI CoGetCurrentProcess(void)
2352 return GetCurrentProcessId();
2355 /******************************************************************************
2356 * CoRegisterMessageFilter [OLE32.@]
2358 * Registers a message filter.
2361 * lpMessageFilter [I] Pointer to interface.
2362 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2366 * Failure: HRESULT code.
2368 HRESULT WINAPI CoRegisterMessageFilter(
2369 LPMESSAGEFILTER lpMessageFilter,
2370 LPMESSAGEFILTER *lplpMessageFilter)
2373 if (lplpMessageFilter) {
2374 *lplpMessageFilter = NULL;
2379 /***********************************************************************
2380 * CoIsOle1Class [OLE32.@]
2382 * Determines whether the specified class an OLE v1 class.
2385 * clsid [I] Class to test.
2388 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2390 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2392 FIXME("%s\n", debugstr_guid(clsid));
2396 /***********************************************************************
2397 * IsEqualGUID [OLE32.@]
2399 * Compares two Unique Identifiers.
2402 * rguid1 [I] The first GUID to compare.
2403 * rguid2 [I] The other GUID to compare.
2409 BOOL WINAPI IsEqualGUID(
2413 return !memcmp(rguid1,rguid2,sizeof(GUID));
2416 /***********************************************************************
2417 * CoInitializeSecurity [OLE32.@]
2419 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2420 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2421 void* pReserved1, DWORD dwAuthnLevel,
2422 DWORD dwImpLevel, void* pReserved2,
2423 DWORD dwCapabilities, void* pReserved3)
2425 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2426 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2427 dwCapabilities, pReserved3);
2431 /***********************************************************************
2432 * CoSuspendClassObjects [OLE32.@]
2434 * Suspends all registered class objects to prevent further requests coming in
2435 * for those objects.
2439 * Failure: HRESULT code.
2441 HRESULT WINAPI CoSuspendClassObjects(void)
2447 /***********************************************************************
2448 * CoAddRefServerProcess [OLE32.@]
2450 * Helper function for incrementing the reference count of a local-server
2454 * New reference count.
2456 ULONG WINAPI CoAddRefServerProcess(void)
2462 /***********************************************************************
2463 * CoReleaseServerProcess [OLE32.@]
2465 * Helper function for decrementing the reference count of a local-server
2469 * New reference count.
2471 ULONG WINAPI CoReleaseServerProcess(void)
2477 /***********************************************************************
2478 * CoIsHandlerConnected [OLE32.@]
2480 * Determines whether a proxy is connected to a remote stub.
2483 * pUnk [I] Pointer to object that may or may not be connected.
2486 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2489 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2491 FIXME("%p\n", pUnk);
2496 /***********************************************************************
2497 * CoQueryProxyBlanket [OLE32.@]
2499 * Retrieves the security settings being used by a proxy.
2502 * pProxy [I] Pointer to the proxy object.
2503 * pAuthnSvc [O] The type of authentication service.
2504 * pAuthzSvc [O] The type of authorization service.
2505 * ppServerPrincName [O] Optional. The server prinicple name.
2506 * pAuthnLevel [O] The authentication level.
2507 * pImpLevel [O] The impersonation level.
2508 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2509 * pCapabilities [O] Flags affecting the security behaviour.
2513 * Failure: HRESULT code.
2516 * CoCopyProxy, CoSetProxyBlanket.
2518 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2519 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2520 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2522 IClientSecurity *pCliSec;
2525 TRACE("%p\n", pProxy);
2527 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2530 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2531 pAuthzSvc, ppServerPrincName,
2532 pAuthnLevel, pImpLevel, ppAuthInfo,
2534 IClientSecurity_Release(pCliSec);
2537 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2541 /***********************************************************************
2542 * CoSetProxyBlanket [OLE32.@]
2544 * Sets the security settings for a proxy.
2547 * pProxy [I] Pointer to the proxy object.
2548 * AuthnSvc [I] The type of authentication service.
2549 * AuthzSvc [I] The type of authorization service.
2550 * pServerPrincName [I] The server prinicple name.
2551 * AuthnLevel [I] The authentication level.
2552 * ImpLevel [I] The impersonation level.
2553 * pAuthInfo [I] Information specific to the authorization/authentication service.
2554 * Capabilities [I] Flags affecting the security behaviour.
2558 * Failure: HRESULT code.
2561 * CoQueryProxyBlanket, CoCopyProxy.
2563 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2564 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2565 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2567 IClientSecurity *pCliSec;
2570 TRACE("%p\n", pProxy);
2572 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2575 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2576 AuthzSvc, pServerPrincName,
2577 AuthnLevel, ImpLevel, pAuthInfo,
2579 IClientSecurity_Release(pCliSec);
2582 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2586 /***********************************************************************
2587 * CoCopyProxy [OLE32.@]
2592 * pProxy [I] Pointer to the proxy object.
2593 * ppCopy [O] Copy of the proxy.
2597 * Failure: HRESULT code.
2600 * CoQueryProxyBlanket, CoSetProxyBlanket.
2602 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2604 IClientSecurity *pCliSec;
2607 TRACE("%p\n", pProxy);
2609 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2612 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2613 IClientSecurity_Release(pCliSec);
2616 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2621 /***********************************************************************
2622 * CoWaitForMultipleHandles [OLE32.@]
2624 * Waits for one or more handles to become signaled.
2627 * dwFlags [I] Flags. See notes.
2628 * dwTimeout [I] Timeout in milliseconds.
2629 * cHandles [I] Number of handles pointed to by pHandles.
2630 * pHandles [I] Handles to wait for.
2631 * lpdwindex [O] Index of handle that was signaled.
2635 * Failure: RPC_S_CALLPENDING on timeout.
2639 * The dwFlags parameter can be zero or more of the following:
2640 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2641 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2644 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2646 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2647 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2650 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2651 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2652 DWORD start_time = GetTickCount();
2654 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2655 pHandles, lpdwindex);
2659 DWORD now = GetTickCount();
2662 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2664 hr = RPC_S_CALLPENDING;
2668 TRACE("waiting for rpc completion or window message\n");
2670 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2671 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2672 QS_ALLINPUT, wait_flags);
2674 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2677 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2679 /* FIXME: filter the messages here */
2680 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2681 TranslateMessage(&msg);
2682 DispatchMessageW(&msg);
2685 else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2687 /* handle signaled, store index */
2688 *lpdwindex = (res - WAIT_OBJECT_0);
2691 else if (res == WAIT_TIMEOUT)
2693 hr = RPC_S_CALLPENDING;
2698 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2703 TRACE("-- 0x%08lx\n", hr);
2707 /***********************************************************************
2710 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2712 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2715 case DLL_PROCESS_ATTACH:
2716 OLE32_hInstance = hinstDLL;
2717 COMPOBJ_InitProcess();
2718 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2721 case DLL_PROCESS_DETACH:
2722 if (TRACE_ON(ole)) CoRevokeMallocSpy();
2723 COMPOBJ_UninitProcess();
2724 OLE32_hInstance = 0;
2727 case DLL_THREAD_DETACH:
2734 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */