4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
27 * Therefore do not test against COINIT_MULTITHREADED
29 * TODO list: (items bunched together depend on each other)
31 * - Implement the service control manager (in rpcss) to keep track
32 * of registered class objects: ISCM::ServerRegisterClsid et al
33 * - Implement the OXID resolver so we don't need magic endpoint names for
34 * clients and servers to meet up
36 * - Pump the message loop during RPC calls.
37 * - Call IMessageFilter functions.
39 * - Make all ole interface marshaling use NDR to be wire compatible with
41 * - Use & interpret ORPCTHIS & ORPCTHAT.
54 #define NONAMELESSUNION
55 #define NONAMELESSSTRUCT
66 #include "compobj_private.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
73 HINSTANCE OLE32_hInstance
= 0; /* FIXME: make static ... */
75 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
77 /****************************************************************************
78 * This section defines variables internal to the COM module.
80 * TODO: Most of these things will have to be made thread-safe.
83 static HRESULT
COM_GetRegisteredClassObject(REFCLSID rclsid
, DWORD dwClsContext
, LPUNKNOWN
* ppUnk
);
84 static void COM_RevokeAllClasses(void);
86 const CLSID CLSID_StdGlobalInterfaceTable
= { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
88 APARTMENT
*MTA
; /* protected by csApartment */
89 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
91 static CRITICAL_SECTION csApartment
;
92 static CRITICAL_SECTION_DEBUG critsect_debug
=
95 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
96 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
98 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
101 * This lock count counts the number of times CoInitialize is called. It is
102 * decreased every time CoUninitialize is called. When it hits 0, the COM
103 * libraries are freed
105 static LONG s_COMLockCount
= 0;
108 * This linked list contains the list of registered class objects. These
109 * are mostly used to register the factories for out-of-proc servers of OLE
112 * TODO: Make this data structure aware of inter-process communication. This
113 * means that parts of this will be exported to the Wine Server.
115 typedef struct tagRegisteredClass
117 CLSID classIdentifier
;
118 LPUNKNOWN classObject
;
122 LPSTREAM pMarshaledData
; /* FIXME: only really need to store OXID and IPID */
123 struct tagRegisteredClass
* nextClass
;
126 static RegisteredClass
* firstRegisteredClass
= NULL
;
128 static CRITICAL_SECTION csRegisteredClassList
;
129 static CRITICAL_SECTION_DEBUG class_cs_debug
=
131 0, 0, &csRegisteredClassList
,
132 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
133 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
135 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
137 /*****************************************************************************
138 * This section contains OpenDllList definitions
140 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
141 * other functions that do LoadLibrary _without_ giving back a HMODULE.
142 * Without this list these handles would never be freed.
144 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
145 * next unload-call but not before 600 sec.
148 typedef struct tagOpenDll
{
150 struct tagOpenDll
*next
;
153 static OpenDll
*openDllList
= NULL
; /* linked list of open dlls */
155 static CRITICAL_SECTION csOpenDllList
;
156 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
158 0, 0, &csOpenDllList
,
159 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
160 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
162 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
164 static const WCHAR wszAptWinClass
[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
165 '0','x','#','#','#','#','#','#','#','#',' ',0};
166 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
168 static void COMPOBJ_DLLList_Add(HANDLE hLibrary
);
169 static void COMPOBJ_DllList_FreeUnused(int Timeout
);
171 static void COMPOBJ_InitProcess( void )
175 /* Dispatching to the correct thread in an apartment is done through
176 * window messages rather than RPC transports. When an interface is
177 * marshalled into another apartment in the same process, a window of the
178 * following class is created. The *caller* of CoMarshalInterface (ie the
179 * application) is responsible for pumping the message loop in that thread.
180 * The WM_USER messages which point to the RPCs are then dispatched to
181 * COM_AptWndProc by the user's code from the apartment in which the interface
184 memset(&wclass
, 0, sizeof(wclass
));
185 wclass
.lpfnWndProc
= apartment_wndproc
;
186 wclass
.hInstance
= OLE32_hInstance
;
187 wclass
.lpszClassName
= wszAptWinClass
;
188 RegisterClassW(&wclass
);
191 static void COMPOBJ_UninitProcess( void )
193 UnregisterClassW(wszAptWinClass
, OLE32_hInstance
);
196 static void COM_TlsDestroy(void)
198 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
201 if (info
->apt
) apartment_release(info
->apt
);
202 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
203 if (info
->state
) IUnknown_Release(info
->state
);
204 HeapFree(GetProcessHeap(), 0, info
);
205 NtCurrentTeb()->ReservedForOle
= NULL
;
209 /******************************************************************************
213 /* allocates memory and fills in the necessary fields for a new apartment
215 static APARTMENT
*apartment_construct(DWORD model
)
219 TRACE("creating new apartment, model=%ld\n", model
);
221 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
222 apt
->tid
= GetCurrentThreadId();
224 list_init(&apt
->proxies
);
225 list_init(&apt
->stubmgrs
);
228 apt
->remunk_exported
= FALSE
;
230 InitializeCriticalSection(&apt
->cs
);
231 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
235 if (model
& COINIT_APARTMENTTHREADED
)
237 /* FIXME: should be randomly generated by in an RPC call to rpcss */
238 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
239 apt
->win
= CreateWindowW(wszAptWinClass
, NULL
, 0,
241 0, 0, OLE32_hInstance
, NULL
);
245 /* FIXME: should be randomly generated by in an RPC call to rpcss */
246 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
249 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
251 /* the locking here is not currently needed for the MTA case, but it
252 * doesn't hurt and makes the code simpler */
253 EnterCriticalSection(&csApartment
);
254 list_add_head(&apts
, &apt
->entry
);
255 LeaveCriticalSection(&csApartment
);
260 /* gets and existing apartment if one exists or otherwise creates an apartment
261 * structure which stores OLE apartment-local information and stores a pointer
262 * to it in the thread-local storage */
263 static APARTMENT
*apartment_get_or_create(DWORD model
)
265 APARTMENT
*apt
= COM_CurrentApt();
269 if (model
& COINIT_APARTMENTTHREADED
)
271 apt
= apartment_construct(model
);
272 COM_CurrentInfo()->apt
= apt
;
276 EnterCriticalSection(&csApartment
);
278 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
279 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
283 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
284 apartment_addref(MTA
);
287 MTA
= apartment_construct(model
);
290 COM_CurrentInfo()->apt
= apt
;
292 LeaveCriticalSection(&csApartment
);
299 DWORD
apartment_addref(struct apartment
*apt
)
301 DWORD refs
= InterlockedIncrement(&apt
->refs
);
302 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
306 DWORD
apartment_release(struct apartment
*apt
)
310 EnterCriticalSection(&csApartment
);
312 ret
= InterlockedDecrement(&apt
->refs
);
313 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
314 /* destruction stuff that needs to happen under csApartment CS */
317 if (apt
== MTA
) MTA
= NULL
;
318 list_remove(&apt
->entry
);
321 LeaveCriticalSection(&csApartment
);
325 struct list
*cursor
, *cursor2
;
327 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
329 /* no locking is needed for this apartment, because no other thread
330 * can access it at this point */
332 apartment_disconnectproxies(apt
);
334 if (apt
->win
) DestroyWindow(apt
->win
);
336 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
338 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
339 /* release the implicit reference given by the fact that the
340 * stub has external references (it must do since it is in the
341 * stub manager list in the apartment and all non-apartment users
342 * must have a ref on the apartment and so it cannot be destroyed).
344 stub_manager_int_release(stubmgr
);
347 /* if this assert fires, then another thread took a reference to a
348 * stub manager without taking a reference to the containing
349 * apartment, which it must do. */
350 assert(list_empty(&apt
->stubmgrs
));
352 if (apt
->filter
) IUnknown_Release(apt
->filter
);
354 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
355 DeleteCriticalSection(&apt
->cs
);
357 HeapFree(GetProcessHeap(), 0, apt
);
363 /* The given OXID must be local to this process:
365 * The ref parameter is here mostly to ensure people remember that
366 * they get one, you should normally take a ref for thread safety.
368 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
370 APARTMENT
*result
= NULL
;
373 EnterCriticalSection(&csApartment
);
374 LIST_FOR_EACH( cursor
, &apts
)
376 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
377 if (apt
->oxid
== oxid
)
380 if (ref
) apartment_addref(result
);
384 LeaveCriticalSection(&csApartment
);
389 /* gets the apartment which has a given creator thread ID. The caller must
390 * release the reference from the apartment as soon as the apartment pointer
391 * is no longer required. */
392 APARTMENT
*apartment_findfromtid(DWORD tid
)
394 APARTMENT
*result
= NULL
;
397 EnterCriticalSection(&csApartment
);
398 LIST_FOR_EACH( cursor
, &apts
)
400 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
404 apartment_addref(result
);
408 LeaveCriticalSection(&csApartment
);
413 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
418 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
421 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
425 /*****************************************************************************
426 * This section contains OpenDllList implemantation
429 static void COMPOBJ_DLLList_Add(HANDLE hLibrary
)
436 EnterCriticalSection( &csOpenDllList
);
438 if (openDllList
== NULL
) {
439 /* empty list -- add first node */
440 openDllList
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
441 openDllList
->hLibrary
=hLibrary
;
442 openDllList
->next
= NULL
;
444 /* search for this dll */
446 for (ptr
= openDllList
; ptr
->next
!= NULL
; ptr
=ptr
->next
) {
447 if (ptr
->hLibrary
== hLibrary
) {
453 /* dll not found, add it */
455 openDllList
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
456 openDllList
->hLibrary
= hLibrary
;
457 openDllList
->next
= tmp
;
461 LeaveCriticalSection( &csOpenDllList
);
464 static void COMPOBJ_DllList_FreeUnused(int Timeout
)
466 OpenDll
*curr
, *next
, *prev
= NULL
;
467 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
468 DllCanUnloadNowFunc DllCanUnloadNow
;
472 EnterCriticalSection( &csOpenDllList
);
474 for (curr
= openDllList
; curr
!= NULL
; ) {
475 DllCanUnloadNow
= (DllCanUnloadNowFunc
) GetProcAddress(curr
->hLibrary
, "DllCanUnloadNow");
477 if ( (DllCanUnloadNow
!= NULL
) && (DllCanUnloadNow() == S_OK
) ) {
480 TRACE("freeing %p\n", curr
->hLibrary
);
481 FreeLibrary(curr
->hLibrary
);
483 HeapFree(GetProcessHeap(), 0, curr
);
484 if (curr
== openDllList
) {
497 LeaveCriticalSection( &csOpenDllList
);
500 /******************************************************************************
501 * CoBuildVersion [OLE32.@]
502 * CoBuildVersion [COMPOBJ.1]
504 * Gets the build version of the DLL.
509 * Current build version, hiword is majornumber, loword is minornumber
511 DWORD WINAPI
CoBuildVersion(void)
513 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
514 return (rmm
<<16)+rup
;
517 /******************************************************************************
518 * CoInitialize [OLE32.@]
520 * Initializes the COM libraries by calling CoInitializeEx with
521 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
524 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
527 * Success: S_OK if not already initialized, S_FALSE otherwise.
528 * Failure: HRESULT code.
533 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
536 * Just delegate to the newer method.
538 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
541 /******************************************************************************
542 * CoInitializeEx [OLE32.@]
544 * Initializes the COM libraries.
547 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
548 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
551 * S_OK if successful,
552 * S_FALSE if this function was called already.
553 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
558 * The behavior used to set the IMalloc used for memory management is
560 * The dwCoInit parameter must specify of of the following apartment
562 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
563 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
564 * The parameter may also specify zero or more of the following flags:
565 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
566 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
571 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
576 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
578 if (lpReserved
!=NULL
)
580 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
584 * Check the lock count. If this is the first time going through the initialize
585 * process, we have to initialize the libraries.
587 * And crank-up that lock count.
589 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
592 * Initialize the various COM libraries and data structures.
594 TRACE("() - Initializing the COM libraries\n");
596 /* we may need to defer this until after apartment initialisation */
597 RunningObjectTableImpl_Initialize();
600 if (!(apt
= COM_CurrentInfo()->apt
))
602 apt
= apartment_get_or_create(dwCoInit
);
603 if (!apt
) return E_OUTOFMEMORY
;
605 else if (dwCoInit
!= apt
->model
)
607 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
608 code then we are probably using the wrong threading model to implement that API. */
609 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt
->model
, dwCoInit
);
610 return RPC_E_CHANGED_MODE
;
615 COM_CurrentInfo()->inits
++;
620 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
621 pending RPCs are ignored. Non-COM messages are discarded at this point.
623 static void COM_FlushMessageQueue(void)
626 APARTMENT
*apt
= COM_CurrentApt();
628 if (!apt
|| !apt
->win
) return;
630 TRACE("Flushing STA message queue\n");
632 while (PeekMessageA(&message
, NULL
, 0, 0, PM_REMOVE
))
634 if (message
.hwnd
!= apt
->win
)
636 WARN("discarding message 0x%x for window %p\n", message
.message
, message
.hwnd
);
640 TranslateMessage(&message
);
641 DispatchMessageA(&message
);
645 /***********************************************************************
646 * CoUninitialize [OLE32.@]
648 * This method will decrement the refcount on the current apartment, freeing
649 * the resources associated with it if it is the last thread in the apartment.
650 * If the last apartment is freed, the function will additionally release
651 * any COM resources associated with the process.
661 void WINAPI
CoUninitialize(void)
663 struct oletls
* info
= COM_CurrentInfo();
668 /* will only happen on OOM */
674 ERR("Mismatched CoUninitialize\n");
680 apartment_release(info
->apt
);
685 * Decrease the reference count.
686 * If we are back to 0 locks on the COM library, make sure we free
687 * all the associated data structures.
689 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
692 TRACE("() - Releasing the COM libraries\n");
694 RunningObjectTableImpl_UnInitialize();
696 /* Release the references to the registered class objects */
697 COM_RevokeAllClasses();
699 /* This will free the loaded COM Dlls */
700 CoFreeAllLibraries();
702 /* This ensures we deal with any pending RPCs */
703 COM_FlushMessageQueue();
705 else if (lCOMRefCnt
<1) {
706 ERR( "CoUninitialize() - not CoInitialized.\n" );
707 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
711 /******************************************************************************
712 * CoDisconnectObject [OLE32.@]
713 * CoDisconnectObject [COMPOBJ.15]
715 * Disconnects all connections to this object from remote processes. Dispatches
716 * pending RPCs while blocking new RPCs from occurring, and then calls
717 * IMarshal::DisconnectObject on the given object.
719 * Typically called when the object server is forced to shut down, for instance by
723 * lpUnk [I] The object whose stub should be disconnected.
724 * reserved [I] Reserved. Should be set to 0.
728 * Failure: HRESULT code.
731 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
733 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
739 TRACE("(%p, 0x%08lx)\n", lpUnk
, reserved
);
741 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
744 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
745 IMarshal_Release(marshal
);
749 apt
= COM_CurrentApt();
751 return CO_E_NOTINITIALIZED
;
753 apartment_disconnectobject(apt
, lpUnk
);
755 /* Note: native is pretty broken here because it just silently
756 * fails, without returning an appropriate error code if the object was
757 * not found, making apps think that the object was disconnected, when
758 * it actually wasn't */
763 /******************************************************************************
764 * CoCreateGuid [OLE32.@]
766 * Simply forwards to UuidCreate in RPCRT4.
769 * pguid [O] Points to the GUID to initialize.
773 * Failure: HRESULT code.
778 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
780 return UuidCreate(pguid
);
783 /******************************************************************************
784 * CLSIDFromString [OLE32.@]
785 * IIDFromString [OLE32.@]
787 * Converts a unique identifier from its string representation into
791 * idstr [I] The string representation of the GUID.
792 * id [O] GUID converted from the string.
796 * CO_E_CLASSSTRING if idstr is not a valid CLSID
800 * In Windows, if idstr is not a valid CLSID string then it gets
801 * treated as a ProgID. Wine currently doesn't do this. If idstr is
802 * NULL it's treated as an all-zero GUID.
807 HRESULT WINAPI
__CLSIDFromStringA(LPCSTR idstr
, CLSID
*id
)
814 memset( id
, 0, sizeof (CLSID
) );
818 /* validate the CLSID string */
819 if (strlen(idstr
) != 38)
820 return CO_E_CLASSSTRING
;
822 s
= (const BYTE
*) idstr
;
823 if ((s
[0]!='{') || (s
[9]!='-') || (s
[14]!='-') || (s
[19]!='-') || (s
[24]!='-') || (s
[37]!='}'))
824 return CO_E_CLASSSTRING
;
826 for (i
=1; i
<37; i
++) {
827 if ((i
== 9)||(i
== 14)||(i
== 19)||(i
== 24)) continue;
828 if (!(((s
[i
] >= '0') && (s
[i
] <= '9')) ||
829 ((s
[i
] >= 'a') && (s
[i
] <= 'f')) ||
830 ((s
[i
] >= 'A') && (s
[i
] <= 'F'))))
831 return CO_E_CLASSSTRING
;
834 TRACE("%s -> %p\n", s
, id
);
836 /* quick lookup table */
837 memset(table
, 0, 256);
839 for (i
= 0; i
< 10; i
++) {
842 for (i
= 0; i
< 6; i
++) {
843 table
['A' + i
] = i
+10;
844 table
['a' + i
] = i
+10;
847 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
849 id
->Data1
= (table
[s
[1]] << 28 | table
[s
[2]] << 24 | table
[s
[3]] << 20 | table
[s
[4]] << 16 |
850 table
[s
[5]] << 12 | table
[s
[6]] << 8 | table
[s
[7]] << 4 | table
[s
[8]]);
851 id
->Data2
= table
[s
[10]] << 12 | table
[s
[11]] << 8 | table
[s
[12]] << 4 | table
[s
[13]];
852 id
->Data3
= table
[s
[15]] << 12 | table
[s
[16]] << 8 | table
[s
[17]] << 4 | table
[s
[18]];
854 /* these are just sequential bytes */
855 id
->Data4
[0] = table
[s
[20]] << 4 | table
[s
[21]];
856 id
->Data4
[1] = table
[s
[22]] << 4 | table
[s
[23]];
857 id
->Data4
[2] = table
[s
[25]] << 4 | table
[s
[26]];
858 id
->Data4
[3] = table
[s
[27]] << 4 | table
[s
[28]];
859 id
->Data4
[4] = table
[s
[29]] << 4 | table
[s
[30]];
860 id
->Data4
[5] = table
[s
[31]] << 4 | table
[s
[32]];
861 id
->Data4
[6] = table
[s
[33]] << 4 | table
[s
[34]];
862 id
->Data4
[7] = table
[s
[35]] << 4 | table
[s
[36]];
867 /*****************************************************************************/
869 HRESULT WINAPI
CLSIDFromString(LPOLESTR idstr
, CLSID
*id
)
874 if (!WideCharToMultiByte( CP_ACP
, 0, idstr
, -1, xid
, sizeof(xid
), NULL
, NULL
))
875 return CO_E_CLASSSTRING
;
878 ret
= __CLSIDFromStringA(xid
,id
);
879 if(ret
!= S_OK
) { /* It appears a ProgID is also valid */
880 ret
= CLSIDFromProgID(idstr
, id
);
885 /* Converts a GUID into the respective string representation. */
886 HRESULT
WINE_StringFromCLSID(
887 const CLSID
*id
, /* [in] GUID to be converted */
888 LPSTR idstr
/* [out] pointer to buffer to contain converted guid */
890 static const char *hex
= "0123456789ABCDEF";
895 { ERR("called with id=Null\n");
900 sprintf(idstr
, "{%08lX-%04X-%04X-%02X%02X-",
901 id
->Data1
, id
->Data2
, id
->Data3
,
902 id
->Data4
[0], id
->Data4
[1]);
906 for (i
= 2; i
< 8; i
++) {
907 *s
++ = hex
[id
->Data4
[i
]>>4];
908 *s
++ = hex
[id
->Data4
[i
] & 0xf];
914 TRACE("%p->%s\n", id
, idstr
);
920 /******************************************************************************
921 * StringFromCLSID [OLE32.@]
922 * StringFromIID [OLE32.@]
924 * Converts a GUID into the respective string representation.
925 * The target string is allocated using the OLE IMalloc.
928 * id [I] the GUID to be converted.
929 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
936 * StringFromGUID2, CLSIDFromString
938 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
944 if ((ret
= CoGetMalloc(0,&mllc
)))
947 ret
=WINE_StringFromCLSID(id
,buf
);
949 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, buf
, -1, NULL
, 0 );
950 *idstr
= IMalloc_Alloc( mllc
, len
* sizeof(WCHAR
) );
951 MultiByteToWideChar( CP_ACP
, 0, buf
, -1, *idstr
, len
);
956 /******************************************************************************
957 * StringFromGUID2 [OLE32.@]
958 * StringFromGUID2 [COMPOBJ.76]
960 * Modified version of StringFromCLSID that allows you to specify max
964 * id [I] GUID to convert to string.
965 * str [O] Buffer where the result will be stored.
966 * cmax [I] Size of the buffer in characters.
969 * Success: The length of the resulting string in characters.
972 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
976 if (WINE_StringFromCLSID(id
,xguid
))
978 return MultiByteToWideChar( CP_ACP
, 0, xguid
, -1, str
, cmax
);
981 /* open HKCR\\CLSID\\{string form of clsid} key */
982 DWORD
COM_OpenKeyForCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*key
)
984 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
985 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
986 strcpyW(path
, wszCLSIDSlash
);
987 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
988 return RegOpenKeyExW(HKEY_CLASSES_ROOT
, path
, 0, access
, key
);
991 /******************************************************************************
992 * ProgIDFromCLSID [OLE32.@]
994 * Converts a class id into the respective program ID.
997 * clsid [I] Class ID, as found in registry.
998 * lplpszProgID [O] Associated ProgID.
1003 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1005 HRESULT WINAPI
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*lplpszProgID
)
1007 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
1012 if (ERROR_SUCCESS
!= COM_OpenKeyForCLSID(clsid
, KEY_READ
, &hkey_clsid
))
1013 ret
= REGDB_E_CLASSNOTREG
;
1017 if (RegOpenKeyExW(hkey_clsid
, wszProgID
, 0, KEY_READ
, &hkey
))
1018 ret
= REGDB_E_CLASSNOTREG
;
1019 RegCloseKey(hkey_clsid
);
1026 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
1027 ret
= REGDB_E_CLASSNOTREG
;
1031 *lplpszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
1034 if (RegQueryValueW(hkey
, NULL
, *lplpszProgID
, &progidlen
))
1035 ret
= REGDB_E_CLASSNOTREG
;
1038 ret
= E_OUTOFMEMORY
;
1046 /******************************************************************************
1047 * CLSIDFromProgID [OLE32.@]
1049 * Converts a program id into the respective GUID.
1052 * progid [I] Unicode program ID, as found in registry.
1053 * riid [O] Associated CLSID.
1057 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1059 HRESULT WINAPI
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID riid
)
1061 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
1062 WCHAR buf2
[CHARS_IN_GUID
];
1063 LONG buf2len
= sizeof(buf2
);
1066 WCHAR
*buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
1067 strcpyW( buf
, progid
);
1068 strcatW( buf
, clsidW
);
1069 if (RegOpenKeyW(HKEY_CLASSES_ROOT
,buf
,&xhkey
))
1071 HeapFree(GetProcessHeap(),0,buf
);
1072 return CO_E_CLASSSTRING
;
1074 HeapFree(GetProcessHeap(),0,buf
);
1076 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
1079 return CO_E_CLASSSTRING
;
1082 return CLSIDFromString(buf2
,riid
);
1086 /*****************************************************************************
1087 * CoGetPSClsid [OLE32.@]
1089 * Retrieves the CLSID of the proxy/stub factory that implements
1090 * IPSFactoryBuffer for the specified interface.
1093 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1094 * pclsid [O] Where to store returned proxy/stub CLSID.
1099 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1103 * The standard marshaller activates the object with the CLSID
1104 * returned and uses the CreateProxy and CreateStub methods on its
1105 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1108 * CoGetPSClsid determines this CLSID by searching the
1109 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1110 * in the registry and any interface id registered by
1111 * CoRegisterPSClsid within the current process.
1115 * We only search the registry, not ids registered with
1116 * CoRegisterPSClsid.
1117 * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1118 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1119 * considered a bug in native unless an application depends on this (unlikely).
1121 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
1123 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1124 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1125 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
1126 WCHAR value
[CHARS_IN_GUID
];
1130 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
1132 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1133 strcpyW(path
, wszInterface
);
1134 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
1135 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
1137 /* Open the key.. */
1138 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, path
, 0, KEY_READ
, &hkey
))
1140 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
1141 return REGDB_E_IIDNOTREG
;
1144 /* ... Once we have the key, query the registry to get the
1145 value of CLSID as a string, and convert it into a
1146 proper CLSID structure to be passed back to the app */
1147 len
= sizeof(value
);
1148 if (ERROR_SUCCESS
!= RegQueryValueW(hkey
, NULL
, value
, &len
))
1151 return REGDB_E_IIDNOTREG
;
1155 /* We have the CLSid we want back from the registry as a string, so
1156 lets convert it into a CLSID structure */
1157 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
1158 return REGDB_E_IIDNOTREG
;
1160 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
1166 /***********************************************************************
1167 * WriteClassStm (OLE32.@)
1169 * Writes a CLSID to a stream.
1172 * pStm [I] Stream to write to.
1173 * rclsid [I] CLSID to write.
1177 * Failure: HRESULT code.
1179 HRESULT WINAPI
WriteClassStm(IStream
*pStm
,REFCLSID rclsid
)
1181 TRACE("(%p,%p)\n",pStm
,rclsid
);
1184 return E_INVALIDARG
;
1186 return IStream_Write(pStm
,rclsid
,sizeof(CLSID
),NULL
);
1189 /***********************************************************************
1190 * ReadClassStm (OLE32.@)
1192 * Reads a CLSID from a stream.
1195 * pStm [I] Stream to read from.
1196 * rclsid [O] CLSID to read.
1200 * Failure: HRESULT code.
1202 HRESULT WINAPI
ReadClassStm(IStream
*pStm
,CLSID
*pclsid
)
1207 TRACE("(%p,%p)\n",pStm
,pclsid
);
1210 return E_INVALIDARG
;
1212 res
= IStream_Read(pStm
,(void*)pclsid
,sizeof(CLSID
),&nbByte
);
1217 if (nbByte
!= sizeof(CLSID
))
1225 * COM_GetRegisteredClassObject
1227 * This internal method is used to scan the registered class list to
1228 * find a class object.
1231 * rclsid Class ID of the class to find.
1232 * dwClsContext Class context to match.
1233 * ppv [out] returns a pointer to the class object. Complying
1234 * to normal COM usage, this method will increase the
1235 * reference count on this object.
1237 static HRESULT
COM_GetRegisteredClassObject(
1242 HRESULT hr
= S_FALSE
;
1243 RegisteredClass
* curClass
;
1245 EnterCriticalSection( &csRegisteredClassList
);
1253 * Iterate through the whole list and try to match the class ID.
1255 curClass
= firstRegisteredClass
;
1257 while (curClass
!= 0)
1260 * Check if we have a match on the class ID.
1262 if (IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
1265 * Since we don't do out-of process or DCOM just right away, let's ignore the
1270 * We have a match, return the pointer to the class object.
1272 *ppUnk
= curClass
->classObject
;
1274 IUnknown_AddRef(curClass
->classObject
);
1281 * Step to the next class in the list.
1283 curClass
= curClass
->nextClass
;
1287 LeaveCriticalSection( &csRegisteredClassList
);
1289 * If we get to here, we haven't found our class.
1294 /******************************************************************************
1295 * CoRegisterClassObject [OLE32.@]
1297 * Registers the class object for a given class ID. Servers housed in EXE
1298 * files use this method instead of exporting DllGetClassObject to allow
1299 * other code to connect to their objects.
1302 * rclsid [I] CLSID of the object to register.
1303 * pUnk [I] IUnknown of the object.
1304 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1305 * flags [I] REGCLS flags indicating how connections are made.
1306 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1310 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1311 * CO_E_OBJISREG if the object is already registered. We should not return this.
1314 * CoRevokeClassObject, CoGetClassObject
1317 * MSDN claims that multiple interface registrations are legal, but we
1318 * can't do that with our current implementation.
1320 HRESULT WINAPI
CoRegisterClassObject(
1325 LPDWORD lpdwRegister
)
1327 RegisteredClass
* newClass
;
1328 LPUNKNOWN foundObject
;
1331 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1332 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
1334 if ( (lpdwRegister
==0) || (pUnk
==0) )
1335 return E_INVALIDARG
;
1337 if (!COM_CurrentApt())
1339 ERR("COM was not initialized\n");
1340 return CO_E_NOTINITIALIZED
;
1346 * First, check if the class is already registered.
1347 * If it is, this should cause an error.
1349 hr
= COM_GetRegisteredClassObject(rclsid
, dwClsContext
, &foundObject
);
1351 if (flags
& REGCLS_MULTIPLEUSE
) {
1352 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
1353 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
1354 IUnknown_Release(foundObject
);
1357 IUnknown_Release(foundObject
);
1358 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
1359 return CO_E_OBJISREG
;
1362 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
1363 if ( newClass
== NULL
)
1364 return E_OUTOFMEMORY
;
1366 EnterCriticalSection( &csRegisteredClassList
);
1368 newClass
->classIdentifier
= *rclsid
;
1369 newClass
->runContext
= dwClsContext
;
1370 newClass
->connectFlags
= flags
;
1371 newClass
->pMarshaledData
= NULL
;
1374 * Use the address of the chain node as the cookie since we are sure it's
1375 * unique. FIXME: not on 64-bit platforms.
1377 newClass
->dwCookie
= (DWORD
)newClass
;
1378 newClass
->nextClass
= firstRegisteredClass
;
1381 * Since we're making a copy of the object pointer, we have to increase its
1384 newClass
->classObject
= pUnk
;
1385 IUnknown_AddRef(newClass
->classObject
);
1387 firstRegisteredClass
= newClass
;
1388 LeaveCriticalSection( &csRegisteredClassList
);
1390 *lpdwRegister
= newClass
->dwCookie
;
1392 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
1393 IClassFactory
*classfac
;
1395 hr
= IUnknown_QueryInterface(newClass
->classObject
, &IID_IClassFactory
,
1396 (LPVOID
*)&classfac
);
1399 hr
= CreateStreamOnHGlobal(0, TRUE
, &newClass
->pMarshaledData
);
1401 FIXME("Failed to create stream on hglobal, %lx\n", hr
);
1402 IUnknown_Release(classfac
);
1405 hr
= CoMarshalInterface(newClass
->pMarshaledData
, &IID_IClassFactory
,
1406 (LPVOID
)classfac
, MSHCTX_LOCAL
, NULL
,
1407 MSHLFLAGS_TABLESTRONG
);
1409 FIXME("CoMarshalInterface failed, %lx!\n",hr
);
1410 IUnknown_Release(classfac
);
1414 IUnknown_Release(classfac
);
1416 RPC_StartLocalServer(&newClass
->classIdentifier
, newClass
->pMarshaledData
);
1421 /***********************************************************************
1422 * CoRevokeClassObject [OLE32.@]
1424 * Removes a class object from the class registry.
1427 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1431 * Failure: HRESULT code.
1434 * CoRegisterClassObject
1436 HRESULT WINAPI
CoRevokeClassObject(
1439 HRESULT hr
= E_INVALIDARG
;
1440 RegisteredClass
** prevClassLink
;
1441 RegisteredClass
* curClass
;
1443 TRACE("(%08lx)\n",dwRegister
);
1445 EnterCriticalSection( &csRegisteredClassList
);
1448 * Iterate through the whole list and try to match the cookie.
1450 curClass
= firstRegisteredClass
;
1451 prevClassLink
= &firstRegisteredClass
;
1453 while (curClass
!= 0)
1456 * Check if we have a match on the cookie.
1458 if (curClass
->dwCookie
== dwRegister
)
1461 * Remove the class from the chain.
1463 *prevClassLink
= curClass
->nextClass
;
1466 * Release the reference to the class object.
1468 IUnknown_Release(curClass
->classObject
);
1470 if (curClass
->pMarshaledData
)
1473 memset(&zero
, 0, sizeof(zero
));
1474 /* FIXME: stop local server thread */
1475 IStream_Seek(curClass
->pMarshaledData
, zero
, SEEK_SET
, NULL
);
1476 CoReleaseMarshalData(curClass
->pMarshaledData
);
1480 * Free the memory used by the chain node.
1482 HeapFree(GetProcessHeap(), 0, curClass
);
1489 * Step to the next class in the list.
1491 prevClassLink
= &(curClass
->nextClass
);
1492 curClass
= curClass
->nextClass
;
1496 LeaveCriticalSection( &csRegisteredClassList
);
1498 * If we get to here, we haven't found our class.
1503 /***********************************************************************
1504 * COM_RegReadPath [internal]
1506 * Reads a registry value and expands it when necessary
1508 HRESULT
COM_RegReadPath(HKEY hkeyroot
, const WCHAR
*keyname
, const WCHAR
*valuename
, WCHAR
* dst
, DWORD dstlen
)
1513 WCHAR src
[MAX_PATH
];
1514 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1516 if((hres
= RegOpenKeyExW(hkeyroot
, keyname
, 0, KEY_READ
, &key
)) == ERROR_SUCCESS
) {
1517 if( (hres
= RegQueryValueExW(key
, NULL
, NULL
, &keytype
, (LPBYTE
)src
, &dwLength
)) == ERROR_SUCCESS
) {
1518 if (keytype
== REG_EXPAND_SZ
) {
1519 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) hres
= ERROR_MORE_DATA
;
1521 lstrcpynW(dst
, src
, dstlen
);
1529 /***********************************************************************
1530 * CoGetClassObject [OLE32.@]
1532 * FIXME. If request allows of several options and there is a failure
1533 * with one (other than not being registered) do we try the
1534 * others or return failure? (E.g. inprocess is registered but
1535 * the DLL is not found but the server version works)
1537 HRESULT WINAPI
CoGetClassObject(
1538 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
1539 REFIID iid
, LPVOID
*ppv
)
1541 LPUNKNOWN regClassObject
;
1542 HRESULT hres
= E_UNEXPECTED
;
1544 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
1547 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo
->pwszName
));
1548 FIXME("\t\tpAuthInfo=%p\n",pServerInfo
->pAuthInfo
);
1552 * First, try and see if we can't match the class ID with one of the
1553 * registered classes.
1555 if (S_OK
== COM_GetRegisteredClassObject(rclsid
, dwClsContext
, ®ClassObject
))
1557 /* Get the required interface from the retrieved pointer. */
1558 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
1561 * Since QI got another reference on the pointer, we want to release the
1562 * one we already have. If QI was unsuccessful, this will release the object. This
1563 * is good since we are not returning it in the "out" parameter.
1565 IUnknown_Release(regClassObject
);
1570 /* first try: in-process */
1571 if ((CLSCTX_INPROC_SERVER
| CLSCTX_INPROC_HANDLER
) & dwClsContext
)
1573 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1575 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
1576 DllGetClassObjectFunc DllGetClassObject
;
1577 WCHAR dllpath
[MAX_PATH
+1];
1580 if (ERROR_SUCCESS
!= COM_OpenKeyForCLSID(rclsid
, KEY_READ
, &hkey
))
1582 ERR("class %s not registered\n", debugstr_guid(rclsid
));
1583 hres
= REGDB_E_CLASSNOTREG
;
1586 if (COM_RegReadPath(hkey
, wszInprocServer32
, NULL
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1588 /* failure: CLSID is not found in registry */
1589 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
1590 hres
= REGDB_E_CLASSNOTREG
;
1594 if ((hLibrary
= LoadLibraryExW(dllpath
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
)) == 0)
1596 /* failure: DLL could not be loaded */
1597 ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(dllpath
));
1598 hres
= E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1600 else if (!(DllGetClassObject
= (DllGetClassObjectFunc
)GetProcAddress(hLibrary
, "DllGetClassObject")))
1602 /* failure: the dll did not export DllGetClassObject */
1603 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath
));
1604 FreeLibrary( hLibrary
);
1605 hres
= CO_E_DLLNOTFOUND
;
1609 /* OK: get the ClassObject */
1610 COMPOBJ_DLLList_Add( hLibrary
);
1611 return DllGetClassObject(rclsid
, iid
, ppv
);
1616 /* Next try out of process */
1617 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
1619 return RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
1622 /* Finally try remote: this requires networked DCOM (a lot of work) */
1623 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
1625 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1626 hres
= E_NOINTERFACE
;
1632 /***********************************************************************
1633 * CoResumeClassObjects (OLE32.@)
1635 * Resumes all class objects registered with REGCLS_SUSPENDED.
1639 * Failure: HRESULT code.
1641 HRESULT WINAPI
CoResumeClassObjects(void)
1647 /***********************************************************************
1648 * GetClassFile (OLE32.@)
1650 * This function supplies the CLSID associated with the given filename.
1652 HRESULT WINAPI
GetClassFile(LPCOLESTR filePathName
,CLSID
*pclsid
)
1656 int nbElm
, length
, i
;
1658 LPOLESTR
*pathDec
=0,absFile
=0,progId
=0;
1660 static const WCHAR bkslashW
[] = {'\\',0};
1661 static const WCHAR dotW
[] = {'.',0};
1663 TRACE("%s, %p\n", debugstr_w(filePathName
), pclsid
);
1665 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1666 if((StgIsStorageFile(filePathName
))==S_OK
){
1668 res
=StgOpenStorage(filePathName
,NULL
,STGM_READ
| STGM_SHARE_DENY_WRITE
,NULL
,0,&pstg
);
1671 res
=ReadClassStg(pstg
,pclsid
);
1673 IStorage_Release(pstg
);
1677 /* if the file is not a storage object then attemps to match various bits in the file against a
1678 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1681 for(i=0;i<nFileTypes;i++)
1683 for(i=0;j<nPatternsForType;j++){
1688 pat=ReadPatternFromRegistry(i,j);
1689 hFile=CreateFileW(filePathName,,,,,,hFile);
1690 SetFilePosition(hFile,pat.offset);
1691 ReadFile(hFile,buf,pat.size,&r,NULL);
1692 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1694 *pclsid=ReadCLSIDFromRegistry(i);
1700 /* if the above strategies fail then search for the extension key in the registry */
1702 /* get the last element (absolute file) in the path name */
1703 nbElm
=FileMonikerImpl_DecomposePath(filePathName
,&pathDec
);
1704 absFile
=pathDec
[nbElm
-1];
1706 /* failed if the path represente a directory and not an absolute file name*/
1707 if (!lstrcmpW(absFile
, bkslashW
))
1708 return MK_E_INVALIDEXTENSION
;
1710 /* get the extension of the file */
1712 length
=lstrlenW(absFile
);
1713 for(i
= length
-1; (i
>= 0) && *(extension
= &absFile
[i
]) != '.'; i
--)
1716 if (!extension
|| !lstrcmpW(extension
, dotW
))
1717 return MK_E_INVALIDEXTENSION
;
1719 res
=RegQueryValueW(HKEY_CLASSES_ROOT
, extension
, NULL
, &sizeProgId
);
1721 /* get the progId associated to the extension */
1722 progId
= CoTaskMemAlloc(sizeProgId
);
1723 res
= RegQueryValueW(HKEY_CLASSES_ROOT
, extension
, progId
, &sizeProgId
);
1725 if (res
==ERROR_SUCCESS
)
1726 /* return the clsid associated to the progId */
1727 res
= CLSIDFromProgID(progId
,pclsid
);
1729 for(i
=0; pathDec
[i
]!=NULL
;i
++)
1730 CoTaskMemFree(pathDec
[i
]);
1731 CoTaskMemFree(pathDec
);
1733 CoTaskMemFree(progId
);
1735 if (res
==ERROR_SUCCESS
)
1738 return MK_E_INVALIDEXTENSION
;
1741 /***********************************************************************
1742 * CoCreateInstance [OLE32.@]
1744 HRESULT WINAPI
CoCreateInstance(
1746 LPUNKNOWN pUnkOuter
,
1752 LPCLASSFACTORY lpclf
= 0;
1754 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED
;
1763 * Initialize the "out" parameter
1768 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1769 * Rather than create a class factory, we can just check for it here
1771 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
)) {
1772 if (StdGlobalInterfaceTableInstance
== NULL
)
1773 StdGlobalInterfaceTableInstance
= StdGlobalInterfaceTable_Construct();
1774 hres
= IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable
*) StdGlobalInterfaceTableInstance
, iid
, ppv
);
1775 if (hres
) return hres
;
1777 TRACE("Retrieved GIT (%p)\n", *ppv
);
1782 * Get a class factory to construct the object we want.
1784 hres
= CoGetClassObject(rclsid
,
1791 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1792 debugstr_guid(rclsid
),hres
);
1797 * Create the object and don't forget to release the factory
1799 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
1800 IClassFactory_Release(lpclf
);
1802 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1803 debugstr_guid(iid
), debugstr_guid(rclsid
),hres
);
1808 /***********************************************************************
1809 * CoCreateInstanceEx [OLE32.@]
1811 HRESULT WINAPI
CoCreateInstanceEx(
1813 LPUNKNOWN pUnkOuter
,
1815 COSERVERINFO
* pServerInfo
,
1819 IUnknown
* pUnk
= NULL
;
1822 ULONG successCount
= 0;
1827 if ( (cmq
==0) || (pResults
==NULL
))
1828 return E_INVALIDARG
;
1830 if (pServerInfo
!=NULL
)
1831 FIXME("() non-NULL pServerInfo not supported!\n");
1834 * Initialize all the "out" parameters.
1836 for (index
= 0; index
< cmq
; index
++)
1838 pResults
[index
].pItf
= NULL
;
1839 pResults
[index
].hr
= E_NOINTERFACE
;
1843 * Get the object and get its IUnknown pointer.
1845 hr
= CoCreateInstance(rclsid
,
1855 * Then, query for all the interfaces requested.
1857 for (index
= 0; index
< cmq
; index
++)
1859 pResults
[index
].hr
= IUnknown_QueryInterface(pUnk
,
1860 pResults
[index
].pIID
,
1861 (VOID
**)&(pResults
[index
].pItf
));
1863 if (pResults
[index
].hr
== S_OK
)
1868 * Release our temporary unknown pointer.
1870 IUnknown_Release(pUnk
);
1872 if (successCount
== 0)
1873 return E_NOINTERFACE
;
1875 if (successCount
!=cmq
)
1876 return CO_S_NOTALLINTERFACES
;
1881 /***********************************************************************
1882 * CoLoadLibrary (OLE32.@)
1887 * lpszLibName [I] Path to library.
1888 * bAutoFree [I] Whether the library should automatically be freed.
1891 * Success: Handle to loaded library.
1895 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1897 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
1899 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
1901 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
1904 /***********************************************************************
1905 * CoFreeLibrary [OLE32.@]
1907 * Unloads a library from memory.
1910 * hLibrary [I] Handle to library to unload.
1916 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1918 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
1920 FreeLibrary(hLibrary
);
1924 /***********************************************************************
1925 * CoFreeAllLibraries [OLE32.@]
1927 * Function for backwards compatibility only. Does nothing.
1933 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1935 void WINAPI
CoFreeAllLibraries(void)
1941 /***********************************************************************
1942 * CoFreeUnusedLibraries [OLE32.@]
1943 * CoFreeUnusedLibraries [COMPOBJ.17]
1945 * Frees any unused libraries. Unused are identified as those that return
1946 * S_OK from their DllCanUnloadNow function.
1952 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1954 void WINAPI
CoFreeUnusedLibraries(void)
1956 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1957 * through the main apartment's thread to call DllCanUnloadNow */
1958 COMPOBJ_DllList_FreeUnused(0);
1961 /***********************************************************************
1962 * CoFileTimeNow [OLE32.@]
1963 * CoFileTimeNow [COMPOBJ.82]
1965 * Retrieves the current time in FILETIME format.
1968 * lpFileTime [O] The current time.
1973 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
1975 GetSystemTimeAsFileTime( lpFileTime
);
1979 static void COM_RevokeAllClasses()
1981 EnterCriticalSection( &csRegisteredClassList
);
1983 while (firstRegisteredClass
!=0)
1985 CoRevokeClassObject(firstRegisteredClass
->dwCookie
);
1988 LeaveCriticalSection( &csRegisteredClassList
);
1991 /******************************************************************************
1992 * CoLockObjectExternal [OLE32.@]
1994 * Increments or decrements the external reference count of a stub object.
1997 * pUnk [I] Stub object.
1998 * fLock [I] If TRUE then increments the external ref-count,
1999 * otherwise decrements.
2000 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2001 * calling CoDisconnectObject.
2005 * Failure: HRESULT code.
2007 HRESULT WINAPI
CoLockObjectExternal(
2010 BOOL fLastUnlockReleases
)
2012 struct stub_manager
*stubmgr
;
2013 struct apartment
*apt
;
2015 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2016 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
2018 apt
= COM_CurrentApt();
2019 if (!apt
) return CO_E_NOTINITIALIZED
;
2021 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
2026 stub_manager_ext_addref(stubmgr
, 1);
2028 stub_manager_ext_release(stubmgr
, 1);
2030 stub_manager_int_release(stubmgr
);
2036 WARN("stub object not found %p\n", pUnk
);
2037 /* Note: native is pretty broken here because it just silently
2038 * fails, without returning an appropriate error code, making apps
2039 * think that the object was disconnected, when it actually wasn't */
2044 /***********************************************************************
2045 * CoInitializeWOW (OLE32.@)
2047 * WOW equivalent of CoInitialize?
2056 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
2058 FIXME("(0x%08lx,0x%08lx),stub!\n",x
,y
);
2062 /***********************************************************************
2063 * CoGetState [OLE32.@]
2065 * Retrieves the thread state object previously stored by CoSetState().
2068 * ppv [I] Address where pointer to object will be stored.
2072 * Failure: E_OUTOFMEMORY.
2075 * Crashes on all invalid ppv addresses, including NULL.
2076 * If the function returns a non-NULL object then the caller must release its
2077 * reference on the object when the object is no longer required.
2082 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
2084 struct oletls
*info
= COM_CurrentInfo();
2085 if (!info
) return E_OUTOFMEMORY
;
2091 IUnknown_AddRef(info
->state
);
2093 TRACE("apt->state=%p\n", info
->state
);
2099 /***********************************************************************
2100 * CoSetState [OLE32.@]
2102 * Sets the thread state object.
2105 * pv [I] Pointer to state object to be stored.
2108 * The system keeps a reference on the object while the object stored.
2112 * Failure: E_OUTOFMEMORY.
2114 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
2116 struct oletls
*info
= COM_CurrentInfo();
2117 if (!info
) return E_OUTOFMEMORY
;
2119 if (pv
) IUnknown_AddRef(pv
);
2123 TRACE("-- release %p now\n", info
->state
);
2124 IUnknown_Release(info
->state
);
2133 /******************************************************************************
2134 * OleGetAutoConvert [OLE32.@]
2136 HRESULT WINAPI
OleGetAutoConvert(REFCLSID clsidOld
, LPCLSID pClsidNew
)
2138 static const WCHAR wszAutoConvertTo
[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2140 WCHAR buf
[CHARS_IN_GUID
];
2144 if (ERROR_SUCCESS
!= COM_OpenKeyForCLSID(clsidOld
, KEY_READ
, &hkey
))
2146 res
= REGDB_E_CLASSNOTREG
;
2151 /* we can just query for the default value of AutoConvertTo key like that,
2152 without opening the AutoConvertTo key and querying for NULL (default) */
2153 if (RegQueryValueW(hkey
, wszAutoConvertTo
, buf
, &len
))
2155 res
= REGDB_E_KEYMISSING
;
2158 res
= CLSIDFromString(buf
, pClsidNew
);
2160 if (hkey
) RegCloseKey(hkey
);
2164 /******************************************************************************
2165 * CoTreatAsClass [OLE32.@]
2167 * Sets the TreatAs value of a class.
2170 * clsidOld [I] Class to set TreatAs value on.
2171 * clsidNew [I] The class the clsidOld should be treated as.
2175 * Failure: HRESULT code.
2180 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
2182 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2183 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
2185 WCHAR szClsidNew
[CHARS_IN_GUID
];
2187 WCHAR auto_treat_as
[CHARS_IN_GUID
];
2188 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
2191 if (ERROR_SUCCESS
!= COM_OpenKeyForCLSID(clsidOld
, KEY_READ
| KEY_WRITE
, &hkey
))
2193 res
= REGDB_E_CLASSNOTREG
;
2196 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
2198 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
2199 !CLSIDFromString(auto_treat_as
, &id
))
2201 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
2203 res
= REGDB_E_WRITEREGDB
;
2209 RegDeleteKeyW(hkey
, wszTreatAs
);
2213 else if (!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
)) &&
2214 !RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)))
2216 res
= REGDB_E_WRITEREGDB
;
2221 if (hkey
) RegCloseKey(hkey
);
2225 /******************************************************************************
2226 * CoGetTreatAsClass [OLE32.@]
2228 * Gets the TreatAs value of a class.
2231 * clsidOld [I] Class to get the TreatAs value of.
2232 * clsidNew [I] The class the clsidOld should be treated as.
2236 * Failure: HRESULT code.
2241 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
2243 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
2245 WCHAR szClsidNew
[CHARS_IN_GUID
];
2247 LONG len
= sizeof(szClsidNew
);
2249 FIXME("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
2250 memcpy(clsidNew
,clsidOld
,sizeof(CLSID
)); /* copy over old value */
2252 if (COM_OpenKeyForCLSID(clsidOld
, KEY_READ
, &hkey
))
2254 res
= REGDB_E_CLASSNOTREG
;
2257 if (RegQueryValueW(hkey
, wszTreatAs
, szClsidNew
, &len
))
2262 res
= CLSIDFromString(szClsidNew
,clsidNew
);
2264 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew
), res
);
2266 if (hkey
) RegCloseKey(hkey
);
2270 /******************************************************************************
2271 * CoGetCurrentProcess [OLE32.@]
2272 * CoGetCurrentProcess [COMPOBJ.34]
2274 * Gets the current process ID.
2277 * The current process ID.
2280 * Is DWORD really the correct return type for this function?
2282 DWORD WINAPI
CoGetCurrentProcess(void)
2284 return GetCurrentProcessId();
2287 /******************************************************************************
2288 * CoRegisterMessageFilter [OLE32.@]
2290 * Registers a message filter.
2293 * lpMessageFilter [I] Pointer to interface.
2294 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2298 * Failure: HRESULT code.
2300 HRESULT WINAPI
CoRegisterMessageFilter(
2301 LPMESSAGEFILTER lpMessageFilter
,
2302 LPMESSAGEFILTER
*lplpMessageFilter
)
2305 if (lplpMessageFilter
) {
2306 *lplpMessageFilter
= NULL
;
2311 /***********************************************************************
2312 * CoIsOle1Class [OLE32.@]
2314 * Determines whether the specified class an OLE v1 class.
2317 * clsid [I] Class to test.
2320 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2322 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
2324 FIXME("%s\n", debugstr_guid(clsid
));
2328 /***********************************************************************
2329 * IsEqualGUID [OLE32.@]
2331 * Compares two Unique Identifiers.
2334 * rguid1 [I] The first GUID to compare.
2335 * rguid2 [I] The other GUID to compare.
2341 BOOL WINAPI
IsEqualGUID(
2345 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
2348 /***********************************************************************
2349 * CoInitializeSecurity [OLE32.@]
2351 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
2352 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
2353 void* pReserved1
, DWORD dwAuthnLevel
,
2354 DWORD dwImpLevel
, void* pReserved2
,
2355 DWORD dwCapabilities
, void* pReserved3
)
2357 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc
, cAuthSvc
,
2358 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
2359 dwCapabilities
, pReserved3
);
2363 /***********************************************************************
2364 * CoSuspendClassObjects [OLE32.@]
2366 * Suspends all registered class objects to prevent further requests coming in
2367 * for those objects.
2371 * Failure: HRESULT code.
2373 HRESULT WINAPI
CoSuspendClassObjects(void)
2379 /***********************************************************************
2380 * CoAddRefServerProcess [OLE32.@]
2382 * Helper function for incrementing the reference count of a local-server
2386 * New reference count.
2388 ULONG WINAPI
CoAddRefServerProcess(void)
2394 /***********************************************************************
2395 * CoReleaseServerProcess [OLE32.@]
2397 * Helper function for decrementing the reference count of a local-server
2401 * New reference count.
2403 ULONG WINAPI
CoReleaseServerProcess(void)
2409 /***********************************************************************
2410 * CoIsHandlerConnected [OLE32.@]
2412 * Determines whether a proxy is connected to a remote stub.
2415 * pUnk [I] Pointer to object that may or may not be connected.
2418 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2421 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
2423 FIXME("%p\n", pUnk
);
2428 /***********************************************************************
2429 * CoAllowSetForegroundWindow [OLE32.@]
2432 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
2434 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
2438 /***********************************************************************
2439 * CoQueryProxyBlanket [OLE32.@]
2441 * Retrieves the security settings being used by a proxy.
2444 * pProxy [I] Pointer to the proxy object.
2445 * pAuthnSvc [O] The type of authentication service.
2446 * pAuthzSvc [O] The type of authorization service.
2447 * ppServerPrincName [O] Optional. The server prinicple name.
2448 * pAuthnLevel [O] The authentication level.
2449 * pImpLevel [O] The impersonation level.
2450 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2451 * pCapabilities [O] Flags affecting the security behaviour.
2455 * Failure: HRESULT code.
2458 * CoCopyProxy, CoSetProxyBlanket.
2460 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
2461 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
2462 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
2464 IClientSecurity
*pCliSec
;
2467 TRACE("%p\n", pProxy
);
2469 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
2472 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
2473 pAuthzSvc
, ppServerPrincName
,
2474 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
2476 IClientSecurity_Release(pCliSec
);
2479 if (FAILED(hr
)) ERR("-- failed with 0x%08lx\n", hr
);
2483 /***********************************************************************
2484 * CoSetProxyBlanket [OLE32.@]
2486 * Sets the security settings for a proxy.
2489 * pProxy [I] Pointer to the proxy object.
2490 * AuthnSvc [I] The type of authentication service.
2491 * AuthzSvc [I] The type of authorization service.
2492 * pServerPrincName [I] The server prinicple name.
2493 * AuthnLevel [I] The authentication level.
2494 * ImpLevel [I] The impersonation level.
2495 * pAuthInfo [I] Information specific to the authorization/authentication service.
2496 * Capabilities [I] Flags affecting the security behaviour.
2500 * Failure: HRESULT code.
2503 * CoQueryProxyBlanket, CoCopyProxy.
2505 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
2506 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
2507 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
2509 IClientSecurity
*pCliSec
;
2512 TRACE("%p\n", pProxy
);
2514 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
2517 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
2518 AuthzSvc
, pServerPrincName
,
2519 AuthnLevel
, ImpLevel
, pAuthInfo
,
2521 IClientSecurity_Release(pCliSec
);
2524 if (FAILED(hr
)) ERR("-- failed with 0x%08lx\n", hr
);
2528 /***********************************************************************
2529 * CoCopyProxy [OLE32.@]
2534 * pProxy [I] Pointer to the proxy object.
2535 * ppCopy [O] Copy of the proxy.
2539 * Failure: HRESULT code.
2542 * CoQueryProxyBlanket, CoSetProxyBlanket.
2544 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
2546 IClientSecurity
*pCliSec
;
2549 TRACE("%p\n", pProxy
);
2551 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
2554 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
2555 IClientSecurity_Release(pCliSec
);
2558 if (FAILED(hr
)) ERR("-- failed with 0x%08lx\n", hr
);
2563 /***********************************************************************
2564 * CoWaitForMultipleHandles [OLE32.@]
2566 * Waits for one or more handles to become signaled.
2569 * dwFlags [I] Flags. See notes.
2570 * dwTimeout [I] Timeout in milliseconds.
2571 * cHandles [I] Number of handles pointed to by pHandles.
2572 * pHandles [I] Handles to wait for.
2573 * lpdwindex [O] Index of handle that was signaled.
2577 * Failure: RPC_S_CALLPENDING on timeout.
2581 * The dwFlags parameter can be zero or more of the following:
2582 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2583 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2586 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2588 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
2589 ULONG cHandles
, const HANDLE
* pHandles
, LPDWORD lpdwindex
)
2592 DWORD wait_flags
= (dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0 |
2593 (dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0;
2594 DWORD start_time
= GetTickCount();
2596 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
2597 pHandles
, lpdwindex
);
2601 DWORD now
= GetTickCount();
2604 if ((dwTimeout
!= INFINITE
) && (start_time
+ dwTimeout
>= now
))
2606 hr
= RPC_S_CALLPENDING
;
2610 TRACE("waiting for rpc completion or window message\n");
2612 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
2613 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
2614 QS_ALLINPUT
, wait_flags
);
2616 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
2619 while (PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
))
2621 /* FIXME: filter the messages here */
2622 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
2623 TranslateMessage(&msg
);
2624 DispatchMessageW(&msg
);
2627 else if ((res
>= WAIT_OBJECT_0
) && (res
< WAIT_OBJECT_0
+ cHandles
))
2629 /* handle signaled, store index */
2630 *lpdwindex
= (res
- WAIT_OBJECT_0
);
2633 else if (res
== WAIT_TIMEOUT
)
2635 hr
= RPC_S_CALLPENDING
;
2640 ERR("Unexpected wait termination: %ld, %ld\n", res
, GetLastError());
2645 TRACE("-- 0x%08lx\n", hr
);
2649 /***********************************************************************
2652 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID fImpLoad
)
2654 TRACE("%p 0x%lx %p\n", hinstDLL
, fdwReason
, fImpLoad
);
2657 case DLL_PROCESS_ATTACH
:
2658 OLE32_hInstance
= hinstDLL
;
2659 COMPOBJ_InitProcess();
2660 if (TRACE_ON(ole
)) CoRegisterMallocSpy((LPVOID
)-1);
2663 case DLL_PROCESS_DETACH
:
2664 if (TRACE_ON(ole
)) CoRevokeMallocSpy();
2665 COMPOBJ_UninitProcess();
2666 OLE32_hInstance
= 0;
2669 case DLL_THREAD_DETACH
:
2676 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */