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 "ole32_main.h"
70 #include "compobj_private.h"
72 #include "wine/debug.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
76 typedef LPCSTR LPCOLESTR16
;
78 /****************************************************************************
79 * This section defines variables internal to the COM module.
81 * TODO: Most of these things will have to be made thread-safe.
84 static HRESULT
COM_GetRegisteredClassObject(REFCLSID rclsid
, DWORD dwClsContext
, LPUNKNOWN
* ppUnk
);
85 static void COM_RevokeAllClasses(void);
87 const CLSID CLSID_StdGlobalInterfaceTable
= { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
89 APARTMENT
*MTA
; /* protected by csApartment */
90 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
92 static CRITICAL_SECTION csApartment
;
93 static CRITICAL_SECTION_DEBUG critsect_debug
=
96 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
97 0, 0, { 0, (DWORD
)(__FILE__
": csApartment") }
99 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
102 * This lock count counts the number of times CoInitialize is called. It is
103 * decreased every time CoUninitialize is called. When it hits 0, the COM
104 * libraries are freed
106 static LONG s_COMLockCount
= 0;
109 * This linked list contains the list of registered class objects. These
110 * are mostly used to register the factories for out-of-proc servers of OLE
113 * TODO: Make this data structure aware of inter-process communication. This
114 * means that parts of this will be exported to the Wine Server.
116 typedef struct tagRegisteredClass
118 CLSID classIdentifier
;
119 LPUNKNOWN classObject
;
123 LPSTREAM pMarshaledData
; /* FIXME: only really need to store OXID and IPID */
124 struct tagRegisteredClass
* nextClass
;
127 static RegisteredClass
* firstRegisteredClass
= NULL
;
129 static CRITICAL_SECTION csRegisteredClassList
;
130 static CRITICAL_SECTION_DEBUG class_cs_debug
=
132 0, 0, &csRegisteredClassList
,
133 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
134 0, 0, { 0, (DWORD
)(__FILE__
": csRegisteredClassList") }
136 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
138 /*****************************************************************************
139 * This section contains OpenDllList definitions
141 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
142 * other functions that do LoadLibrary _without_ giving back a HMODULE.
143 * Without this list these handles would never be freed.
145 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
146 * next unload-call but not before 600 sec.
149 typedef struct tagOpenDll
{
151 struct tagOpenDll
*next
;
154 static OpenDll
*openDllList
= NULL
; /* linked list of open dlls */
156 static CRITICAL_SECTION csOpenDllList
;
157 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
159 0, 0, &csOpenDllList
,
160 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
161 0, 0, { 0, (DWORD
)(__FILE__
": csOpenDllList") }
163 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
165 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',' ',
166 '0','x','#','#','#','#','#','#','#','#',' ',0};
167 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
169 static void COMPOBJ_DLLList_Add(HANDLE hLibrary
);
170 static void COMPOBJ_DllList_FreeUnused(int Timeout
);
172 void COMPOBJ_InitProcess( void )
176 /* Dispatching to the correct thread in an apartment is done through
177 * window messages rather than RPC transports. When an interface is
178 * marshalled into another apartment in the same process, a window of the
179 * following class is created. The *caller* of CoMarshalInterface (ie the
180 * application) is responsible for pumping the message loop in that thread.
181 * The WM_USER messages which point to the RPCs are then dispatched to
182 * COM_AptWndProc by the user's code from the apartment in which the interface
185 memset(&wclass
, 0, sizeof(wclass
));
186 wclass
.lpfnWndProc
= apartment_wndproc
;
187 wclass
.hInstance
= OLE32_hInstance
;
188 wclass
.lpszClassName
= wszAptWinClass
;
189 RegisterClassW(&wclass
);
192 void COMPOBJ_UninitProcess( void )
194 UnregisterClassW(wszAptWinClass
, OLE32_hInstance
);
197 void COM_TlsDestroy()
199 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
202 if (info
->apt
) apartment_release(info
->apt
);
203 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
204 if (info
->state
) IUnknown_Release(info
->state
);
205 HeapFree(GetProcessHeap(), 0, info
);
206 NtCurrentTeb()->ReservedForOle
= NULL
;
210 /******************************************************************************
214 /* allocates memory and fills in the necessary fields for a new apartment
216 static APARTMENT
*apartment_construct(DWORD model
)
220 TRACE("creating new apartment, model=%ld\n", model
);
222 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
223 apt
->tid
= GetCurrentThreadId();
224 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
225 GetCurrentProcess(), &apt
->thread
,
226 THREAD_ALL_ACCESS
, FALSE
, 0);
228 list_init(&apt
->proxies
);
229 list_init(&apt
->stubmgrs
);
232 apt
->remunk_exported
= FALSE
;
234 InitializeCriticalSection(&apt
->cs
);
235 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
239 if (model
& COINIT_APARTMENTTHREADED
)
241 /* FIXME: should be randomly generated by in an RPC call to rpcss */
242 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
243 apt
->win
= CreateWindowW(wszAptWinClass
, NULL
, 0,
245 0, 0, OLE32_hInstance
, NULL
);
249 /* FIXME: should be randomly generated by in an RPC call to rpcss */
250 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
253 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
255 /* the locking here is not currently needed for the MTA case, but it
256 * doesn't hurt and makes the code simpler */
257 EnterCriticalSection(&csApartment
);
258 list_add_head(&apts
, &apt
->entry
);
259 LeaveCriticalSection(&csApartment
);
264 /* gets and existing apartment if one exists or otherwise creates an apartment
265 * structure which stores OLE apartment-local information and stores a pointer
266 * to it in the thread-local storage */
267 static APARTMENT
*apartment_get_or_create(DWORD model
)
269 APARTMENT
*apt
= COM_CurrentApt();
273 if (model
& COINIT_APARTMENTTHREADED
)
275 apt
= apartment_construct(model
);
276 COM_CurrentInfo()->apt
= apt
;
280 EnterCriticalSection(&csApartment
);
282 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
283 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
287 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
288 apartment_addref(MTA
);
291 MTA
= apartment_construct(model
);
294 COM_CurrentInfo()->apt
= apt
;
296 LeaveCriticalSection(&csApartment
);
303 DWORD
apartment_addref(struct apartment
*apt
)
305 DWORD refs
= InterlockedIncrement(&apt
->refs
);
306 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
310 DWORD
apartment_release(struct apartment
*apt
)
314 EnterCriticalSection(&csApartment
);
316 ret
= InterlockedDecrement(&apt
->refs
);
317 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
318 /* destruction stuff that needs to happen under csApartment CS */
321 if (apt
== MTA
) MTA
= NULL
;
322 list_remove(&apt
->entry
);
325 LeaveCriticalSection(&csApartment
);
329 struct list
*cursor
, *cursor2
;
331 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
333 /* no locking is needed for this apartment, because no other thread
334 * can access it at this point */
336 apartment_disconnectproxies(apt
);
338 if (apt
->win
) DestroyWindow(apt
->win
);
340 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
342 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
343 /* release the implicit reference given by the fact that the
344 * stub has external references (it must do since it is in the
345 * stub manager list in the apartment and all non-apartment users
346 * must have a ref on the apartment and so it cannot be destroyed).
348 stub_manager_int_release(stubmgr
);
351 /* if this assert fires, then another thread took a reference to a
352 * stub manager without taking a reference to the containing
353 * apartment, which it must do. */
354 assert(list_empty(&apt
->stubmgrs
));
356 if (apt
->filter
) IUnknown_Release(apt
->filter
);
358 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
359 DeleteCriticalSection(&apt
->cs
);
360 CloseHandle(apt
->thread
);
362 HeapFree(GetProcessHeap(), 0, apt
);
368 /* The given OXID must be local to this process:
370 * The ref parameter is here mostly to ensure people remember that
371 * they get one, you should normally take a ref for thread safety.
373 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
375 APARTMENT
*result
= NULL
;
378 EnterCriticalSection(&csApartment
);
379 LIST_FOR_EACH( cursor
, &apts
)
381 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
382 if (apt
->oxid
== oxid
)
385 if (ref
) apartment_addref(result
);
389 LeaveCriticalSection(&csApartment
);
394 /* gets the apartment which has a given creator thread ID. The caller must
395 * release the reference from the apartment as soon as the apartment pointer
396 * is no longer required. */
397 APARTMENT
*apartment_findfromtid(DWORD tid
)
399 APARTMENT
*result
= NULL
;
402 EnterCriticalSection(&csApartment
);
403 LIST_FOR_EACH( cursor
, &apts
)
405 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
409 apartment_addref(result
);
413 LeaveCriticalSection(&csApartment
);
418 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
423 return RPC_ExecuteCall((struct dispatch_params
*)lParam
);
425 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
429 /*****************************************************************************
430 * This section contains OpenDllList implemantation
433 static void COMPOBJ_DLLList_Add(HANDLE hLibrary
)
440 EnterCriticalSection( &csOpenDllList
);
442 if (openDllList
== NULL
) {
443 /* empty list -- add first node */
444 openDllList
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
445 openDllList
->hLibrary
=hLibrary
;
446 openDllList
->next
= NULL
;
448 /* search for this dll */
450 for (ptr
= openDllList
; ptr
->next
!= NULL
; ptr
=ptr
->next
) {
451 if (ptr
->hLibrary
== hLibrary
) {
457 /* dll not found, add it */
459 openDllList
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
460 openDllList
->hLibrary
= hLibrary
;
461 openDllList
->next
= tmp
;
465 LeaveCriticalSection( &csOpenDllList
);
468 static void COMPOBJ_DllList_FreeUnused(int Timeout
)
470 OpenDll
*curr
, *next
, *prev
= NULL
;
471 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
472 DllCanUnloadNowFunc DllCanUnloadNow
;
476 EnterCriticalSection( &csOpenDllList
);
478 for (curr
= openDllList
; curr
!= NULL
; ) {
479 DllCanUnloadNow
= (DllCanUnloadNowFunc
) GetProcAddress(curr
->hLibrary
, "DllCanUnloadNow");
481 if ( (DllCanUnloadNow
!= NULL
) && (DllCanUnloadNow() == S_OK
) ) {
484 TRACE("freeing %p\n", curr
->hLibrary
);
485 FreeLibrary(curr
->hLibrary
);
487 HeapFree(GetProcessHeap(), 0, curr
);
488 if (curr
== openDllList
) {
501 LeaveCriticalSection( &csOpenDllList
);
504 /******************************************************************************
505 * CoBuildVersion [OLE32.@]
506 * CoBuildVersion [COMPOBJ.1]
508 * Gets the build version of the DLL.
513 * Current build version, hiword is majornumber, loword is minornumber
515 DWORD WINAPI
CoBuildVersion(void)
517 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
518 return (rmm
<<16)+rup
;
521 /******************************************************************************
522 * CoInitialize [OLE32.@]
524 * Initializes the COM libraries by calling CoInitializeEx with
525 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
528 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
531 * Success: S_OK if not already initialized, S_FALSE otherwise.
532 * Failure: HRESULT code.
537 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
540 * Just delegate to the newer method.
542 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
545 /******************************************************************************
546 * CoInitializeEx [OLE32.@]
548 * Initializes the COM libraries.
551 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
552 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
555 * S_OK if successful,
556 * S_FALSE if this function was called already.
557 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
562 * The behavior used to set the IMalloc used for memory management is
564 * The dwCoInit parameter must specify of of the following apartment
566 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
567 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
568 * The parameter may also specify zero or more of the following flags:
569 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
570 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
575 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
580 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
582 if (lpReserved
!=NULL
)
584 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
588 * Check the lock count. If this is the first time going through the initialize
589 * process, we have to initialize the libraries.
591 * And crank-up that lock count.
593 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
596 * Initialize the various COM libraries and data structures.
598 TRACE("() - Initializing the COM libraries\n");
600 /* we may need to defer this until after apartment initialisation */
601 RunningObjectTableImpl_Initialize();
604 if (!(apt
= COM_CurrentInfo()->apt
))
606 apt
= apartment_get_or_create(dwCoInit
);
607 if (!apt
) return E_OUTOFMEMORY
;
609 else if (dwCoInit
!= apt
->model
)
611 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
612 code then we are probably using the wrong threading model to implement that API. */
613 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt
->model
, dwCoInit
);
614 return RPC_E_CHANGED_MODE
;
619 COM_CurrentInfo()->inits
++;
624 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
625 pending RPCs are ignored. Non-COM messages are discarded at this point.
627 void COM_FlushMessageQueue(void)
630 APARTMENT
*apt
= COM_CurrentApt();
632 if (!apt
|| !apt
->win
) return;
634 TRACE("Flushing STA message queue\n");
636 while (PeekMessageA(&message
, NULL
, 0, 0, PM_REMOVE
))
638 if (message
.hwnd
!= apt
->win
)
640 WARN("discarding message 0x%x for window %p\n", message
.message
, message
.hwnd
);
644 TranslateMessage(&message
);
645 DispatchMessageA(&message
);
649 /***********************************************************************
650 * CoUninitialize [OLE32.@]
652 * This method will decrement the refcount on the current apartment, freeing
653 * the resources associated with it if it is the last thread in the apartment.
654 * If the last apartment is freed, the function will additionally release
655 * any COM resources associated with the process.
665 void WINAPI
CoUninitialize(void)
667 struct oletls
* info
= COM_CurrentInfo();
672 /* will only happen on OOM */
678 ERR("Mismatched CoUninitialize\n");
684 apartment_release(info
->apt
);
689 * Decrease the reference count.
690 * If we are back to 0 locks on the COM library, make sure we free
691 * all the associated data structures.
693 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
696 TRACE("() - Releasing the COM libraries\n");
698 RunningObjectTableImpl_UnInitialize();
700 /* Release the references to the registered class objects */
701 COM_RevokeAllClasses();
703 /* This will free the loaded COM Dlls */
704 CoFreeAllLibraries();
706 /* This ensures we deal with any pending RPCs */
707 COM_FlushMessageQueue();
709 else if (lCOMRefCnt
<1) {
710 ERR( "CoUninitialize() - not CoInitialized.\n" );
711 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
715 /******************************************************************************
716 * CoDisconnectObject [OLE32.@]
717 * CoDisconnectObject [COMPOBJ.15]
719 * Disconnects all connections to this object from remote processes. Dispatches
720 * pending RPCs while blocking new RPCs from occurring, and then calls
721 * IMarshal::DisconnectObject on the given object.
723 * Typically called when the object server is forced to shut down, for instance by
727 * lpUnk [I] The object whose stub should be disconnected.
728 * reserved [I] Reserved. Should be set to 0.
732 * Failure: HRESULT code.
735 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
737 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
743 TRACE("(%p, 0x%08lx)\n", lpUnk
, reserved
);
745 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
748 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
749 IMarshal_Release(marshal
);
753 apt
= COM_CurrentApt();
755 return CO_E_NOTINITIALIZED
;
757 apartment_disconnectobject(apt
, lpUnk
);
759 /* Note: native is pretty broken here because it just silently
760 * fails, without returning an appropriate error code if the object was
761 * not found, making apps think that the object was disconnected, when
762 * it actually wasn't */
767 /******************************************************************************
768 * CoCreateGuid [OLE32.@]
770 * Simply forwards to UuidCreate in RPCRT4.
773 * pguid [O] Points to the GUID to initialize.
777 * Failure: HRESULT code.
782 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
784 return UuidCreate(pguid
);
787 /******************************************************************************
788 * CLSIDFromString [OLE32.@]
789 * IIDFromString [OLE32.@]
791 * Converts a unique identifier from its string representation into
795 * idstr [I] The string representation of the GUID.
796 * id [O] GUID converted from the string.
800 * CO_E_CLASSSTRING if idstr is not a valid CLSID
804 * In Windows, if idstr is not a valid CLSID string then it gets
805 * treated as a ProgID. Wine currently doesn't do this. If idstr is
806 * NULL it's treated as an all-zero GUID.
811 HRESULT WINAPI
__CLSIDFromStringA(LPCSTR idstr
, CLSID
*id
)
813 const BYTE
*s
= (const BYTE
*) idstr
;
818 s
= "{00000000-0000-0000-0000-000000000000}";
819 else { /* validate the CLSID string */
822 return CO_E_CLASSSTRING
;
824 if ((s
[0]!='{') || (s
[9]!='-') || (s
[14]!='-') || (s
[19]!='-') || (s
[24]!='-') || (s
[37]!='}'))
825 return CO_E_CLASSSTRING
;
827 for (i
=1; i
<37; i
++) {
828 if ((i
== 9)||(i
== 14)||(i
== 19)||(i
== 24)) continue;
829 if (!(((s
[i
] >= '0') && (s
[i
] <= '9')) ||
830 ((s
[i
] >= 'a') && (s
[i
] <= 'f')) ||
831 ((s
[i
] >= 'A') && (s
[i
] <= 'F'))))
832 return CO_E_CLASSSTRING
;
836 TRACE("%s -> %p\n", s
, id
);
838 /* quick lookup table */
839 memset(table
, 0, 256);
841 for (i
= 0; i
< 10; i
++) {
844 for (i
= 0; i
< 6; i
++) {
845 table
['A' + i
] = i
+10;
846 table
['a' + i
] = i
+10;
849 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
851 id
->Data1
= (table
[s
[1]] << 28 | table
[s
[2]] << 24 | table
[s
[3]] << 20 | table
[s
[4]] << 16 |
852 table
[s
[5]] << 12 | table
[s
[6]] << 8 | table
[s
[7]] << 4 | table
[s
[8]]);
853 id
->Data2
= table
[s
[10]] << 12 | table
[s
[11]] << 8 | table
[s
[12]] << 4 | table
[s
[13]];
854 id
->Data3
= table
[s
[15]] << 12 | table
[s
[16]] << 8 | table
[s
[17]] << 4 | table
[s
[18]];
856 /* these are just sequential bytes */
857 id
->Data4
[0] = table
[s
[20]] << 4 | table
[s
[21]];
858 id
->Data4
[1] = table
[s
[22]] << 4 | table
[s
[23]];
859 id
->Data4
[2] = table
[s
[25]] << 4 | table
[s
[26]];
860 id
->Data4
[3] = table
[s
[27]] << 4 | table
[s
[28]];
861 id
->Data4
[4] = table
[s
[29]] << 4 | table
[s
[30]];
862 id
->Data4
[5] = table
[s
[31]] << 4 | table
[s
[32]];
863 id
->Data4
[6] = table
[s
[33]] << 4 | table
[s
[34]];
864 id
->Data4
[7] = table
[s
[35]] << 4 | table
[s
[36]];
869 /*****************************************************************************/
871 HRESULT WINAPI
CLSIDFromString(LPOLESTR idstr
, CLSID
*id
)
876 if (!WideCharToMultiByte( CP_ACP
, 0, idstr
, -1, xid
, sizeof(xid
), NULL
, NULL
))
877 return CO_E_CLASSSTRING
;
880 ret
= __CLSIDFromStringA(xid
,id
);
881 if(ret
!= S_OK
) { /* It appears a ProgID is also valid */
882 ret
= CLSIDFromProgID(idstr
, id
);
887 /* Converts a GUID into the respective string representation. */
888 HRESULT
WINE_StringFromCLSID(
889 const CLSID
*id
, /* [in] GUID to be converted */
890 LPSTR idstr
/* [out] pointer to buffer to contain converted guid */
892 static const char *hex
= "0123456789ABCDEF";
897 { ERR("called with id=Null\n");
902 sprintf(idstr
, "{%08lX-%04X-%04X-%02X%02X-",
903 id
->Data1
, id
->Data2
, id
->Data3
,
904 id
->Data4
[0], id
->Data4
[1]);
908 for (i
= 2; i
< 8; i
++) {
909 *s
++ = hex
[id
->Data4
[i
]>>4];
910 *s
++ = hex
[id
->Data4
[i
] & 0xf];
916 TRACE("%p->%s\n", id
, idstr
);
922 /******************************************************************************
923 * StringFromCLSID [OLE32.@]
924 * StringFromIID [OLE32.@]
926 * Converts a GUID into the respective string representation.
927 * The target string is allocated using the OLE IMalloc.
930 * id [I] the GUID to be converted.
931 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
938 * StringFromGUID2, CLSIDFromString
940 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
946 if ((ret
= CoGetMalloc(0,&mllc
)))
949 ret
=WINE_StringFromCLSID(id
,buf
);
951 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, buf
, -1, NULL
, 0 );
952 *idstr
= IMalloc_Alloc( mllc
, len
* sizeof(WCHAR
) );
953 MultiByteToWideChar( CP_ACP
, 0, buf
, -1, *idstr
, len
);
958 /******************************************************************************
959 * StringFromGUID2 [OLE32.@]
960 * StringFromGUID2 [COMPOBJ.76]
962 * Modified version of StringFromCLSID that allows you to specify max
966 * id [I] GUID to convert to string.
967 * str [O] Buffer where the result will be stored.
968 * cmax [I] Size of the buffer in characters.
971 * Success: The length of the resulting string in characters.
974 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
978 if (WINE_StringFromCLSID(id
,xguid
))
980 return MultiByteToWideChar( CP_ACP
, 0, xguid
, -1, str
, cmax
);
983 /******************************************************************************
984 * ProgIDFromCLSID [OLE32.@]
986 * Converts a class id into the respective program ID.
989 * clsid [I] Class ID, as found in registry.
990 * lplpszProgID [O] Associated ProgID.
995 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
997 HRESULT WINAPI
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*lplpszProgID
)
999 char strCLSID
[50], *buf
, *buf2
;
1005 WINE_StringFromCLSID(clsid
, strCLSID
);
1007 buf
= HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID
)+14);
1008 sprintf(buf
,"CLSID\\%s\\ProgID", strCLSID
);
1009 if (RegOpenKeyA(HKEY_CLASSES_ROOT
, buf
, &xhkey
))
1010 ret
= REGDB_E_CLASSNOTREG
;
1012 HeapFree(GetProcessHeap(), 0, buf
);
1016 buf2
= HeapAlloc(GetProcessHeap(), 0, 255);
1018 if (RegQueryValueA(xhkey
, NULL
, buf2
, &buf2len
))
1019 ret
= REGDB_E_CLASSNOTREG
;
1023 if (CoGetMalloc(0,&mllc
))
1024 ret
= E_OUTOFMEMORY
;
1027 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, buf2
, -1, NULL
, 0 );
1028 *lplpszProgID
= IMalloc_Alloc(mllc
, len
* sizeof(WCHAR
) );
1029 MultiByteToWideChar( CP_ACP
, 0, buf2
, -1, *lplpszProgID
, len
);
1032 HeapFree(GetProcessHeap(), 0, buf2
);
1039 /******************************************************************************
1040 * CLSIDFromProgID [COMPOBJ.61]
1042 * Converts a program ID into the respective GUID.
1045 * progid [I] program id as found in registry
1046 * riid [O] associated CLSID
1050 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1052 HRESULT WINAPI
CLSIDFromProgID16(LPCOLESTR16 progid
, LPCLSID riid
)
1059 buf
= HeapAlloc(GetProcessHeap(),0,strlen(progid
)+8);
1060 sprintf(buf
,"%s\\CLSID",progid
);
1061 if ((err
=RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&xhkey
))) {
1062 HeapFree(GetProcessHeap(),0,buf
);
1063 return CO_E_CLASSSTRING
;
1065 HeapFree(GetProcessHeap(),0,buf
);
1066 buf2len
= sizeof(buf2
);
1067 if ((err
=RegQueryValueA(xhkey
,NULL
,buf2
,&buf2len
))) {
1069 return CO_E_CLASSSTRING
;
1072 return __CLSIDFromStringA(buf2
,riid
);
1075 /******************************************************************************
1076 * CLSIDFromProgID [OLE32.@]
1078 * Converts a program id into the respective GUID.
1081 * progid [I] Unicode program ID, as found in registry.
1082 * riid [O] Associated CLSID.
1086 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1088 HRESULT WINAPI
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID riid
)
1090 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
1092 DWORD buf2len
= sizeof(buf2
);
1095 WCHAR
*buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
1096 strcpyW( buf
, progid
);
1097 strcatW( buf
, clsidW
);
1098 if (RegOpenKeyW(HKEY_CLASSES_ROOT
,buf
,&xhkey
))
1100 HeapFree(GetProcessHeap(),0,buf
);
1101 return CO_E_CLASSSTRING
;
1103 HeapFree(GetProcessHeap(),0,buf
);
1105 if (RegQueryValueA(xhkey
,NULL
,buf2
,&buf2len
))
1108 return CO_E_CLASSSTRING
;
1111 return __CLSIDFromStringA(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 char *buf
, buf2
[40];
1157 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
1159 /* Get the input iid as a string */
1160 WINE_StringFromCLSID(riid
, buf2
);
1161 /* Allocate memory for the registry key we will construct.
1162 (length of iid string plus constant length of static text */
1163 buf
= HeapAlloc(GetProcessHeap(), 0, strlen(buf2
)+27);
1165 return E_OUTOFMEMORY
;
1167 /* Construct the registry key we want */
1168 sprintf(buf
,"Interface\\%s\\ProxyStubClsid32", buf2
);
1170 /* Open the key.. */
1171 if (RegOpenKeyA(HKEY_CLASSES_ROOT
, buf
, &xhkey
))
1173 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
1174 HeapFree(GetProcessHeap(),0,buf
);
1175 return REGDB_E_IIDNOTREG
;
1177 HeapFree(GetProcessHeap(),0,buf
);
1179 /* ... Once we have the key, query the registry to get the
1180 value of CLSID as a string, and convert it into a
1181 proper CLSID structure to be passed back to the app */
1182 buf2len
= sizeof(buf2
);
1183 if ( (RegQueryValueA(xhkey
,NULL
,buf2
,&buf2len
)) )
1186 return REGDB_E_IIDNOTREG
;
1190 /* We have the CLSid we want back from the registry as a string, so
1191 lets convert it into a CLSID structure */
1192 if ( (__CLSIDFromStringA(buf2
,pclsid
)) != NOERROR
)
1193 return REGDB_E_IIDNOTREG
;
1195 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
1201 /***********************************************************************
1202 * WriteClassStm (OLE32.@)
1204 * Writes a CLSID to a stream.
1207 * pStm [I] Stream to write to.
1208 * rclsid [I] CLSID to write.
1212 * Failure: HRESULT code.
1214 HRESULT WINAPI
WriteClassStm(IStream
*pStm
,REFCLSID rclsid
)
1216 TRACE("(%p,%p)\n",pStm
,rclsid
);
1219 return E_INVALIDARG
;
1221 return IStream_Write(pStm
,rclsid
,sizeof(CLSID
),NULL
);
1224 /***********************************************************************
1225 * ReadClassStm (OLE32.@)
1227 * Reads a CLSID from a stream.
1230 * pStm [I] Stream to read from.
1231 * rclsid [O] CLSID to read.
1235 * Failure: HRESULT code.
1237 HRESULT WINAPI
ReadClassStm(IStream
*pStm
,CLSID
*pclsid
)
1242 TRACE("(%p,%p)\n",pStm
,pclsid
);
1245 return E_INVALIDARG
;
1247 res
= IStream_Read(pStm
,(void*)pclsid
,sizeof(CLSID
),&nbByte
);
1252 if (nbByte
!= sizeof(CLSID
))
1260 * COM_GetRegisteredClassObject
1262 * This internal method is used to scan the registered class list to
1263 * find a class object.
1266 * rclsid Class ID of the class to find.
1267 * dwClsContext Class context to match.
1268 * ppv [out] returns a pointer to the class object. Complying
1269 * to normal COM usage, this method will increase the
1270 * reference count on this object.
1272 static HRESULT
COM_GetRegisteredClassObject(
1277 HRESULT hr
= S_FALSE
;
1278 RegisteredClass
* curClass
;
1280 EnterCriticalSection( &csRegisteredClassList
);
1288 * Iterate through the whole list and try to match the class ID.
1290 curClass
= firstRegisteredClass
;
1292 while (curClass
!= 0)
1295 * Check if we have a match on the class ID.
1297 if (IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
1300 * Since we don't do out-of process or DCOM just right away, let's ignore the
1305 * We have a match, return the pointer to the class object.
1307 *ppUnk
= curClass
->classObject
;
1309 IUnknown_AddRef(curClass
->classObject
);
1316 * Step to the next class in the list.
1318 curClass
= curClass
->nextClass
;
1322 LeaveCriticalSection( &csRegisteredClassList
);
1324 * If we get to here, we haven't found our class.
1329 /******************************************************************************
1330 * CoRegisterClassObject [OLE32.@]
1332 * Registers the class object for a given class ID. Servers housed in EXE
1333 * files use this method instead of exporting DllGetClassObject to allow
1334 * other code to connect to their objects.
1337 * rclsid [I] CLSID of the object to register.
1338 * pUnk [I] IUnknown of the object.
1339 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1340 * flags [I] REGCLS flags indicating how connections are made.
1341 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1345 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1346 * CO_E_OBJISREG if the object is already registered. We should not return this.
1349 * CoRevokeClassObject, CoGetClassObject
1352 * MSDN claims that multiple interface registrations are legal, but we
1353 * can't do that with our current implementation.
1355 HRESULT WINAPI
CoRegisterClassObject(
1360 LPDWORD lpdwRegister
)
1362 RegisteredClass
* newClass
;
1363 LPUNKNOWN foundObject
;
1366 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1367 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
1369 if ( (lpdwRegister
==0) || (pUnk
==0) )
1370 return E_INVALIDARG
;
1372 if (!COM_CurrentApt())
1374 ERR("COM was not initialized\n");
1375 return CO_E_NOTINITIALIZED
;
1381 * First, check if the class is already registered.
1382 * If it is, this should cause an error.
1384 hr
= COM_GetRegisteredClassObject(rclsid
, dwClsContext
, &foundObject
);
1386 IUnknown_Release(foundObject
);
1387 return CO_E_OBJISREG
;
1390 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
1391 if ( newClass
== NULL
)
1392 return E_OUTOFMEMORY
;
1394 EnterCriticalSection( &csRegisteredClassList
);
1396 newClass
->classIdentifier
= *rclsid
;
1397 newClass
->runContext
= dwClsContext
;
1398 newClass
->connectFlags
= flags
;
1400 * Use the address of the chain node as the cookie since we are sure it's
1401 * unique. FIXME: not on 64-bit platforms.
1403 newClass
->dwCookie
= (DWORD
)newClass
;
1404 newClass
->nextClass
= firstRegisteredClass
;
1407 * Since we're making a copy of the object pointer, we have to increase its
1410 newClass
->classObject
= pUnk
;
1411 IUnknown_AddRef(newClass
->classObject
);
1413 firstRegisteredClass
= newClass
;
1414 LeaveCriticalSection( &csRegisteredClassList
);
1416 *lpdwRegister
= newClass
->dwCookie
;
1418 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
1419 IClassFactory
*classfac
;
1421 hr
= IUnknown_QueryInterface(newClass
->classObject
, &IID_IClassFactory
,
1422 (LPVOID
*)&classfac
);
1425 hr
= CreateStreamOnHGlobal(0, TRUE
, &newClass
->pMarshaledData
);
1427 FIXME("Failed to create stream on hglobal, %lx\n", hr
);
1428 IUnknown_Release(classfac
);
1431 hr
= CoMarshalInterface(newClass
->pMarshaledData
, &IID_IClassFactory
,
1432 (LPVOID
)classfac
, MSHCTX_LOCAL
, NULL
,
1433 MSHLFLAGS_TABLESTRONG
);
1435 FIXME("CoMarshalInterface failed, %lx!\n",hr
);
1436 IUnknown_Release(classfac
);
1440 IUnknown_Release(classfac
);
1442 RPC_StartLocalServer(&newClass
->classIdentifier
, newClass
->pMarshaledData
);
1447 /***********************************************************************
1448 * CoRevokeClassObject [OLE32.@]
1450 * Removes a class object from the class registry.
1453 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1457 * Failure: HRESULT code.
1460 * CoRegisterClassObject
1462 HRESULT WINAPI
CoRevokeClassObject(
1465 HRESULT hr
= E_INVALIDARG
;
1466 RegisteredClass
** prevClassLink
;
1467 RegisteredClass
* curClass
;
1469 TRACE("(%08lx)\n",dwRegister
);
1471 EnterCriticalSection( &csRegisteredClassList
);
1474 * Iterate through the whole list and try to match the cookie.
1476 curClass
= firstRegisteredClass
;
1477 prevClassLink
= &firstRegisteredClass
;
1479 while (curClass
!= 0)
1482 * Check if we have a match on the cookie.
1484 if (curClass
->dwCookie
== dwRegister
)
1487 * Remove the class from the chain.
1489 *prevClassLink
= curClass
->nextClass
;
1492 * Release the reference to the class object.
1494 IUnknown_Release(curClass
->classObject
);
1496 if (curClass
->pMarshaledData
)
1499 memset(&zero
, 0, sizeof(zero
));
1500 /* FIXME: stop local server thread */
1501 IStream_Seek(curClass
->pMarshaledData
, zero
, SEEK_SET
, NULL
);
1502 CoReleaseMarshalData(curClass
->pMarshaledData
);
1506 * Free the memory used by the chain node.
1508 HeapFree(GetProcessHeap(), 0, curClass
);
1515 * Step to the next class in the list.
1517 prevClassLink
= &(curClass
->nextClass
);
1518 curClass
= curClass
->nextClass
;
1522 LeaveCriticalSection( &csRegisteredClassList
);
1524 * If we get to here, we haven't found our class.
1529 /***********************************************************************
1530 * compobj_RegReadPath [internal]
1532 * Reads a registry value and expands it when necessary
1534 HRESULT
compobj_RegReadPath(char * keyname
, char * valuename
, char * dst
, DWORD dstlen
)
1540 DWORD dwLength
= dstlen
;
1542 if((hres
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &key
)) == ERROR_SUCCESS
) {
1543 if( (hres
= RegQueryValueExA(key
, NULL
, NULL
, &keytype
, (LPBYTE
)src
, &dwLength
)) == ERROR_SUCCESS
) {
1544 if (keytype
== REG_EXPAND_SZ
) {
1545 if (dstlen
<= ExpandEnvironmentStringsA(src
, dst
, dstlen
)) hres
= ERROR_MORE_DATA
;
1547 lstrcpynA(dst
, src
, dstlen
);
1555 /***********************************************************************
1556 * CoGetClassObject [COMPOBJ.7]
1557 * CoGetClassObject [OLE32.@]
1559 * FIXME. If request allows of several options and there is a failure
1560 * with one (other than not being registered) do we try the
1561 * others or return failure? (E.g. inprocess is registered but
1562 * the DLL is not found but the server version works)
1564 HRESULT WINAPI
CoGetClassObject(
1565 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
1566 REFIID iid
, LPVOID
*ppv
1568 LPUNKNOWN regClassObject
;
1569 HRESULT hres
= E_UNEXPECTED
;
1572 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
1573 DllGetClassObjectFunc DllGetClassObject
;
1575 WINE_StringFromCLSID((LPCLSID
)rclsid
,xclsid
);
1577 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
1580 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo
->pwszName
));
1581 FIXME("\t\tpAuthInfo=%p\n",pServerInfo
->pAuthInfo
);
1585 * First, try and see if we can't match the class ID with one of the
1586 * registered classes.
1588 if (S_OK
== COM_GetRegisteredClassObject(rclsid
, dwClsContext
, ®ClassObject
))
1591 * 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
) {
1607 char keyname
[MAX_PATH
];
1608 char dllpath
[MAX_PATH
+1];
1610 sprintf(keyname
,"CLSID\\%s\\InprocServer32",xclsid
);
1612 if ( compobj_RegReadPath(keyname
, NULL
, dllpath
, sizeof(dllpath
)) != ERROR_SUCCESS
) {
1613 /* failure: CLSID is not found in registry */
1614 WARN("class %s not registered inproc\n", xclsid
);
1615 hres
= REGDB_E_CLASSNOTREG
;
1617 if ((hLibrary
= LoadLibraryExA(dllpath
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
)) == 0) {
1618 /* failure: DLL could not be loaded */
1619 ERR("couldn't load InprocServer32 dll %s\n", dllpath
);
1620 hres
= E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1621 } else if (!(DllGetClassObject
= (DllGetClassObjectFunc
)GetProcAddress(hLibrary
, "DllGetClassObject"))) {
1622 /* failure: the dll did not export DllGetClassObject */
1623 ERR("couldn't find function DllGetClassObject in %s\n", dllpath
);
1624 FreeLibrary( hLibrary
);
1625 hres
= CO_E_DLLNOTFOUND
;
1627 /* OK: get the ClassObject */
1628 COMPOBJ_DLLList_Add( hLibrary
);
1629 return DllGetClassObject(rclsid
, iid
, ppv
);
1634 /* Next try out of process */
1635 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
1637 return RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
1640 /* Finally try remote: this requires networked DCOM (a lot of work) */
1641 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
1643 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1644 hres
= E_NOINTERFACE
;
1649 /***********************************************************************
1650 * CoResumeClassObjects (OLE32.@)
1652 * Resumes all class objects registered with REGCLS_SUSPENDED.
1656 * Failure: HRESULT code.
1658 HRESULT WINAPI
CoResumeClassObjects(void)
1664 /***********************************************************************
1665 * GetClassFile (OLE32.@)
1667 * This function supplies the CLSID associated with the given filename.
1669 HRESULT WINAPI
GetClassFile(LPCOLESTR filePathName
,CLSID
*pclsid
)
1673 int nbElm
, length
, i
;
1675 LPOLESTR
*pathDec
=0,absFile
=0,progId
=0;
1677 static const WCHAR bkslashW
[] = {'\\',0};
1678 static const WCHAR dotW
[] = {'.',0};
1680 TRACE("%s, %p\n", debugstr_w(filePathName
), pclsid
);
1682 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1683 if((StgIsStorageFile(filePathName
))==S_OK
){
1685 res
=StgOpenStorage(filePathName
,NULL
,STGM_READ
| STGM_SHARE_DENY_WRITE
,NULL
,0,&pstg
);
1688 res
=ReadClassStg(pstg
,pclsid
);
1690 IStorage_Release(pstg
);
1694 /* if the file is not a storage object then attemps to match various bits in the file against a
1695 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1698 for(i=0;i<nFileTypes;i++)
1700 for(i=0;j<nPatternsForType;j++){
1705 pat=ReadPatternFromRegistry(i,j);
1706 hFile=CreateFileW(filePathName,,,,,,hFile);
1707 SetFilePosition(hFile,pat.offset);
1708 ReadFile(hFile,buf,pat.size,&r,NULL);
1709 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1711 *pclsid=ReadCLSIDFromRegistry(i);
1717 /* if the above strategies fail then search for the extension key in the registry */
1719 /* get the last element (absolute file) in the path name */
1720 nbElm
=FileMonikerImpl_DecomposePath(filePathName
,&pathDec
);
1721 absFile
=pathDec
[nbElm
-1];
1723 /* failed if the path represente a directory and not an absolute file name*/
1724 if (!lstrcmpW(absFile
, bkslashW
))
1725 return MK_E_INVALIDEXTENSION
;
1727 /* get the extension of the file */
1729 length
=lstrlenW(absFile
);
1730 for(i
= length
-1; (i
>= 0) && *(extension
= &absFile
[i
]) != '.'; i
--)
1733 if (!extension
|| !lstrcmpW(extension
, dotW
))
1734 return MK_E_INVALIDEXTENSION
;
1736 res
=RegQueryValueW(HKEY_CLASSES_ROOT
, extension
, NULL
, &sizeProgId
);
1738 /* get the progId associated to the extension */
1739 progId
= CoTaskMemAlloc(sizeProgId
);
1740 res
= RegQueryValueW(HKEY_CLASSES_ROOT
, extension
, progId
, &sizeProgId
);
1742 if (res
==ERROR_SUCCESS
)
1743 /* return the clsid associated to the progId */
1744 res
= CLSIDFromProgID(progId
,pclsid
);
1746 for(i
=0; pathDec
[i
]!=NULL
;i
++)
1747 CoTaskMemFree(pathDec
[i
]);
1748 CoTaskMemFree(pathDec
);
1750 CoTaskMemFree(progId
);
1752 if (res
==ERROR_SUCCESS
)
1755 return MK_E_INVALIDEXTENSION
;
1757 /***********************************************************************
1758 * CoCreateInstance [COMPOBJ.13]
1759 * CoCreateInstance [OLE32.@]
1761 HRESULT WINAPI
CoCreateInstance(
1763 LPUNKNOWN pUnkOuter
,
1769 LPCLASSFACTORY lpclf
= 0;
1771 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED
;
1780 * Initialize the "out" parameter
1785 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1786 * Rather than create a class factory, we can just check for it here
1788 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
)) {
1789 if (StdGlobalInterfaceTableInstance
== NULL
)
1790 StdGlobalInterfaceTableInstance
= StdGlobalInterfaceTable_Construct();
1791 hres
= IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable
*) StdGlobalInterfaceTableInstance
, iid
, ppv
);
1792 if (hres
) return hres
;
1794 TRACE("Retrieved GIT (%p)\n", *ppv
);
1799 * Get a class factory to construct the object we want.
1801 hres
= CoGetClassObject(rclsid
,
1808 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1809 debugstr_guid(rclsid
),hres
);
1814 * Create the object and don't forget to release the factory
1816 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
1817 IClassFactory_Release(lpclf
);
1819 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1820 debugstr_guid(iid
), debugstr_guid(rclsid
),hres
);
1825 /***********************************************************************
1826 * CoCreateInstanceEx [OLE32.@]
1828 HRESULT WINAPI
CoCreateInstanceEx(
1830 LPUNKNOWN pUnkOuter
,
1832 COSERVERINFO
* pServerInfo
,
1836 IUnknown
* pUnk
= NULL
;
1839 ULONG successCount
= 0;
1844 if ( (cmq
==0) || (pResults
==NULL
))
1845 return E_INVALIDARG
;
1847 if (pServerInfo
!=NULL
)
1848 FIXME("() non-NULL pServerInfo not supported!\n");
1851 * Initialize all the "out" parameters.
1853 for (index
= 0; index
< cmq
; index
++)
1855 pResults
[index
].pItf
= NULL
;
1856 pResults
[index
].hr
= E_NOINTERFACE
;
1860 * Get the object and get its IUnknown pointer.
1862 hr
= CoCreateInstance(rclsid
,
1872 * Then, query for all the interfaces requested.
1874 for (index
= 0; index
< cmq
; index
++)
1876 pResults
[index
].hr
= IUnknown_QueryInterface(pUnk
,
1877 pResults
[index
].pIID
,
1878 (VOID
**)&(pResults
[index
].pItf
));
1880 if (pResults
[index
].hr
== S_OK
)
1885 * Release our temporary unknown pointer.
1887 IUnknown_Release(pUnk
);
1889 if (successCount
== 0)
1890 return E_NOINTERFACE
;
1892 if (successCount
!=cmq
)
1893 return CO_S_NOTALLINTERFACES
;
1898 /***********************************************************************
1899 * CoLoadLibrary (OLE32.@)
1904 * lpszLibName [I] Path to library.
1905 * bAutoFree [I] Whether the library should automatically be freed.
1908 * Success: Handle to loaded library.
1912 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1914 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
1916 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
1918 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
1921 /***********************************************************************
1922 * CoFreeLibrary [OLE32.@]
1924 * Unloads a library from memory.
1927 * hLibrary [I] Handle to library to unload.
1933 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1935 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
1937 FreeLibrary(hLibrary
);
1941 /***********************************************************************
1942 * CoFreeAllLibraries [OLE32.@]
1944 * Function for backwards compatibility only. Does nothing.
1950 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1952 void WINAPI
CoFreeAllLibraries(void)
1958 /***********************************************************************
1959 * CoFreeUnusedLibraries [OLE32.@]
1960 * CoFreeUnusedLibraries [COMPOBJ.17]
1962 * Frees any unused libraries. Unused are identified as those that return
1963 * S_OK from their DllCanUnloadNow function.
1969 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1971 void WINAPI
CoFreeUnusedLibraries(void)
1973 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1974 * through the main apartment's thread to call DllCanUnloadNow */
1975 COMPOBJ_DllList_FreeUnused(0);
1978 /***********************************************************************
1979 * CoFileTimeNow [OLE32.@]
1980 * CoFileTimeNow [COMPOBJ.82]
1982 * Retrieves the current time in FILETIME format.
1985 * lpFileTime [O] The current time.
1990 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
1992 GetSystemTimeAsFileTime( lpFileTime
);
1996 static void COM_RevokeAllClasses()
1998 EnterCriticalSection( &csRegisteredClassList
);
2000 while (firstRegisteredClass
!=0)
2002 CoRevokeClassObject(firstRegisteredClass
->dwCookie
);
2005 LeaveCriticalSection( &csRegisteredClassList
);
2008 /******************************************************************************
2009 * CoLockObjectExternal [OLE32.@]
2011 * Increments or decrements the external reference count of a stub object.
2014 * pUnk [I] Stub object.
2015 * fLock [I] If TRUE then increments the external ref-count,
2016 * otherwise decrements.
2017 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2018 * calling CoDisconnectObject.
2022 * Failure: HRESULT code.
2024 HRESULT WINAPI
CoLockObjectExternal(
2027 BOOL fLastUnlockReleases
)
2029 struct stub_manager
*stubmgr
;
2030 struct apartment
*apt
;
2032 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2033 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
2035 apt
= COM_CurrentApt();
2036 if (!apt
) return CO_E_NOTINITIALIZED
;
2038 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
2043 stub_manager_ext_addref(stubmgr
, 1);
2045 stub_manager_ext_release(stubmgr
, 1);
2047 stub_manager_int_release(stubmgr
);
2053 WARN("stub object not found %p\n", pUnk
);
2054 /* Note: native is pretty broken here because it just silently
2055 * fails, without returning an appropriate error code, making apps
2056 * think that the object was disconnected, when it actually wasn't */
2061 /***********************************************************************
2062 * CoInitializeWOW (OLE32.@)
2064 * WOW equivalent of CoInitialize?
2073 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
2075 FIXME("(0x%08lx,0x%08lx),stub!\n",x
,y
);
2079 /***********************************************************************
2080 * CoGetState [OLE32.@]
2082 * Retrieves the thread state object previously stored by CoSetState().
2085 * ppv [I] Address where pointer to object will be stored.
2089 * Failure: E_OUTOFMEMORY.
2092 * Crashes on all invalid ppv addresses, including NULL.
2093 * If the function returns a non-NULL object then the caller must release its
2094 * reference on the object when the object is no longer required.
2099 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
2101 struct oletls
*info
= COM_CurrentInfo();
2102 if (!info
) return E_OUTOFMEMORY
;
2108 IUnknown_AddRef(info
->state
);
2110 TRACE("apt->state=%p\n", info
->state
);
2116 /***********************************************************************
2117 * CoSetState [OLE32.@]
2119 * Sets the thread state object.
2122 * pv [I] Pointer to state object to be stored.
2125 * The system keeps a reference on the object while the object stored.
2129 * Failure: E_OUTOFMEMORY.
2131 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
2133 struct oletls
*info
= COM_CurrentInfo();
2134 if (!info
) return E_OUTOFMEMORY
;
2136 if (pv
) IUnknown_AddRef(pv
);
2140 TRACE("-- release %p now\n", info
->state
);
2141 IUnknown_Release(info
->state
);
2150 /******************************************************************************
2151 * OleGetAutoConvert [OLE32.@]
2153 HRESULT WINAPI
OleGetAutoConvert(REFCLSID clsidOld
, LPCLSID pClsidNew
)
2161 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
2162 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
2164 res
= REGDB_E_CLASSNOTREG
;
2168 /* we can just query for the default value of AutoConvertTo key like that,
2169 without opening the AutoConvertTo key and querying for NULL (default) */
2170 if (RegQueryValueA(hkey
,"AutoConvertTo",buf
,&len
))
2172 res
= REGDB_E_KEYMISSING
;
2175 MultiByteToWideChar( CP_ACP
, 0, buf
, -1, wbuf
, sizeof(wbuf
)/sizeof(WCHAR
) );
2176 CLSIDFromString(wbuf
,pClsidNew
);
2178 if (hkey
) RegCloseKey(hkey
);
2182 /******************************************************************************
2183 * CoTreatAsClass [OLE32.@]
2185 * Sets the TreatAs value of a class.
2188 * clsidOld [I] Class to set TreatAs value on.
2189 * clsidNew [I] The class the clsidOld should be treated as.
2193 * Failure: HRESULT code.
2198 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
2202 char szClsidNew
[39];
2204 char auto_treat_as
[39];
2205 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
2208 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
2209 WINE_StringFromCLSID(clsidNew
, szClsidNew
);
2210 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
2212 res
= REGDB_E_CLASSNOTREG
;
2215 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
2217 if (!RegQueryValueA(hkey
, "AutoTreatAs", auto_treat_as
, &auto_treat_as_size
) &&
2218 !__CLSIDFromStringA(auto_treat_as
, &id
))
2220 if (RegSetValueA(hkey
, "TreatAs", REG_SZ
, auto_treat_as
, strlen(auto_treat_as
)+1))
2222 res
= REGDB_E_WRITEREGDB
;
2228 RegDeleteKeyA(hkey
, "TreatAs");
2232 else if (RegSetValueA(hkey
, "TreatAs", REG_SZ
, szClsidNew
, strlen(szClsidNew
)+1))
2234 res
= REGDB_E_WRITEREGDB
;
2239 if (hkey
) RegCloseKey(hkey
);
2243 /******************************************************************************
2244 * CoGetTreatAsClass [OLE32.@]
2246 * Gets the TreatAs value of a class.
2249 * clsidOld [I] Class to get the TreatAs value of.
2250 * clsidNew [I] The class the clsidOld should be treated as.
2254 * Failure: HRESULT code.
2259 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
2262 char buf
[200], szClsidNew
[200];
2264 LONG len
= sizeof(szClsidNew
);
2266 FIXME("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
2267 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
2268 memcpy(clsidNew
,clsidOld
,sizeof(CLSID
)); /* copy over old value */
2270 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
2272 res
= REGDB_E_CLASSNOTREG
;
2275 if (RegQueryValueA(hkey
, "TreatAs", szClsidNew
, &len
))
2280 res
= __CLSIDFromStringA(szClsidNew
,clsidNew
);
2282 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew
,res
);
2284 if (hkey
) RegCloseKey(hkey
);
2289 /******************************************************************************
2290 * CoGetCurrentProcess [OLE32.@]
2291 * CoGetCurrentProcess [COMPOBJ.34]
2293 * Gets the current process ID.
2296 * The current process ID.
2299 * Is DWORD really the correct return type for this function?
2301 DWORD WINAPI
CoGetCurrentProcess(void)
2303 return GetCurrentProcessId();
2306 /******************************************************************************
2307 * CoRegisterMessageFilter [OLE32.@]
2309 * Registers a message filter.
2312 * lpMessageFilter [I] Pointer to interface.
2313 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2317 * Failure: HRESULT code.
2319 HRESULT WINAPI
CoRegisterMessageFilter(
2320 LPMESSAGEFILTER lpMessageFilter
,
2321 LPMESSAGEFILTER
*lplpMessageFilter
)
2324 if (lplpMessageFilter
) {
2325 *lplpMessageFilter
= NULL
;
2330 /***********************************************************************
2331 * CoIsOle1Class [OLE32.@]
2333 * Determines whether the specified class an OLE v1 class.
2336 * clsid [I] Class to test.
2339 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2341 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
2343 FIXME("%s\n", debugstr_guid(clsid
));
2347 /***********************************************************************
2348 * IsEqualGUID [OLE32.@]
2350 * Compares two Unique Identifiers.
2353 * rguid1 [I] The first GUID to compare.
2354 * rguid2 [I] The other GUID to compare.
2360 BOOL WINAPI
IsEqualGUID(
2364 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
2367 /***********************************************************************
2368 * CoInitializeSecurity [OLE32.@]
2370 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
2371 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
2372 void* pReserved1
, DWORD dwAuthnLevel
,
2373 DWORD dwImpLevel
, void* pReserved2
,
2374 DWORD dwCapabilities
, void* pReserved3
)
2376 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc
, cAuthSvc
,
2377 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
2378 dwCapabilities
, pReserved3
);
2382 /***********************************************************************
2383 * CoSuspendClassObjects [OLE32.@]
2385 * Suspends all registered class objects to prevent further requests coming in
2386 * for those objects.
2390 * Failure: HRESULT code.
2392 HRESULT WINAPI
CoSuspendClassObjects(void)
2398 /***********************************************************************
2399 * CoAddRefServerProcess [OLE32.@]
2401 * Helper function for incrementing the reference count of a local-server
2405 * New reference count.
2407 ULONG WINAPI
CoAddRefServerProcess(void)
2413 /***********************************************************************
2414 * CoReleaseServerProcess [OLE32.@]
2416 * Helper function for decrementing the reference count of a local-server
2420 * New reference count.
2422 ULONG WINAPI
CoReleaseServerProcess(void)
2428 /***********************************************************************
2429 * CoQueryProxyBlanket [OLE32.@]
2431 * Retrieves the security settings being used by a proxy.
2434 * pProxy [I] Pointer to the proxy object.
2435 * pAuthnSvc [O] The type of authentication service.
2436 * pAuthzSvc [O] The type of authorization service.
2437 * ppServerPrincName [O] Optional. The server prinicple name.
2438 * pAuthnLevel [O] The authentication level.
2439 * pImpLevel [O] The impersonation level.
2440 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2441 * pCapabilities [O] Flags affecting the security behaviour.
2445 * Failure: HRESULT code.
2448 * CoCopyProxy, CoSetProxyBlanket.
2450 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
2451 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
2452 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
2454 IClientSecurity
*pCliSec
;
2457 TRACE("%p\n", pProxy
);
2459 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
2462 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
2463 pAuthzSvc
, ppServerPrincName
,
2464 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
2466 IClientSecurity_Release(pCliSec
);
2469 if (FAILED(hr
)) ERR("-- failed with 0x%08lx\n", hr
);
2473 /***********************************************************************
2474 * CoSetProxyBlanket [OLE32.@]
2476 * Sets the security settings for a proxy.
2479 * pProxy [I] Pointer to the proxy object.
2480 * AuthnSvc [I] The type of authentication service.
2481 * AuthzSvc [I] The type of authorization service.
2482 * pServerPrincName [I] The server prinicple name.
2483 * AuthnLevel [I] The authentication level.
2484 * ImpLevel [I] The impersonation level.
2485 * pAuthInfo [I] Information specific to the authorization/authentication service.
2486 * Capabilities [I] Flags affecting the security behaviour.
2490 * Failure: HRESULT code.
2493 * CoQueryProxyBlanket, CoCopyProxy.
2495 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
2496 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
2497 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
2499 IClientSecurity
*pCliSec
;
2502 TRACE("%p\n", pProxy
);
2504 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
2507 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
2508 AuthzSvc
, pServerPrincName
,
2509 AuthnLevel
, ImpLevel
, pAuthInfo
,
2511 IClientSecurity_Release(pCliSec
);
2514 if (FAILED(hr
)) ERR("-- failed with 0x%08lx\n", hr
);
2518 /***********************************************************************
2519 * CoCopyProxy [OLE32.@]
2524 * pProxy [I] Pointer to the proxy object.
2525 * ppCopy [O] Copy of the proxy.
2529 * Failure: HRESULT code.
2532 * CoQueryProxyBlanket, CoSetProxyBlanket.
2534 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
2536 IClientSecurity
*pCliSec
;
2539 TRACE("%p\n", pProxy
);
2541 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
2544 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
2545 IClientSecurity_Release(pCliSec
);
2548 if (FAILED(hr
)) ERR("-- failed with 0x%08lx\n", hr
);
2553 /***********************************************************************
2554 * CoWaitForMultipleHandles [OLE32.@]
2556 * Waits for one or more handles to become signaled.
2559 * dwFlags [I] Flags. See notes.
2560 * dwTimeout [I] Timeout in milliseconds.
2561 * cHandles [I] Number of handles pointed to by pHandles.
2562 * pHandles [I] Handles to wait for.
2563 * lpdwindex [O] Index of handle that was signaled.
2567 * Failure: RPC_S_CALLPENDING on timeout.
2571 * The dwFlags parameter can be zero or more of the following:
2572 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2573 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2576 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2578 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
2579 ULONG cHandles
, const HANDLE
* pHandles
, LPDWORD lpdwindex
)
2582 DWORD wait_flags
= (dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0 |
2583 (dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0;
2584 DWORD start_time
= GetTickCount();
2586 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
2587 pHandles
, lpdwindex
);
2591 DWORD now
= GetTickCount();
2594 if ((dwTimeout
!= INFINITE
) && (start_time
+ dwTimeout
>= now
))
2596 hr
= RPC_S_CALLPENDING
;
2600 TRACE("waiting for rpc completion or window message\n");
2602 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
2603 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
2604 QS_ALLINPUT
, wait_flags
);
2606 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
2609 while (PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
))
2611 /* FIXME: filter the messages here */
2612 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
2613 TranslateMessage(&msg
);
2614 DispatchMessageW(&msg
);
2617 else if ((res
>= WAIT_OBJECT_0
) && (res
< WAIT_OBJECT_0
+ cHandles
))
2619 /* handle signaled, store index */
2620 *lpdwindex
= (res
- WAIT_OBJECT_0
);
2623 else if (res
== WAIT_TIMEOUT
)
2625 hr
= RPC_S_CALLPENDING
;
2630 ERR("Unexpected wait termination: %ld, %ld\n", res
, GetLastError());
2635 TRACE("-- 0x%08lx\n", hr
);