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
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
55 #define USE_COM_CONTEXT_DEF
62 #include "compobj_private.h"
64 #include "wine/unicode.h"
65 #include "wine/debug.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
69 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
71 /****************************************************************************
72 * This section defines variables internal to the COM module.
75 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
76 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
);
77 static void COM_RevokeAllClasses(const struct apartment
*apt
);
78 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, HKEY hkeydll
, REFCLSID rclsid
, REFIID riid
, BOOL hostifnecessary
, void **ppv
);
80 static APARTMENT
*MTA
; /* protected by csApartment */
81 static APARTMENT
*MainApartment
; /* the first STA apartment */
82 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
84 static CRITICAL_SECTION csApartment
;
85 static CRITICAL_SECTION_DEBUG critsect_debug
=
88 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
89 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
91 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
93 struct registered_psclsid
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;
106 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
107 static LONG s_COMServerProcessReferences
= 0;
110 * This linked list contains the list of registered class objects. These
111 * are mostly used to register the factories for out-of-proc servers of OLE
114 * TODO: Make this data structure aware of inter-process communication. This
115 * means that parts of this will be exported to rpcss.
117 typedef struct tagRegisteredClass
120 CLSID classIdentifier
;
122 LPUNKNOWN classObject
;
126 LPSTREAM pMarshaledData
; /* FIXME: only really need to store OXID and IPID */
127 void *RpcRegistration
;
130 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
132 static CRITICAL_SECTION csRegisteredClassList
;
133 static CRITICAL_SECTION_DEBUG class_cs_debug
=
135 0, 0, &csRegisteredClassList
,
136 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
137 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
139 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
141 /*****************************************************************************
142 * This section contains OpenDllList definitions
144 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
145 * other functions that do LoadLibrary _without_ giving back a HMODULE.
146 * Without this list these handles would never be freed.
148 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
149 * next unload-call but not before 600 sec.
152 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
153 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
155 typedef struct tagOpenDll
160 DllGetClassObjectFunc DllGetClassObject
;
161 DllCanUnloadNowFunc DllCanUnloadNow
;
165 static struct list openDllList
= LIST_INIT(openDllList
);
167 static CRITICAL_SECTION csOpenDllList
;
168 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
170 0, 0, &csOpenDllList
,
171 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
172 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
174 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
176 struct apartment_loaded_dll
184 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',' ',
185 '0','x','#','#','#','#','#','#','#','#',' ',0};
186 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
187 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
188 BOOL apartment_threaded
,
189 REFCLSID rclsid
, REFIID riid
, void **ppv
);
190 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
);
192 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
);
193 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
);
194 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
);
196 static DWORD
COM_RegReadPath(HKEY hkeyroot
, const WCHAR
*keyname
, const WCHAR
*valuename
, WCHAR
* dst
, DWORD dstlen
);
198 static void COMPOBJ_InitProcess( void )
202 /* Dispatching to the correct thread in an apartment is done through
203 * window messages rather than RPC transports. When an interface is
204 * marshalled into another apartment in the same process, a window of the
205 * following class is created. The *caller* of CoMarshalInterface (i.e., the
206 * application) is responsible for pumping the message loop in that thread.
207 * The WM_USER messages which point to the RPCs are then dispatched to
208 * apartment_wndproc by the user's code from the apartment in which the
209 * interface was unmarshalled.
211 memset(&wclass
, 0, sizeof(wclass
));
212 wclass
.lpfnWndProc
= apartment_wndproc
;
213 wclass
.hInstance
= hProxyDll
;
214 wclass
.lpszClassName
= wszAptWinClass
;
215 RegisterClassW(&wclass
);
218 static void COMPOBJ_UninitProcess( void )
220 UnregisterClassW(wszAptWinClass
, hProxyDll
);
223 static void COM_TlsDestroy(void)
225 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
228 if (info
->apt
) apartment_release(info
->apt
);
229 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
230 if (info
->state
) IUnknown_Release(info
->state
);
231 if (info
->spy
) IUnknown_Release(info
->spy
);
232 if (info
->context_token
) IObjContext_Release(info
->context_token
);
233 HeapFree(GetProcessHeap(), 0, info
);
234 NtCurrentTeb()->ReservedForOle
= NULL
;
238 /******************************************************************************
242 /* allocates memory and fills in the necessary fields for a new apartment
243 * object. must be called inside apartment cs */
244 static APARTMENT
*apartment_construct(DWORD model
)
248 TRACE("creating new apartment, model=%d\n", model
);
250 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
251 apt
->tid
= GetCurrentThreadId();
253 list_init(&apt
->proxies
);
254 list_init(&apt
->stubmgrs
);
255 list_init(&apt
->psclsids
);
256 list_init(&apt
->loaded_dlls
);
259 apt
->remunk_exported
= FALSE
;
261 InitializeCriticalSection(&apt
->cs
);
262 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
264 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
266 if (apt
->multi_threaded
)
268 /* FIXME: should be randomly generated by in an RPC call to rpcss */
269 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
273 /* FIXME: should be randomly generated by in an RPC call to rpcss */
274 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
277 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
279 list_add_head(&apts
, &apt
->entry
);
284 /* gets and existing apartment if one exists or otherwise creates an apartment
285 * structure which stores OLE apartment-local information and stores a pointer
286 * to it in the thread-local storage */
287 static APARTMENT
*apartment_get_or_create(DWORD model
)
289 APARTMENT
*apt
= COM_CurrentApt();
293 if (model
& COINIT_APARTMENTTHREADED
)
295 EnterCriticalSection(&csApartment
);
297 apt
= apartment_construct(model
);
302 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
305 LeaveCriticalSection(&csApartment
);
308 apartment_createwindowifneeded(apt
);
312 EnterCriticalSection(&csApartment
);
314 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
315 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
319 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
320 apartment_addref(MTA
);
323 MTA
= apartment_construct(model
);
327 LeaveCriticalSection(&csApartment
);
329 COM_CurrentInfo()->apt
= apt
;
335 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
337 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
340 DWORD
apartment_addref(struct apartment
*apt
)
342 DWORD refs
= InterlockedIncrement(&apt
->refs
);
343 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
347 DWORD
apartment_release(struct apartment
*apt
)
351 EnterCriticalSection(&csApartment
);
353 ret
= InterlockedDecrement(&apt
->refs
);
354 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
355 /* destruction stuff that needs to happen under csApartment CS */
358 if (apt
== MTA
) MTA
= NULL
;
359 else if (apt
== MainApartment
) MainApartment
= NULL
;
360 list_remove(&apt
->entry
);
363 LeaveCriticalSection(&csApartment
);
367 struct list
*cursor
, *cursor2
;
369 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
371 /* Release the references to the registered class objects */
372 COM_RevokeAllClasses(apt
);
374 /* no locking is needed for this apartment, because no other thread
375 * can access it at this point */
377 apartment_disconnectproxies(apt
);
379 if (apt
->win
) DestroyWindow(apt
->win
);
380 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
382 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
384 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
385 /* release the implicit reference given by the fact that the
386 * stub has external references (it must do since it is in the
387 * stub manager list in the apartment and all non-apartment users
388 * must have a ref on the apartment and so it cannot be destroyed).
390 stub_manager_int_release(stubmgr
);
393 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->psclsids
)
395 struct registered_psclsid
*registered_psclsid
=
396 LIST_ENTRY(cursor
, struct registered_psclsid
, entry
);
398 list_remove(®istered_psclsid
->entry
);
399 HeapFree(GetProcessHeap(), 0, registered_psclsid
);
402 /* if this assert fires, then another thread took a reference to a
403 * stub manager without taking a reference to the containing
404 * apartment, which it must do. */
405 assert(list_empty(&apt
->stubmgrs
));
407 if (apt
->filter
) IUnknown_Release(apt
->filter
);
409 /* free as many unused libraries as possible... */
410 apartment_freeunusedlibraries(apt
, 0);
412 /* ... and free the memory for the apartment loaded dll entry and
413 * release the dll list reference without freeing the library for the
415 while ((cursor
= list_head(&apt
->loaded_dlls
)))
417 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
418 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
420 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
423 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
424 DeleteCriticalSection(&apt
->cs
);
426 HeapFree(GetProcessHeap(), 0, apt
);
432 /* The given OXID must be local to this process:
434 * The ref parameter is here mostly to ensure people remember that
435 * they get one, you should normally take a ref for thread safety.
437 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
439 APARTMENT
*result
= NULL
;
442 EnterCriticalSection(&csApartment
);
443 LIST_FOR_EACH( cursor
, &apts
)
445 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
446 if (apt
->oxid
== oxid
)
449 if (ref
) apartment_addref(result
);
453 LeaveCriticalSection(&csApartment
);
458 /* gets the apartment which has a given creator thread ID. The caller must
459 * release the reference from the apartment as soon as the apartment pointer
460 * is no longer required. */
461 APARTMENT
*apartment_findfromtid(DWORD tid
)
463 APARTMENT
*result
= NULL
;
466 EnterCriticalSection(&csApartment
);
467 LIST_FOR_EACH( cursor
, &apts
)
469 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
473 apartment_addref(result
);
477 LeaveCriticalSection(&csApartment
);
482 /* gets the main apartment if it exists. The caller must
483 * release the reference from the apartment as soon as the apartment pointer
484 * is no longer required. */
485 static APARTMENT
*apartment_findmain(void)
489 EnterCriticalSection(&csApartment
);
491 result
= MainApartment
;
492 if (result
) apartment_addref(result
);
494 LeaveCriticalSection(&csApartment
);
499 /* gets the multi-threaded apartment if it exists. The caller must
500 * release the reference from the apartment as soon as the apartment pointer
501 * is no longer required. */
502 static APARTMENT
*apartment_find_multi_threaded(void)
504 APARTMENT
*result
= NULL
;
507 EnterCriticalSection(&csApartment
);
509 LIST_FOR_EACH( cursor
, &apts
)
511 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
512 if (apt
->multi_threaded
)
515 apartment_addref(result
);
520 LeaveCriticalSection(&csApartment
);
524 struct host_object_params
527 CLSID clsid
; /* clsid of object to marshal */
528 IID iid
; /* interface to marshal */
529 HANDLE event
; /* event signalling when ready for multi-threaded case */
530 HRESULT hr
; /* result for multi-threaded case */
531 IStream
*stream
; /* stream that the object will be marshaled into */
532 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
535 static HRESULT
apartment_hostobject(struct apartment
*apt
,
536 const struct host_object_params
*params
)
540 static const LARGE_INTEGER llZero
;
541 WCHAR dllpath
[MAX_PATH
+1];
543 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
545 if (COM_RegReadPath(params
->hkeydll
, NULL
, NULL
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
547 /* failure: CLSID is not found in registry */
548 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
549 return REGDB_E_CLASSNOTREG
;
552 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
553 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
557 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
559 IUnknown_Release(object
);
560 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
565 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
570 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
573 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
575 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
579 struct host_thread_params
581 COINIT threading_model
;
586 /* thread for hosting an object to allow an object to appear to be created in
587 * an apartment with an incompatible threading model */
588 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
590 struct host_thread_params
*params
= p
;
593 struct apartment
*apt
;
597 hr
= CoInitializeEx(NULL
, params
->threading_model
);
598 if (FAILED(hr
)) return hr
;
600 apt
= COM_CurrentApt();
601 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
603 apartment_createwindowifneeded(apt
);
604 params
->apartment_hwnd
= apartment_getwindow(apt
);
607 params
->apartment_hwnd
= NULL
;
609 /* force the message queue to be created before signaling parent thread */
610 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
612 SetEvent(params
->ready_event
);
613 params
= NULL
; /* can't touch params after here as it may be invalid */
615 while (GetMessageW(&msg
, NULL
, 0, 0))
617 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
619 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
620 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
621 SetEvent(obj_params
->event
);
625 TranslateMessage(&msg
);
626 DispatchMessageW(&msg
);
637 /* finds or creates a host apartment, creates the object inside it and returns
638 * a proxy to it so that the object can be used in the apartment of the
639 * caller of this function */
640 static HRESULT
apartment_hostobject_in_hostapt(
641 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
642 HKEY hkeydll
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
644 struct host_object_params params
;
645 HWND apartment_hwnd
= NULL
;
646 DWORD apartment_tid
= 0;
649 if (!multi_threaded
&& main_apartment
)
651 APARTMENT
*host_apt
= apartment_findmain();
654 apartment_hwnd
= apartment_getwindow(host_apt
);
655 apartment_release(host_apt
);
661 EnterCriticalSection(&apt
->cs
);
663 if (!apt
->host_apt_tid
)
665 struct host_thread_params thread_params
;
669 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
670 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
671 thread_params
.apartment_hwnd
= NULL
;
672 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
675 CloseHandle(handles
[0]);
676 LeaveCriticalSection(&apt
->cs
);
677 return E_OUTOFMEMORY
;
679 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
680 CloseHandle(handles
[0]);
681 CloseHandle(handles
[1]);
682 if (wait_value
== WAIT_OBJECT_0
)
683 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
686 LeaveCriticalSection(&apt
->cs
);
687 return E_OUTOFMEMORY
;
691 if (multi_threaded
|| !main_apartment
)
693 apartment_hwnd
= apt
->host_apt_hwnd
;
694 apartment_tid
= apt
->host_apt_tid
;
697 LeaveCriticalSection(&apt
->cs
);
700 /* another thread may have become the main apartment in the time it took
701 * us to create the thread for the host apartment */
702 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
704 APARTMENT
*host_apt
= apartment_findmain();
707 apartment_hwnd
= apartment_getwindow(host_apt
);
708 apartment_release(host_apt
);
712 params
.hkeydll
= hkeydll
;
713 params
.clsid
= *rclsid
;
715 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
718 params
.apartment_threaded
= !multi_threaded
;
722 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
723 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
727 WaitForSingleObject(params
.event
, INFINITE
);
730 CloseHandle(params
.event
);
736 ERR("host apartment didn't create window\n");
740 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
743 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
744 IStream_Release(params
.stream
);
748 /* create a window for the apartment or return the current one if one has
749 * already been created */
750 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
752 if (apt
->multi_threaded
)
757 HWND hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0,
759 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
762 ERR("CreateWindow failed with error %d\n", GetLastError());
763 return HRESULT_FROM_WIN32(GetLastError());
765 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
766 /* someone beat us to it */
773 /* retrieves the window for the main- or apartment-threaded apartment */
774 HWND
apartment_getwindow(const struct apartment
*apt
)
776 assert(!apt
->multi_threaded
);
780 void apartment_joinmta(void)
782 apartment_addref(MTA
);
783 COM_CurrentInfo()->apt
= MTA
;
786 /* gets the specified class object by loading the appropriate DLL, if
787 * necessary and calls the DllGetClassObject function for the DLL */
788 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
789 BOOL apartment_threaded
,
790 REFCLSID rclsid
, REFIID riid
, void **ppv
)
792 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
795 struct apartment_loaded_dll
*apartment_loaded_dll
;
797 if (!strcmpiW(dllpath
, wszOle32
))
799 /* we don't need to control the lifetime of this dll, so use the local
800 * implementation of DllGetClassObject directly */
801 TRACE("calling ole32!DllGetClassObject\n");
802 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
805 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
810 EnterCriticalSection(&apt
->cs
);
812 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
813 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
815 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
822 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
823 if (!apartment_loaded_dll
)
827 apartment_loaded_dll
->unload_time
= 0;
828 apartment_loaded_dll
->multi_threaded
= FALSE
;
829 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
831 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
835 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
836 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
840 LeaveCriticalSection(&apt
->cs
);
844 /* one component being multi-threaded overrides any number of
845 * apartment-threaded components */
846 if (!apartment_threaded
)
847 apartment_loaded_dll
->multi_threaded
= TRUE
;
849 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
850 /* OK: get the ClassObject */
851 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
854 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
860 /* frees unused libraries loaded by apartment_getclassobject by calling the
861 * DLL's DllCanUnloadNow entry point */
862 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
864 struct apartment_loaded_dll
*entry
, *next
;
865 EnterCriticalSection(&apt
->cs
);
866 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
868 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
870 DWORD real_delay
= delay
;
872 if (real_delay
== INFINITE
)
874 /* DLLs that return multi-threaded objects aren't unloaded
875 * straight away to cope for programs that have races between
876 * last object destruction and threads in the DLLs that haven't
877 * finished, despite DllCanUnloadNow returning S_OK */
878 if (entry
->multi_threaded
)
879 real_delay
= 10 * 60 * 1000; /* 10 minutes */
884 if (!real_delay
|| (entry
->unload_time
&& (entry
->unload_time
< GetTickCount())))
886 list_remove(&entry
->entry
);
887 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
888 HeapFree(GetProcessHeap(), 0, entry
);
891 entry
->unload_time
= GetTickCount() + real_delay
;
893 else if (entry
->unload_time
)
894 entry
->unload_time
= 0;
896 LeaveCriticalSection(&apt
->cs
);
899 /*****************************************************************************
900 * This section contains OpenDllList implementation
903 /* caller must ensure that library_name is not already in the open dll list */
904 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
910 DllCanUnloadNowFunc DllCanUnloadNow
;
911 DllGetClassObjectFunc DllGetClassObject
;
915 *ret
= COMPOBJ_DllList_Get(library_name
);
916 if (*ret
) return S_OK
;
918 /* do this outside the csOpenDllList to avoid creating a lock dependency on
920 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
923 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
924 /* failure: DLL could not be loaded */
925 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
928 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
929 /* Note: failing to find DllCanUnloadNow is not a failure */
930 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
931 if (!DllGetClassObject
)
933 /* failure: the dll did not export DllGetClassObject */
934 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
935 FreeLibrary(hLibrary
);
936 return CO_E_DLLNOTFOUND
;
939 EnterCriticalSection( &csOpenDllList
);
941 *ret
= COMPOBJ_DllList_Get(library_name
);
944 /* another caller to this function already added the dll while we
945 * weren't in the critical section */
946 FreeLibrary(hLibrary
);
950 len
= strlenW(library_name
);
951 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
953 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
954 if (entry
&& entry
->library_name
)
956 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
957 entry
->library
= hLibrary
;
959 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
960 entry
->DllGetClassObject
= DllGetClassObject
;
961 list_add_tail(&openDllList
, &entry
->entry
);
965 HeapFree(GetProcessHeap(), 0, entry
);
967 FreeLibrary(hLibrary
);
972 LeaveCriticalSection( &csOpenDllList
);
977 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
981 EnterCriticalSection(&csOpenDllList
);
982 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
984 if (!strcmpiW(library_name
, ptr
->library_name
) &&
985 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
991 LeaveCriticalSection(&csOpenDllList
);
995 /* pass FALSE for free_entry to release a reference without destroying the
996 * entry if it reaches zero or TRUE otherwise */
997 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
999 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
1001 EnterCriticalSection(&csOpenDllList
);
1002 list_remove(&entry
->entry
);
1003 LeaveCriticalSection(&csOpenDllList
);
1005 TRACE("freeing %p\n", entry
->library
);
1006 FreeLibrary(entry
->library
);
1008 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
1009 HeapFree(GetProcessHeap(), 0, entry
);
1013 /* frees memory associated with active dll list */
1014 static void COMPOBJ_DllList_Free(void)
1016 OpenDll
*entry
, *cursor2
;
1017 EnterCriticalSection(&csOpenDllList
);
1018 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
1020 list_remove(&entry
->entry
);
1022 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
1023 HeapFree(GetProcessHeap(), 0, entry
);
1025 LeaveCriticalSection(&csOpenDllList
);
1028 /******************************************************************************
1029 * CoBuildVersion [OLE32.@]
1031 * Gets the build version of the DLL.
1036 * Current build version, hiword is majornumber, loword is minornumber
1038 DWORD WINAPI
CoBuildVersion(void)
1040 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1041 return (rmm
<<16)+rup
;
1044 /******************************************************************************
1045 * CoRegisterInitializeSpy [OLE32.@]
1047 * Add a Spy that watches CoInitializeEx calls
1050 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1051 * cookie [II] cookie receiver
1054 * Success: S_OK if not already initialized, S_FALSE otherwise.
1055 * Failure: HRESULT code.
1060 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1062 struct oletls
*info
= COM_CurrentInfo();
1065 TRACE("(%p, %p)\n", spy
, cookie
);
1067 if (!spy
|| !cookie
|| !info
)
1070 WARN("Could not allocate tls\n");
1071 return E_INVALIDARG
;
1076 FIXME("Already registered?\n");
1077 return E_UNEXPECTED
;
1080 hr
= IUnknown_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1083 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1089 /******************************************************************************
1090 * CoRevokeInitializeSpy [OLE32.@]
1092 * Remove a spy that previously watched CoInitializeEx calls
1095 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1098 * Success: S_OK if a spy is removed
1099 * Failure: E_INVALIDARG
1104 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1106 struct oletls
*info
= COM_CurrentInfo();
1107 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1109 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1110 return E_INVALIDARG
;
1112 IUnknown_Release(info
->spy
);
1118 /******************************************************************************
1119 * CoInitialize [OLE32.@]
1121 * Initializes the COM libraries by calling CoInitializeEx with
1122 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1125 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1128 * Success: S_OK if not already initialized, S_FALSE otherwise.
1129 * Failure: HRESULT code.
1134 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1137 * Just delegate to the newer method.
1139 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1142 /******************************************************************************
1143 * CoInitializeEx [OLE32.@]
1145 * Initializes the COM libraries.
1148 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1149 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1152 * S_OK if successful,
1153 * S_FALSE if this function was called already.
1154 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1159 * The behavior used to set the IMalloc used for memory management is
1161 * The dwCoInit parameter must specify one of the following apartment
1163 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1164 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1165 * The parameter may also specify zero or more of the following flags:
1166 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1167 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1172 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1174 struct oletls
*info
= COM_CurrentInfo();
1178 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1180 if (lpReserved
!=NULL
)
1182 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1186 * Check the lock count. If this is the first time going through the initialize
1187 * process, we have to initialize the libraries.
1189 * And crank-up that lock count.
1191 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1194 * Initialize the various COM libraries and data structures.
1196 TRACE("() - Initializing the COM libraries\n");
1198 /* we may need to defer this until after apartment initialisation */
1199 RunningObjectTableImpl_Initialize();
1203 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1205 if (!(apt
= info
->apt
))
1207 apt
= apartment_get_or_create(dwCoInit
);
1208 if (!apt
) return E_OUTOFMEMORY
;
1210 else if (!apartment_is_model(apt
, dwCoInit
))
1212 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1213 code then we are probably using the wrong threading model to implement that API. */
1214 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1215 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1216 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1217 return RPC_E_CHANGED_MODE
;
1225 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1230 /***********************************************************************
1231 * CoUninitialize [OLE32.@]
1233 * This method will decrement the refcount on the current apartment, freeing
1234 * the resources associated with it if it is the last thread in the apartment.
1235 * If the last apartment is freed, the function will additionally release
1236 * any COM resources associated with the process.
1246 void WINAPI
CoUninitialize(void)
1248 struct oletls
* info
= COM_CurrentInfo();
1253 /* will only happen on OOM */
1257 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1262 ERR("Mismatched CoUninitialize\n");
1265 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1271 apartment_release(info
->apt
);
1276 * Decrease the reference count.
1277 * If we are back to 0 locks on the COM library, make sure we free
1278 * all the associated data structures.
1280 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
1283 TRACE("() - Releasing the COM libraries\n");
1285 RunningObjectTableImpl_UnInitialize();
1287 else if (lCOMRefCnt
<1) {
1288 ERR( "CoUninitialize() - not CoInitialized.\n" );
1289 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
1292 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1295 /******************************************************************************
1296 * CoDisconnectObject [OLE32.@]
1298 * Disconnects all connections to this object from remote processes. Dispatches
1299 * pending RPCs while blocking new RPCs from occurring, and then calls
1300 * IMarshal::DisconnectObject on the given object.
1302 * Typically called when the object server is forced to shut down, for instance by
1306 * lpUnk [I] The object whose stub should be disconnected.
1307 * reserved [I] Reserved. Should be set to 0.
1311 * Failure: HRESULT code.
1314 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1316 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
1322 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
1324 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
1327 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
1328 IMarshal_Release(marshal
);
1332 apt
= COM_CurrentApt();
1334 return CO_E_NOTINITIALIZED
;
1336 apartment_disconnectobject(apt
, lpUnk
);
1338 /* Note: native is pretty broken here because it just silently
1339 * fails, without returning an appropriate error code if the object was
1340 * not found, making apps think that the object was disconnected, when
1341 * it actually wasn't */
1346 /******************************************************************************
1347 * CoCreateGuid [OLE32.@]
1349 * Simply forwards to UuidCreate in RPCRT4.
1352 * pguid [O] Points to the GUID to initialize.
1356 * Failure: HRESULT code.
1361 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
1363 DWORD status
= UuidCreate(pguid
);
1364 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
1365 return HRESULT_FROM_WIN32( status
);
1368 /******************************************************************************
1369 * CLSIDFromString [OLE32.@]
1370 * IIDFromString [OLE32.@]
1372 * Converts a unique identifier from its string representation into
1376 * idstr [I] The string representation of the GUID.
1377 * id [O] GUID converted from the string.
1381 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1386 static HRESULT
__CLSIDFromString(LPCWSTR s
, CLSID
*id
)
1392 memset( id
, 0, sizeof (CLSID
) );
1396 /* validate the CLSID string */
1397 if (strlenW(s
) != 38)
1398 return CO_E_CLASSSTRING
;
1400 if ((s
[0]!='{') || (s
[9]!='-') || (s
[14]!='-') || (s
[19]!='-') || (s
[24]!='-') || (s
[37]!='}'))
1401 return CO_E_CLASSSTRING
;
1403 for (i
=1; i
<37; i
++) {
1404 if ((i
== 9)||(i
== 14)||(i
== 19)||(i
== 24)) continue;
1405 if (!(((s
[i
] >= '0') && (s
[i
] <= '9')) ||
1406 ((s
[i
] >= 'a') && (s
[i
] <= 'f')) ||
1407 ((s
[i
] >= 'A') && (s
[i
] <= 'F'))))
1408 return CO_E_CLASSSTRING
;
1411 TRACE("%s -> %p\n", debugstr_w(s
), id
);
1413 /* quick lookup table */
1414 memset(table
, 0, 256);
1416 for (i
= 0; i
< 10; i
++) {
1419 for (i
= 0; i
< 6; i
++) {
1420 table
['A' + i
] = i
+10;
1421 table
['a' + i
] = i
+10;
1424 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1426 id
->Data1
= (table
[s
[1]] << 28 | table
[s
[2]] << 24 | table
[s
[3]] << 20 | table
[s
[4]] << 16 |
1427 table
[s
[5]] << 12 | table
[s
[6]] << 8 | table
[s
[7]] << 4 | table
[s
[8]]);
1428 id
->Data2
= table
[s
[10]] << 12 | table
[s
[11]] << 8 | table
[s
[12]] << 4 | table
[s
[13]];
1429 id
->Data3
= table
[s
[15]] << 12 | table
[s
[16]] << 8 | table
[s
[17]] << 4 | table
[s
[18]];
1431 /* these are just sequential bytes */
1432 id
->Data4
[0] = table
[s
[20]] << 4 | table
[s
[21]];
1433 id
->Data4
[1] = table
[s
[22]] << 4 | table
[s
[23]];
1434 id
->Data4
[2] = table
[s
[25]] << 4 | table
[s
[26]];
1435 id
->Data4
[3] = table
[s
[27]] << 4 | table
[s
[28]];
1436 id
->Data4
[4] = table
[s
[29]] << 4 | table
[s
[30]];
1437 id
->Data4
[5] = table
[s
[31]] << 4 | table
[s
[32]];
1438 id
->Data4
[6] = table
[s
[33]] << 4 | table
[s
[34]];
1439 id
->Data4
[7] = table
[s
[35]] << 4 | table
[s
[36]];
1444 /*****************************************************************************/
1446 HRESULT WINAPI
CLSIDFromString(LPOLESTR idstr
, CLSID
*id
)
1451 return E_INVALIDARG
;
1453 ret
= __CLSIDFromString(idstr
, id
);
1454 if(ret
!= S_OK
) { /* It appears a ProgID is also valid */
1455 ret
= CLSIDFromProgID(idstr
, id
);
1461 /******************************************************************************
1462 * StringFromCLSID [OLE32.@]
1463 * StringFromIID [OLE32.@]
1465 * Converts a GUID into the respective string representation.
1466 * The target string is allocated using the OLE IMalloc.
1469 * id [I] the GUID to be converted.
1470 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1477 * StringFromGUID2, CLSIDFromString
1479 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
1484 if ((ret
= CoGetMalloc(0,&mllc
))) return ret
;
1485 if (!(*idstr
= IMalloc_Alloc( mllc
, CHARS_IN_GUID
* sizeof(WCHAR
) ))) return E_OUTOFMEMORY
;
1486 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
1490 /******************************************************************************
1491 * StringFromGUID2 [OLE32.@]
1493 * Modified version of StringFromCLSID that allows you to specify max
1497 * id [I] GUID to convert to string.
1498 * str [O] Buffer where the result will be stored.
1499 * cmax [I] Size of the buffer in characters.
1502 * Success: The length of the resulting string in characters.
1505 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
1507 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
1508 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1509 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1510 '%','0','2','X','%','0','2','X','}',0 };
1511 if (cmax
< CHARS_IN_GUID
) return 0;
1512 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
1513 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
1514 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
1515 return CHARS_IN_GUID
;
1518 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1519 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
1521 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
1522 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
1526 strcpyW(path
, wszCLSIDSlash
);
1527 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
1528 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, path
, 0, keyname
? KEY_READ
: access
, &key
);
1529 if (res
== ERROR_FILE_NOT_FOUND
)
1530 return REGDB_E_CLASSNOTREG
;
1531 else if (res
!= ERROR_SUCCESS
)
1532 return REGDB_E_READREGDB
;
1540 res
= RegOpenKeyExW(key
, keyname
, 0, access
, subkey
);
1542 if (res
== ERROR_FILE_NOT_FOUND
)
1543 return REGDB_E_KEYMISSING
;
1544 else if (res
!= ERROR_SUCCESS
)
1545 return REGDB_E_READREGDB
;
1550 /* open HKCR\\AppId\\{string form of appid clsid} key */
1551 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
1553 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
1554 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
1556 WCHAR buf
[CHARS_IN_GUID
];
1557 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
1563 /* read the AppID value under the class's key */
1564 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
1569 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
1571 if (res
== ERROR_FILE_NOT_FOUND
)
1572 return REGDB_E_KEYMISSING
;
1573 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
1574 return REGDB_E_READREGDB
;
1576 strcpyW(keyname
, szAppIdKey
);
1577 strcatW(keyname
, buf
);
1578 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, access
, subkey
);
1579 if (res
== ERROR_FILE_NOT_FOUND
)
1580 return REGDB_E_KEYMISSING
;
1581 else if (res
!= ERROR_SUCCESS
)
1582 return REGDB_E_READREGDB
;
1587 /******************************************************************************
1588 * ProgIDFromCLSID [OLE32.@]
1590 * Converts a class id into the respective program ID.
1593 * clsid [I] Class ID, as found in registry.
1594 * ppszProgID [O] Associated ProgID.
1599 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1601 HRESULT WINAPI
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
1603 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
1610 ERR("ppszProgId isn't optional\n");
1611 return E_INVALIDARG
;
1615 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
1619 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
1620 ret
= REGDB_E_CLASSNOTREG
;
1624 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
1627 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
))
1628 ret
= REGDB_E_CLASSNOTREG
;
1631 ret
= E_OUTOFMEMORY
;
1638 /******************************************************************************
1639 * CLSIDFromProgID [OLE32.@]
1641 * Converts a program id into the respective GUID.
1644 * progid [I] Unicode program ID, as found in registry.
1645 * clsid [O] Associated CLSID.
1649 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1651 HRESULT WINAPI
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
1653 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
1654 WCHAR buf2
[CHARS_IN_GUID
];
1655 LONG buf2len
= sizeof(buf2
);
1659 if (!progid
|| !clsid
)
1661 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid
, clsid
);
1662 return E_INVALIDARG
;
1665 /* initialise clsid in case of failure */
1666 memset(clsid
, 0, sizeof(*clsid
));
1668 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
1669 strcpyW( buf
, progid
);
1670 strcatW( buf
, clsidW
);
1671 if (RegOpenKeyW(HKEY_CLASSES_ROOT
,buf
,&xhkey
))
1673 HeapFree(GetProcessHeap(),0,buf
);
1674 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
1675 return CO_E_CLASSSTRING
;
1677 HeapFree(GetProcessHeap(),0,buf
);
1679 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
1682 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
1683 return CO_E_CLASSSTRING
;
1686 return __CLSIDFromString(buf2
,clsid
);
1690 /*****************************************************************************
1691 * CoGetPSClsid [OLE32.@]
1693 * Retrieves the CLSID of the proxy/stub factory that implements
1694 * IPSFactoryBuffer for the specified interface.
1697 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1698 * pclsid [O] Where to store returned proxy/stub CLSID.
1703 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1707 * The standard marshaller activates the object with the CLSID
1708 * returned and uses the CreateProxy and CreateStub methods on its
1709 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1712 * CoGetPSClsid determines this CLSID by searching the
1713 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1714 * in the registry and any interface id registered by
1715 * CoRegisterPSClsid within the current process.
1719 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1720 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1721 * considered a bug in native unless an application depends on this (unlikely).
1724 * CoRegisterPSClsid.
1726 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
1728 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1729 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1730 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
1731 WCHAR value
[CHARS_IN_GUID
];
1734 APARTMENT
*apt
= COM_CurrentApt();
1735 struct registered_psclsid
*registered_psclsid
;
1737 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
1741 ERR("apartment not initialised\n");
1742 return CO_E_NOTINITIALIZED
;
1747 ERR("pclsid isn't optional\n");
1748 return E_INVALIDARG
;
1751 EnterCriticalSection(&apt
->cs
);
1753 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
1754 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
1756 *pclsid
= registered_psclsid
->clsid
;
1757 LeaveCriticalSection(&apt
->cs
);
1761 LeaveCriticalSection(&apt
->cs
);
1763 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1764 strcpyW(path
, wszInterface
);
1765 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
1766 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
1768 /* Open the key.. */
1769 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, path
, 0, KEY_READ
, &hkey
))
1771 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
1772 return REGDB_E_IIDNOTREG
;
1775 /* ... Once we have the key, query the registry to get the
1776 value of CLSID as a string, and convert it into a
1777 proper CLSID structure to be passed back to the app */
1778 len
= sizeof(value
);
1779 if (ERROR_SUCCESS
!= RegQueryValueW(hkey
, NULL
, value
, &len
))
1782 return REGDB_E_IIDNOTREG
;
1786 /* We have the CLSID we want back from the registry as a string, so
1787 let's convert it into a CLSID structure */
1788 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
1789 return REGDB_E_IIDNOTREG
;
1791 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
1795 /*****************************************************************************
1796 * CoRegisterPSClsid [OLE32.@]
1798 * Register a proxy/stub CLSID for the given interface in the current process
1802 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1803 * rclsid [I] CLSID of the proxy/stub.
1807 * Failure: E_OUTOFMEMORY
1811 * This function does not add anything to the registry and the effects are
1812 * limited to the lifetime of the current process.
1817 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
1819 APARTMENT
*apt
= COM_CurrentApt();
1820 struct registered_psclsid
*registered_psclsid
;
1822 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
1826 ERR("apartment not initialised\n");
1827 return CO_E_NOTINITIALIZED
;
1830 EnterCriticalSection(&apt
->cs
);
1832 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
1833 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
1835 registered_psclsid
->clsid
= *rclsid
;
1836 LeaveCriticalSection(&apt
->cs
);
1840 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
1841 if (!registered_psclsid
)
1843 LeaveCriticalSection(&apt
->cs
);
1844 return E_OUTOFMEMORY
;
1847 registered_psclsid
->iid
= *riid
;
1848 registered_psclsid
->clsid
= *rclsid
;
1849 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
1851 LeaveCriticalSection(&apt
->cs
);
1858 * COM_GetRegisteredClassObject
1860 * This internal method is used to scan the registered class list to
1861 * find a class object.
1864 * rclsid Class ID of the class to find.
1865 * dwClsContext Class context to match.
1866 * ppv [out] returns a pointer to the class object. Complying
1867 * to normal COM usage, this method will increase the
1868 * reference count on this object.
1870 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
1871 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
1873 HRESULT hr
= S_FALSE
;
1874 RegisteredClass
*curClass
;
1876 EnterCriticalSection( &csRegisteredClassList
);
1878 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1881 * Check if we have a match on the class ID and context.
1883 if ((apt
->oxid
== curClass
->apartment_id
) &&
1884 (dwClsContext
& curClass
->runContext
) &&
1885 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
1888 * We have a match, return the pointer to the class object.
1890 *ppUnk
= curClass
->classObject
;
1892 IUnknown_AddRef(curClass
->classObject
);
1899 LeaveCriticalSection( &csRegisteredClassList
);
1904 /******************************************************************************
1905 * CoRegisterClassObject [OLE32.@]
1907 * Registers the class object for a given class ID. Servers housed in EXE
1908 * files use this method instead of exporting DllGetClassObject to allow
1909 * other code to connect to their objects.
1912 * rclsid [I] CLSID of the object to register.
1913 * pUnk [I] IUnknown of the object.
1914 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1915 * flags [I] REGCLS flags indicating how connections are made.
1916 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1920 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1921 * CO_E_OBJISREG if the object is already registered. We should not return this.
1924 * CoRevokeClassObject, CoGetClassObject
1927 * In-process objects are only registered for the current apartment.
1928 * CoGetClassObject() and CoCreateInstance() will not return objects registered
1929 * in other apartments.
1932 * MSDN claims that multiple interface registrations are legal, but we
1933 * can't do that with our current implementation.
1935 HRESULT WINAPI
CoRegisterClassObject(
1940 LPDWORD lpdwRegister
)
1942 RegisteredClass
* newClass
;
1943 LPUNKNOWN foundObject
;
1947 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1948 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
1950 if ( (lpdwRegister
==0) || (pUnk
==0) )
1951 return E_INVALIDARG
;
1953 apt
= COM_CurrentApt();
1956 ERR("COM was not initialized\n");
1957 return CO_E_NOTINITIALIZED
;
1962 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1963 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1964 if (flags
& REGCLS_MULTIPLEUSE
)
1965 dwClsContext
|= CLSCTX_INPROC_SERVER
;
1968 * First, check if the class is already registered.
1969 * If it is, this should cause an error.
1971 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
1973 if (flags
& REGCLS_MULTIPLEUSE
) {
1974 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
1975 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
1976 IUnknown_Release(foundObject
);
1979 IUnknown_Release(foundObject
);
1980 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
1981 return CO_E_OBJISREG
;
1984 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
1985 if ( newClass
== NULL
)
1986 return E_OUTOFMEMORY
;
1988 newClass
->classIdentifier
= *rclsid
;
1989 newClass
->apartment_id
= apt
->oxid
;
1990 newClass
->runContext
= dwClsContext
;
1991 newClass
->connectFlags
= flags
;
1992 newClass
->pMarshaledData
= NULL
;
1993 newClass
->RpcRegistration
= NULL
;
1996 * Use the address of the chain node as the cookie since we are sure it's
1997 * unique. FIXME: not on 64-bit platforms.
1999 newClass
->dwCookie
= (DWORD
)newClass
;
2002 * Since we're making a copy of the object pointer, we have to increase its
2005 newClass
->classObject
= pUnk
;
2006 IUnknown_AddRef(newClass
->classObject
);
2008 EnterCriticalSection( &csRegisteredClassList
);
2009 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2010 LeaveCriticalSection( &csRegisteredClassList
);
2012 *lpdwRegister
= newClass
->dwCookie
;
2014 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2015 hr
= CreateStreamOnHGlobal(0, TRUE
, &newClass
->pMarshaledData
);
2017 FIXME("Failed to create stream on hglobal, %x\n", hr
);
2020 hr
= CoMarshalInterface(newClass
->pMarshaledData
, &IID_IClassFactory
,
2021 newClass
->classObject
, MSHCTX_LOCAL
, NULL
,
2022 MSHLFLAGS_TABLESTRONG
);
2024 FIXME("CoMarshalInterface failed, %x!\n",hr
);
2028 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2029 newClass
->pMarshaledData
,
2030 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2031 &newClass
->RpcRegistration
);
2036 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
2038 list_remove(&curClass
->entry
);
2040 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
2041 RPC_StopLocalServer(curClass
->RpcRegistration
);
2044 * Release the reference to the class object.
2046 IUnknown_Release(curClass
->classObject
);
2048 if (curClass
->pMarshaledData
)
2051 memset(&zero
, 0, sizeof(zero
));
2052 IStream_Seek(curClass
->pMarshaledData
, zero
, STREAM_SEEK_SET
, NULL
);
2053 CoReleaseMarshalData(curClass
->pMarshaledData
);
2054 IStream_Release(curClass
->pMarshaledData
);
2057 HeapFree(GetProcessHeap(), 0, curClass
);
2060 static void COM_RevokeAllClasses(const struct apartment
*apt
)
2062 RegisteredClass
*curClass
, *cursor
;
2064 EnterCriticalSection( &csRegisteredClassList
);
2066 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
2068 if (curClass
->apartment_id
== apt
->oxid
)
2069 COM_RevokeRegisteredClassObject(curClass
);
2072 LeaveCriticalSection( &csRegisteredClassList
);
2075 /***********************************************************************
2076 * CoRevokeClassObject [OLE32.@]
2078 * Removes a class object from the class registry.
2081 * dwRegister [I] Cookie returned from CoRegisterClassObject().
2085 * Failure: HRESULT code.
2088 * Must be called from the same apartment that called CoRegisterClassObject(),
2089 * otherwise it will fail with RPC_E_WRONG_THREAD.
2092 * CoRegisterClassObject
2094 HRESULT WINAPI
CoRevokeClassObject(
2097 HRESULT hr
= E_INVALIDARG
;
2098 RegisteredClass
*curClass
;
2101 TRACE("(%08x)\n",dwRegister
);
2103 apt
= COM_CurrentApt();
2106 ERR("COM was not initialized\n");
2107 return CO_E_NOTINITIALIZED
;
2110 EnterCriticalSection( &csRegisteredClassList
);
2112 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2115 * Check if we have a match on the cookie.
2117 if (curClass
->dwCookie
== dwRegister
)
2119 if (curClass
->apartment_id
== apt
->oxid
)
2121 COM_RevokeRegisteredClassObject(curClass
);
2126 ERR("called from wrong apartment, should be called from %s\n",
2127 wine_dbgstr_longlong(curClass
->apartment_id
));
2128 hr
= RPC_E_WRONG_THREAD
;
2134 LeaveCriticalSection( &csRegisteredClassList
);
2139 /***********************************************************************
2140 * COM_RegReadPath [internal]
2142 * Reads a registry value and expands it when necessary
2144 static DWORD
COM_RegReadPath(HKEY hkeyroot
, const WCHAR
*keyname
, const WCHAR
*valuename
, WCHAR
* dst
, DWORD dstlen
)
2149 WCHAR src
[MAX_PATH
];
2150 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
2152 if((ret
= RegOpenKeyExW(hkeyroot
, keyname
, 0, KEY_READ
, &key
)) == ERROR_SUCCESS
) {
2153 if( (ret
= RegQueryValueExW(key
, NULL
, NULL
, &keytype
, (LPBYTE
)src
, &dwLength
)) == ERROR_SUCCESS
) {
2154 if (keytype
== REG_EXPAND_SZ
) {
2155 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
2157 lstrcpynW(dst
, src
, dstlen
);
2165 static void get_threading_model(HKEY key
, LPWSTR value
, DWORD len
)
2167 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2170 DWORD dwLength
= len
* sizeof(WCHAR
);
2172 ret
= RegQueryValueExW(key
, wszThreadingModel
, NULL
, &keytype
, (LPBYTE
)value
, &dwLength
);
2173 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2177 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, HKEY hkeydll
,
2178 REFCLSID rclsid
, REFIID riid
,
2179 BOOL hostifnecessary
, void **ppv
)
2181 WCHAR dllpath
[MAX_PATH
+1];
2182 BOOL apartment_threaded
;
2184 if (hostifnecessary
)
2186 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2187 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2188 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2189 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2191 get_threading_model(hkeydll
, threading_model
, ARRAYSIZE(threading_model
));
2193 if (!strcmpiW(threading_model
, wszApartment
))
2195 apartment_threaded
= TRUE
;
2196 if (apt
->multi_threaded
)
2197 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, hkeydll
, rclsid
, riid
, ppv
);
2200 else if (!strcmpiW(threading_model
, wszFree
))
2202 apartment_threaded
= FALSE
;
2203 if (!apt
->multi_threaded
)
2204 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, hkeydll
, rclsid
, riid
, ppv
);
2206 /* everything except "Apartment", "Free" and "Both" */
2207 else if (strcmpiW(threading_model
, wszBoth
))
2209 apartment_threaded
= TRUE
;
2210 /* everything else is main-threaded */
2211 if (threading_model
[0])
2212 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2213 debugstr_w(threading_model
), debugstr_guid(rclsid
));
2215 if (apt
->multi_threaded
|| !apt
->main
)
2216 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, hkeydll
, rclsid
, riid
, ppv
);
2219 apartment_threaded
= FALSE
;
2222 apartment_threaded
= !apt
->multi_threaded
;
2224 if (COM_RegReadPath(hkeydll
, NULL
, NULL
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2226 /* failure: CLSID is not found in registry */
2227 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2228 return REGDB_E_CLASSNOTREG
;
2231 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2235 /***********************************************************************
2236 * CoGetClassObject [OLE32.@]
2238 * Creates an object of the specified class.
2241 * rclsid [I] Class ID to create an instance of.
2242 * dwClsContext [I] Flags to restrict the location of the created instance.
2243 * pServerInfo [I] Optional. Details for connecting to a remote server.
2244 * iid [I] The ID of the interface of the instance to return.
2245 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2249 * Failure: HRESULT code.
2252 * The dwClsContext parameter can be one or more of the following:
2253 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2254 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2255 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2256 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2259 * CoCreateInstance()
2261 HRESULT WINAPI
CoGetClassObject(
2262 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2263 REFIID iid
, LPVOID
*ppv
)
2265 LPUNKNOWN regClassObject
;
2266 HRESULT hres
= E_UNEXPECTED
;
2268 BOOL release_apt
= FALSE
;
2270 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2273 return E_INVALIDARG
;
2277 if (!(apt
= COM_CurrentApt()))
2279 if (!(apt
= apartment_find_multi_threaded()))
2281 ERR("apartment not initialised\n");
2282 return CO_E_NOTINITIALIZED
;
2288 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2289 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2293 * First, try and see if we can't match the class ID with one of the
2294 * registered classes.
2296 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
2299 /* Get the required interface from the retrieved pointer. */
2300 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
2303 * Since QI got another reference on the pointer, we want to release the
2304 * one we already have. If QI was unsuccessful, this will release the object. This
2305 * is good since we are not returning it in the "out" parameter.
2307 IUnknown_Release(regClassObject
);
2308 if (release_apt
) apartment_release(apt
);
2312 /* First try in-process server */
2313 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2315 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2318 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
2320 if (release_apt
) apartment_release(apt
);
2321 return FTMarshalCF_Create(iid
, ppv
);
2324 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
2327 if (hres
== REGDB_E_CLASSNOTREG
)
2328 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2329 else if (hres
== REGDB_E_KEYMISSING
)
2331 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
2332 hres
= REGDB_E_CLASSNOTREG
;
2336 if (SUCCEEDED(hres
))
2338 hres
= get_inproc_class_object(apt
, hkey
, rclsid
, iid
,
2339 !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2343 /* return if we got a class, otherwise fall through to one of the
2345 if (SUCCEEDED(hres
))
2347 if (release_apt
) apartment_release(apt
);
2352 /* Next try in-process handler */
2353 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
2355 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2358 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
2361 if (hres
== REGDB_E_CLASSNOTREG
)
2362 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2363 else if (hres
== REGDB_E_KEYMISSING
)
2365 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
2366 hres
= REGDB_E_CLASSNOTREG
;
2370 if (SUCCEEDED(hres
))
2372 hres
= get_inproc_class_object(apt
, hkey
, rclsid
, iid
,
2373 !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2377 /* return if we got a class, otherwise fall through to one of the
2379 if (SUCCEEDED(hres
))
2381 if (release_apt
) apartment_release(apt
);
2385 if (release_apt
) apartment_release(apt
);
2387 /* Next try out of process */
2388 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
2390 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
2391 if (SUCCEEDED(hres
))
2395 /* Finally try remote: this requires networked DCOM (a lot of work) */
2396 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
2398 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2399 hres
= E_NOINTERFACE
;
2403 ERR("no class object %s could be created for context 0x%x\n",
2404 debugstr_guid(rclsid
), dwClsContext
);
2408 /***********************************************************************
2409 * CoResumeClassObjects (OLE32.@)
2411 * Resumes all class objects registered with REGCLS_SUSPENDED.
2415 * Failure: HRESULT code.
2417 HRESULT WINAPI
CoResumeClassObjects(void)
2423 /***********************************************************************
2424 * CoCreateInstance [OLE32.@]
2426 * Creates an instance of the specified class.
2429 * rclsid [I] Class ID to create an instance of.
2430 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2431 * dwClsContext [I] Flags to restrict the location of the created instance.
2432 * iid [I] The ID of the interface of the instance to return.
2433 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2437 * Failure: HRESULT code.
2440 * The dwClsContext parameter can be one or more of the following:
2441 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2442 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2443 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2444 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2446 * Aggregation is the concept of deferring the IUnknown of an object to another
2447 * object. This allows a separate object to behave as though it was part of
2448 * the object and to allow this the pUnkOuter parameter can be set. Note that
2449 * not all objects support having an outer of unknown.
2452 * CoGetClassObject()
2454 HRESULT WINAPI
CoCreateInstance(
2456 LPUNKNOWN pUnkOuter
,
2462 LPCLASSFACTORY lpclf
= 0;
2465 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
2466 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
2475 * Initialize the "out" parameter
2479 if (!(apt
= COM_CurrentApt()))
2481 if (!(apt
= apartment_find_multi_threaded()))
2483 ERR("apartment not initialised\n");
2484 return CO_E_NOTINITIALIZED
;
2486 apartment_release(apt
);
2490 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2491 * Rather than create a class factory, we can just check for it here
2493 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
)) {
2494 if (StdGlobalInterfaceTableInstance
== NULL
)
2495 StdGlobalInterfaceTableInstance
= StdGlobalInterfaceTable_Construct();
2496 hres
= IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable
*) StdGlobalInterfaceTableInstance
, iid
, ppv
);
2497 if (hres
) return hres
;
2499 TRACE("Retrieved GIT (%p)\n", *ppv
);
2504 * Get a class factory to construct the object we want.
2506 hres
= CoGetClassObject(rclsid
,
2516 * Create the object and don't forget to release the factory
2518 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
2519 IClassFactory_Release(lpclf
);
2522 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
2523 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid
));
2525 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid
), debugstr_guid(rclsid
),hres
);
2531 /***********************************************************************
2532 * CoCreateInstanceEx [OLE32.@]
2534 HRESULT WINAPI
CoCreateInstanceEx(
2536 LPUNKNOWN pUnkOuter
,
2538 COSERVERINFO
* pServerInfo
,
2542 IUnknown
* pUnk
= NULL
;
2545 ULONG successCount
= 0;
2550 if ( (cmq
==0) || (pResults
==NULL
))
2551 return E_INVALIDARG
;
2553 if (pServerInfo
!=NULL
)
2554 FIXME("() non-NULL pServerInfo not supported!\n");
2557 * Initialize all the "out" parameters.
2559 for (index
= 0; index
< cmq
; index
++)
2561 pResults
[index
].pItf
= NULL
;
2562 pResults
[index
].hr
= E_NOINTERFACE
;
2566 * Get the object and get its IUnknown pointer.
2568 hr
= CoCreateInstance(rclsid
,
2578 * Then, query for all the interfaces requested.
2580 for (index
= 0; index
< cmq
; index
++)
2582 pResults
[index
].hr
= IUnknown_QueryInterface(pUnk
,
2583 pResults
[index
].pIID
,
2584 (VOID
**)&(pResults
[index
].pItf
));
2586 if (pResults
[index
].hr
== S_OK
)
2591 * Release our temporary unknown pointer.
2593 IUnknown_Release(pUnk
);
2595 if (successCount
== 0)
2596 return E_NOINTERFACE
;
2598 if (successCount
!=cmq
)
2599 return CO_S_NOTALLINTERFACES
;
2604 /***********************************************************************
2605 * CoLoadLibrary (OLE32.@)
2610 * lpszLibName [I] Path to library.
2611 * bAutoFree [I] Whether the library should automatically be freed.
2614 * Success: Handle to loaded library.
2618 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2620 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
2622 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
2624 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
2627 /***********************************************************************
2628 * CoFreeLibrary [OLE32.@]
2630 * Unloads a library from memory.
2633 * hLibrary [I] Handle to library to unload.
2639 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2641 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
2643 FreeLibrary(hLibrary
);
2647 /***********************************************************************
2648 * CoFreeAllLibraries [OLE32.@]
2650 * Function for backwards compatibility only. Does nothing.
2656 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2658 void WINAPI
CoFreeAllLibraries(void)
2663 /***********************************************************************
2664 * CoFreeUnusedLibrariesEx [OLE32.@]
2666 * Frees any previously unused libraries whose delay has expired and marks
2667 * currently unused libraries for unloading. Unused are identified as those that
2668 * return S_OK from their DllCanUnloadNow function.
2671 * dwUnloadDelay [I] Unload delay in milliseconds.
2672 * dwReserved [I] Reserved. Set to 0.
2678 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2680 void WINAPI
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
2682 struct apartment
*apt
= COM_CurrentApt();
2685 ERR("apartment not initialised\n");
2689 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
2692 /***********************************************************************
2693 * CoFreeUnusedLibraries [OLE32.@]
2695 * Frees any unused libraries. Unused are identified as those that return
2696 * S_OK from their DllCanUnloadNow function.
2702 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2704 void WINAPI
CoFreeUnusedLibraries(void)
2706 CoFreeUnusedLibrariesEx(INFINITE
, 0);
2709 /***********************************************************************
2710 * CoFileTimeNow [OLE32.@]
2712 * Retrieves the current time in FILETIME format.
2715 * lpFileTime [O] The current time.
2720 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
2722 GetSystemTimeAsFileTime( lpFileTime
);
2726 /******************************************************************************
2727 * CoLockObjectExternal [OLE32.@]
2729 * Increments or decrements the external reference count of a stub object.
2732 * pUnk [I] Stub object.
2733 * fLock [I] If TRUE then increments the external ref-count,
2734 * otherwise decrements.
2735 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2736 * calling CoDisconnectObject.
2740 * Failure: HRESULT code.
2743 * If fLock is TRUE and an object is passed in that doesn't have a stub
2744 * manager then a new stub manager is created for the object.
2746 HRESULT WINAPI
CoLockObjectExternal(
2749 BOOL fLastUnlockReleases
)
2751 struct stub_manager
*stubmgr
;
2752 struct apartment
*apt
;
2754 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2755 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
2757 apt
= COM_CurrentApt();
2758 if (!apt
) return CO_E_NOTINITIALIZED
;
2760 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
2765 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
2767 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
2769 stub_manager_int_release(stubmgr
);
2775 stubmgr
= new_stub_manager(apt
, pUnk
);
2779 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
2780 stub_manager_int_release(stubmgr
);
2787 WARN("stub object not found %p\n", pUnk
);
2788 /* Note: native is pretty broken here because it just silently
2789 * fails, without returning an appropriate error code, making apps
2790 * think that the object was disconnected, when it actually wasn't */
2795 /***********************************************************************
2796 * CoInitializeWOW (OLE32.@)
2798 * WOW equivalent of CoInitialize?
2807 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
2809 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
2813 /***********************************************************************
2814 * CoGetState [OLE32.@]
2816 * Retrieves the thread state object previously stored by CoSetState().
2819 * ppv [I] Address where pointer to object will be stored.
2823 * Failure: E_OUTOFMEMORY.
2826 * Crashes on all invalid ppv addresses, including NULL.
2827 * If the function returns a non-NULL object then the caller must release its
2828 * reference on the object when the object is no longer required.
2833 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
2835 struct oletls
*info
= COM_CurrentInfo();
2836 if (!info
) return E_OUTOFMEMORY
;
2842 IUnknown_AddRef(info
->state
);
2844 TRACE("apt->state=%p\n", info
->state
);
2850 /***********************************************************************
2851 * CoSetState [OLE32.@]
2853 * Sets the thread state object.
2856 * pv [I] Pointer to state object to be stored.
2859 * The system keeps a reference on the object while the object stored.
2863 * Failure: E_OUTOFMEMORY.
2865 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
2867 struct oletls
*info
= COM_CurrentInfo();
2868 if (!info
) return E_OUTOFMEMORY
;
2870 if (pv
) IUnknown_AddRef(pv
);
2874 TRACE("-- release %p now\n", info
->state
);
2875 IUnknown_Release(info
->state
);
2884 /******************************************************************************
2885 * CoTreatAsClass [OLE32.@]
2887 * Sets the TreatAs value of a class.
2890 * clsidOld [I] Class to set TreatAs value on.
2891 * clsidNew [I] The class the clsidOld should be treated as.
2895 * Failure: HRESULT code.
2900 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
2902 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2903 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
2905 WCHAR szClsidNew
[CHARS_IN_GUID
];
2907 WCHAR auto_treat_as
[CHARS_IN_GUID
];
2908 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
2911 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
2914 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
2916 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
2917 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
2919 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
2921 res
= REGDB_E_WRITEREGDB
;
2927 RegDeleteKeyW(hkey
, wszTreatAs
);
2931 else if (!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
)) &&
2932 !RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)))
2934 res
= REGDB_E_WRITEREGDB
;
2939 if (hkey
) RegCloseKey(hkey
);
2943 /******************************************************************************
2944 * CoGetTreatAsClass [OLE32.@]
2946 * Gets the TreatAs value of a class.
2949 * clsidOld [I] Class to get the TreatAs value of.
2950 * clsidNew [I] The class the clsidOld should be treated as.
2954 * Failure: HRESULT code.
2959 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
2961 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
2963 WCHAR szClsidNew
[CHARS_IN_GUID
];
2965 LONG len
= sizeof(szClsidNew
);
2967 FIXME("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
2968 *clsidNew
= *clsidOld
; /* copy over old value */
2970 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
2976 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
2981 res
= CLSIDFromString(szClsidNew
,clsidNew
);
2983 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
2985 if (hkey
) RegCloseKey(hkey
);
2989 /******************************************************************************
2990 * CoGetCurrentProcess [OLE32.@]
2992 * Gets the current process ID.
2995 * The current process ID.
2998 * Is DWORD really the correct return type for this function?
3000 DWORD WINAPI
CoGetCurrentProcess(void)
3002 return GetCurrentProcessId();
3005 /******************************************************************************
3006 * CoRegisterMessageFilter [OLE32.@]
3008 * Registers a message filter.
3011 * lpMessageFilter [I] Pointer to interface.
3012 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3016 * Failure: HRESULT code.
3019 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3020 * lpMessageFilter removes the message filter.
3022 * If lplpMessageFilter is not NULL the previous message filter will be
3023 * returned in the memory pointer to this parameter and the caller is
3024 * responsible for releasing the object.
3026 * The current thread be in an apartment otherwise the function will crash.
3028 HRESULT WINAPI
CoRegisterMessageFilter(
3029 LPMESSAGEFILTER lpMessageFilter
,
3030 LPMESSAGEFILTER
*lplpMessageFilter
)
3032 struct apartment
*apt
;
3033 IMessageFilter
*lpOldMessageFilter
;
3035 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3037 apt
= COM_CurrentApt();
3039 /* can't set a message filter in a multi-threaded apartment */
3040 if (!apt
|| apt
->multi_threaded
)
3042 WARN("can't set message filter in MTA or uninitialized apt\n");
3043 return CO_E_NOT_SUPPORTED
;
3046 if (lpMessageFilter
)
3047 IMessageFilter_AddRef(lpMessageFilter
);
3049 EnterCriticalSection(&apt
->cs
);
3051 lpOldMessageFilter
= apt
->filter
;
3052 apt
->filter
= lpMessageFilter
;
3054 LeaveCriticalSection(&apt
->cs
);
3056 if (lplpMessageFilter
)
3057 *lplpMessageFilter
= lpOldMessageFilter
;
3058 else if (lpOldMessageFilter
)
3059 IMessageFilter_Release(lpOldMessageFilter
);
3064 /***********************************************************************
3065 * CoIsOle1Class [OLE32.@]
3067 * Determines whether the specified class an OLE v1 class.
3070 * clsid [I] Class to test.
3073 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3075 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3077 FIXME("%s\n", debugstr_guid(clsid
));
3081 /***********************************************************************
3082 * IsEqualGUID [OLE32.@]
3084 * Compares two Unique Identifiers.
3087 * rguid1 [I] The first GUID to compare.
3088 * rguid2 [I] The other GUID to compare.
3094 BOOL WINAPI
IsEqualGUID(
3098 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3101 /***********************************************************************
3102 * CoInitializeSecurity [OLE32.@]
3104 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3105 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3106 void* pReserved1
, DWORD dwAuthnLevel
,
3107 DWORD dwImpLevel
, void* pReserved2
,
3108 DWORD dwCapabilities
, void* pReserved3
)
3110 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3111 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3112 dwCapabilities
, pReserved3
);
3116 /***********************************************************************
3117 * CoSuspendClassObjects [OLE32.@]
3119 * Suspends all registered class objects to prevent further requests coming in
3120 * for those objects.
3124 * Failure: HRESULT code.
3126 HRESULT WINAPI
CoSuspendClassObjects(void)
3132 /***********************************************************************
3133 * CoAddRefServerProcess [OLE32.@]
3135 * Helper function for incrementing the reference count of a local-server
3139 * New reference count.
3142 * CoReleaseServerProcess().
3144 ULONG WINAPI
CoAddRefServerProcess(void)
3150 EnterCriticalSection(&csRegisteredClassList
);
3151 refs
= ++s_COMServerProcessReferences
;
3152 LeaveCriticalSection(&csRegisteredClassList
);
3154 TRACE("refs before: %d\n", refs
- 1);
3159 /***********************************************************************
3160 * CoReleaseServerProcess [OLE32.@]
3162 * Helper function for decrementing the reference count of a local-server
3166 * New reference count.
3169 * When reference count reaches 0, this function suspends all registered
3170 * classes so no new connections are accepted.
3173 * CoAddRefServerProcess(), CoSuspendClassObjects().
3175 ULONG WINAPI
CoReleaseServerProcess(void)
3181 EnterCriticalSection(&csRegisteredClassList
);
3183 refs
= --s_COMServerProcessReferences
;
3184 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3186 LeaveCriticalSection(&csRegisteredClassList
);
3188 TRACE("refs after: %d\n", refs
);
3193 /***********************************************************************
3194 * CoIsHandlerConnected [OLE32.@]
3196 * Determines whether a proxy is connected to a remote stub.
3199 * pUnk [I] Pointer to object that may or may not be connected.
3202 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3205 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
3207 FIXME("%p\n", pUnk
);
3212 /***********************************************************************
3213 * CoAllowSetForegroundWindow [OLE32.@]
3216 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
3218 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
3222 /***********************************************************************
3223 * CoQueryProxyBlanket [OLE32.@]
3225 * Retrieves the security settings being used by a proxy.
3228 * pProxy [I] Pointer to the proxy object.
3229 * pAuthnSvc [O] The type of authentication service.
3230 * pAuthzSvc [O] The type of authorization service.
3231 * ppServerPrincName [O] Optional. The server prinicple name.
3232 * pAuthnLevel [O] The authentication level.
3233 * pImpLevel [O] The impersonation level.
3234 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3235 * pCapabilities [O] Flags affecting the security behaviour.
3239 * Failure: HRESULT code.
3242 * CoCopyProxy, CoSetProxyBlanket.
3244 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
3245 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
3246 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
3248 IClientSecurity
*pCliSec
;
3251 TRACE("%p\n", pProxy
);
3253 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3256 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
3257 pAuthzSvc
, ppServerPrincName
,
3258 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
3260 IClientSecurity_Release(pCliSec
);
3263 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3267 /***********************************************************************
3268 * CoSetProxyBlanket [OLE32.@]
3270 * Sets the security settings for a proxy.
3273 * pProxy [I] Pointer to the proxy object.
3274 * AuthnSvc [I] The type of authentication service.
3275 * AuthzSvc [I] The type of authorization service.
3276 * pServerPrincName [I] The server prinicple name.
3277 * AuthnLevel [I] The authentication level.
3278 * ImpLevel [I] The impersonation level.
3279 * pAuthInfo [I] Information specific to the authorization/authentication service.
3280 * Capabilities [I] Flags affecting the security behaviour.
3284 * Failure: HRESULT code.
3287 * CoQueryProxyBlanket, CoCopyProxy.
3289 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
3290 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
3291 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
3293 IClientSecurity
*pCliSec
;
3296 TRACE("%p\n", pProxy
);
3298 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3301 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
3302 AuthzSvc
, pServerPrincName
,
3303 AuthnLevel
, ImpLevel
, pAuthInfo
,
3305 IClientSecurity_Release(pCliSec
);
3308 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3312 /***********************************************************************
3313 * CoCopyProxy [OLE32.@]
3318 * pProxy [I] Pointer to the proxy object.
3319 * ppCopy [O] Copy of the proxy.
3323 * Failure: HRESULT code.
3326 * CoQueryProxyBlanket, CoSetProxyBlanket.
3328 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
3330 IClientSecurity
*pCliSec
;
3333 TRACE("%p\n", pProxy
);
3335 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3338 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
3339 IClientSecurity_Release(pCliSec
);
3342 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3347 /***********************************************************************
3348 * CoGetCallContext [OLE32.@]
3350 * Gets the context of the currently executing server call in the current
3354 * riid [I] Context interface to return.
3355 * ppv [O] Pointer to memory that will receive the context on return.
3359 * Failure: HRESULT code.
3361 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
3363 struct oletls
*info
= COM_CurrentInfo();
3365 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
3368 return E_OUTOFMEMORY
;
3370 if (!info
->call_state
)
3371 return RPC_E_CALL_COMPLETE
;
3373 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
3376 /***********************************************************************
3377 * CoSwitchCallContext [OLE32.@]
3379 * Switches the context of the currently executing server call in the current
3383 * pObject [I] Pointer to new context object
3384 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3388 * Failure: HRESULT code.
3390 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
3392 struct oletls
*info
= COM_CurrentInfo();
3394 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
3397 return E_OUTOFMEMORY
;
3399 *ppOldObject
= info
->call_state
;
3400 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
3405 /***********************************************************************
3406 * CoQueryClientBlanket [OLE32.@]
3408 * Retrieves the authentication information about the client of the currently
3409 * executing server call in the current thread.
3412 * pAuthnSvc [O] Optional. The type of authentication service.
3413 * pAuthzSvc [O] Optional. The type of authorization service.
3414 * pServerPrincName [O] Optional. The server prinicple name.
3415 * pAuthnLevel [O] Optional. The authentication level.
3416 * pImpLevel [O] Optional. The impersonation level.
3417 * pPrivs [O] Optional. Information about the privileges of the client.
3418 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3422 * Failure: HRESULT code.
3425 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3427 HRESULT WINAPI
CoQueryClientBlanket(
3430 OLECHAR
**pServerPrincName
,
3433 RPC_AUTHZ_HANDLE
*pPrivs
,
3434 DWORD
*pCapabilities
)
3436 IServerSecurity
*pSrvSec
;
3439 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3440 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
3441 pPrivs
, pCapabilities
);
3443 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3446 hr
= IServerSecurity_QueryBlanket(
3447 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
3448 pImpLevel
, pPrivs
, pCapabilities
);
3449 IServerSecurity_Release(pSrvSec
);
3455 /***********************************************************************
3456 * CoImpersonateClient [OLE32.@]
3458 * Impersonates the client of the currently executing server call in the
3466 * Failure: HRESULT code.
3469 * If this function fails then the current thread will not be impersonating
3470 * the client and all actions will take place on behalf of the server.
3471 * Therefore, it is important to check the return value from this function.
3474 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3476 HRESULT WINAPI
CoImpersonateClient(void)
3478 IServerSecurity
*pSrvSec
;
3483 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3486 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
3487 IServerSecurity_Release(pSrvSec
);
3493 /***********************************************************************
3494 * CoRevertToSelf [OLE32.@]
3496 * Ends the impersonation of the client of the currently executing server
3497 * call in the current thread.
3504 * Failure: HRESULT code.
3507 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3509 HRESULT WINAPI
CoRevertToSelf(void)
3511 IServerSecurity
*pSrvSec
;
3516 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3519 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
3520 IServerSecurity_Release(pSrvSec
);
3526 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
3528 /* first try to retrieve messages for incoming COM calls to the apartment window */
3529 return PeekMessageW(msg
, apt
->win
, WM_USER
, WM_APP
- 1, PM_REMOVE
|PM_NOYIELD
) ||
3530 /* next retrieve other messages necessary for the app to remain responsive */
3531 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
3532 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
3535 /***********************************************************************
3536 * CoWaitForMultipleHandles [OLE32.@]
3538 * Waits for one or more handles to become signaled.
3541 * dwFlags [I] Flags. See notes.
3542 * dwTimeout [I] Timeout in milliseconds.
3543 * cHandles [I] Number of handles pointed to by pHandles.
3544 * pHandles [I] Handles to wait for.
3545 * lpdwindex [O] Index of handle that was signaled.
3549 * Failure: RPC_S_CALLPENDING on timeout.
3553 * The dwFlags parameter can be zero or more of the following:
3554 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3555 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3558 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3560 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
3561 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
3564 DWORD start_time
= GetTickCount();
3565 APARTMENT
*apt
= COM_CurrentApt();
3566 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
3568 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
3569 pHandles
, lpdwindex
);
3573 DWORD now
= GetTickCount();
3576 if (now
- start_time
> dwTimeout
)
3578 hr
= RPC_S_CALLPENDING
;
3584 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
3585 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
3587 TRACE("waiting for rpc completion or window message\n");
3589 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
3590 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
3591 QS_ALLINPUT
, wait_flags
);
3593 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
3597 /* call message filter */
3599 if (COM_CurrentApt()->filter
)
3601 PENDINGTYPE pendingtype
=
3602 COM_CurrentInfo()->pending_call_count_server
?
3603 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
3604 DWORD be_handled
= IMessageFilter_MessagePending(
3605 COM_CurrentApt()->filter
, 0 /* FIXME */,
3606 now
- start_time
, pendingtype
);
3607 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
3610 case PENDINGMSG_CANCELCALL
:
3611 WARN("call canceled\n");
3612 hr
= RPC_E_CALL_CANCELED
;
3614 case PENDINGMSG_WAITNOPROCESS
:
3615 case PENDINGMSG_WAITDEFPROCESS
:
3617 /* FIXME: MSDN is very vague about the difference
3618 * between WAITNOPROCESS and WAITDEFPROCESS - there
3619 * appears to be none, so it is possibly a left-over
3620 * from the 16-bit world. */
3625 /* note: using "if" here instead of "while" might seem less
3626 * efficient, but only if we are optimising for quick delivery
3627 * of pending messages, rather than quick completion of the
3629 if (COM_PeekMessage(apt
, &msg
))
3631 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
3632 TranslateMessage(&msg
);
3633 DispatchMessageW(&msg
);
3634 if (msg
.message
== WM_QUIT
)
3636 TRACE("resending WM_QUIT to outer message loop\n");
3637 PostQuitMessage(msg
.wParam
);
3638 /* no longer need to process messages */
3639 message_loop
= FALSE
;
3647 TRACE("waiting for rpc completion\n");
3649 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
3650 (dwFlags
& COWAIT_WAITALL
) ? TRUE
: FALSE
,
3651 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
3652 (dwFlags
& COWAIT_ALERTABLE
) ? TRUE
: FALSE
);
3655 if (res
< WAIT_OBJECT_0
+ cHandles
)
3657 /* handle signaled, store index */
3658 *lpdwindex
= (res
- WAIT_OBJECT_0
);
3661 else if (res
== WAIT_TIMEOUT
)
3663 hr
= RPC_S_CALLPENDING
;
3668 ERR("Unexpected wait termination: %d, %d\n", res
, GetLastError());
3673 TRACE("-- 0x%08x\n", hr
);
3678 /***********************************************************************
3679 * CoGetObject [OLE32.@]
3681 * Gets the object named by converting the name to a moniker and binding to it.
3684 * pszName [I] String representing the object.
3685 * pBindOptions [I] Parameters affecting the binding to the named object.
3686 * riid [I] Interface to bind to on the objecct.
3687 * ppv [O] On output, the interface riid of the object represented
3692 * Failure: HRESULT code.
3695 * MkParseDisplayName.
3697 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
3698 REFIID riid
, void **ppv
)
3705 hr
= CreateBindCtx(0, &pbc
);
3709 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
3716 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
3719 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
3720 IMoniker_Release(pmk
);
3724 IBindCtx_Release(pbc
);
3729 /***********************************************************************
3730 * CoRegisterChannelHook [OLE32.@]
3732 * Registers a process-wide hook that is called during ORPC calls.
3735 * guidExtension [I] GUID of the channel hook to register.
3736 * pChannelHook [I] Channel hook object to register.
3740 * Failure: HRESULT code.
3742 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
3744 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
3746 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
3749 typedef struct Context
3751 const IComThreadingInfoVtbl
*lpVtbl
;
3752 const IContextCallbackVtbl
*lpCallbackVtbl
;
3753 const IObjContextVtbl
*lpContextVtbl
;
3758 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
3760 return (Context
*)((char*)iface
- FIELD_OFFSET(Context
, lpVtbl
));
3763 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
3765 return (Context
*)((char*)iface
- FIELD_OFFSET(Context
, lpCallbackVtbl
));
3768 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
3770 return (Context
*)((char*)iface
- FIELD_OFFSET(Context
, lpContextVtbl
));
3773 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
3777 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
3778 IsEqualIID(riid
, &IID_IUnknown
))
3780 *ppv
= &iface
->lpVtbl
;
3782 else if (IsEqualIID(riid
, &IID_IContextCallback
))
3784 *ppv
= &iface
->lpCallbackVtbl
;
3786 else if (IsEqualIID(riid
, &IID_IObjContext
))
3788 *ppv
= &iface
->lpContextVtbl
;
3793 IUnknown_AddRef((IUnknown
*)*ppv
);
3797 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
3798 return E_NOINTERFACE
;
3801 static ULONG
Context_AddRef(Context
*This
)
3803 return InterlockedIncrement(&This
->refs
);
3806 static ULONG
Context_Release(Context
*This
)
3808 ULONG refs
= InterlockedDecrement(&This
->refs
);
3810 HeapFree(GetProcessHeap(), 0, This
);
3814 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
3816 Context
*This
= impl_from_IComThreadingInfo(iface
);
3817 return Context_QueryInterface(This
, riid
, ppv
);
3820 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
3822 Context
*This
= impl_from_IComThreadingInfo(iface
);
3823 return Context_AddRef(This
);
3826 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
3828 Context
*This
= impl_from_IComThreadingInfo(iface
);
3829 return Context_Release(This
);
3832 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
3834 Context
*This
= impl_from_IComThreadingInfo(iface
);
3836 TRACE("(%p)\n", apttype
);
3838 *apttype
= This
->apttype
;
3842 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
3844 Context
*This
= impl_from_IComThreadingInfo(iface
);
3846 TRACE("(%p)\n", thdtype
);
3848 switch (This
->apttype
)
3851 case APTTYPE_MAINSTA
:
3852 *thdtype
= THDTYPE_PROCESSMESSAGES
;
3855 *thdtype
= THDTYPE_BLOCKMESSAGES
;
3861 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
3863 FIXME("(%p): stub\n", logical_thread_id
);
3867 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
3869 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
3873 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
3875 Context_CTI_QueryInterface
,
3877 Context_CTI_Release
,
3878 Context_CTI_GetCurrentApartmentType
,
3879 Context_CTI_GetCurrentThreadType
,
3880 Context_CTI_GetCurrentLogicalThreadId
,
3881 Context_CTI_SetCurrentLogicalThreadId
3884 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
3886 Context
*This
= impl_from_IContextCallback(iface
);
3887 return Context_QueryInterface(This
, riid
, ppv
);
3890 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
3892 Context
*This
= impl_from_IContextCallback(iface
);
3893 return Context_AddRef(This
);
3896 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
3898 Context
*This
= impl_from_IContextCallback(iface
);
3899 return Context_Release(This
);
3902 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
3903 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
3905 Context
*This
= impl_from_IContextCallback(iface
);
3907 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
3911 static const IContextCallbackVtbl Context_Callback_Vtbl
=
3913 Context_CC_QueryInterface
,
3916 Context_CC_ContextCallback
3919 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
3921 Context
*This
= impl_from_IObjContext(iface
);
3922 return Context_QueryInterface(This
, riid
, ppv
);
3925 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
3927 Context
*This
= impl_from_IObjContext(iface
);
3928 return Context_AddRef(This
);
3931 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
3933 Context
*This
= impl_from_IObjContext(iface
);
3934 return Context_Release(This
);
3937 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
3939 Context
*This
= impl_from_IObjContext(iface
);
3941 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
3945 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
3947 Context
*This
= impl_from_IObjContext(iface
);
3949 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
3953 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
3955 Context
*This
= impl_from_IObjContext(iface
);
3957 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
3961 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
3963 Context
*This
= impl_from_IObjContext(iface
);
3965 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
3969 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
3971 Context
*This
= impl_from_IObjContext(iface
);
3972 FIXME("(%p/%p)\n", This
, iface
);
3975 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
3977 Context
*This
= impl_from_IObjContext(iface
);
3978 FIXME("(%p/%p)\n", This
, iface
);
3981 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
3983 Context
*This
= impl_from_IObjContext(iface
);
3984 FIXME("(%p/%p)\n", This
, iface
);
3987 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
3989 Context
*This
= impl_from_IObjContext(iface
);
3990 FIXME("(%p/%p)\n", This
, iface
);
3993 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
3995 Context
*This
= impl_from_IObjContext(iface
);
3996 FIXME("(%p/%p)\n", This
, iface
);
3999 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4001 Context
*This
= impl_from_IObjContext(iface
);
4002 FIXME("(%p/%p)\n", This
, iface
);
4005 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4007 Context
*This
= impl_from_IObjContext(iface
);
4008 FIXME("(%p/%p)\n", This
, iface
);
4011 static const IObjContextVtbl Context_Object_Vtbl
=
4013 Context_OC_QueryInterface
,
4016 Context_OC_SetProperty
,
4017 Context_OC_RemoveProperty
,
4018 Context_OC_GetProperty
,
4019 Context_OC_EnumContextProps
,
4020 Context_OC_Reserved1
,
4021 Context_OC_Reserved2
,
4022 Context_OC_Reserved3
,
4023 Context_OC_Reserved4
,
4024 Context_OC_Reserved5
,
4025 Context_OC_Reserved6
,
4026 Context_OC_Reserved7
4029 /***********************************************************************
4030 * CoGetObjectContext [OLE32.@]
4032 * Retrieves an object associated with the current context (i.e. apartment).
4035 * riid [I] ID of the interface of the object to retrieve.
4036 * ppv [O] Address where object will be stored on return.
4040 * Failure: HRESULT code.
4042 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4044 APARTMENT
*apt
= COM_CurrentApt();
4048 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4053 if (!(apt
= apartment_find_multi_threaded()))
4055 ERR("apartment not initialised\n");
4056 return CO_E_NOTINITIALIZED
;
4058 apartment_release(apt
);
4061 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4063 return E_OUTOFMEMORY
;
4065 context
->lpVtbl
= &Context_Threading_Vtbl
;
4066 context
->lpCallbackVtbl
= &Context_Callback_Vtbl
;
4067 context
->lpContextVtbl
= &Context_Object_Vtbl
;
4069 if (apt
->multi_threaded
)
4070 context
->apttype
= APTTYPE_MTA
;
4072 context
->apttype
= APTTYPE_MAINSTA
;
4074 context
->apttype
= APTTYPE_STA
;
4076 hr
= IUnknown_QueryInterface((IUnknown
*)&context
->lpVtbl
, riid
, ppv
);
4077 IUnknown_Release((IUnknown
*)&context
->lpVtbl
);
4083 /***********************************************************************
4084 * CoGetContextToken [OLE32.@]
4086 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4088 struct oletls
*info
= COM_CurrentInfo();
4090 TRACE("(%p)\n", token
);
4093 return E_OUTOFMEMORY
;
4098 if (!(apt
= apartment_find_multi_threaded()))
4100 ERR("apartment not initialised\n");
4101 return CO_E_NOTINITIALIZED
;
4103 apartment_release(apt
);
4109 if (!info
->context_token
)
4114 hr
= CoGetObjectContext(&IID_IObjContext
, (void **)&ctx
);
4115 if (FAILED(hr
)) return hr
;
4116 info
->context_token
= ctx
;
4119 *token
= (ULONG_PTR
)info
->context_token
;
4120 TRACE("apt->context_token=%p\n", info
->context_token
);
4126 /***********************************************************************
4129 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID fImpLoad
)
4131 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, fImpLoad
);
4134 case DLL_PROCESS_ATTACH
:
4135 hProxyDll
= hinstDLL
;
4136 COMPOBJ_InitProcess();
4137 if (TRACE_ON(ole
)) CoRegisterMallocSpy((LPVOID
)-1);
4140 case DLL_PROCESS_DETACH
:
4141 if (TRACE_ON(ole
)) CoRevokeMallocSpy();
4142 OLEDD_UnInitialize();
4143 COMPOBJ_UninitProcess();
4144 RPC_UnregisterAllChannelHooks();
4145 COMPOBJ_DllList_Free();
4148 case DLL_THREAD_DETACH
:
4155 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */