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
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
37 * - Make all ole interface marshaling use NDR to be wire compatible with
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
62 #include "compobj_private.h"
64 #include "wine/unicode.h"
65 #include "wine/debug.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
69 HINSTANCE OLE32_hInstance
= 0; /* FIXME: make static ... */
71 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
73 /****************************************************************************
74 * This section defines variables internal to the COM module.
76 * TODO: Most of these things will have to be made thread-safe.
79 static HRESULT
COM_GetRegisteredClassObject(REFCLSID rclsid
, DWORD dwClsContext
, LPUNKNOWN
* ppUnk
);
80 static void COM_RevokeAllClasses(void);
81 static HRESULT
get_inproc_class_object(HKEY hkeydll
, REFCLSID rclsid
, REFIID riid
, void **ppv
);
83 static APARTMENT
*MTA
; /* protected by csApartment */
84 static APARTMENT
*MainApartment
; /* the first STA apartment */
85 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
87 static CRITICAL_SECTION csApartment
;
88 static CRITICAL_SECTION_DEBUG critsect_debug
=
91 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
92 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
94 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
96 struct registered_psclsid
104 * This lock count counts the number of times CoInitialize is called. It is
105 * decreased every time CoUninitialize is called. When it hits 0, the COM
106 * libraries are freed
108 static LONG s_COMLockCount
= 0;
109 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
110 static LONG s_COMServerProcessReferences
= 0;
113 * This linked list contains the list of registered class objects. These
114 * are mostly used to register the factories for out-of-proc servers of OLE
117 * TODO: Make this data structure aware of inter-process communication. This
118 * means that parts of this will be exported to the Wine Server.
120 typedef struct tagRegisteredClass
123 CLSID classIdentifier
;
124 LPUNKNOWN classObject
;
128 LPSTREAM pMarshaledData
; /* FIXME: only really need to store OXID and IPID */
129 void *RpcRegistration
;
132 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
134 static CRITICAL_SECTION csRegisteredClassList
;
135 static CRITICAL_SECTION_DEBUG class_cs_debug
=
137 0, 0, &csRegisteredClassList
,
138 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
139 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
141 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
143 /*****************************************************************************
144 * This section contains OpenDllList definitions
146 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
147 * other functions that do LoadLibrary _without_ giving back a HMODULE.
148 * Without this list these handles would never be freed.
150 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
151 * next unload-call but not before 600 sec.
154 typedef struct tagOpenDll
{
156 struct tagOpenDll
*next
;
159 static OpenDll
*openDllList
= NULL
; /* linked list of open dlls */
161 static CRITICAL_SECTION csOpenDllList
;
162 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
164 0, 0, &csOpenDllList
,
165 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
166 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
168 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
170 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',' ',
171 '0','x','#','#','#','#','#','#','#','#',' ',0};
172 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
174 static void COMPOBJ_DLLList_Add(HANDLE hLibrary
);
175 static void COMPOBJ_DllList_FreeUnused(int Timeout
);
177 static void COMPOBJ_InitProcess( void )
181 /* Dispatching to the correct thread in an apartment is done through
182 * window messages rather than RPC transports. When an interface is
183 * marshalled into another apartment in the same process, a window of the
184 * following class is created. The *caller* of CoMarshalInterface (ie the
185 * application) is responsible for pumping the message loop in that thread.
186 * The WM_USER messages which point to the RPCs are then dispatched to
187 * COM_AptWndProc by the user's code from the apartment in which the interface
190 memset(&wclass
, 0, sizeof(wclass
));
191 wclass
.lpfnWndProc
= apartment_wndproc
;
192 wclass
.hInstance
= OLE32_hInstance
;
193 wclass
.lpszClassName
= wszAptWinClass
;
194 RegisterClassW(&wclass
);
197 static void COMPOBJ_UninitProcess( void )
199 UnregisterClassW(wszAptWinClass
, OLE32_hInstance
);
202 static void COM_TlsDestroy(void)
204 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
207 if (info
->apt
) apartment_release(info
->apt
);
208 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
209 if (info
->state
) IUnknown_Release(info
->state
);
210 HeapFree(GetProcessHeap(), 0, info
);
211 NtCurrentTeb()->ReservedForOle
= NULL
;
215 /******************************************************************************
219 /* allocates memory and fills in the necessary fields for a new apartment
220 * object. must be called inside apartment cs */
221 static APARTMENT
*apartment_construct(DWORD model
)
225 TRACE("creating new apartment, model=%d\n", model
);
227 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
228 apt
->tid
= GetCurrentThreadId();
230 list_init(&apt
->proxies
);
231 list_init(&apt
->stubmgrs
);
232 list_init(&apt
->psclsids
);
235 apt
->remunk_exported
= FALSE
;
237 InitializeCriticalSection(&apt
->cs
);
238 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
240 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
242 if (apt
->multi_threaded
)
244 /* FIXME: should be randomly generated by in an RPC call to rpcss */
245 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
249 /* FIXME: should be randomly generated by in an RPC call to rpcss */
250 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
253 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
255 list_add_head(&apts
, &apt
->entry
);
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 EnterCriticalSection(&csApartment
);
273 apt
= apartment_construct(model
);
278 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
281 LeaveCriticalSection(&csApartment
);
285 EnterCriticalSection(&csApartment
);
287 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
288 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
292 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
293 apartment_addref(MTA
);
296 MTA
= apartment_construct(model
);
300 LeaveCriticalSection(&csApartment
);
302 COM_CurrentInfo()->apt
= apt
;
308 static inline BOOL
apartment_is_model(APARTMENT
*apt
, DWORD model
)
310 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
313 DWORD
apartment_addref(struct apartment
*apt
)
315 DWORD refs
= InterlockedIncrement(&apt
->refs
);
316 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
320 DWORD
apartment_release(struct apartment
*apt
)
324 EnterCriticalSection(&csApartment
);
326 ret
= InterlockedDecrement(&apt
->refs
);
327 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
328 /* destruction stuff that needs to happen under csApartment CS */
331 if (apt
== MTA
) MTA
= NULL
;
332 else if (apt
== MainApartment
) MainApartment
= NULL
;
333 list_remove(&apt
->entry
);
336 LeaveCriticalSection(&csApartment
);
340 struct list
*cursor
, *cursor2
;
342 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
344 /* no locking is needed for this apartment, because no other thread
345 * can access it at this point */
347 apartment_disconnectproxies(apt
);
349 if (apt
->win
) DestroyWindow(apt
->win
);
351 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
353 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
354 /* release the implicit reference given by the fact that the
355 * stub has external references (it must do since it is in the
356 * stub manager list in the apartment and all non-apartment users
357 * must have a ref on the apartment and so it cannot be destroyed).
359 stub_manager_int_release(stubmgr
);
362 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->psclsids
)
364 struct registered_psclsid
*registered_psclsid
=
365 LIST_ENTRY(cursor
, struct registered_psclsid
, entry
);
367 list_remove(®istered_psclsid
->entry
);
368 HeapFree(GetProcessHeap(), 0, registered_psclsid
);
371 /* if this assert fires, then another thread took a reference to a
372 * stub manager without taking a reference to the containing
373 * apartment, which it must do. */
374 assert(list_empty(&apt
->stubmgrs
));
376 if (apt
->filter
) IUnknown_Release(apt
->filter
);
378 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
379 DeleteCriticalSection(&apt
->cs
);
381 HeapFree(GetProcessHeap(), 0, apt
);
387 /* The given OXID must be local to this process:
389 * The ref parameter is here mostly to ensure people remember that
390 * they get one, you should normally take a ref for thread safety.
392 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
394 APARTMENT
*result
= NULL
;
397 EnterCriticalSection(&csApartment
);
398 LIST_FOR_EACH( cursor
, &apts
)
400 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
401 if (apt
->oxid
== oxid
)
404 if (ref
) apartment_addref(result
);
408 LeaveCriticalSection(&csApartment
);
413 /* gets the apartment which has a given creator thread ID. The caller must
414 * release the reference from the apartment as soon as the apartment pointer
415 * is no longer required. */
416 APARTMENT
*apartment_findfromtid(DWORD tid
)
418 APARTMENT
*result
= NULL
;
421 EnterCriticalSection(&csApartment
);
422 LIST_FOR_EACH( cursor
, &apts
)
424 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
428 apartment_addref(result
);
432 LeaveCriticalSection(&csApartment
);
437 /* gets an apartment which has a given type. The caller must
438 * release the reference from the apartment as soon as the apartment pointer
439 * is no longer required. */
440 static APARTMENT
*apartment_findfromtype(BOOL multi_threaded
, BOOL main_apartment
)
442 APARTMENT
*result
= NULL
;
443 struct apartment
*apt
;
445 EnterCriticalSection(&csApartment
);
447 if (!multi_threaded
&& main_apartment
)
449 result
= MainApartment
;
450 if (result
) apartment_addref(result
);
451 LeaveCriticalSection(&csApartment
);
455 LIST_FOR_EACH_ENTRY( apt
, &apts
, struct apartment
, entry
)
457 if (apt
->multi_threaded
== multi_threaded
)
460 apartment_addref(result
);
464 LeaveCriticalSection(&csApartment
);
469 struct host_object_params
472 CLSID clsid
; /* clsid of object to marshal */
473 IID iid
; /* interface to marshal */
474 IStream
*stream
; /* stream that the object will be marshaled into */
477 static HRESULT
apartment_hostobject(const struct host_object_params
*params
)
481 static const LARGE_INTEGER llZero
;
485 hr
= get_inproc_class_object(params
->hkeydll
, ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
489 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
491 IUnknown_Release(object
);
492 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
497 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
502 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
505 return apartment_hostobject((const struct host_object_params
*)lParam
);
507 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
511 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
513 if (apt
->multi_threaded
)
518 HWND hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0,
520 0, 0, OLE32_hInstance
, NULL
);
523 ERR("CreateWindow failed with error %d\n", GetLastError());
524 return HRESULT_FROM_WIN32(GetLastError());
526 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
527 /* someone beat us to it */
534 HWND
apartment_getwindow(struct apartment
*apt
)
536 assert(!apt
->multi_threaded
);
540 void apartment_joinmta(void)
542 apartment_addref(MTA
);
543 COM_CurrentInfo()->apt
= MTA
;
546 /*****************************************************************************
547 * This section contains OpenDllList implementation
550 static void COMPOBJ_DLLList_Add(HANDLE hLibrary
)
557 EnterCriticalSection( &csOpenDllList
);
559 if (openDllList
== NULL
) {
560 /* empty list -- add first node */
561 openDllList
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
562 openDllList
->hLibrary
=hLibrary
;
563 openDllList
->next
= NULL
;
565 /* search for this dll */
567 for (ptr
= openDllList
; ptr
->next
!= NULL
; ptr
=ptr
->next
) {
568 if (ptr
->hLibrary
== hLibrary
) {
574 /* dll not found, add it */
576 openDllList
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
577 openDllList
->hLibrary
= hLibrary
;
578 openDllList
->next
= tmp
;
582 LeaveCriticalSection( &csOpenDllList
);
585 static void COMPOBJ_DllList_FreeUnused(int Timeout
)
587 OpenDll
*curr
, *next
, *prev
= NULL
;
588 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
589 DllCanUnloadNowFunc DllCanUnloadNow
;
593 EnterCriticalSection( &csOpenDllList
);
595 for (curr
= openDllList
; curr
!= NULL
; ) {
596 DllCanUnloadNow
= (DllCanUnloadNowFunc
) GetProcAddress(curr
->hLibrary
, "DllCanUnloadNow");
598 if ( (DllCanUnloadNow
!= NULL
) && (DllCanUnloadNow() == S_OK
) ) {
601 TRACE("freeing %p\n", curr
->hLibrary
);
602 FreeLibrary(curr
->hLibrary
);
604 HeapFree(GetProcessHeap(), 0, curr
);
605 if (curr
== openDllList
) {
618 LeaveCriticalSection( &csOpenDllList
);
621 /******************************************************************************
622 * CoBuildVersion [OLE32.@]
623 * CoBuildVersion [COMPOBJ.1]
625 * Gets the build version of the DLL.
630 * Current build version, hiword is majornumber, loword is minornumber
632 DWORD WINAPI
CoBuildVersion(void)
634 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
635 return (rmm
<<16)+rup
;
638 /******************************************************************************
639 * CoInitialize [OLE32.@]
641 * Initializes the COM libraries by calling CoInitializeEx with
642 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
645 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
648 * Success: S_OK if not already initialized, S_FALSE otherwise.
649 * Failure: HRESULT code.
654 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
657 * Just delegate to the newer method.
659 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
662 /******************************************************************************
663 * CoInitializeEx [OLE32.@]
665 * Initializes the COM libraries.
668 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
669 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
672 * S_OK if successful,
673 * S_FALSE if this function was called already.
674 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
679 * The behavior used to set the IMalloc used for memory management is
681 * The dwCoInit parameter must specify one of the following apartment
683 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
684 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
685 * The parameter may also specify zero or more of the following flags:
686 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
687 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
692 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
697 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
699 if (lpReserved
!=NULL
)
701 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
705 * Check the lock count. If this is the first time going through the initialize
706 * process, we have to initialize the libraries.
708 * And crank-up that lock count.
710 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
713 * Initialize the various COM libraries and data structures.
715 TRACE("() - Initializing the COM libraries\n");
717 /* we may need to defer this until after apartment initialisation */
718 RunningObjectTableImpl_Initialize();
721 if (!(apt
= COM_CurrentInfo()->apt
))
723 apt
= apartment_get_or_create(dwCoInit
);
724 if (!apt
) return E_OUTOFMEMORY
;
726 else if (!apartment_is_model(apt
, dwCoInit
))
728 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
729 code then we are probably using the wrong threading model to implement that API. */
730 ERR("Attempt to change threading model of this apartment from %s to %s\n",
731 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
732 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
733 return RPC_E_CHANGED_MODE
;
738 COM_CurrentInfo()->inits
++;
743 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
744 pending RPCs are ignored. Non-COM messages are discarded at this point.
746 static void COM_FlushMessageQueue(void)
749 APARTMENT
*apt
= COM_CurrentApt();
751 if (!apt
|| !apt
->win
) return;
753 TRACE("Flushing STA message queue\n");
755 while (PeekMessageA(&message
, NULL
, 0, 0, PM_REMOVE
))
757 if (message
.hwnd
!= apt
->win
)
759 WARN("discarding message 0x%x for window %p\n", message
.message
, message
.hwnd
);
763 TranslateMessage(&message
);
764 DispatchMessageA(&message
);
768 /***********************************************************************
769 * CoUninitialize [OLE32.@]
771 * This method will decrement the refcount on the current apartment, freeing
772 * the resources associated with it if it is the last thread in the apartment.
773 * If the last apartment is freed, the function will additionally release
774 * any COM resources associated with the process.
784 void WINAPI
CoUninitialize(void)
786 struct oletls
* info
= COM_CurrentInfo();
791 /* will only happen on OOM */
797 ERR("Mismatched CoUninitialize\n");
803 apartment_release(info
->apt
);
808 * Decrease the reference count.
809 * If we are back to 0 locks on the COM library, make sure we free
810 * all the associated data structures.
812 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
815 TRACE("() - Releasing the COM libraries\n");
817 RunningObjectTableImpl_UnInitialize();
819 /* Release the references to the registered class objects */
820 COM_RevokeAllClasses();
822 /* This will free the loaded COM Dlls */
823 CoFreeAllLibraries();
825 /* This ensures we deal with any pending RPCs */
826 COM_FlushMessageQueue();
828 else if (lCOMRefCnt
<1) {
829 ERR( "CoUninitialize() - not CoInitialized.\n" );
830 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
834 /******************************************************************************
835 * CoDisconnectObject [OLE32.@]
836 * CoDisconnectObject [COMPOBJ.15]
838 * Disconnects all connections to this object from remote processes. Dispatches
839 * pending RPCs while blocking new RPCs from occurring, and then calls
840 * IMarshal::DisconnectObject on the given object.
842 * Typically called when the object server is forced to shut down, for instance by
846 * lpUnk [I] The object whose stub should be disconnected.
847 * reserved [I] Reserved. Should be set to 0.
851 * Failure: HRESULT code.
854 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
856 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
862 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
864 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
867 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
868 IMarshal_Release(marshal
);
872 apt
= COM_CurrentApt();
874 return CO_E_NOTINITIALIZED
;
876 apartment_disconnectobject(apt
, lpUnk
);
878 /* Note: native is pretty broken here because it just silently
879 * fails, without returning an appropriate error code if the object was
880 * not found, making apps think that the object was disconnected, when
881 * it actually wasn't */
886 /******************************************************************************
887 * CoCreateGuid [OLE32.@]
889 * Simply forwards to UuidCreate in RPCRT4.
892 * pguid [O] Points to the GUID to initialize.
896 * Failure: HRESULT code.
901 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
903 return UuidCreate(pguid
);
906 /******************************************************************************
907 * CLSIDFromString [OLE32.@]
908 * IIDFromString [OLE32.@]
910 * Converts a unique identifier from its string representation into
914 * idstr [I] The string representation of the GUID.
915 * id [O] GUID converted from the string.
919 * CO_E_CLASSSTRING if idstr is not a valid CLSID
924 static HRESULT WINAPI
__CLSIDFromString(LPCWSTR s
, CLSID
*id
)
930 memset( id
, 0, sizeof (CLSID
) );
934 /* validate the CLSID string */
935 if (strlenW(s
) != 38)
936 return CO_E_CLASSSTRING
;
938 if ((s
[0]!='{') || (s
[9]!='-') || (s
[14]!='-') || (s
[19]!='-') || (s
[24]!='-') || (s
[37]!='}'))
939 return CO_E_CLASSSTRING
;
941 for (i
=1; i
<37; i
++) {
942 if ((i
== 9)||(i
== 14)||(i
== 19)||(i
== 24)) continue;
943 if (!(((s
[i
] >= '0') && (s
[i
] <= '9')) ||
944 ((s
[i
] >= 'a') && (s
[i
] <= 'f')) ||
945 ((s
[i
] >= 'A') && (s
[i
] <= 'F'))))
946 return CO_E_CLASSSTRING
;
949 TRACE("%s -> %p\n", debugstr_w(s
), id
);
951 /* quick lookup table */
952 memset(table
, 0, 256);
954 for (i
= 0; i
< 10; i
++) {
957 for (i
= 0; i
< 6; i
++) {
958 table
['A' + i
] = i
+10;
959 table
['a' + i
] = i
+10;
962 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
964 id
->Data1
= (table
[s
[1]] << 28 | table
[s
[2]] << 24 | table
[s
[3]] << 20 | table
[s
[4]] << 16 |
965 table
[s
[5]] << 12 | table
[s
[6]] << 8 | table
[s
[7]] << 4 | table
[s
[8]]);
966 id
->Data2
= table
[s
[10]] << 12 | table
[s
[11]] << 8 | table
[s
[12]] << 4 | table
[s
[13]];
967 id
->Data3
= table
[s
[15]] << 12 | table
[s
[16]] << 8 | table
[s
[17]] << 4 | table
[s
[18]];
969 /* these are just sequential bytes */
970 id
->Data4
[0] = table
[s
[20]] << 4 | table
[s
[21]];
971 id
->Data4
[1] = table
[s
[22]] << 4 | table
[s
[23]];
972 id
->Data4
[2] = table
[s
[25]] << 4 | table
[s
[26]];
973 id
->Data4
[3] = table
[s
[27]] << 4 | table
[s
[28]];
974 id
->Data4
[4] = table
[s
[29]] << 4 | table
[s
[30]];
975 id
->Data4
[5] = table
[s
[31]] << 4 | table
[s
[32]];
976 id
->Data4
[6] = table
[s
[33]] << 4 | table
[s
[34]];
977 id
->Data4
[7] = table
[s
[35]] << 4 | table
[s
[36]];
982 /*****************************************************************************/
984 HRESULT WINAPI
CLSIDFromString(LPOLESTR idstr
, CLSID
*id
)
991 ret
= __CLSIDFromString(idstr
, id
);
992 if(ret
!= S_OK
) { /* It appears a ProgID is also valid */
993 ret
= CLSIDFromProgID(idstr
, id
);
998 /* Converts a GUID into the respective string representation. */
999 HRESULT
WINE_StringFromCLSID(
1000 const CLSID
*id
, /* [in] GUID to be converted */
1001 LPSTR idstr
/* [out] pointer to buffer to contain converted guid */
1003 static const char hex
[] = "0123456789ABCDEF";
1008 { ERR("called with id=Null\n");
1013 sprintf(idstr
, "{%08X-%04X-%04X-%02X%02X-",
1014 id
->Data1
, id
->Data2
, id
->Data3
,
1015 id
->Data4
[0], id
->Data4
[1]);
1019 for (i
= 2; i
< 8; i
++) {
1020 *s
++ = hex
[id
->Data4
[i
]>>4];
1021 *s
++ = hex
[id
->Data4
[i
] & 0xf];
1027 TRACE("%p->%s\n", id
, idstr
);
1033 /******************************************************************************
1034 * StringFromCLSID [OLE32.@]
1035 * StringFromIID [OLE32.@]
1037 * Converts a GUID into the respective string representation.
1038 * The target string is allocated using the OLE IMalloc.
1041 * id [I] the GUID to be converted.
1042 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1049 * StringFromGUID2, CLSIDFromString
1051 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
1057 if ((ret
= CoGetMalloc(0,&mllc
)))
1060 ret
=WINE_StringFromCLSID(id
,buf
);
1062 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, buf
, -1, NULL
, 0 );
1063 *idstr
= IMalloc_Alloc( mllc
, len
* sizeof(WCHAR
) );
1064 MultiByteToWideChar( CP_ACP
, 0, buf
, -1, *idstr
, len
);
1069 /******************************************************************************
1070 * StringFromGUID2 [OLE32.@]
1071 * StringFromGUID2 [COMPOBJ.76]
1073 * Modified version of StringFromCLSID that allows you to specify max
1077 * id [I] GUID to convert to string.
1078 * str [O] Buffer where the result will be stored.
1079 * cmax [I] Size of the buffer in characters.
1082 * Success: The length of the resulting string in characters.
1085 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
1089 if (WINE_StringFromCLSID(id
,xguid
))
1091 return MultiByteToWideChar( CP_ACP
, 0, xguid
, -1, str
, cmax
);
1094 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1095 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
1097 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
1098 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
1102 strcpyW(path
, wszCLSIDSlash
);
1103 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
1104 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, path
, 0, keyname
? KEY_READ
: access
, &key
);
1105 if (res
== ERROR_FILE_NOT_FOUND
)
1106 return REGDB_E_CLASSNOTREG
;
1107 else if (res
!= ERROR_SUCCESS
)
1108 return REGDB_E_READREGDB
;
1116 res
= RegOpenKeyExW(key
, keyname
, 0, access
, subkey
);
1118 if (res
== ERROR_FILE_NOT_FOUND
)
1119 return REGDB_E_KEYMISSING
;
1120 else if (res
!= ERROR_SUCCESS
)
1121 return REGDB_E_READREGDB
;
1126 /* open HKCR\\AppId\\{string form of appid clsid} key */
1127 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
1129 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
1130 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
1132 WCHAR buf
[CHARS_IN_GUID
];
1133 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
1139 /* read the AppID value under the class's key */
1140 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
1145 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
1147 if (res
== ERROR_FILE_NOT_FOUND
)
1148 return REGDB_E_KEYMISSING
;
1149 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
1150 return REGDB_E_READREGDB
;
1152 strcpyW(keyname
, szAppIdKey
);
1153 strcatW(keyname
, buf
);
1154 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, access
, subkey
);
1155 if (res
== ERROR_FILE_NOT_FOUND
)
1156 return REGDB_E_KEYMISSING
;
1157 else if (res
!= ERROR_SUCCESS
)
1158 return REGDB_E_READREGDB
;
1163 /******************************************************************************
1164 * ProgIDFromCLSID [OLE32.@]
1166 * Converts a class id into the respective program ID.
1169 * clsid [I] Class ID, as found in registry.
1170 * ppszProgID [O] Associated ProgID.
1175 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1177 HRESULT WINAPI
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
1179 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
1186 ERR("ppszProgId isn't optional\n");
1187 return E_INVALIDARG
;
1191 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
1195 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
1196 ret
= REGDB_E_CLASSNOTREG
;
1200 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
1203 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
))
1204 ret
= REGDB_E_CLASSNOTREG
;
1207 ret
= E_OUTOFMEMORY
;
1214 /******************************************************************************
1215 * CLSIDFromProgID [OLE32.@]
1217 * Converts a program id into the respective GUID.
1220 * progid [I] Unicode program ID, as found in registry.
1221 * clsid [O] Associated CLSID.
1225 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1227 HRESULT WINAPI
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
1229 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
1230 WCHAR buf2
[CHARS_IN_GUID
];
1231 LONG buf2len
= sizeof(buf2
);
1235 if (!progid
|| !clsid
)
1237 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid
, clsid
);
1238 return E_INVALIDARG
;
1241 /* initialise clsid in case of failure */
1242 memset(clsid
, 0, sizeof(*clsid
));
1244 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
1245 strcpyW( buf
, progid
);
1246 strcatW( buf
, clsidW
);
1247 if (RegOpenKeyW(HKEY_CLASSES_ROOT
,buf
,&xhkey
))
1249 HeapFree(GetProcessHeap(),0,buf
);
1250 return CO_E_CLASSSTRING
;
1252 HeapFree(GetProcessHeap(),0,buf
);
1254 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
1257 return CO_E_CLASSSTRING
;
1260 return CLSIDFromString(buf2
,clsid
);
1264 /*****************************************************************************
1265 * CoGetPSClsid [OLE32.@]
1267 * Retrieves the CLSID of the proxy/stub factory that implements
1268 * IPSFactoryBuffer for the specified interface.
1271 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1272 * pclsid [O] Where to store returned proxy/stub CLSID.
1277 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1281 * The standard marshaller activates the object with the CLSID
1282 * returned and uses the CreateProxy and CreateStub methods on its
1283 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1286 * CoGetPSClsid determines this CLSID by searching the
1287 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1288 * in the registry and any interface id registered by
1289 * CoRegisterPSClsid within the current process.
1293 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1294 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1295 * considered a bug in native unless an application depends on this (unlikely).
1298 * CoRegisterPSClsid.
1300 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
1302 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1303 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1304 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
1305 WCHAR value
[CHARS_IN_GUID
];
1308 APARTMENT
*apt
= COM_CurrentApt();
1309 struct registered_psclsid
*registered_psclsid
;
1311 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
1315 ERR("apartment not initialised\n");
1316 return CO_E_NOTINITIALIZED
;
1321 ERR("pclsid isn't optional\n");
1322 return E_INVALIDARG
;
1325 EnterCriticalSection(&apt
->cs
);
1327 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
1328 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
1330 *pclsid
= registered_psclsid
->clsid
;
1331 LeaveCriticalSection(&apt
->cs
);
1335 LeaveCriticalSection(&apt
->cs
);
1337 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1338 strcpyW(path
, wszInterface
);
1339 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
1340 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
1342 /* Open the key.. */
1343 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, path
, 0, KEY_READ
, &hkey
))
1345 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
1346 return REGDB_E_IIDNOTREG
;
1349 /* ... Once we have the key, query the registry to get the
1350 value of CLSID as a string, and convert it into a
1351 proper CLSID structure to be passed back to the app */
1352 len
= sizeof(value
);
1353 if (ERROR_SUCCESS
!= RegQueryValueW(hkey
, NULL
, value
, &len
))
1356 return REGDB_E_IIDNOTREG
;
1360 /* We have the CLSid we want back from the registry as a string, so
1361 lets convert it into a CLSID structure */
1362 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
1363 return REGDB_E_IIDNOTREG
;
1365 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
1369 /*****************************************************************************
1370 * CoRegisterPSClsid [OLE32.@]
1372 * Register a proxy/stub CLSID for the given interface in the current process
1376 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1377 * rclsid [I] CLSID of the proxy/stub.
1381 * Failure: E_OUTOFMEMORY
1385 * This function does not add anything to the registry and the effects are
1386 * limited to the lifetime of the current process.
1391 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
1393 APARTMENT
*apt
= COM_CurrentApt();
1394 struct registered_psclsid
*registered_psclsid
;
1396 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
1400 ERR("apartment not initialised\n");
1401 return CO_E_NOTINITIALIZED
;
1404 EnterCriticalSection(&apt
->cs
);
1406 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
1407 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
1409 registered_psclsid
->clsid
= *rclsid
;
1410 LeaveCriticalSection(&apt
->cs
);
1414 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
1415 if (!registered_psclsid
)
1417 LeaveCriticalSection(&apt
->cs
);
1418 return E_OUTOFMEMORY
;
1421 registered_psclsid
->iid
= *riid
;
1422 registered_psclsid
->clsid
= *rclsid
;
1423 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
1425 LeaveCriticalSection(&apt
->cs
);
1432 * COM_GetRegisteredClassObject
1434 * This internal method is used to scan the registered class list to
1435 * find a class object.
1438 * rclsid Class ID of the class to find.
1439 * dwClsContext Class context to match.
1440 * ppv [out] returns a pointer to the class object. Complying
1441 * to normal COM usage, this method will increase the
1442 * reference count on this object.
1444 static HRESULT
COM_GetRegisteredClassObject(
1449 HRESULT hr
= S_FALSE
;
1450 RegisteredClass
*curClass
;
1457 EnterCriticalSection( &csRegisteredClassList
);
1459 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1462 * Check if we have a match on the class ID and context.
1464 if ((dwClsContext
& curClass
->runContext
) &&
1465 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
1468 * We have a match, return the pointer to the class object.
1470 *ppUnk
= curClass
->classObject
;
1472 IUnknown_AddRef(curClass
->classObject
);
1479 LeaveCriticalSection( &csRegisteredClassList
);
1484 /******************************************************************************
1485 * CoRegisterClassObject [OLE32.@]
1487 * Registers the class object for a given class ID. Servers housed in EXE
1488 * files use this method instead of exporting DllGetClassObject to allow
1489 * other code to connect to their objects.
1492 * rclsid [I] CLSID of the object to register.
1493 * pUnk [I] IUnknown of the object.
1494 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1495 * flags [I] REGCLS flags indicating how connections are made.
1496 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1500 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1501 * CO_E_OBJISREG if the object is already registered. We should not return this.
1504 * CoRevokeClassObject, CoGetClassObject
1507 * MSDN claims that multiple interface registrations are legal, but we
1508 * can't do that with our current implementation.
1510 HRESULT WINAPI
CoRegisterClassObject(
1515 LPDWORD lpdwRegister
)
1517 RegisteredClass
* newClass
;
1518 LPUNKNOWN foundObject
;
1521 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1522 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
1524 if ( (lpdwRegister
==0) || (pUnk
==0) )
1525 return E_INVALIDARG
;
1527 if (!COM_CurrentApt())
1529 ERR("COM was not initialized\n");
1530 return CO_E_NOTINITIALIZED
;
1535 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1536 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1537 if (flags
& REGCLS_MULTIPLEUSE
)
1538 dwClsContext
|= CLSCTX_INPROC_SERVER
;
1541 * First, check if the class is already registered.
1542 * If it is, this should cause an error.
1544 hr
= COM_GetRegisteredClassObject(rclsid
, dwClsContext
, &foundObject
);
1546 if (flags
& REGCLS_MULTIPLEUSE
) {
1547 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
1548 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
1549 IUnknown_Release(foundObject
);
1552 IUnknown_Release(foundObject
);
1553 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
1554 return CO_E_OBJISREG
;
1557 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
1558 if ( newClass
== NULL
)
1559 return E_OUTOFMEMORY
;
1561 newClass
->classIdentifier
= *rclsid
;
1562 newClass
->runContext
= dwClsContext
;
1563 newClass
->connectFlags
= flags
;
1564 newClass
->pMarshaledData
= NULL
;
1565 newClass
->RpcRegistration
= NULL
;
1568 * Use the address of the chain node as the cookie since we are sure it's
1569 * unique. FIXME: not on 64-bit platforms.
1571 newClass
->dwCookie
= (DWORD
)newClass
;
1574 * Since we're making a copy of the object pointer, we have to increase its
1577 newClass
->classObject
= pUnk
;
1578 IUnknown_AddRef(newClass
->classObject
);
1580 EnterCriticalSection( &csRegisteredClassList
);
1581 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
1582 LeaveCriticalSection( &csRegisteredClassList
);
1584 *lpdwRegister
= newClass
->dwCookie
;
1586 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
1587 IClassFactory
*classfac
;
1589 hr
= IUnknown_QueryInterface(newClass
->classObject
, &IID_IClassFactory
,
1590 (LPVOID
*)&classfac
);
1593 hr
= CreateStreamOnHGlobal(0, TRUE
, &newClass
->pMarshaledData
);
1595 FIXME("Failed to create stream on hglobal, %x\n", hr
);
1596 IUnknown_Release(classfac
);
1599 hr
= CoMarshalInterface(newClass
->pMarshaledData
, &IID_IClassFactory
,
1600 (LPVOID
)classfac
, MSHCTX_LOCAL
, NULL
,
1601 MSHLFLAGS_TABLESTRONG
);
1603 FIXME("CoMarshalInterface failed, %x!\n",hr
);
1604 IUnknown_Release(classfac
);
1608 IUnknown_Release(classfac
);
1610 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
1611 newClass
->pMarshaledData
,
1612 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
1613 &newClass
->RpcRegistration
);
1618 /***********************************************************************
1619 * CoRevokeClassObject [OLE32.@]
1621 * Removes a class object from the class registry.
1624 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1628 * Failure: HRESULT code.
1631 * CoRegisterClassObject
1633 HRESULT WINAPI
CoRevokeClassObject(
1636 HRESULT hr
= E_INVALIDARG
;
1637 RegisteredClass
*curClass
;
1639 TRACE("(%08x)\n",dwRegister
);
1641 EnterCriticalSection( &csRegisteredClassList
);
1643 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1646 * Check if we have a match on the cookie.
1648 if (curClass
->dwCookie
== dwRegister
)
1650 list_remove(&curClass
->entry
);
1652 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
1653 RPC_StopLocalServer(curClass
->RpcRegistration
);
1656 * Release the reference to the class object.
1658 IUnknown_Release(curClass
->classObject
);
1660 if (curClass
->pMarshaledData
)
1663 memset(&zero
, 0, sizeof(zero
));
1664 IStream_Seek(curClass
->pMarshaledData
, zero
, STREAM_SEEK_SET
, NULL
);
1665 CoReleaseMarshalData(curClass
->pMarshaledData
);
1669 * Free the memory used by the chain node.
1671 HeapFree(GetProcessHeap(), 0, curClass
);
1678 LeaveCriticalSection( &csRegisteredClassList
);
1683 /***********************************************************************
1684 * COM_RegReadPath [internal]
1686 * Reads a registry value and expands it when necessary
1688 static DWORD
COM_RegReadPath(HKEY hkeyroot
, const WCHAR
*keyname
, const WCHAR
*valuename
, WCHAR
* dst
, DWORD dstlen
)
1693 WCHAR src
[MAX_PATH
];
1694 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1696 if((ret
= RegOpenKeyExW(hkeyroot
, keyname
, 0, KEY_READ
, &key
)) == ERROR_SUCCESS
) {
1697 if( (ret
= RegQueryValueExW(key
, NULL
, NULL
, &keytype
, (LPBYTE
)src
, &dwLength
)) == ERROR_SUCCESS
) {
1698 if (keytype
== REG_EXPAND_SZ
) {
1699 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1701 lstrcpynW(dst
, src
, dstlen
);
1709 static void get_threading_model(HKEY key
, LPWSTR value
, DWORD len
)
1711 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
1714 DWORD dwLength
= len
* sizeof(WCHAR
);
1716 ret
= RegQueryValueExW(key
, wszThreadingModel
, NULL
, &keytype
, (LPBYTE
)value
, &dwLength
);
1717 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
1721 static HRESULT
get_inproc_class_object(HKEY hkeydll
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1723 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
1724 static const WCHAR wszFree
[] = {'F','r','e','e',0};
1725 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
1727 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
1728 DllGetClassObjectFunc DllGetClassObject
;
1729 WCHAR dllpath
[MAX_PATH
+1];
1730 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
1733 get_threading_model(hkeydll
, threading_model
, ARRAYSIZE(threading_model
));
1735 if (!strcmpiW(threading_model
, wszApartment
))
1737 APARTMENT
*apt
= COM_CurrentApt();
1738 if (apt
->multi_threaded
)
1740 /* try to find an STA */
1741 APARTMENT
*host_apt
= apartment_findfromtype(FALSE
, FALSE
);
1743 FIXME("create a host apartment for apartment-threaded object %s\n", debugstr_guid(rclsid
));
1746 struct host_object_params params
;
1747 HWND hwnd
= apartment_getwindow(host_apt
);
1749 params
.hkeydll
= hkeydll
;
1750 params
.clsid
= *rclsid
;
1752 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1755 hr
= SendMessageW(hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1757 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1758 IStream_Release(params
.stream
);
1764 else if (!strcmpiW(threading_model
, wszFree
))
1766 APARTMENT
*apt
= COM_CurrentApt();
1767 if (!apt
->multi_threaded
)
1769 FIXME("should create object %s in multi-threaded apartment\n",
1770 debugstr_guid(rclsid
));
1773 /* everything except "Apartment", "Free" and "Both" */
1774 else if (strcmpiW(threading_model
, wszBoth
))
1776 APARTMENT
*apt
= COM_CurrentApt();
1778 /* everything else is main-threaded */
1779 if (threading_model
[0])
1780 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
1781 debugstr_w(threading_model
), debugstr_guid(rclsid
));
1783 if (apt
->multi_threaded
|| !apt
->main
)
1785 /* try to find an STA */
1786 APARTMENT
*host_apt
= apartment_findfromtype(FALSE
, TRUE
);
1788 FIXME("create a host apartment for main-threaded object %s\n", debugstr_guid(rclsid
));
1791 struct host_object_params params
;
1792 HWND hwnd
= apartment_getwindow(host_apt
);
1794 params
.hkeydll
= hkeydll
;
1795 params
.clsid
= *rclsid
;
1797 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1800 hr
= SendMessageW(hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1802 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1803 IStream_Release(params
.stream
);
1809 if (COM_RegReadPath(hkeydll
, NULL
, NULL
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1811 /* failure: CLSID is not found in registry */
1812 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
1813 return REGDB_E_CLASSNOTREG
;
1816 if ((hLibrary
= LoadLibraryExW(dllpath
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
)) == 0)
1818 /* failure: DLL could not be loaded */
1819 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath
));
1820 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1823 if (!(DllGetClassObject
= (DllGetClassObjectFunc
)GetProcAddress(hLibrary
, "DllGetClassObject")))
1825 /* failure: the dll did not export DllGetClassObject */
1826 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath
));
1827 FreeLibrary( hLibrary
);
1828 return CO_E_DLLNOTFOUND
;
1831 /* OK: get the ClassObject */
1832 COMPOBJ_DLLList_Add( hLibrary
);
1833 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1836 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1841 /***********************************************************************
1842 * CoGetClassObject [OLE32.@]
1844 * FIXME. If request allows of several options and there is a failure
1845 * with one (other than not being registered) do we try the
1846 * others or return failure? (E.g. inprocess is registered but
1847 * the DLL is not found but the server version works)
1849 HRESULT WINAPI
CoGetClassObject(
1850 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
1851 REFIID iid
, LPVOID
*ppv
)
1853 LPUNKNOWN regClassObject
;
1854 HRESULT hres
= E_UNEXPECTED
;
1856 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
1859 return E_INVALIDARG
;
1863 if (!COM_CurrentApt())
1865 ERR("apartment not initialised\n");
1866 return CO_E_NOTINITIALIZED
;
1870 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo
->pwszName
));
1871 FIXME("\t\tpAuthInfo=%p\n",pServerInfo
->pAuthInfo
);
1875 * First, try and see if we can't match the class ID with one of the
1876 * registered classes.
1878 if (S_OK
== COM_GetRegisteredClassObject(rclsid
, dwClsContext
, ®ClassObject
))
1880 /* Get the required interface from the retrieved pointer. */
1881 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
1884 * Since QI got another reference on the pointer, we want to release the
1885 * one we already have. If QI was unsuccessful, this will release the object. This
1886 * is good since we are not returning it in the "out" parameter.
1888 IUnknown_Release(regClassObject
);
1893 /* First try in-process server */
1894 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
1896 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1899 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
1900 return FTMarshalCF_Create(iid
, ppv
);
1902 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
1905 if (hres
== REGDB_E_CLASSNOTREG
)
1906 ERR("class %s not registered\n", debugstr_guid(rclsid
));
1908 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
1911 if (SUCCEEDED(hres
))
1913 hres
= get_inproc_class_object(hkey
, rclsid
, iid
, ppv
);
1917 /* return if we got a class, otherwise fall through to one of the
1919 if (SUCCEEDED(hres
))
1923 /* Next try in-process handler */
1924 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
1926 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1929 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
1932 if (hres
== REGDB_E_CLASSNOTREG
)
1933 ERR("class %s not registered\n", debugstr_guid(rclsid
));
1935 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
1938 if (SUCCEEDED(hres
))
1940 hres
= get_inproc_class_object(hkey
, rclsid
, iid
, ppv
);
1944 /* return if we got a class, otherwise fall through to one of the
1946 if (SUCCEEDED(hres
))
1950 /* Next try out of process */
1951 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
1953 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
1954 if (SUCCEEDED(hres
))
1958 /* Finally try remote: this requires networked DCOM (a lot of work) */
1959 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
1961 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1962 hres
= E_NOINTERFACE
;
1966 ERR("no class object %s could be created for context 0x%x\n",
1967 debugstr_guid(rclsid
), dwClsContext
);
1971 /***********************************************************************
1972 * CoResumeClassObjects (OLE32.@)
1974 * Resumes all class objects registered with REGCLS_SUSPENDED.
1978 * Failure: HRESULT code.
1980 HRESULT WINAPI
CoResumeClassObjects(void)
1986 /***********************************************************************
1987 * GetClassFile (OLE32.@)
1989 * This function supplies the CLSID associated with the given filename.
1991 HRESULT WINAPI
GetClassFile(LPCOLESTR filePathName
,CLSID
*pclsid
)
1995 int nbElm
, length
, i
;
1997 LPOLESTR
*pathDec
=0,absFile
=0,progId
=0;
1999 static const WCHAR bkslashW
[] = {'\\',0};
2000 static const WCHAR dotW
[] = {'.',0};
2002 TRACE("%s, %p\n", debugstr_w(filePathName
), pclsid
);
2004 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
2005 if((StgIsStorageFile(filePathName
))==S_OK
){
2007 res
=StgOpenStorage(filePathName
,NULL
,STGM_READ
| STGM_SHARE_DENY_WRITE
,NULL
,0,&pstg
);
2010 res
=ReadClassStg(pstg
,pclsid
);
2012 IStorage_Release(pstg
);
2016 /* if the file is not a storage object then attemps to match various bits in the file against a
2017 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
2020 for(i=0;i<nFileTypes;i++)
2022 for(i=0;j<nPatternsForType;j++){
2027 pat=ReadPatternFromRegistry(i,j);
2028 hFile=CreateFileW(filePathName,,,,,,hFile);
2029 SetFilePosition(hFile,pat.offset);
2030 ReadFile(hFile,buf,pat.size,&r,NULL);
2031 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
2033 *pclsid=ReadCLSIDFromRegistry(i);
2039 /* if the above strategies fail then search for the extension key in the registry */
2041 /* get the last element (absolute file) in the path name */
2042 nbElm
=FileMonikerImpl_DecomposePath(filePathName
,&pathDec
);
2043 absFile
=pathDec
[nbElm
-1];
2045 /* failed if the path represente a directory and not an absolute file name*/
2046 if (!lstrcmpW(absFile
, bkslashW
))
2047 return MK_E_INVALIDEXTENSION
;
2049 /* get the extension of the file */
2051 length
=lstrlenW(absFile
);
2052 for(i
= length
-1; (i
>= 0) && *(extension
= &absFile
[i
]) != '.'; i
--)
2055 if (!extension
|| !lstrcmpW(extension
, dotW
))
2056 return MK_E_INVALIDEXTENSION
;
2058 res
=RegQueryValueW(HKEY_CLASSES_ROOT
, extension
, NULL
, &sizeProgId
);
2060 /* get the progId associated to the extension */
2061 progId
= CoTaskMemAlloc(sizeProgId
);
2062 res
= RegQueryValueW(HKEY_CLASSES_ROOT
, extension
, progId
, &sizeProgId
);
2064 if (res
==ERROR_SUCCESS
)
2065 /* return the clsid associated to the progId */
2066 res
= CLSIDFromProgID(progId
,pclsid
);
2068 for(i
=0; pathDec
[i
]!=NULL
;i
++)
2069 CoTaskMemFree(pathDec
[i
]);
2070 CoTaskMemFree(pathDec
);
2072 CoTaskMemFree(progId
);
2074 if (res
==ERROR_SUCCESS
)
2077 return MK_E_INVALIDEXTENSION
;
2080 /***********************************************************************
2081 * CoCreateInstance [OLE32.@]
2083 * Creates an instance of the specified class.
2086 * rclsid [I] Class ID to create an instance of.
2087 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2088 * dwClsContext [I] Flags to restrict the location of the created instance.
2089 * iid [I] The ID of the interface of the instance to return.
2090 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2094 * Failure: HRESULT code.
2097 * The dwClsContext parameter can be one or more of the following:
2098 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2099 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2100 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2101 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2103 * Aggregation is the concept of deferring the IUnknown of an object to another
2104 * object. This allows a separate object to behave as though it was part of
2105 * the object and to allow this the pUnkOuter parameter can be set. Note that
2106 * not all objects support having an outer of unknown.
2109 * CoGetClassObject()
2111 HRESULT WINAPI
CoCreateInstance(
2113 LPUNKNOWN pUnkOuter
,
2119 LPCLASSFACTORY lpclf
= 0;
2121 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
2122 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
2131 * Initialize the "out" parameter
2135 if (!COM_CurrentApt())
2137 ERR("apartment not initialised\n");
2138 return CO_E_NOTINITIALIZED
;
2142 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2143 * Rather than create a class factory, we can just check for it here
2145 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
)) {
2146 if (StdGlobalInterfaceTableInstance
== NULL
)
2147 StdGlobalInterfaceTableInstance
= StdGlobalInterfaceTable_Construct();
2148 hres
= IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable
*) StdGlobalInterfaceTableInstance
, iid
, ppv
);
2149 if (hres
) return hres
;
2151 TRACE("Retrieved GIT (%p)\n", *ppv
);
2156 * Get a class factory to construct the object we want.
2158 hres
= CoGetClassObject(rclsid
,
2168 * Create the object and don't forget to release the factory
2170 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
2171 IClassFactory_Release(lpclf
);
2173 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2174 debugstr_guid(iid
), debugstr_guid(rclsid
),hres
);
2179 /***********************************************************************
2180 * CoCreateInstanceEx [OLE32.@]
2182 HRESULT WINAPI
CoCreateInstanceEx(
2184 LPUNKNOWN pUnkOuter
,
2186 COSERVERINFO
* pServerInfo
,
2190 IUnknown
* pUnk
= NULL
;
2193 ULONG successCount
= 0;
2198 if ( (cmq
==0) || (pResults
==NULL
))
2199 return E_INVALIDARG
;
2201 if (pServerInfo
!=NULL
)
2202 FIXME("() non-NULL pServerInfo not supported!\n");
2205 * Initialize all the "out" parameters.
2207 for (index
= 0; index
< cmq
; index
++)
2209 pResults
[index
].pItf
= NULL
;
2210 pResults
[index
].hr
= E_NOINTERFACE
;
2214 * Get the object and get its IUnknown pointer.
2216 hr
= CoCreateInstance(rclsid
,
2226 * Then, query for all the interfaces requested.
2228 for (index
= 0; index
< cmq
; index
++)
2230 pResults
[index
].hr
= IUnknown_QueryInterface(pUnk
,
2231 pResults
[index
].pIID
,
2232 (VOID
**)&(pResults
[index
].pItf
));
2234 if (pResults
[index
].hr
== S_OK
)
2239 * Release our temporary unknown pointer.
2241 IUnknown_Release(pUnk
);
2243 if (successCount
== 0)
2244 return E_NOINTERFACE
;
2246 if (successCount
!=cmq
)
2247 return CO_S_NOTALLINTERFACES
;
2252 /***********************************************************************
2253 * CoLoadLibrary (OLE32.@)
2258 * lpszLibName [I] Path to library.
2259 * bAutoFree [I] Whether the library should automatically be freed.
2262 * Success: Handle to loaded library.
2266 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2268 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
2270 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
2272 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
2275 /***********************************************************************
2276 * CoFreeLibrary [OLE32.@]
2278 * Unloads a library from memory.
2281 * hLibrary [I] Handle to library to unload.
2287 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2289 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
2291 FreeLibrary(hLibrary
);
2295 /***********************************************************************
2296 * CoFreeAllLibraries [OLE32.@]
2298 * Function for backwards compatibility only. Does nothing.
2304 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2306 void WINAPI
CoFreeAllLibraries(void)
2312 /***********************************************************************
2313 * CoFreeUnusedLibraries [OLE32.@]
2314 * CoFreeUnusedLibraries [COMPOBJ.17]
2316 * Frees any unused libraries. Unused are identified as those that return
2317 * S_OK from their DllCanUnloadNow function.
2323 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2325 void WINAPI
CoFreeUnusedLibraries(void)
2327 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2328 * through the main apartment's thread to call DllCanUnloadNow */
2329 COMPOBJ_DllList_FreeUnused(0);
2332 /***********************************************************************
2333 * CoFileTimeNow [OLE32.@]
2334 * CoFileTimeNow [COMPOBJ.82]
2336 * Retrieves the current time in FILETIME format.
2339 * lpFileTime [O] The current time.
2344 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
2346 GetSystemTimeAsFileTime( lpFileTime
);
2350 static void COM_RevokeAllClasses(void)
2352 EnterCriticalSection( &csRegisteredClassList
);
2354 while (list_head(&RegisteredClassList
))
2356 RegisteredClass
*curClass
= LIST_ENTRY(list_head(&RegisteredClassList
),
2357 RegisteredClass
, entry
);
2358 CoRevokeClassObject(curClass
->dwCookie
);
2361 LeaveCriticalSection( &csRegisteredClassList
);
2364 /******************************************************************************
2365 * CoLockObjectExternal [OLE32.@]
2367 * Increments or decrements the external reference count of a stub object.
2370 * pUnk [I] Stub object.
2371 * fLock [I] If TRUE then increments the external ref-count,
2372 * otherwise decrements.
2373 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2374 * calling CoDisconnectObject.
2378 * Failure: HRESULT code.
2381 * If fLock is TRUE and an object is passed in that doesn't have a stub
2382 * manager then a new stub manager is created for the object.
2384 HRESULT WINAPI
CoLockObjectExternal(
2387 BOOL fLastUnlockReleases
)
2389 struct stub_manager
*stubmgr
;
2390 struct apartment
*apt
;
2392 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2393 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
2395 apt
= COM_CurrentApt();
2396 if (!apt
) return CO_E_NOTINITIALIZED
;
2398 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
2403 stub_manager_ext_addref(stubmgr
, 1);
2405 stub_manager_ext_release(stubmgr
, 1, fLastUnlockReleases
);
2407 stub_manager_int_release(stubmgr
);
2413 stubmgr
= new_stub_manager(apt
, pUnk
);
2417 stub_manager_ext_addref(stubmgr
, 1);
2418 stub_manager_int_release(stubmgr
);
2425 WARN("stub object not found %p\n", pUnk
);
2426 /* Note: native is pretty broken here because it just silently
2427 * fails, without returning an appropriate error code, making apps
2428 * think that the object was disconnected, when it actually wasn't */
2433 /***********************************************************************
2434 * CoInitializeWOW (OLE32.@)
2436 * WOW equivalent of CoInitialize?
2445 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
2447 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
2451 /***********************************************************************
2452 * CoGetState [OLE32.@]
2454 * Retrieves the thread state object previously stored by CoSetState().
2457 * ppv [I] Address where pointer to object will be stored.
2461 * Failure: E_OUTOFMEMORY.
2464 * Crashes on all invalid ppv addresses, including NULL.
2465 * If the function returns a non-NULL object then the caller must release its
2466 * reference on the object when the object is no longer required.
2471 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
2473 struct oletls
*info
= COM_CurrentInfo();
2474 if (!info
) return E_OUTOFMEMORY
;
2480 IUnknown_AddRef(info
->state
);
2482 TRACE("apt->state=%p\n", info
->state
);
2488 /***********************************************************************
2489 * CoSetState [OLE32.@]
2491 * Sets the thread state object.
2494 * pv [I] Pointer to state object to be stored.
2497 * The system keeps a reference on the object while the object stored.
2501 * Failure: E_OUTOFMEMORY.
2503 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
2505 struct oletls
*info
= COM_CurrentInfo();
2506 if (!info
) return E_OUTOFMEMORY
;
2508 if (pv
) IUnknown_AddRef(pv
);
2512 TRACE("-- release %p now\n", info
->state
);
2513 IUnknown_Release(info
->state
);
2522 /******************************************************************************
2523 * CoTreatAsClass [OLE32.@]
2525 * Sets the TreatAs value of a class.
2528 * clsidOld [I] Class to set TreatAs value on.
2529 * clsidNew [I] The class the clsidOld should be treated as.
2533 * Failure: HRESULT code.
2538 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
2540 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2541 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
2543 WCHAR szClsidNew
[CHARS_IN_GUID
];
2545 WCHAR auto_treat_as
[CHARS_IN_GUID
];
2546 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
2549 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
2552 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
2554 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
2555 !CLSIDFromString(auto_treat_as
, &id
))
2557 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
2559 res
= REGDB_E_WRITEREGDB
;
2565 RegDeleteKeyW(hkey
, wszTreatAs
);
2569 else if (!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
)) &&
2570 !RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)))
2572 res
= REGDB_E_WRITEREGDB
;
2577 if (hkey
) RegCloseKey(hkey
);
2581 /******************************************************************************
2582 * CoGetTreatAsClass [OLE32.@]
2584 * Gets the TreatAs value of a class.
2587 * clsidOld [I] Class to get the TreatAs value of.
2588 * clsidNew [I] The class the clsidOld should be treated as.
2592 * Failure: HRESULT code.
2597 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
2599 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
2601 WCHAR szClsidNew
[CHARS_IN_GUID
];
2603 LONG len
= sizeof(szClsidNew
);
2605 FIXME("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
2606 memcpy(clsidNew
,clsidOld
,sizeof(CLSID
)); /* copy over old value */
2608 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
2611 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
2616 res
= CLSIDFromString(szClsidNew
,clsidNew
);
2618 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
2620 if (hkey
) RegCloseKey(hkey
);
2624 /******************************************************************************
2625 * CoGetCurrentProcess [OLE32.@]
2626 * CoGetCurrentProcess [COMPOBJ.34]
2628 * Gets the current process ID.
2631 * The current process ID.
2634 * Is DWORD really the correct return type for this function?
2636 DWORD WINAPI
CoGetCurrentProcess(void)
2638 return GetCurrentProcessId();
2641 /******************************************************************************
2642 * CoRegisterMessageFilter [OLE32.@]
2644 * Registers a message filter.
2647 * lpMessageFilter [I] Pointer to interface.
2648 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2652 * Failure: HRESULT code.
2655 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2656 * lpMessageFilter removes the message filter.
2658 * If lplpMessageFilter is not NULL the previous message filter will be
2659 * returned in the memory pointer to this parameter and the caller is
2660 * responsible for releasing the object.
2662 * The current thread be in an apartment otherwise the function will crash.
2664 HRESULT WINAPI
CoRegisterMessageFilter(
2665 LPMESSAGEFILTER lpMessageFilter
,
2666 LPMESSAGEFILTER
*lplpMessageFilter
)
2668 struct apartment
*apt
;
2669 IMessageFilter
*lpOldMessageFilter
;
2671 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
2673 apt
= COM_CurrentApt();
2675 /* can't set a message filter in a multi-threaded apartment */
2676 if (!apt
|| apt
->multi_threaded
)
2678 WARN("can't set message filter in MTA or uninitialized apt\n");
2679 return CO_E_NOT_SUPPORTED
;
2682 if (lpMessageFilter
)
2683 IMessageFilter_AddRef(lpMessageFilter
);
2685 EnterCriticalSection(&apt
->cs
);
2687 lpOldMessageFilter
= apt
->filter
;
2688 apt
->filter
= lpMessageFilter
;
2690 LeaveCriticalSection(&apt
->cs
);
2692 if (lplpMessageFilter
)
2693 *lplpMessageFilter
= lpOldMessageFilter
;
2694 else if (lpOldMessageFilter
)
2695 IMessageFilter_Release(lpOldMessageFilter
);
2700 /***********************************************************************
2701 * CoIsOle1Class [OLE32.@]
2703 * Determines whether the specified class an OLE v1 class.
2706 * clsid [I] Class to test.
2709 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2711 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
2713 FIXME("%s\n", debugstr_guid(clsid
));
2717 /***********************************************************************
2718 * IsEqualGUID [OLE32.@]
2720 * Compares two Unique Identifiers.
2723 * rguid1 [I] The first GUID to compare.
2724 * rguid2 [I] The other GUID to compare.
2730 BOOL WINAPI
IsEqualGUID(
2734 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
2737 /***********************************************************************
2738 * CoInitializeSecurity [OLE32.@]
2740 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
2741 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
2742 void* pReserved1
, DWORD dwAuthnLevel
,
2743 DWORD dwImpLevel
, void* pReserved2
,
2744 DWORD dwCapabilities
, void* pReserved3
)
2746 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
2747 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
2748 dwCapabilities
, pReserved3
);
2752 /***********************************************************************
2753 * CoSuspendClassObjects [OLE32.@]
2755 * Suspends all registered class objects to prevent further requests coming in
2756 * for those objects.
2760 * Failure: HRESULT code.
2762 HRESULT WINAPI
CoSuspendClassObjects(void)
2768 /***********************************************************************
2769 * CoAddRefServerProcess [OLE32.@]
2771 * Helper function for incrementing the reference count of a local-server
2775 * New reference count.
2778 * CoReleaseServerProcess().
2780 ULONG WINAPI
CoAddRefServerProcess(void)
2786 EnterCriticalSection(&csRegisteredClassList
);
2787 refs
= ++s_COMServerProcessReferences
;
2788 LeaveCriticalSection(&csRegisteredClassList
);
2790 TRACE("refs before: %d\n", refs
- 1);
2795 /***********************************************************************
2796 * CoReleaseServerProcess [OLE32.@]
2798 * Helper function for decrementing the reference count of a local-server
2802 * New reference count.
2805 * When reference count reaches 0, this function suspends all registered
2806 * classes so no new connections are accepted.
2809 * CoAddRefServerProcess(), CoSuspendClassObjects().
2811 ULONG WINAPI
CoReleaseServerProcess(void)
2817 EnterCriticalSection(&csRegisteredClassList
);
2819 refs
= --s_COMServerProcessReferences
;
2820 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
2822 LeaveCriticalSection(&csRegisteredClassList
);
2824 TRACE("refs after: %d\n", refs
);
2829 /***********************************************************************
2830 * CoIsHandlerConnected [OLE32.@]
2832 * Determines whether a proxy is connected to a remote stub.
2835 * pUnk [I] Pointer to object that may or may not be connected.
2838 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2841 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
2843 FIXME("%p\n", pUnk
);
2848 /***********************************************************************
2849 * CoAllowSetForegroundWindow [OLE32.@]
2852 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
2854 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
2858 /***********************************************************************
2859 * CoQueryProxyBlanket [OLE32.@]
2861 * Retrieves the security settings being used by a proxy.
2864 * pProxy [I] Pointer to the proxy object.
2865 * pAuthnSvc [O] The type of authentication service.
2866 * pAuthzSvc [O] The type of authorization service.
2867 * ppServerPrincName [O] Optional. The server prinicple name.
2868 * pAuthnLevel [O] The authentication level.
2869 * pImpLevel [O] The impersonation level.
2870 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2871 * pCapabilities [O] Flags affecting the security behaviour.
2875 * Failure: HRESULT code.
2878 * CoCopyProxy, CoSetProxyBlanket.
2880 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
2881 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
2882 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
2884 IClientSecurity
*pCliSec
;
2887 TRACE("%p\n", pProxy
);
2889 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
2892 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
2893 pAuthzSvc
, ppServerPrincName
,
2894 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
2896 IClientSecurity_Release(pCliSec
);
2899 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
2903 /***********************************************************************
2904 * CoSetProxyBlanket [OLE32.@]
2906 * Sets the security settings for a proxy.
2909 * pProxy [I] Pointer to the proxy object.
2910 * AuthnSvc [I] The type of authentication service.
2911 * AuthzSvc [I] The type of authorization service.
2912 * pServerPrincName [I] The server prinicple name.
2913 * AuthnLevel [I] The authentication level.
2914 * ImpLevel [I] The impersonation level.
2915 * pAuthInfo [I] Information specific to the authorization/authentication service.
2916 * Capabilities [I] Flags affecting the security behaviour.
2920 * Failure: HRESULT code.
2923 * CoQueryProxyBlanket, CoCopyProxy.
2925 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
2926 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
2927 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
2929 IClientSecurity
*pCliSec
;
2932 TRACE("%p\n", pProxy
);
2934 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
2937 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
2938 AuthzSvc
, pServerPrincName
,
2939 AuthnLevel
, ImpLevel
, pAuthInfo
,
2941 IClientSecurity_Release(pCliSec
);
2944 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
2948 /***********************************************************************
2949 * CoCopyProxy [OLE32.@]
2954 * pProxy [I] Pointer to the proxy object.
2955 * ppCopy [O] Copy of the proxy.
2959 * Failure: HRESULT code.
2962 * CoQueryProxyBlanket, CoSetProxyBlanket.
2964 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
2966 IClientSecurity
*pCliSec
;
2969 TRACE("%p\n", pProxy
);
2971 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
2974 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
2975 IClientSecurity_Release(pCliSec
);
2978 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
2983 /***********************************************************************
2984 * CoGetCallContext [OLE32.@]
2986 * Gets the context of the currently executing server call in the current
2990 * riid [I] Context interface to return.
2991 * ppv [O] Pointer to memory that will receive the context on return.
2995 * Failure: HRESULT code.
2997 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
2999 FIXME("(%s, %p): stub\n", debugstr_guid(riid
), ppv
);
3002 return E_NOINTERFACE
;
3005 /***********************************************************************
3006 * CoQueryClientBlanket [OLE32.@]
3008 * Retrieves the authentication information about the client of the currently
3009 * executing server call in the current thread.
3012 * pAuthnSvc [O] Optional. The type of authentication service.
3013 * pAuthzSvc [O] Optional. The type of authorization service.
3014 * pServerPrincName [O] Optional. The server prinicple name.
3015 * pAuthnLevel [O] Optional. The authentication level.
3016 * pImpLevel [O] Optional. The impersonation level.
3017 * pPrivs [O] Optional. Information about the privileges of the client.
3018 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3022 * Failure: HRESULT code.
3025 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3027 HRESULT WINAPI
CoQueryClientBlanket(
3030 OLECHAR
**pServerPrincName
,
3033 RPC_AUTHZ_HANDLE
*pPrivs
,
3034 DWORD
*pCapabilities
)
3036 IServerSecurity
*pSrvSec
;
3039 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3040 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
3041 pPrivs
, pCapabilities
);
3043 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3046 hr
= IServerSecurity_QueryBlanket(
3047 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
3048 pImpLevel
, pPrivs
, pCapabilities
);
3049 IServerSecurity_Release(pSrvSec
);
3055 /***********************************************************************
3056 * CoImpersonateClient [OLE32.@]
3058 * Impersonates the client of the currently executing server call in the
3066 * Failure: HRESULT code.
3069 * If this function fails then the current thread will not be impersonating
3070 * the client and all actions will take place on behalf of the server.
3071 * Therefore, it is important to check the return value from this function.
3074 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3076 HRESULT WINAPI
CoImpersonateClient(void)
3078 IServerSecurity
*pSrvSec
;
3083 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3086 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
3087 IServerSecurity_Release(pSrvSec
);
3093 /***********************************************************************
3094 * CoRevertToSelf [OLE32.@]
3096 * Ends the impersonation of the client of the currently executing server
3097 * call in the current thread.
3104 * Failure: HRESULT code.
3107 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3109 HRESULT WINAPI
CoRevertToSelf(void)
3111 IServerSecurity
*pSrvSec
;
3116 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3119 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
3120 IServerSecurity_Release(pSrvSec
);
3126 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
3128 /* first try to retrieve messages for incoming COM calls to the apartment window */
3129 return PeekMessageW(msg
, apt
->win
, WM_USER
, WM_APP
- 1, PM_REMOVE
|PM_NOYIELD
) ||
3130 /* next retrieve other messages necessary for the app to remain responsive */
3131 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_POSTMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
3134 /***********************************************************************
3135 * CoWaitForMultipleHandles [OLE32.@]
3137 * Waits for one or more handles to become signaled.
3140 * dwFlags [I] Flags. See notes.
3141 * dwTimeout [I] Timeout in milliseconds.
3142 * cHandles [I] Number of handles pointed to by pHandles.
3143 * pHandles [I] Handles to wait for.
3144 * lpdwindex [O] Index of handle that was signaled.
3148 * Failure: RPC_S_CALLPENDING on timeout.
3152 * The dwFlags parameter can be zero or more of the following:
3153 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3154 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3157 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3159 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
3160 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
3163 DWORD start_time
= GetTickCount();
3164 APARTMENT
*apt
= COM_CurrentApt();
3165 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
3167 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
3168 pHandles
, lpdwindex
);
3172 DWORD now
= GetTickCount();
3175 if ((dwTimeout
!= INFINITE
) && (start_time
+ dwTimeout
>= now
))
3177 hr
= RPC_S_CALLPENDING
;
3183 DWORD wait_flags
= (dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0 |
3184 (dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0;
3186 TRACE("waiting for rpc completion or window message\n");
3188 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
3189 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
3190 QS_ALLINPUT
, wait_flags
);
3192 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
3196 /* call message filter */
3198 if (COM_CurrentApt()->filter
)
3200 PENDINGTYPE pendingtype
=
3201 COM_CurrentInfo()->pending_call_count_server
?
3202 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
3203 DWORD be_handled
= IMessageFilter_MessagePending(
3204 COM_CurrentApt()->filter
, 0 /* FIXME */,
3205 now
- start_time
, pendingtype
);
3206 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
3209 case PENDINGMSG_CANCELCALL
:
3210 WARN("call canceled\n");
3211 hr
= RPC_E_CALL_CANCELED
;
3213 case PENDINGMSG_WAITNOPROCESS
:
3214 case PENDINGMSG_WAITDEFPROCESS
:
3216 /* FIXME: MSDN is very vague about the difference
3217 * between WAITNOPROCESS and WAITDEFPROCESS - there
3218 * appears to be none, so it is possibly a left-over
3219 * from the 16-bit world. */
3224 /* note: using "if" here instead of "while" might seem less
3225 * efficient, but only if we are optimising for quick delivery
3226 * of pending messages, rather than quick completion of the
3228 if (COM_PeekMessage(apt
, &msg
))
3230 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
3231 TranslateMessage(&msg
);
3232 DispatchMessageW(&msg
);
3233 if (msg
.message
== WM_QUIT
)
3235 TRACE("resending WM_QUIT to outer message loop\n");
3236 PostQuitMessage(msg
.wParam
);
3237 /* no longer need to process messages */
3238 message_loop
= FALSE
;
3246 TRACE("waiting for rpc completion\n");
3248 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
3249 (dwFlags
& COWAIT_WAITALL
) ? TRUE
: FALSE
,
3250 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
3251 (dwFlags
& COWAIT_ALERTABLE
) ? TRUE
: FALSE
);
3254 if ((res
>= WAIT_OBJECT_0
) && (res
< WAIT_OBJECT_0
+ cHandles
))
3256 /* handle signaled, store index */
3257 *lpdwindex
= (res
- WAIT_OBJECT_0
);
3260 else if (res
== WAIT_TIMEOUT
)
3262 hr
= RPC_S_CALLPENDING
;
3267 ERR("Unexpected wait termination: %d, %d\n", res
, GetLastError());
3272 TRACE("-- 0x%08x\n", hr
);
3277 /***********************************************************************
3278 * CoGetObject [OLE32.@]
3280 * Gets the object named by coverting the name to a moniker and binding to it.
3283 * pszName [I] String representing the object.
3284 * pBindOptions [I] Parameters affecting the binding to the named object.
3285 * riid [I] Interface to bind to on the objecct.
3286 * ppv [O] On output, the interface riid of the object represented
3291 * Failure: HRESULT code.
3294 * MkParseDisplayName.
3296 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
3297 REFIID riid
, void **ppv
)
3304 hr
= CreateBindCtx(0, &pbc
);
3308 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
3315 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
3318 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
3319 IMoniker_Release(pmk
);
3323 IBindCtx_Release(pbc
);
3328 /***********************************************************************
3329 * CoRegisterChannelHook [OLE32.@]
3331 * Registers a process-wide hook that is called during ORPC calls.
3334 * guidExtension [I] GUID of the channel hook to register.
3335 * pChannelHook [I] Channel hook object to register.
3339 * Failure: HRESULT code.
3341 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
3343 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
3345 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
3348 /***********************************************************************
3351 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID fImpLoad
)
3353 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, fImpLoad
);
3356 case DLL_PROCESS_ATTACH
:
3357 OLE32_hInstance
= hinstDLL
;
3358 COMPOBJ_InitProcess();
3359 if (TRACE_ON(ole
)) CoRegisterMallocSpy((LPVOID
)-1);
3362 case DLL_PROCESS_DETACH
:
3363 if (TRACE_ON(ole
)) CoRevokeMallocSpy();
3364 COMPOBJ_UninitProcess();
3365 RPC_UnregisterAllChannelHooks();
3366 OLE32_hInstance
= 0;
3369 case DLL_THREAD_DETACH
:
3376 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */