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 * - Call IMessageFilter functions.
38 * - Make all ole interface marshaling use NDR to be wire compatible with
40 * - Use & interpret ORPCTHIS & ORPCTHAT.
53 #define NONAMELESSUNION
54 #define NONAMELESSSTRUCT
65 #include "compobj_private.h"
67 #include "wine/unicode.h"
68 #include "wine/debug.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(ole);
72 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
74 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
76 /****************************************************************************
77 * This section defines variables internal to the COM module.
79 * TODO: Most of these things will have to be made thread-safe.
82 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
83 static void COM_RevokeAllClasses(void);
85 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
87 APARTMENT *MTA; /* protected by csApartment */
88 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
90 static CRITICAL_SECTION csApartment;
91 static CRITICAL_SECTION_DEBUG critsect_debug =
94 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
95 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
97 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
100 * This lock count counts the number of times CoInitialize is called. It is
101 * decreased every time CoUninitialize is called. When it hits 0, the COM
102 * libraries are freed
104 static LONG s_COMLockCount = 0;
107 * This linked list contains the list of registered class objects. These
108 * are mostly used to register the factories for out-of-proc servers of OLE
111 * TODO: Make this data structure aware of inter-process communication. This
112 * means that parts of this will be exported to the Wine Server.
114 typedef struct tagRegisteredClass
116 CLSID classIdentifier;
117 LPUNKNOWN classObject;
121 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
122 struct tagRegisteredClass* nextClass;
125 static RegisteredClass* firstRegisteredClass = NULL;
127 static CRITICAL_SECTION csRegisteredClassList;
128 static CRITICAL_SECTION_DEBUG class_cs_debug =
130 0, 0, &csRegisteredClassList,
131 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
132 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
134 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
136 /*****************************************************************************
137 * This section contains OpenDllList definitions
139 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
140 * other functions that do LoadLibrary _without_ giving back a HMODULE.
141 * Without this list these handles would never be freed.
143 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
144 * next unload-call but not before 600 sec.
147 typedef struct tagOpenDll {
149 struct tagOpenDll *next;
152 static OpenDll *openDllList = NULL; /* linked list of open dlls */
154 static CRITICAL_SECTION csOpenDllList;
155 static CRITICAL_SECTION_DEBUG dll_cs_debug =
157 0, 0, &csOpenDllList,
158 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
159 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
161 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
163 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',' ',
164 '0','x','#','#','#','#','#','#','#','#',' ',0};
165 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
167 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
168 static void COMPOBJ_DllList_FreeUnused(int Timeout);
170 static void COMPOBJ_InitProcess( void )
174 /* Dispatching to the correct thread in an apartment is done through
175 * window messages rather than RPC transports. When an interface is
176 * marshalled into another apartment in the same process, a window of the
177 * following class is created. The *caller* of CoMarshalInterface (ie the
178 * application) is responsible for pumping the message loop in that thread.
179 * The WM_USER messages which point to the RPCs are then dispatched to
180 * COM_AptWndProc by the user's code from the apartment in which the interface
183 memset(&wclass, 0, sizeof(wclass));
184 wclass.lpfnWndProc = apartment_wndproc;
185 wclass.hInstance = OLE32_hInstance;
186 wclass.lpszClassName = wszAptWinClass;
187 RegisterClassW(&wclass);
190 static void COMPOBJ_UninitProcess( void )
192 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
195 static void COM_TlsDestroy(void)
197 struct oletls *info = NtCurrentTeb()->ReservedForOle;
200 if (info->apt) apartment_release(info->apt);
201 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
202 if (info->state) IUnknown_Release(info->state);
203 HeapFree(GetProcessHeap(), 0, info);
204 NtCurrentTeb()->ReservedForOle = NULL;
208 /******************************************************************************
212 /* allocates memory and fills in the necessary fields for a new apartment
214 static APARTMENT *apartment_construct(DWORD model)
218 TRACE("creating new apartment, model=%ld\n", model);
220 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
221 apt->tid = GetCurrentThreadId();
223 list_init(&apt->proxies);
224 list_init(&apt->stubmgrs);
227 apt->remunk_exported = FALSE;
229 InitializeCriticalSection(&apt->cs);
230 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
234 if (model & COINIT_APARTMENTTHREADED)
236 /* FIXME: should be randomly generated by in an RPC call to rpcss */
237 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
241 /* FIXME: should be randomly generated by in an RPC call to rpcss */
242 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
245 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
247 /* the locking here is not currently needed for the MTA case, but it
248 * doesn't hurt and makes the code simpler */
249 EnterCriticalSection(&csApartment);
250 list_add_head(&apts, &apt->entry);
251 LeaveCriticalSection(&csApartment);
256 /* gets and existing apartment if one exists or otherwise creates an apartment
257 * structure which stores OLE apartment-local information and stores a pointer
258 * to it in the thread-local storage */
259 static APARTMENT *apartment_get_or_create(DWORD model)
261 APARTMENT *apt = COM_CurrentApt();
265 if (model & COINIT_APARTMENTTHREADED)
267 apt = apartment_construct(model);
268 COM_CurrentInfo()->apt = apt;
272 EnterCriticalSection(&csApartment);
274 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
275 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
279 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
280 apartment_addref(MTA);
283 MTA = apartment_construct(model);
286 COM_CurrentInfo()->apt = apt;
288 LeaveCriticalSection(&csApartment);
295 DWORD apartment_addref(struct apartment *apt)
297 DWORD refs = InterlockedIncrement(&apt->refs);
298 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
302 DWORD apartment_release(struct apartment *apt)
306 EnterCriticalSection(&csApartment);
308 ret = InterlockedDecrement(&apt->refs);
309 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
310 /* destruction stuff that needs to happen under csApartment CS */
313 if (apt == MTA) MTA = NULL;
314 list_remove(&apt->entry);
317 LeaveCriticalSection(&csApartment);
321 struct list *cursor, *cursor2;
323 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
325 /* no locking is needed for this apartment, because no other thread
326 * can access it at this point */
328 apartment_disconnectproxies(apt);
330 if (apt->win) DestroyWindow(apt->win);
332 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
334 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
335 /* release the implicit reference given by the fact that the
336 * stub has external references (it must do since it is in the
337 * stub manager list in the apartment and all non-apartment users
338 * must have a ref on the apartment and so it cannot be destroyed).
340 stub_manager_int_release(stubmgr);
343 /* if this assert fires, then another thread took a reference to a
344 * stub manager without taking a reference to the containing
345 * apartment, which it must do. */
346 assert(list_empty(&apt->stubmgrs));
348 if (apt->filter) IUnknown_Release(apt->filter);
350 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
351 DeleteCriticalSection(&apt->cs);
353 HeapFree(GetProcessHeap(), 0, apt);
359 /* The given OXID must be local to this process:
361 * The ref parameter is here mostly to ensure people remember that
362 * they get one, you should normally take a ref for thread safety.
364 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
366 APARTMENT *result = NULL;
369 EnterCriticalSection(&csApartment);
370 LIST_FOR_EACH( cursor, &apts )
372 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
373 if (apt->oxid == oxid)
376 if (ref) apartment_addref(result);
380 LeaveCriticalSection(&csApartment);
385 /* gets the apartment which has a given creator thread ID. The caller must
386 * release the reference from the apartment as soon as the apartment pointer
387 * is no longer required. */
388 APARTMENT *apartment_findfromtid(DWORD tid)
390 APARTMENT *result = NULL;
393 EnterCriticalSection(&csApartment);
394 LIST_FOR_EACH( cursor, &apts )
396 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
400 apartment_addref(result);
404 LeaveCriticalSection(&csApartment);
409 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
414 RPC_ExecuteCall((struct dispatch_params *)lParam);
417 return DefWindowProcW(hWnd, msg, wParam, lParam);
421 HRESULT apartment_createwindowifneeded(struct apartment *apt)
423 if (!(apt->model & COINIT_APARTMENTTHREADED))
428 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
430 0, 0, OLE32_hInstance, NULL);
433 ERR("CreateWindow failed with error %ld\n", GetLastError());
434 return HRESULT_FROM_WIN32(GetLastError());
436 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
437 /* someone beat us to it */
444 HWND apartment_getwindow(struct apartment *apt)
446 assert(apt->model & COINIT_APARTMENTTHREADED);
450 void apartment_joinmta(void)
452 apartment_addref(MTA);
453 COM_CurrentInfo()->apt = MTA;
456 /*****************************************************************************
457 * This section contains OpenDllList implemantation
460 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
467 EnterCriticalSection( &csOpenDllList );
469 if (openDllList == NULL) {
470 /* empty list -- add first node */
471 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
472 openDllList->hLibrary=hLibrary;
473 openDllList->next = NULL;
475 /* search for this dll */
477 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
478 if (ptr->hLibrary == hLibrary) {
484 /* dll not found, add it */
486 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
487 openDllList->hLibrary = hLibrary;
488 openDllList->next = tmp;
492 LeaveCriticalSection( &csOpenDllList );
495 static void COMPOBJ_DllList_FreeUnused(int Timeout)
497 OpenDll *curr, *next, *prev = NULL;
498 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
499 DllCanUnloadNowFunc DllCanUnloadNow;
503 EnterCriticalSection( &csOpenDllList );
505 for (curr = openDllList; curr != NULL; ) {
506 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
508 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
511 TRACE("freeing %p\n", curr->hLibrary);
512 FreeLibrary(curr->hLibrary);
514 HeapFree(GetProcessHeap(), 0, curr);
515 if (curr == openDllList) {
528 LeaveCriticalSection( &csOpenDllList );
531 /******************************************************************************
532 * CoBuildVersion [OLE32.@]
533 * CoBuildVersion [COMPOBJ.1]
535 * Gets the build version of the DLL.
540 * Current build version, hiword is majornumber, loword is minornumber
542 DWORD WINAPI CoBuildVersion(void)
544 TRACE("Returning version %d, build %d.\n", rmm, rup);
545 return (rmm<<16)+rup;
548 /******************************************************************************
549 * CoInitialize [OLE32.@]
551 * Initializes the COM libraries by calling CoInitializeEx with
552 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
555 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
558 * Success: S_OK if not already initialized, S_FALSE otherwise.
559 * Failure: HRESULT code.
564 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
567 * Just delegate to the newer method.
569 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
572 /******************************************************************************
573 * CoInitializeEx [OLE32.@]
575 * Initializes the COM libraries.
578 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
579 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
582 * S_OK if successful,
583 * S_FALSE if this function was called already.
584 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
589 * The behavior used to set the IMalloc used for memory management is
591 * The dwCoInit parameter must specify of of the following apartment
593 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
594 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
595 * The parameter may also specify zero or more of the following flags:
596 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
597 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
602 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
607 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
609 if (lpReserved!=NULL)
611 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
615 * Check the lock count. If this is the first time going through the initialize
616 * process, we have to initialize the libraries.
618 * And crank-up that lock count.
620 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
623 * Initialize the various COM libraries and data structures.
625 TRACE("() - Initializing the COM libraries\n");
627 /* we may need to defer this until after apartment initialisation */
628 RunningObjectTableImpl_Initialize();
631 if (!(apt = COM_CurrentInfo()->apt))
633 apt = apartment_get_or_create(dwCoInit);
634 if (!apt) return E_OUTOFMEMORY;
636 else if (dwCoInit != apt->model)
638 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
639 code then we are probably using the wrong threading model to implement that API. */
640 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
641 return RPC_E_CHANGED_MODE;
646 COM_CurrentInfo()->inits++;
651 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
652 pending RPCs are ignored. Non-COM messages are discarded at this point.
654 static void COM_FlushMessageQueue(void)
657 APARTMENT *apt = COM_CurrentApt();
659 if (!apt || !apt->win) return;
661 TRACE("Flushing STA message queue\n");
663 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
665 if (message.hwnd != apt->win)
667 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
671 TranslateMessage(&message);
672 DispatchMessageA(&message);
676 /***********************************************************************
677 * CoUninitialize [OLE32.@]
679 * This method will decrement the refcount on the current apartment, freeing
680 * the resources associated with it if it is the last thread in the apartment.
681 * If the last apartment is freed, the function will additionally release
682 * any COM resources associated with the process.
692 void WINAPI CoUninitialize(void)
694 struct oletls * info = COM_CurrentInfo();
699 /* will only happen on OOM */
705 ERR("Mismatched CoUninitialize\n");
711 apartment_release(info->apt);
716 * Decrease the reference count.
717 * If we are back to 0 locks on the COM library, make sure we free
718 * all the associated data structures.
720 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
723 TRACE("() - Releasing the COM libraries\n");
725 RunningObjectTableImpl_UnInitialize();
727 /* Release the references to the registered class objects */
728 COM_RevokeAllClasses();
730 /* This will free the loaded COM Dlls */
731 CoFreeAllLibraries();
733 /* This ensures we deal with any pending RPCs */
734 COM_FlushMessageQueue();
736 else if (lCOMRefCnt<1) {
737 ERR( "CoUninitialize() - not CoInitialized.\n" );
738 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
742 /******************************************************************************
743 * CoDisconnectObject [OLE32.@]
744 * CoDisconnectObject [COMPOBJ.15]
746 * Disconnects all connections to this object from remote processes. Dispatches
747 * pending RPCs while blocking new RPCs from occurring, and then calls
748 * IMarshal::DisconnectObject on the given object.
750 * Typically called when the object server is forced to shut down, for instance by
754 * lpUnk [I] The object whose stub should be disconnected.
755 * reserved [I] Reserved. Should be set to 0.
759 * Failure: HRESULT code.
762 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
764 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
770 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
772 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
775 hr = IMarshal_DisconnectObject(marshal, reserved);
776 IMarshal_Release(marshal);
780 apt = COM_CurrentApt();
782 return CO_E_NOTINITIALIZED;
784 apartment_disconnectobject(apt, lpUnk);
786 /* Note: native is pretty broken here because it just silently
787 * fails, without returning an appropriate error code if the object was
788 * not found, making apps think that the object was disconnected, when
789 * it actually wasn't */
794 /******************************************************************************
795 * CoCreateGuid [OLE32.@]
797 * Simply forwards to UuidCreate in RPCRT4.
800 * pguid [O] Points to the GUID to initialize.
804 * Failure: HRESULT code.
809 HRESULT WINAPI CoCreateGuid(GUID *pguid)
811 return UuidCreate(pguid);
814 /******************************************************************************
815 * CLSIDFromString [OLE32.@]
816 * IIDFromString [OLE32.@]
818 * Converts a unique identifier from its string representation into
822 * idstr [I] The string representation of the GUID.
823 * id [O] GUID converted from the string.
827 * CO_E_CLASSSTRING if idstr is not a valid CLSID
832 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
838 memset( id, 0, sizeof (CLSID) );
842 /* validate the CLSID string */
843 if (strlenW(s) != 38)
844 return CO_E_CLASSSTRING;
846 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
847 return CO_E_CLASSSTRING;
849 for (i=1; i<37; i++) {
850 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
851 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
852 ((s[i] >= 'a') && (s[i] <= 'f')) ||
853 ((s[i] >= 'A') && (s[i] <= 'F'))))
854 return CO_E_CLASSSTRING;
857 TRACE("%s -> %p\n", debugstr_w(s), id);
859 /* quick lookup table */
860 memset(table, 0, 256);
862 for (i = 0; i < 10; i++) {
865 for (i = 0; i < 6; i++) {
866 table['A' + i] = i+10;
867 table['a' + i] = i+10;
870 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
872 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
873 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
874 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
875 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
877 /* these are just sequential bytes */
878 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
879 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
880 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
881 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
882 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
883 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
884 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
885 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
890 /*****************************************************************************/
892 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
896 ret = __CLSIDFromString(idstr, id);
897 if(ret != S_OK) { /* It appears a ProgID is also valid */
898 ret = CLSIDFromProgID(idstr, id);
903 /* Converts a GUID into the respective string representation. */
904 HRESULT WINE_StringFromCLSID(
905 const CLSID *id, /* [in] GUID to be converted */
906 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
908 static const char *hex = "0123456789ABCDEF";
913 { ERR("called with id=Null\n");
918 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
919 id->Data1, id->Data2, id->Data3,
920 id->Data4[0], id->Data4[1]);
924 for (i = 2; i < 8; i++) {
925 *s++ = hex[id->Data4[i]>>4];
926 *s++ = hex[id->Data4[i] & 0xf];
932 TRACE("%p->%s\n", id, idstr);
938 /******************************************************************************
939 * StringFromCLSID [OLE32.@]
940 * StringFromIID [OLE32.@]
942 * Converts a GUID into the respective string representation.
943 * The target string is allocated using the OLE IMalloc.
946 * id [I] the GUID to be converted.
947 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
954 * StringFromGUID2, CLSIDFromString
956 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
962 if ((ret = CoGetMalloc(0,&mllc)))
965 ret=WINE_StringFromCLSID(id,buf);
967 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
968 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
969 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
974 /******************************************************************************
975 * StringFromGUID2 [OLE32.@]
976 * StringFromGUID2 [COMPOBJ.76]
978 * Modified version of StringFromCLSID that allows you to specify max
982 * id [I] GUID to convert to string.
983 * str [O] Buffer where the result will be stored.
984 * cmax [I] Size of the buffer in characters.
987 * Success: The length of the resulting string in characters.
990 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
994 if (WINE_StringFromCLSID(id,xguid))
996 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
999 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1000 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1002 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1003 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1007 strcpyW(path, wszCLSIDSlash);
1008 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1009 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1010 if (res == ERROR_FILE_NOT_FOUND)
1011 return REGDB_E_CLASSNOTREG;
1012 else if (res != ERROR_SUCCESS)
1013 return REGDB_E_READREGDB;
1021 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1023 if (res == ERROR_FILE_NOT_FOUND)
1024 return REGDB_E_KEYMISSING;
1025 else if (res != ERROR_SUCCESS)
1026 return REGDB_E_READREGDB;
1031 /******************************************************************************
1032 * ProgIDFromCLSID [OLE32.@]
1034 * Converts a class id into the respective program ID.
1037 * clsid [I] Class ID, as found in registry.
1038 * lplpszProgID [O] Associated ProgID.
1043 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1045 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1047 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1052 *lplpszProgID = NULL;
1053 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1057 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1058 ret = REGDB_E_CLASSNOTREG;
1062 *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1065 if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen))
1066 ret = REGDB_E_CLASSNOTREG;
1069 ret = E_OUTOFMEMORY;
1076 /******************************************************************************
1077 * CLSIDFromProgID [OLE32.@]
1079 * Converts a program id into the respective GUID.
1082 * progid [I] Unicode program ID, as found in registry.
1083 * riid [O] Associated CLSID.
1087 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1089 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1091 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1092 WCHAR buf2[CHARS_IN_GUID];
1093 LONG buf2len = sizeof(buf2);
1096 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1097 strcpyW( buf, progid );
1098 strcatW( buf, clsidW );
1099 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1101 HeapFree(GetProcessHeap(),0,buf);
1102 return CO_E_CLASSSTRING;
1104 HeapFree(GetProcessHeap(),0,buf);
1106 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1109 return CO_E_CLASSSTRING;
1112 return CLSIDFromString(buf2,riid);
1116 /*****************************************************************************
1117 * CoGetPSClsid [OLE32.@]
1119 * Retrieves the CLSID of the proxy/stub factory that implements
1120 * IPSFactoryBuffer for the specified interface.
1123 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1124 * pclsid [O] Where to store returned proxy/stub CLSID.
1129 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1133 * The standard marshaller activates the object with the CLSID
1134 * returned and uses the CreateProxy and CreateStub methods on its
1135 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1138 * CoGetPSClsid determines this CLSID by searching the
1139 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1140 * in the registry and any interface id registered by
1141 * CoRegisterPSClsid within the current process.
1145 * We only search the registry, not ids registered with
1146 * CoRegisterPSClsid.
1147 * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1148 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1149 * considered a bug in native unless an application depends on this (unlikely).
1151 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1153 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1154 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1155 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1156 WCHAR value[CHARS_IN_GUID];
1160 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1162 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1163 strcpyW(path, wszInterface);
1164 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1165 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1167 /* Open the key.. */
1168 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1170 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1171 return REGDB_E_IIDNOTREG;
1174 /* ... Once we have the key, query the registry to get the
1175 value of CLSID as a string, and convert it into a
1176 proper CLSID structure to be passed back to the app */
1177 len = sizeof(value);
1178 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1181 return REGDB_E_IIDNOTREG;
1185 /* We have the CLSid we want back from the registry as a string, so
1186 lets convert it into a CLSID structure */
1187 if (CLSIDFromString(value, pclsid) != NOERROR)
1188 return REGDB_E_IIDNOTREG;
1190 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1196 /***********************************************************************
1197 * WriteClassStm (OLE32.@)
1199 * Writes a CLSID to a stream.
1202 * pStm [I] Stream to write to.
1203 * rclsid [I] CLSID to write.
1207 * Failure: HRESULT code.
1209 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1211 TRACE("(%p,%p)\n",pStm,rclsid);
1214 return E_INVALIDARG;
1216 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1219 /***********************************************************************
1220 * ReadClassStm (OLE32.@)
1222 * Reads a CLSID from a stream.
1225 * pStm [I] Stream to read from.
1226 * rclsid [O] CLSID to read.
1230 * Failure: HRESULT code.
1232 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1237 TRACE("(%p,%p)\n",pStm,pclsid);
1240 return E_INVALIDARG;
1242 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1247 if (nbByte != sizeof(CLSID))
1255 * COM_GetRegisteredClassObject
1257 * This internal method is used to scan the registered class list to
1258 * find a class object.
1261 * rclsid Class ID of the class to find.
1262 * dwClsContext Class context to match.
1263 * ppv [out] returns a pointer to the class object. Complying
1264 * to normal COM usage, this method will increase the
1265 * reference count on this object.
1267 static HRESULT COM_GetRegisteredClassObject(
1272 HRESULT hr = S_FALSE;
1273 RegisteredClass* curClass;
1275 EnterCriticalSection( &csRegisteredClassList );
1283 * Iterate through the whole list and try to match the class ID.
1285 curClass = firstRegisteredClass;
1287 while (curClass != 0)
1290 * Check if we have a match on the class ID.
1292 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1295 * Since we don't do out-of process or DCOM just right away, let's ignore the
1300 * We have a match, return the pointer to the class object.
1302 *ppUnk = curClass->classObject;
1304 IUnknown_AddRef(curClass->classObject);
1311 * Step to the next class in the list.
1313 curClass = curClass->nextClass;
1317 LeaveCriticalSection( &csRegisteredClassList );
1319 * If we get to here, we haven't found our class.
1324 /******************************************************************************
1325 * CoRegisterClassObject [OLE32.@]
1327 * Registers the class object for a given class ID. Servers housed in EXE
1328 * files use this method instead of exporting DllGetClassObject to allow
1329 * other code to connect to their objects.
1332 * rclsid [I] CLSID of the object to register.
1333 * pUnk [I] IUnknown of the object.
1334 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1335 * flags [I] REGCLS flags indicating how connections are made.
1336 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1340 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1341 * CO_E_OBJISREG if the object is already registered. We should not return this.
1344 * CoRevokeClassObject, CoGetClassObject
1347 * MSDN claims that multiple interface registrations are legal, but we
1348 * can't do that with our current implementation.
1350 HRESULT WINAPI CoRegisterClassObject(
1355 LPDWORD lpdwRegister)
1357 RegisteredClass* newClass;
1358 LPUNKNOWN foundObject;
1361 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1362 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1364 if ( (lpdwRegister==0) || (pUnk==0) )
1365 return E_INVALIDARG;
1367 if (!COM_CurrentApt())
1369 ERR("COM was not initialized\n");
1370 return CO_E_NOTINITIALIZED;
1376 * First, check if the class is already registered.
1377 * If it is, this should cause an error.
1379 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1381 if (flags & REGCLS_MULTIPLEUSE) {
1382 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1383 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1384 IUnknown_Release(foundObject);
1387 IUnknown_Release(foundObject);
1388 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1389 return CO_E_OBJISREG;
1392 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1393 if ( newClass == NULL )
1394 return E_OUTOFMEMORY;
1396 EnterCriticalSection( &csRegisteredClassList );
1398 newClass->classIdentifier = *rclsid;
1399 newClass->runContext = dwClsContext;
1400 newClass->connectFlags = flags;
1401 newClass->pMarshaledData = NULL;
1404 * Use the address of the chain node as the cookie since we are sure it's
1405 * unique. FIXME: not on 64-bit platforms.
1407 newClass->dwCookie = (DWORD)newClass;
1408 newClass->nextClass = firstRegisteredClass;
1411 * Since we're making a copy of the object pointer, we have to increase its
1414 newClass->classObject = pUnk;
1415 IUnknown_AddRef(newClass->classObject);
1417 firstRegisteredClass = newClass;
1418 LeaveCriticalSection( &csRegisteredClassList );
1420 *lpdwRegister = newClass->dwCookie;
1422 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1423 IClassFactory *classfac;
1425 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1426 (LPVOID*)&classfac);
1429 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1431 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1432 IUnknown_Release(classfac);
1435 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1436 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1437 MSHLFLAGS_TABLESTRONG);
1439 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1440 IUnknown_Release(classfac);
1444 IUnknown_Release(classfac);
1446 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1451 /***********************************************************************
1452 * CoRevokeClassObject [OLE32.@]
1454 * Removes a class object from the class registry.
1457 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1461 * Failure: HRESULT code.
1464 * CoRegisterClassObject
1466 HRESULT WINAPI CoRevokeClassObject(
1469 HRESULT hr = E_INVALIDARG;
1470 RegisteredClass** prevClassLink;
1471 RegisteredClass* curClass;
1473 TRACE("(%08lx)\n",dwRegister);
1475 EnterCriticalSection( &csRegisteredClassList );
1478 * Iterate through the whole list and try to match the cookie.
1480 curClass = firstRegisteredClass;
1481 prevClassLink = &firstRegisteredClass;
1483 while (curClass != 0)
1486 * Check if we have a match on the cookie.
1488 if (curClass->dwCookie == dwRegister)
1491 * Remove the class from the chain.
1493 *prevClassLink = curClass->nextClass;
1496 * Release the reference to the class object.
1498 IUnknown_Release(curClass->classObject);
1500 if (curClass->pMarshaledData)
1503 memset(&zero, 0, sizeof(zero));
1504 /* FIXME: stop local server thread */
1505 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1506 CoReleaseMarshalData(curClass->pMarshaledData);
1510 * Free the memory used by the chain node.
1512 HeapFree(GetProcessHeap(), 0, curClass);
1519 * Step to the next class in the list.
1521 prevClassLink = &(curClass->nextClass);
1522 curClass = curClass->nextClass;
1526 LeaveCriticalSection( &csRegisteredClassList );
1528 * If we get to here, we haven't found our class.
1533 /***********************************************************************
1534 * COM_RegReadPath [internal]
1536 * Reads a registry value and expands it when necessary
1538 HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1543 WCHAR src[MAX_PATH];
1544 DWORD dwLength = dstlen * sizeof(WCHAR);
1546 if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1547 if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1548 if (keytype == REG_EXPAND_SZ) {
1549 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1551 lstrcpynW(dst, src, dstlen);
1559 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1562 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1563 DllGetClassObjectFunc DllGetClassObject;
1564 WCHAR dllpath[MAX_PATH+1];
1566 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1568 /* failure: CLSID is not found in registry */
1569 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1570 return REGDB_E_CLASSNOTREG;
1573 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1575 /* failure: DLL could not be loaded */
1576 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1577 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1580 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1582 /* failure: the dll did not export DllGetClassObject */
1583 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1584 FreeLibrary( hLibrary );
1585 return CO_E_DLLNOTFOUND;
1588 /* OK: get the ClassObject */
1589 COMPOBJ_DLLList_Add( hLibrary );
1590 return DllGetClassObject(rclsid, riid, ppv);
1593 /***********************************************************************
1594 * CoGetClassObject [OLE32.@]
1596 * FIXME. If request allows of several options and there is a failure
1597 * with one (other than not being registered) do we try the
1598 * others or return failure? (E.g. inprocess is registered but
1599 * the DLL is not found but the server version works)
1601 HRESULT WINAPI CoGetClassObject(
1602 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1603 REFIID iid, LPVOID *ppv)
1605 LPUNKNOWN regClassObject;
1606 HRESULT hres = E_UNEXPECTED;
1608 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1611 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1612 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1616 * First, try and see if we can't match the class ID with one of the
1617 * registered classes.
1619 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1621 /* Get the required interface from the retrieved pointer. */
1622 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1625 * Since QI got another reference on the pointer, we want to release the
1626 * one we already have. If QI was unsuccessful, this will release the object. This
1627 * is good since we are not returning it in the "out" parameter.
1629 IUnknown_Release(regClassObject);
1634 /* First try in-process server */
1635 if (CLSCTX_INPROC_SERVER & dwClsContext)
1637 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1640 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1643 if (hres == REGDB_E_CLASSNOTREG)
1644 ERR("class %s not registered\n", debugstr_guid(rclsid));
1646 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1649 if (SUCCEEDED(hres))
1651 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1655 /* return if we got a class, otherwise fall through to one of the
1657 if (SUCCEEDED(hres))
1661 /* Next try in-process handler */
1662 if (CLSCTX_INPROC_HANDLER & dwClsContext)
1664 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1667 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1670 if (hres == REGDB_E_CLASSNOTREG)
1671 ERR("class %s not registered\n", debugstr_guid(rclsid));
1673 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1676 if (SUCCEEDED(hres))
1678 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1682 /* return if we got a class, otherwise fall through to one of the
1684 if (SUCCEEDED(hres))
1688 /* Next try out of process */
1689 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1691 return RPC_GetLocalClassObject(rclsid,iid,ppv);
1694 /* Finally try remote: this requires networked DCOM (a lot of work) */
1695 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1697 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1698 hres = E_NOINTERFACE;
1702 ERR("no class object %s could be created for for context 0x%lx\n",
1703 debugstr_guid(rclsid), dwClsContext);
1707 /***********************************************************************
1708 * CoResumeClassObjects (OLE32.@)
1710 * Resumes all class objects registered with REGCLS_SUSPENDED.
1714 * Failure: HRESULT code.
1716 HRESULT WINAPI CoResumeClassObjects(void)
1722 /***********************************************************************
1723 * GetClassFile (OLE32.@)
1725 * This function supplies the CLSID associated with the given filename.
1727 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1731 int nbElm, length, i;
1733 LPOLESTR *pathDec=0,absFile=0,progId=0;
1735 static const WCHAR bkslashW[] = {'\\',0};
1736 static const WCHAR dotW[] = {'.',0};
1738 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1740 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1741 if((StgIsStorageFile(filePathName))==S_OK){
1743 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1746 res=ReadClassStg(pstg,pclsid);
1748 IStorage_Release(pstg);
1752 /* if the file is not a storage object then attemps to match various bits in the file against a
1753 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1756 for(i=0;i<nFileTypes;i++)
1758 for(i=0;j<nPatternsForType;j++){
1763 pat=ReadPatternFromRegistry(i,j);
1764 hFile=CreateFileW(filePathName,,,,,,hFile);
1765 SetFilePosition(hFile,pat.offset);
1766 ReadFile(hFile,buf,pat.size,&r,NULL);
1767 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1769 *pclsid=ReadCLSIDFromRegistry(i);
1775 /* if the above strategies fail then search for the extension key in the registry */
1777 /* get the last element (absolute file) in the path name */
1778 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1779 absFile=pathDec[nbElm-1];
1781 /* failed if the path represente a directory and not an absolute file name*/
1782 if (!lstrcmpW(absFile, bkslashW))
1783 return MK_E_INVALIDEXTENSION;
1785 /* get the extension of the file */
1787 length=lstrlenW(absFile);
1788 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1791 if (!extension || !lstrcmpW(extension, dotW))
1792 return MK_E_INVALIDEXTENSION;
1794 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1796 /* get the progId associated to the extension */
1797 progId = CoTaskMemAlloc(sizeProgId);
1798 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1800 if (res==ERROR_SUCCESS)
1801 /* return the clsid associated to the progId */
1802 res= CLSIDFromProgID(progId,pclsid);
1804 for(i=0; pathDec[i]!=NULL;i++)
1805 CoTaskMemFree(pathDec[i]);
1806 CoTaskMemFree(pathDec);
1808 CoTaskMemFree(progId);
1810 if (res==ERROR_SUCCESS)
1813 return MK_E_INVALIDEXTENSION;
1816 /***********************************************************************
1817 * CoCreateInstance [OLE32.@]
1819 HRESULT WINAPI CoCreateInstance(
1821 LPUNKNOWN pUnkOuter,
1827 LPCLASSFACTORY lpclf = 0;
1829 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
1830 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
1832 if (!COM_CurrentApt())
1834 ERR("apartment not initialised\n");
1835 return CO_E_NOTINITIALIZED;
1845 * Initialize the "out" parameter
1850 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1851 * Rather than create a class factory, we can just check for it here
1853 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1854 if (StdGlobalInterfaceTableInstance == NULL)
1855 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1856 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1857 if (hres) return hres;
1859 TRACE("Retrieved GIT (%p)\n", *ppv);
1864 * Get a class factory to construct the object we want.
1866 hres = CoGetClassObject(rclsid,
1873 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1874 debugstr_guid(rclsid),hres);
1879 * Create the object and don't forget to release the factory
1881 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1882 IClassFactory_Release(lpclf);
1884 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1885 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1890 /***********************************************************************
1891 * CoCreateInstanceEx [OLE32.@]
1893 HRESULT WINAPI CoCreateInstanceEx(
1895 LPUNKNOWN pUnkOuter,
1897 COSERVERINFO* pServerInfo,
1901 IUnknown* pUnk = NULL;
1904 ULONG successCount = 0;
1909 if ( (cmq==0) || (pResults==NULL))
1910 return E_INVALIDARG;
1912 if (pServerInfo!=NULL)
1913 FIXME("() non-NULL pServerInfo not supported!\n");
1916 * Initialize all the "out" parameters.
1918 for (index = 0; index < cmq; index++)
1920 pResults[index].pItf = NULL;
1921 pResults[index].hr = E_NOINTERFACE;
1925 * Get the object and get its IUnknown pointer.
1927 hr = CoCreateInstance(rclsid,
1937 * Then, query for all the interfaces requested.
1939 for (index = 0; index < cmq; index++)
1941 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1942 pResults[index].pIID,
1943 (VOID**)&(pResults[index].pItf));
1945 if (pResults[index].hr == S_OK)
1950 * Release our temporary unknown pointer.
1952 IUnknown_Release(pUnk);
1954 if (successCount == 0)
1955 return E_NOINTERFACE;
1957 if (successCount!=cmq)
1958 return CO_S_NOTALLINTERFACES;
1963 /***********************************************************************
1964 * CoLoadLibrary (OLE32.@)
1969 * lpszLibName [I] Path to library.
1970 * bAutoFree [I] Whether the library should automatically be freed.
1973 * Success: Handle to loaded library.
1977 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1979 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1981 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1983 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1986 /***********************************************************************
1987 * CoFreeLibrary [OLE32.@]
1989 * Unloads a library from memory.
1992 * hLibrary [I] Handle to library to unload.
1998 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2000 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2002 FreeLibrary(hLibrary);
2006 /***********************************************************************
2007 * CoFreeAllLibraries [OLE32.@]
2009 * Function for backwards compatibility only. Does nothing.
2015 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2017 void WINAPI CoFreeAllLibraries(void)
2023 /***********************************************************************
2024 * CoFreeUnusedLibraries [OLE32.@]
2025 * CoFreeUnusedLibraries [COMPOBJ.17]
2027 * Frees any unused libraries. Unused are identified as those that return
2028 * S_OK from their DllCanUnloadNow function.
2034 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2036 void WINAPI CoFreeUnusedLibraries(void)
2038 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2039 * through the main apartment's thread to call DllCanUnloadNow */
2040 COMPOBJ_DllList_FreeUnused(0);
2043 /***********************************************************************
2044 * CoFileTimeNow [OLE32.@]
2045 * CoFileTimeNow [COMPOBJ.82]
2047 * Retrieves the current time in FILETIME format.
2050 * lpFileTime [O] The current time.
2055 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2057 GetSystemTimeAsFileTime( lpFileTime );
2061 static void COM_RevokeAllClasses()
2063 EnterCriticalSection( &csRegisteredClassList );
2065 while (firstRegisteredClass!=0)
2067 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2070 LeaveCriticalSection( &csRegisteredClassList );
2073 /******************************************************************************
2074 * CoLockObjectExternal [OLE32.@]
2076 * Increments or decrements the external reference count of a stub object.
2079 * pUnk [I] Stub object.
2080 * fLock [I] If TRUE then increments the external ref-count,
2081 * otherwise decrements.
2082 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2083 * calling CoDisconnectObject.
2087 * Failure: HRESULT code.
2089 HRESULT WINAPI CoLockObjectExternal(
2092 BOOL fLastUnlockReleases)
2094 struct stub_manager *stubmgr;
2095 struct apartment *apt;
2097 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2098 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2100 apt = COM_CurrentApt();
2101 if (!apt) return CO_E_NOTINITIALIZED;
2103 stubmgr = get_stub_manager_from_object(apt, pUnk);
2108 stub_manager_ext_addref(stubmgr, 1);
2110 stub_manager_ext_release(stubmgr, 1);
2112 stub_manager_int_release(stubmgr);
2118 WARN("stub object not found %p\n", pUnk);
2119 /* Note: native is pretty broken here because it just silently
2120 * fails, without returning an appropriate error code, making apps
2121 * think that the object was disconnected, when it actually wasn't */
2126 /***********************************************************************
2127 * CoInitializeWOW (OLE32.@)
2129 * WOW equivalent of CoInitialize?
2138 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2140 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2144 /***********************************************************************
2145 * CoGetState [OLE32.@]
2147 * Retrieves the thread state object previously stored by CoSetState().
2150 * ppv [I] Address where pointer to object will be stored.
2154 * Failure: E_OUTOFMEMORY.
2157 * Crashes on all invalid ppv addresses, including NULL.
2158 * If the function returns a non-NULL object then the caller must release its
2159 * reference on the object when the object is no longer required.
2164 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2166 struct oletls *info = COM_CurrentInfo();
2167 if (!info) return E_OUTOFMEMORY;
2173 IUnknown_AddRef(info->state);
2175 TRACE("apt->state=%p\n", info->state);
2181 /***********************************************************************
2182 * CoSetState [OLE32.@]
2184 * Sets the thread state object.
2187 * pv [I] Pointer to state object to be stored.
2190 * The system keeps a reference on the object while the object stored.
2194 * Failure: E_OUTOFMEMORY.
2196 HRESULT WINAPI CoSetState(IUnknown * pv)
2198 struct oletls *info = COM_CurrentInfo();
2199 if (!info) return E_OUTOFMEMORY;
2201 if (pv) IUnknown_AddRef(pv);
2205 TRACE("-- release %p now\n", info->state);
2206 IUnknown_Release(info->state);
2215 /******************************************************************************
2216 * OleGetAutoConvert [OLE32.@]
2218 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2220 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2222 WCHAR buf[CHARS_IN_GUID];
2226 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2231 if (RegQueryValueW(hkey, NULL, buf, &len))
2233 res = REGDB_E_KEYMISSING;
2236 res = CLSIDFromString(buf, pClsidNew);
2238 if (hkey) RegCloseKey(hkey);
2242 /******************************************************************************
2243 * CoTreatAsClass [OLE32.@]
2245 * Sets the TreatAs value of a class.
2248 * clsidOld [I] Class to set TreatAs value on.
2249 * clsidNew [I] The class the clsidOld should be treated as.
2253 * Failure: HRESULT code.
2258 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2260 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2261 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2263 WCHAR szClsidNew[CHARS_IN_GUID];
2265 WCHAR auto_treat_as[CHARS_IN_GUID];
2266 LONG auto_treat_as_size = sizeof(auto_treat_as);
2269 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2272 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2274 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2275 !CLSIDFromString(auto_treat_as, &id))
2277 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2279 res = REGDB_E_WRITEREGDB;
2285 RegDeleteKeyW(hkey, wszTreatAs);
2289 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2290 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2292 res = REGDB_E_WRITEREGDB;
2297 if (hkey) RegCloseKey(hkey);
2301 /******************************************************************************
2302 * CoGetTreatAsClass [OLE32.@]
2304 * Gets the TreatAs value of a class.
2307 * clsidOld [I] Class to get the TreatAs value of.
2308 * clsidNew [I] The class the clsidOld should be treated as.
2312 * Failure: HRESULT code.
2317 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2319 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2321 WCHAR szClsidNew[CHARS_IN_GUID];
2323 LONG len = sizeof(szClsidNew);
2325 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2326 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2328 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2331 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2336 res = CLSIDFromString(szClsidNew,clsidNew);
2338 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2340 if (hkey) RegCloseKey(hkey);
2344 /******************************************************************************
2345 * CoGetCurrentProcess [OLE32.@]
2346 * CoGetCurrentProcess [COMPOBJ.34]
2348 * Gets the current process ID.
2351 * The current process ID.
2354 * Is DWORD really the correct return type for this function?
2356 DWORD WINAPI CoGetCurrentProcess(void)
2358 return GetCurrentProcessId();
2361 /******************************************************************************
2362 * CoRegisterMessageFilter [OLE32.@]
2364 * Registers a message filter.
2367 * lpMessageFilter [I] Pointer to interface.
2368 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2372 * Failure: HRESULT code.
2374 HRESULT WINAPI CoRegisterMessageFilter(
2375 LPMESSAGEFILTER lpMessageFilter,
2376 LPMESSAGEFILTER *lplpMessageFilter)
2379 if (lplpMessageFilter) {
2380 *lplpMessageFilter = NULL;
2385 /***********************************************************************
2386 * CoIsOle1Class [OLE32.@]
2388 * Determines whether the specified class an OLE v1 class.
2391 * clsid [I] Class to test.
2394 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2396 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2398 FIXME("%s\n", debugstr_guid(clsid));
2402 /***********************************************************************
2403 * IsEqualGUID [OLE32.@]
2405 * Compares two Unique Identifiers.
2408 * rguid1 [I] The first GUID to compare.
2409 * rguid2 [I] The other GUID to compare.
2415 BOOL WINAPI IsEqualGUID(
2419 return !memcmp(rguid1,rguid2,sizeof(GUID));
2422 /***********************************************************************
2423 * CoInitializeSecurity [OLE32.@]
2425 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2426 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2427 void* pReserved1, DWORD dwAuthnLevel,
2428 DWORD dwImpLevel, void* pReserved2,
2429 DWORD dwCapabilities, void* pReserved3)
2431 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2432 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2433 dwCapabilities, pReserved3);
2437 /***********************************************************************
2438 * CoSuspendClassObjects [OLE32.@]
2440 * Suspends all registered class objects to prevent further requests coming in
2441 * for those objects.
2445 * Failure: HRESULT code.
2447 HRESULT WINAPI CoSuspendClassObjects(void)
2453 /***********************************************************************
2454 * CoAddRefServerProcess [OLE32.@]
2456 * Helper function for incrementing the reference count of a local-server
2460 * New reference count.
2462 ULONG WINAPI CoAddRefServerProcess(void)
2468 /***********************************************************************
2469 * CoReleaseServerProcess [OLE32.@]
2471 * Helper function for decrementing the reference count of a local-server
2475 * New reference count.
2477 ULONG WINAPI CoReleaseServerProcess(void)
2483 /***********************************************************************
2484 * CoIsHandlerConnected [OLE32.@]
2486 * Determines whether a proxy is connected to a remote stub.
2489 * pUnk [I] Pointer to object that may or may not be connected.
2492 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2495 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2497 FIXME("%p\n", pUnk);
2502 /***********************************************************************
2503 * CoAllowSetForegroundWindow [OLE32.@]
2506 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2508 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2512 /***********************************************************************
2513 * CoQueryProxyBlanket [OLE32.@]
2515 * Retrieves the security settings being used by a proxy.
2518 * pProxy [I] Pointer to the proxy object.
2519 * pAuthnSvc [O] The type of authentication service.
2520 * pAuthzSvc [O] The type of authorization service.
2521 * ppServerPrincName [O] Optional. The server prinicple name.
2522 * pAuthnLevel [O] The authentication level.
2523 * pImpLevel [O] The impersonation level.
2524 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2525 * pCapabilities [O] Flags affecting the security behaviour.
2529 * Failure: HRESULT code.
2532 * CoCopyProxy, CoSetProxyBlanket.
2534 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2535 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2536 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2538 IClientSecurity *pCliSec;
2541 TRACE("%p\n", pProxy);
2543 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2546 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2547 pAuthzSvc, ppServerPrincName,
2548 pAuthnLevel, pImpLevel, ppAuthInfo,
2550 IClientSecurity_Release(pCliSec);
2553 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2557 /***********************************************************************
2558 * CoSetProxyBlanket [OLE32.@]
2560 * Sets the security settings for a proxy.
2563 * pProxy [I] Pointer to the proxy object.
2564 * AuthnSvc [I] The type of authentication service.
2565 * AuthzSvc [I] The type of authorization service.
2566 * pServerPrincName [I] The server prinicple name.
2567 * AuthnLevel [I] The authentication level.
2568 * ImpLevel [I] The impersonation level.
2569 * pAuthInfo [I] Information specific to the authorization/authentication service.
2570 * Capabilities [I] Flags affecting the security behaviour.
2574 * Failure: HRESULT code.
2577 * CoQueryProxyBlanket, CoCopyProxy.
2579 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2580 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2581 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2583 IClientSecurity *pCliSec;
2586 TRACE("%p\n", pProxy);
2588 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2591 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2592 AuthzSvc, pServerPrincName,
2593 AuthnLevel, ImpLevel, pAuthInfo,
2595 IClientSecurity_Release(pCliSec);
2598 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2602 /***********************************************************************
2603 * CoCopyProxy [OLE32.@]
2608 * pProxy [I] Pointer to the proxy object.
2609 * ppCopy [O] Copy of the proxy.
2613 * Failure: HRESULT code.
2616 * CoQueryProxyBlanket, CoSetProxyBlanket.
2618 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2620 IClientSecurity *pCliSec;
2623 TRACE("%p\n", pProxy);
2625 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2628 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2629 IClientSecurity_Release(pCliSec);
2632 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2637 /***********************************************************************
2638 * CoWaitForMultipleHandles [OLE32.@]
2640 * Waits for one or more handles to become signaled.
2643 * dwFlags [I] Flags. See notes.
2644 * dwTimeout [I] Timeout in milliseconds.
2645 * cHandles [I] Number of handles pointed to by pHandles.
2646 * pHandles [I] Handles to wait for.
2647 * lpdwindex [O] Index of handle that was signaled.
2651 * Failure: RPC_S_CALLPENDING on timeout.
2655 * The dwFlags parameter can be zero or more of the following:
2656 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2657 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2660 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2662 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2663 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2666 DWORD start_time = GetTickCount();
2667 BOOL message_loop = TRUE;
2669 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2670 pHandles, lpdwindex);
2674 DWORD now = GetTickCount();
2677 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2679 hr = RPC_S_CALLPENDING;
2685 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2686 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2688 TRACE("waiting for rpc completion or window message\n");
2690 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2691 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2692 QS_ALLINPUT, wait_flags);
2694 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2697 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2699 /* FIXME: filter the messages here */
2700 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2701 TranslateMessage(&msg);
2702 DispatchMessageW(&msg);
2703 if (msg.message == WM_QUIT)
2705 TRACE("resending WM_QUIT to outer message loop\n");
2706 PostQuitMessage(msg.wParam);
2707 /* no longer need to process messages */
2708 message_loop = FALSE;
2717 TRACE("waiting for rpc completion\n");
2719 res = WaitForMultipleObjectsEx(cHandles, pHandles,
2720 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
2721 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2722 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
2725 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2727 /* handle signaled, store index */
2728 *lpdwindex = (res - WAIT_OBJECT_0);
2731 else if (res == WAIT_TIMEOUT)
2733 hr = RPC_S_CALLPENDING;
2738 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2743 TRACE("-- 0x%08lx\n", hr);
2747 /***********************************************************************
2750 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2752 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2755 case DLL_PROCESS_ATTACH:
2756 OLE32_hInstance = hinstDLL;
2757 COMPOBJ_InitProcess();
2758 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2761 case DLL_PROCESS_DETACH:
2762 if (TRACE_ON(ole)) CoRevokeMallocSpy();
2763 COMPOBJ_UninitProcess();
2764 OLE32_hInstance = 0;
2767 case DLL_THREAD_DETACH:
2774 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */