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
50 #define WIN32_NO_STATUS
56 #define USE_COM_CONTEXT_DEF
65 #include "compobj_private.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
73 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
75 /****************************************************************************
76 * This section defines variables internal to the COM module.
79 static APARTMENT
*MTA
; /* protected by csApartment */
80 static APARTMENT
*MainApartment
; /* the first STA apartment */
81 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment
;
84 static CRITICAL_SECTION_DEBUG critsect_debug
=
87 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
88 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
90 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
92 enum comclass_threadingmodel
94 ThreadingModel_Apartment
= 1,
95 ThreadingModel_Free
= 2,
96 ThreadingModel_No
= 3,
97 ThreadingModel_Both
= 4,
98 ThreadingModel_Neutral
= 5
101 enum comclass_miscfields
105 MiscStatusContent
= 4,
106 MiscStatusThumbnail
= 8,
107 MiscStatusDocPrint
= 16
110 struct comclassredirect_data
126 ULONG clrdata_offset
;
128 DWORD miscstatuscontent
;
129 DWORD miscstatusthumbnail
;
130 DWORD miscstatusicon
;
131 DWORD miscstatusdocprint
;
134 struct ifacepsredirect_data
146 struct progidredirect_data
153 struct class_reg_data
159 struct comclassredirect_data
*data
;
168 struct registered_psclsid
176 * This is a marshallable object exposing registered local servers.
177 * IServiceProvider is used only because it happens meet requirements
178 * and already has proxy/stub code. If more functionality is needed,
179 * a custom interface may be used instead.
183 IServiceProvider IServiceProvider_iface
;
186 IStream
*marshal_stream
;
190 * This lock count counts the number of times CoInitialize is called. It is
191 * decreased every time CoUninitialize is called. When it hits 0, the COM
192 * libraries are freed
194 static LONG s_COMLockCount
= 0;
195 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
196 static LONG s_COMServerProcessReferences
= 0;
199 * This linked list contains the list of registered class objects. These
200 * are mostly used to register the factories for out-of-proc servers of OLE
203 * TODO: Make this data structure aware of inter-process communication. This
204 * means that parts of this will be exported to rpcss.
206 typedef struct tagRegisteredClass
209 CLSID classIdentifier
;
211 LPUNKNOWN classObject
;
215 void *RpcRegistration
;
218 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
220 static CRITICAL_SECTION csRegisteredClassList
;
221 static CRITICAL_SECTION_DEBUG class_cs_debug
=
223 0, 0, &csRegisteredClassList
,
224 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
225 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
227 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
229 static inline enum comclass_miscfields
dvaspect_to_miscfields(DWORD aspect
)
233 case DVASPECT_CONTENT
:
234 return MiscStatusContent
;
235 case DVASPECT_THUMBNAIL
:
236 return MiscStatusThumbnail
;
238 return MiscStatusIcon
;
239 case DVASPECT_DOCPRINT
:
240 return MiscStatusDocPrint
;
246 BOOL
actctx_get_miscstatus(const CLSID
*clsid
, DWORD aspect
, DWORD
*status
)
248 ACTCTX_SECTION_KEYED_DATA data
;
250 data
.cbSize
= sizeof(data
);
251 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
254 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
255 enum comclass_miscfields misc
= dvaspect_to_miscfields(aspect
);
257 if (!(comclass
->miscmask
& misc
))
259 if (!(comclass
->miscmask
& MiscStatus
))
270 *status
= comclass
->miscstatus
;
273 *status
= comclass
->miscstatusicon
;
275 case MiscStatusContent
:
276 *status
= comclass
->miscstatuscontent
;
278 case MiscStatusThumbnail
:
279 *status
= comclass
->miscstatusthumbnail
;
281 case MiscStatusDocPrint
:
282 *status
= comclass
->miscstatusdocprint
;
294 /* wrapper for NtCreateKey that creates the key recursively if necessary */
295 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
297 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
299 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
301 HANDLE subkey
, root
= attr
->RootDirectory
;
302 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
303 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
306 while (i
< len
&& buffer
[i
] != '\\') i
++;
307 if (i
== len
) return status
;
309 attrs
= attr
->Attributes
;
310 attr
->ObjectName
= &str
;
314 str
.Buffer
= buffer
+ pos
;
315 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
316 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
317 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
318 if (status
) return status
;
319 attr
->RootDirectory
= subkey
;
320 while (i
< len
&& buffer
[i
] == '\\') i
++;
322 while (i
< len
&& buffer
[i
] != '\\') i
++;
324 str
.Buffer
= buffer
+ pos
;
325 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
326 attr
->Attributes
= attrs
;
327 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
328 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
333 static const WCHAR classes_rootW
[] =
334 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
336 static HKEY classes_root_hkey
;
338 /* create the special HKEY_CLASSES_ROOT key */
339 static HKEY
create_classes_root_hkey(DWORD access
)
342 OBJECT_ATTRIBUTES attr
;
345 attr
.Length
= sizeof(attr
);
346 attr
.RootDirectory
= 0;
347 attr
.ObjectName
= &name
;
349 attr
.SecurityDescriptor
= NULL
;
350 attr
.SecurityQualityOfService
= NULL
;
351 RtlInitUnicodeString( &name
, classes_rootW
);
352 if (create_key( &hkey
, access
, &attr
)) return 0;
353 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
355 if (!(access
& KEY_WOW64_64KEY
))
357 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
360 NtClose( hkey
); /* somebody beat us to it */
367 /* map the hkey from special root to normal key if necessary */
368 static inline HKEY
get_classes_root_hkey( HKEY hkey
, REGSAM access
)
371 const BOOL is_win64
= sizeof(void*) > sizeof(int);
372 const BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
374 if (hkey
== HKEY_CLASSES_ROOT
&&
375 ((access
& KEY_WOW64_64KEY
) || !(ret
= classes_root_hkey
)))
376 ret
= create_classes_root_hkey(MAXIMUM_ALLOWED
| (access
& KEY_WOW64_64KEY
));
377 if (force_wow32
&& ret
&& ret
== classes_root_hkey
)
379 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
380 access
&= ~KEY_WOW64_32KEY
;
381 if (create_classes_key(classes_root_hkey
, wow6432nodeW
, access
, &hkey
))
389 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
391 OBJECT_ATTRIBUTES attr
;
392 UNICODE_STRING nameW
;
394 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
396 attr
.Length
= sizeof(attr
);
397 attr
.RootDirectory
= hkey
;
398 attr
.ObjectName
= &nameW
;
400 attr
.SecurityDescriptor
= NULL
;
401 attr
.SecurityQualityOfService
= NULL
;
402 RtlInitUnicodeString( &nameW
, name
);
404 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
407 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
409 OBJECT_ATTRIBUTES attr
;
410 UNICODE_STRING nameW
;
412 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
414 attr
.Length
= sizeof(attr
);
415 attr
.RootDirectory
= hkey
;
416 attr
.ObjectName
= &nameW
;
418 attr
.SecurityDescriptor
= NULL
;
419 attr
.SecurityQualityOfService
= NULL
;
420 RtlInitUnicodeString( &nameW
, name
);
422 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
425 /*****************************************************************************
426 * This section contains OpenDllList definitions
428 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
429 * other functions that do LoadLibrary _without_ giving back a HMODULE.
430 * Without this list these handles would never be freed.
432 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
433 * next unload-call but not before 600 sec.
436 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
437 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
439 typedef struct tagOpenDll
444 DllGetClassObjectFunc DllGetClassObject
;
445 DllCanUnloadNowFunc DllCanUnloadNow
;
449 static struct list openDllList
= LIST_INIT(openDllList
);
451 static CRITICAL_SECTION csOpenDllList
;
452 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
454 0, 0, &csOpenDllList
,
455 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
456 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
458 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
460 struct apartment_loaded_dll
468 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',' ',
469 '0','x','#','#','#','#','#','#','#','#',' ',0};
471 /*****************************************************************************
472 * This section contains OpenDllList implementation
475 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
479 EnterCriticalSection(&csOpenDllList
);
480 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
482 if (!strcmpiW(library_name
, ptr
->library_name
) &&
483 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
489 LeaveCriticalSection(&csOpenDllList
);
493 /* caller must ensure that library_name is not already in the open dll list */
494 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
500 DllCanUnloadNowFunc DllCanUnloadNow
;
501 DllGetClassObjectFunc DllGetClassObject
;
503 TRACE("%s\n", debugstr_w(library_name
));
505 *ret
= COMPOBJ_DllList_Get(library_name
);
506 if (*ret
) return S_OK
;
508 /* do this outside the csOpenDllList to avoid creating a lock dependency on
510 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
513 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
514 /* failure: DLL could not be loaded */
515 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
518 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
519 /* Note: failing to find DllCanUnloadNow is not a failure */
520 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
521 if (!DllGetClassObject
)
523 /* failure: the dll did not export DllGetClassObject */
524 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
525 FreeLibrary(hLibrary
);
526 return CO_E_DLLNOTFOUND
;
529 EnterCriticalSection( &csOpenDllList
);
531 *ret
= COMPOBJ_DllList_Get(library_name
);
534 /* another caller to this function already added the dll while we
535 * weren't in the critical section */
536 FreeLibrary(hLibrary
);
540 len
= strlenW(library_name
);
541 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
543 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
544 if (entry
&& entry
->library_name
)
546 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
547 entry
->library
= hLibrary
;
549 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
550 entry
->DllGetClassObject
= DllGetClassObject
;
551 list_add_tail(&openDllList
, &entry
->entry
);
556 HeapFree(GetProcessHeap(), 0, entry
);
558 FreeLibrary(hLibrary
);
562 LeaveCriticalSection( &csOpenDllList
);
567 /* pass FALSE for free_entry to release a reference without destroying the
568 * entry if it reaches zero or TRUE otherwise */
569 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
571 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
573 EnterCriticalSection(&csOpenDllList
);
574 list_remove(&entry
->entry
);
575 LeaveCriticalSection(&csOpenDllList
);
577 TRACE("freeing %p\n", entry
->library
);
578 FreeLibrary(entry
->library
);
580 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
581 HeapFree(GetProcessHeap(), 0, entry
);
585 /* frees memory associated with active dll list */
586 static void COMPOBJ_DllList_Free(void)
588 OpenDll
*entry
, *cursor2
;
589 EnterCriticalSection(&csOpenDllList
);
590 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
592 list_remove(&entry
->entry
);
594 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
595 HeapFree(GetProcessHeap(), 0, entry
);
597 LeaveCriticalSection(&csOpenDllList
);
598 DeleteCriticalSection(&csOpenDllList
);
601 /******************************************************************************
605 static DWORD
apartment_addref(struct apartment
*apt
)
607 DWORD refs
= InterlockedIncrement(&apt
->refs
);
608 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
612 /* allocates memory and fills in the necessary fields for a new apartment
613 * object. must be called inside apartment cs */
614 static APARTMENT
*apartment_construct(DWORD model
)
618 TRACE("creating new apartment, model=%d\n", model
);
620 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
621 apt
->tid
= GetCurrentThreadId();
623 list_init(&apt
->proxies
);
624 list_init(&apt
->stubmgrs
);
625 list_init(&apt
->psclsids
);
626 list_init(&apt
->loaded_dlls
);
629 apt
->remunk_exported
= FALSE
;
631 InitializeCriticalSection(&apt
->cs
);
632 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
634 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
636 if (apt
->multi_threaded
)
638 /* FIXME: should be randomly generated by in an RPC call to rpcss */
639 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
643 /* FIXME: should be randomly generated by in an RPC call to rpcss */
644 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
647 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
649 list_add_head(&apts
, &apt
->entry
);
654 /* gets and existing apartment if one exists or otherwise creates an apartment
655 * structure which stores OLE apartment-local information and stores a pointer
656 * to it in the thread-local storage */
657 static APARTMENT
*apartment_get_or_create(DWORD model
)
659 APARTMENT
*apt
= COM_CurrentApt();
663 if (model
& COINIT_APARTMENTTHREADED
)
665 EnterCriticalSection(&csApartment
);
667 apt
= apartment_construct(model
);
672 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
675 LeaveCriticalSection(&csApartment
);
678 apartment_createwindowifneeded(apt
);
682 EnterCriticalSection(&csApartment
);
684 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
685 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
689 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
690 apartment_addref(MTA
);
693 MTA
= apartment_construct(model
);
697 LeaveCriticalSection(&csApartment
);
699 COM_CurrentInfo()->apt
= apt
;
705 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
707 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
710 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
712 list_remove(&curClass
->entry
);
714 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
715 RPC_StopLocalServer(curClass
->RpcRegistration
);
717 IUnknown_Release(curClass
->classObject
);
718 HeapFree(GetProcessHeap(), 0, curClass
);
721 static void COM_RevokeAllClasses(const struct apartment
*apt
)
723 RegisteredClass
*curClass
, *cursor
;
725 EnterCriticalSection( &csRegisteredClassList
);
727 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
729 if (curClass
->apartment_id
== apt
->oxid
)
730 COM_RevokeRegisteredClassObject(curClass
);
733 LeaveCriticalSection( &csRegisteredClassList
);
736 /******************************************************************************
737 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
740 typedef struct ManualResetEvent
{
741 ISynchronize ISynchronize_iface
;
742 ISynchronizeHandle ISynchronizeHandle_iface
;
747 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
749 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
752 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
754 MREImpl
*This
= impl_from_ISynchronize(iface
);
756 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
758 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
759 *ppv
= &This
->ISynchronize_iface
;
760 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
761 *ppv
= &This
->ISynchronizeHandle_iface
;
763 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
765 return E_NOINTERFACE
;
768 IUnknown_AddRef((IUnknown
*)*ppv
);
772 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
774 MREImpl
*This
= impl_from_ISynchronize(iface
);
775 LONG ref
= InterlockedIncrement(&This
->ref
);
776 TRACE("%p - ref %d\n", This
, ref
);
781 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
783 MREImpl
*This
= impl_from_ISynchronize(iface
);
784 LONG ref
= InterlockedDecrement(&This
->ref
);
785 TRACE("%p - ref %d\n", This
, ref
);
789 CloseHandle(This
->event
);
790 HeapFree(GetProcessHeap(), 0, This
);
796 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
798 MREImpl
*This
= impl_from_ISynchronize(iface
);
800 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
801 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
804 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
806 MREImpl
*This
= impl_from_ISynchronize(iface
);
808 SetEvent(This
->event
);
812 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
814 MREImpl
*This
= impl_from_ISynchronize(iface
);
816 ResetEvent(This
->event
);
820 static ISynchronizeVtbl vt_ISynchronize
= {
821 ISynchronize_fnQueryInterface
,
822 ISynchronize_fnAddRef
,
823 ISynchronize_fnRelease
,
825 ISynchronize_fnSignal
,
829 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
831 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
834 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
836 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
837 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
840 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
842 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
843 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
846 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
848 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
849 return ISynchronize_Release(&This
->ISynchronize_iface
);
852 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
854 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
860 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
861 SynchronizeHandle_QueryInterface
,
862 SynchronizeHandle_AddRef
,
863 SynchronizeHandle_Release
,
864 SynchronizeHandle_GetHandle
867 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
869 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
873 FIXME("Aggregation not implemented.\n");
876 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
877 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
878 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
880 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
881 ISynchronize_Release(&This
->ISynchronize_iface
);
885 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
887 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
890 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
892 LocalServer
*This
= impl_from_IServiceProvider(iface
);
894 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
896 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
897 *ppv
= &This
->IServiceProvider_iface
;
900 return E_NOINTERFACE
;
903 IUnknown_AddRef((IUnknown
*)*ppv
);
907 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
909 LocalServer
*This
= impl_from_IServiceProvider(iface
);
910 LONG ref
= InterlockedIncrement(&This
->ref
);
912 TRACE("(%p) ref=%d\n", This
, ref
);
917 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
919 LocalServer
*This
= impl_from_IServiceProvider(iface
);
920 LONG ref
= InterlockedDecrement(&This
->ref
);
922 TRACE("(%p) ref=%d\n", This
, ref
);
926 HeapFree(GetProcessHeap(), 0, This
);
932 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
934 LocalServer
*This
= impl_from_IServiceProvider(iface
);
935 APARTMENT
*apt
= COM_CurrentApt();
936 RegisteredClass
*iter
;
937 HRESULT hres
= E_FAIL
;
939 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
944 EnterCriticalSection(&csRegisteredClassList
);
946 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
947 if(iter
->apartment_id
== apt
->oxid
948 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
949 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
950 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
955 LeaveCriticalSection( &csRegisteredClassList
);
960 static const IServiceProviderVtbl LocalServerVtbl
= {
961 LocalServer_QueryInterface
,
964 LocalServer_QueryService
967 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
971 EnterCriticalSection(&apt
->cs
);
973 if(!apt
->local_server
) {
976 obj
= heap_alloc(sizeof(*obj
));
978 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
982 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
983 if(SUCCEEDED(hres
)) {
984 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
985 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
987 IStream_Release(obj
->marshal_stream
);
991 apt
->local_server
= obj
;
995 hres
= E_OUTOFMEMORY
;
1000 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
1002 LeaveCriticalSection(&apt
->cs
);
1005 ERR("Failed: %08x\n", hres
);
1009 /***********************************************************************
1010 * CoRevokeClassObject [OLE32.@]
1012 * Removes a class object from the class registry.
1015 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1019 * Failure: HRESULT code.
1022 * Must be called from the same apartment that called CoRegisterClassObject(),
1023 * otherwise it will fail with RPC_E_WRONG_THREAD.
1026 * CoRegisterClassObject
1028 HRESULT WINAPI
CoRevokeClassObject(
1031 HRESULT hr
= E_INVALIDARG
;
1032 RegisteredClass
*curClass
;
1035 TRACE("(%08x)\n",dwRegister
);
1037 apt
= COM_CurrentApt();
1040 ERR("COM was not initialized\n");
1041 return CO_E_NOTINITIALIZED
;
1044 EnterCriticalSection( &csRegisteredClassList
);
1046 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1049 * Check if we have a match on the cookie.
1051 if (curClass
->dwCookie
== dwRegister
)
1053 if (curClass
->apartment_id
== apt
->oxid
)
1055 COM_RevokeRegisteredClassObject(curClass
);
1060 ERR("called from wrong apartment, should be called from %s\n",
1061 wine_dbgstr_longlong(curClass
->apartment_id
));
1062 hr
= RPC_E_WRONG_THREAD
;
1068 LeaveCriticalSection( &csRegisteredClassList
);
1073 /* frees unused libraries loaded by apartment_getclassobject by calling the
1074 * DLL's DllCanUnloadNow entry point */
1075 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
1077 struct apartment_loaded_dll
*entry
, *next
;
1078 EnterCriticalSection(&apt
->cs
);
1079 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1081 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
1083 DWORD real_delay
= delay
;
1085 if (real_delay
== INFINITE
)
1087 /* DLLs that return multi-threaded objects aren't unloaded
1088 * straight away to cope for programs that have races between
1089 * last object destruction and threads in the DLLs that haven't
1090 * finished, despite DllCanUnloadNow returning S_OK */
1091 if (entry
->multi_threaded
)
1092 real_delay
= 10 * 60 * 1000; /* 10 minutes */
1097 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
1099 list_remove(&entry
->entry
);
1100 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
1101 HeapFree(GetProcessHeap(), 0, entry
);
1105 entry
->unload_time
= GetTickCount() + real_delay
;
1106 if (!entry
->unload_time
) entry
->unload_time
= 1;
1109 else if (entry
->unload_time
)
1110 entry
->unload_time
= 0;
1112 LeaveCriticalSection(&apt
->cs
);
1115 DWORD
apartment_release(struct apartment
*apt
)
1119 EnterCriticalSection(&csApartment
);
1121 ret
= InterlockedDecrement(&apt
->refs
);
1122 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
1123 /* destruction stuff that needs to happen under csApartment CS */
1126 if (apt
== MTA
) MTA
= NULL
;
1127 else if (apt
== MainApartment
) MainApartment
= NULL
;
1128 list_remove(&apt
->entry
);
1131 LeaveCriticalSection(&csApartment
);
1135 struct list
*cursor
, *cursor2
;
1137 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
1139 if(apt
->local_server
) {
1140 LocalServer
*local_server
= apt
->local_server
;
1143 memset(&zero
, 0, sizeof(zero
));
1144 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
1145 CoReleaseMarshalData(local_server
->marshal_stream
);
1146 IStream_Release(local_server
->marshal_stream
);
1147 local_server
->marshal_stream
= NULL
;
1149 apt
->local_server
= NULL
;
1150 local_server
->apt
= NULL
;
1151 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
1154 /* Release the references to the registered class objects */
1155 COM_RevokeAllClasses(apt
);
1157 /* no locking is needed for this apartment, because no other thread
1158 * can access it at this point */
1160 apartment_disconnectproxies(apt
);
1162 if (apt
->win
) DestroyWindow(apt
->win
);
1163 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
1165 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
1167 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
1168 /* release the implicit reference given by the fact that the
1169 * stub has external references (it must do since it is in the
1170 * stub manager list in the apartment and all non-apartment users
1171 * must have a ref on the apartment and so it cannot be destroyed).
1173 stub_manager_int_release(stubmgr
);
1176 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->psclsids
)
1178 struct registered_psclsid
*registered_psclsid
=
1179 LIST_ENTRY(cursor
, struct registered_psclsid
, entry
);
1181 list_remove(®istered_psclsid
->entry
);
1182 HeapFree(GetProcessHeap(), 0, registered_psclsid
);
1185 /* if this assert fires, then another thread took a reference to a
1186 * stub manager without taking a reference to the containing
1187 * apartment, which it must do. */
1188 assert(list_empty(&apt
->stubmgrs
));
1190 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1192 /* free as many unused libraries as possible... */
1193 apartment_freeunusedlibraries(apt
, 0);
1195 /* ... and free the memory for the apartment loaded dll entry and
1196 * release the dll list reference without freeing the library for the
1198 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1200 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1201 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1202 list_remove(cursor
);
1203 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1206 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1207 DeleteCriticalSection(&apt
->cs
);
1209 HeapFree(GetProcessHeap(), 0, apt
);
1215 /* The given OXID must be local to this process:
1217 * The ref parameter is here mostly to ensure people remember that
1218 * they get one, you should normally take a ref for thread safety.
1220 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1222 APARTMENT
*result
= NULL
;
1223 struct list
*cursor
;
1225 EnterCriticalSection(&csApartment
);
1226 LIST_FOR_EACH( cursor
, &apts
)
1228 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1229 if (apt
->oxid
== oxid
)
1232 if (ref
) apartment_addref(result
);
1236 LeaveCriticalSection(&csApartment
);
1241 /* gets the apartment which has a given creator thread ID. The caller must
1242 * release the reference from the apartment as soon as the apartment pointer
1243 * is no longer required. */
1244 APARTMENT
*apartment_findfromtid(DWORD tid
)
1246 APARTMENT
*result
= NULL
;
1247 struct list
*cursor
;
1249 EnterCriticalSection(&csApartment
);
1250 LIST_FOR_EACH( cursor
, &apts
)
1252 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1253 if (apt
->tid
== tid
)
1256 apartment_addref(result
);
1260 LeaveCriticalSection(&csApartment
);
1265 /* gets the main apartment if it exists. The caller must
1266 * release the reference from the apartment as soon as the apartment pointer
1267 * is no longer required. */
1268 static APARTMENT
*apartment_findmain(void)
1272 EnterCriticalSection(&csApartment
);
1274 result
= MainApartment
;
1275 if (result
) apartment_addref(result
);
1277 LeaveCriticalSection(&csApartment
);
1282 /* gets the multi-threaded apartment if it exists. The caller must
1283 * release the reference from the apartment as soon as the apartment pointer
1284 * is no longer required. */
1285 static APARTMENT
*apartment_find_multi_threaded(void)
1287 APARTMENT
*result
= NULL
;
1288 struct list
*cursor
;
1290 EnterCriticalSection(&csApartment
);
1292 LIST_FOR_EACH( cursor
, &apts
)
1294 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1295 if (apt
->multi_threaded
)
1298 apartment_addref(result
);
1303 LeaveCriticalSection(&csApartment
);
1307 /* gets the specified class object by loading the appropriate DLL, if
1308 * necessary and calls the DllGetClassObject function for the DLL */
1309 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1310 BOOL apartment_threaded
,
1311 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1313 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1316 struct apartment_loaded_dll
*apartment_loaded_dll
;
1318 if (!strcmpiW(dllpath
, wszOle32
))
1320 /* we don't need to control the lifetime of this dll, so use the local
1321 * implementation of DllGetClassObject directly */
1322 TRACE("calling ole32!DllGetClassObject\n");
1323 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1326 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1331 EnterCriticalSection(&apt
->cs
);
1333 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1334 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1336 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1343 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1344 if (!apartment_loaded_dll
)
1348 apartment_loaded_dll
->unload_time
= 0;
1349 apartment_loaded_dll
->multi_threaded
= FALSE
;
1350 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1352 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1356 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1357 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1361 LeaveCriticalSection(&apt
->cs
);
1365 /* one component being multi-threaded overrides any number of
1366 * apartment-threaded components */
1367 if (!apartment_threaded
)
1368 apartment_loaded_dll
->multi_threaded
= TRUE
;
1370 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1371 /* OK: get the ClassObject */
1372 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1375 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1381 /***********************************************************************
1382 * COM_RegReadPath [internal]
1384 * Reads a registry value and expands it when necessary
1386 static DWORD
COM_RegReadPath(const struct class_reg_data
*regdata
, WCHAR
*dst
, DWORD dstlen
)
1393 WCHAR src
[MAX_PATH
];
1394 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1396 if( (ret
= RegQueryValueExW(regdata
->u
.hkey
, NULL
, NULL
, &keytype
, (BYTE
*)src
, &dwLength
)) == ERROR_SUCCESS
) {
1397 if (keytype
== REG_EXPAND_SZ
) {
1398 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1400 const WCHAR
*quote_start
;
1401 quote_start
= strchrW(src
, '\"');
1403 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1405 memmove(src
, quote_start
+ 1,
1406 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1407 src
[quote_end
- quote_start
- 1] = '\0';
1410 lstrcpynW(dst
, src
, dstlen
);
1421 nameW
= (WCHAR
*)((BYTE
*)regdata
->u
.actctx
.section
+ regdata
->u
.actctx
.data
->name_offset
);
1422 ActivateActCtx(regdata
->u
.actctx
.hactctx
, &cookie
);
1423 ret
= SearchPathW(NULL
, nameW
, NULL
, dstlen
, dst
, NULL
);
1424 DeactivateActCtx(0, cookie
);
1429 struct host_object_params
1431 struct class_reg_data regdata
;
1432 CLSID clsid
; /* clsid of object to marshal */
1433 IID iid
; /* interface to marshal */
1434 HANDLE event
; /* event signalling when ready for multi-threaded case */
1435 HRESULT hr
; /* result for multi-threaded case */
1436 IStream
*stream
; /* stream that the object will be marshaled into */
1437 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1440 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1441 const struct host_object_params
*params
)
1445 static const LARGE_INTEGER llZero
;
1446 WCHAR dllpath
[MAX_PATH
+1];
1448 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1450 if (COM_RegReadPath(¶ms
->regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1452 /* failure: CLSID is not found in registry */
1453 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1454 return REGDB_E_CLASSNOTREG
;
1457 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1458 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1462 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1464 IUnknown_Release(object
);
1465 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1470 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1475 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1478 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1480 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1484 struct host_thread_params
1486 COINIT threading_model
;
1488 HWND apartment_hwnd
;
1491 /* thread for hosting an object to allow an object to appear to be created in
1492 * an apartment with an incompatible threading model */
1493 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1495 struct host_thread_params
*params
= p
;
1498 struct apartment
*apt
;
1502 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1503 if (FAILED(hr
)) return hr
;
1505 apt
= COM_CurrentApt();
1506 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1508 apartment_createwindowifneeded(apt
);
1509 params
->apartment_hwnd
= apartment_getwindow(apt
);
1512 params
->apartment_hwnd
= NULL
;
1514 /* force the message queue to be created before signaling parent thread */
1515 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1517 SetEvent(params
->ready_event
);
1518 params
= NULL
; /* can't touch params after here as it may be invalid */
1520 while (GetMessageW(&msg
, NULL
, 0, 0))
1522 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1524 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1525 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1526 SetEvent(obj_params
->event
);
1530 TranslateMessage(&msg
);
1531 DispatchMessageW(&msg
);
1542 /* finds or creates a host apartment, creates the object inside it and returns
1543 * a proxy to it so that the object can be used in the apartment of the
1544 * caller of this function */
1545 static HRESULT
apartment_hostobject_in_hostapt(
1546 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1547 const struct class_reg_data
*regdata
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1549 struct host_object_params params
;
1550 HWND apartment_hwnd
= NULL
;
1551 DWORD apartment_tid
= 0;
1554 if (!multi_threaded
&& main_apartment
)
1556 APARTMENT
*host_apt
= apartment_findmain();
1559 apartment_hwnd
= apartment_getwindow(host_apt
);
1560 apartment_release(host_apt
);
1564 if (!apartment_hwnd
)
1566 EnterCriticalSection(&apt
->cs
);
1568 if (!apt
->host_apt_tid
)
1570 struct host_thread_params thread_params
;
1574 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1575 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1576 thread_params
.apartment_hwnd
= NULL
;
1577 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1580 CloseHandle(handles
[0]);
1581 LeaveCriticalSection(&apt
->cs
);
1582 return E_OUTOFMEMORY
;
1584 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1585 CloseHandle(handles
[0]);
1586 CloseHandle(handles
[1]);
1587 if (wait_value
== WAIT_OBJECT_0
)
1588 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1591 LeaveCriticalSection(&apt
->cs
);
1592 return E_OUTOFMEMORY
;
1596 if (multi_threaded
|| !main_apartment
)
1598 apartment_hwnd
= apt
->host_apt_hwnd
;
1599 apartment_tid
= apt
->host_apt_tid
;
1602 LeaveCriticalSection(&apt
->cs
);
1605 /* another thread may have become the main apartment in the time it took
1606 * us to create the thread for the host apartment */
1607 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1609 APARTMENT
*host_apt
= apartment_findmain();
1612 apartment_hwnd
= apartment_getwindow(host_apt
);
1613 apartment_release(host_apt
);
1617 params
.regdata
= *regdata
;
1618 params
.clsid
= *rclsid
;
1620 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1623 params
.apartment_threaded
= !multi_threaded
;
1627 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1628 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1632 WaitForSingleObject(params
.event
, INFINITE
);
1635 CloseHandle(params
.event
);
1639 if (!apartment_hwnd
)
1641 ERR("host apartment didn't create window\n");
1645 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1648 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1649 IStream_Release(params
.stream
);
1653 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1657 /* Dispatching to the correct thread in an apartment is done through
1658 * window messages rather than RPC transports. When an interface is
1659 * marshalled into another apartment in the same process, a window of the
1660 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1661 * application) is responsible for pumping the message loop in that thread.
1662 * The WM_USER messages which point to the RPCs are then dispatched to
1663 * apartment_wndproc by the user's code from the apartment in which the
1664 * interface was unmarshalled.
1666 memset(&wclass
, 0, sizeof(wclass
));
1667 wclass
.lpfnWndProc
= apartment_wndproc
;
1668 wclass
.hInstance
= hProxyDll
;
1669 wclass
.lpszClassName
= wszAptWinClass
;
1670 RegisterClassW(&wclass
);
1674 /* create a window for the apartment or return the current one if one has
1675 * already been created */
1676 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1678 static INIT_ONCE class_init_once
= INIT_ONCE_STATIC_INIT
;
1680 if (apt
->multi_threaded
)
1687 InitOnceExecuteOnce( &class_init_once
, register_class
, NULL
, NULL
);
1689 hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0, 0, 0, 0, 0,
1690 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1693 ERR("CreateWindow failed with error %d\n", GetLastError());
1694 return HRESULT_FROM_WIN32(GetLastError());
1696 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1697 /* someone beat us to it */
1698 DestroyWindow(hwnd
);
1704 /* retrieves the window for the main- or apartment-threaded apartment */
1705 HWND
apartment_getwindow(const struct apartment
*apt
)
1707 assert(!apt
->multi_threaded
);
1711 void apartment_joinmta(void)
1713 apartment_addref(MTA
);
1714 COM_CurrentInfo()->apt
= MTA
;
1717 static void COM_TlsDestroy(void)
1719 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1722 if (info
->apt
) apartment_release(info
->apt
);
1723 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1724 if (info
->state
) IUnknown_Release(info
->state
);
1725 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1726 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1727 HeapFree(GetProcessHeap(), 0, info
);
1728 NtCurrentTeb()->ReservedForOle
= NULL
;
1732 /******************************************************************************
1733 * CoBuildVersion [OLE32.@]
1735 * Gets the build version of the DLL.
1740 * Current build version, hiword is majornumber, loword is minornumber
1742 DWORD WINAPI
CoBuildVersion(void)
1744 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1745 return (rmm
<<16)+rup
;
1748 /******************************************************************************
1749 * CoRegisterInitializeSpy [OLE32.@]
1751 * Add a Spy that watches CoInitializeEx calls
1754 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1755 * cookie [II] cookie receiver
1758 * Success: S_OK if not already initialized, S_FALSE otherwise.
1759 * Failure: HRESULT code.
1764 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1766 struct oletls
*info
= COM_CurrentInfo();
1769 TRACE("(%p, %p)\n", spy
, cookie
);
1771 if (!spy
|| !cookie
|| !info
)
1774 WARN("Could not allocate tls\n");
1775 return E_INVALIDARG
;
1780 FIXME("Already registered?\n");
1781 return E_UNEXPECTED
;
1784 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1787 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1793 /******************************************************************************
1794 * CoRevokeInitializeSpy [OLE32.@]
1796 * Remove a spy that previously watched CoInitializeEx calls
1799 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1802 * Success: S_OK if a spy is removed
1803 * Failure: E_INVALIDARG
1808 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1810 struct oletls
*info
= COM_CurrentInfo();
1811 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1813 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1814 return E_INVALIDARG
;
1816 IInitializeSpy_Release(info
->spy
);
1822 /******************************************************************************
1823 * CoInitialize [OLE32.@]
1825 * Initializes the COM libraries by calling CoInitializeEx with
1826 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1829 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1832 * Success: S_OK if not already initialized, S_FALSE otherwise.
1833 * Failure: HRESULT code.
1838 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1841 * Just delegate to the newer method.
1843 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1846 /******************************************************************************
1847 * CoInitializeEx [OLE32.@]
1849 * Initializes the COM libraries.
1852 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1853 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1856 * S_OK if successful,
1857 * S_FALSE if this function was called already.
1858 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1863 * The behavior used to set the IMalloc used for memory management is
1865 * The dwCoInit parameter must specify one of the following apartment
1867 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1868 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1869 * The parameter may also specify zero or more of the following flags:
1870 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1871 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1876 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1878 struct oletls
*info
= COM_CurrentInfo();
1882 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1884 if (lpReserved
!=NULL
)
1886 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1890 * Check the lock count. If this is the first time going through the initialize
1891 * process, we have to initialize the libraries.
1893 * And crank-up that lock count.
1895 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1898 * Initialize the various COM libraries and data structures.
1900 TRACE("() - Initializing the COM libraries\n");
1902 /* we may need to defer this until after apartment initialisation */
1903 RunningObjectTableImpl_Initialize();
1907 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1909 if (!(apt
= info
->apt
))
1911 apt
= apartment_get_or_create(dwCoInit
);
1912 if (!apt
) return E_OUTOFMEMORY
;
1914 else if (!apartment_is_model(apt
, dwCoInit
))
1916 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1917 code then we are probably using the wrong threading model to implement that API. */
1918 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1919 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1920 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1921 return RPC_E_CHANGED_MODE
;
1929 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1934 /***********************************************************************
1935 * CoUninitialize [OLE32.@]
1937 * This method will decrement the refcount on the current apartment, freeing
1938 * the resources associated with it if it is the last thread in the apartment.
1939 * If the last apartment is freed, the function will additionally release
1940 * any COM resources associated with the process.
1950 void WINAPI DECLSPEC_HOTPATCH
CoUninitialize(void)
1952 struct oletls
* info
= COM_CurrentInfo();
1957 /* will only happen on OOM */
1961 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1966 ERR("Mismatched CoUninitialize\n");
1969 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1975 apartment_release(info
->apt
);
1980 * Decrease the reference count.
1981 * If we are back to 0 locks on the COM library, make sure we free
1982 * all the associated data structures.
1984 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
1987 TRACE("() - Releasing the COM libraries\n");
1989 RunningObjectTableImpl_UnInitialize();
1991 else if (lCOMRefCnt
<1) {
1992 ERR( "CoUninitialize() - not CoInitialized.\n" );
1993 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
1996 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1999 /******************************************************************************
2000 * CoDisconnectObject [OLE32.@]
2002 * Disconnects all connections to this object from remote processes. Dispatches
2003 * pending RPCs while blocking new RPCs from occurring, and then calls
2004 * IMarshal::DisconnectObject on the given object.
2006 * Typically called when the object server is forced to shut down, for instance by
2010 * lpUnk [I] The object whose stub should be disconnected.
2011 * reserved [I] Reserved. Should be set to 0.
2015 * Failure: HRESULT code.
2018 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2020 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2022 struct stub_manager
*manager
;
2027 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2029 if (!lpUnk
) return E_INVALIDARG
;
2031 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2034 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2035 IMarshal_Release(marshal
);
2039 apt
= COM_CurrentApt();
2041 return CO_E_NOTINITIALIZED
;
2043 manager
= get_stub_manager_from_object(apt
, lpUnk
, FALSE
);
2045 stub_manager_disconnect(manager
);
2046 /* Release stub manager twice, to remove the apartment reference. */
2047 stub_manager_int_release(manager
);
2048 stub_manager_int_release(manager
);
2051 /* Note: native is pretty broken here because it just silently
2052 * fails, without returning an appropriate error code if the object was
2053 * not found, making apps think that the object was disconnected, when
2054 * it actually wasn't */
2059 /******************************************************************************
2060 * CoCreateGuid [OLE32.@]
2062 * Simply forwards to UuidCreate in RPCRT4.
2065 * pguid [O] Points to the GUID to initialize.
2069 * Failure: HRESULT code.
2074 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
2078 if(!pguid
) return E_INVALIDARG
;
2080 status
= UuidCreate(pguid
);
2081 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2082 return HRESULT_FROM_WIN32( status
);
2085 static inline BOOL
is_valid_hex(WCHAR c
)
2087 if (!(((c
>= '0') && (c
<= '9')) ||
2088 ((c
>= 'a') && (c
<= 'f')) ||
2089 ((c
>= 'A') && (c
<= 'F'))))
2094 static const BYTE guid_conv_table
[256] =
2096 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2097 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2099 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2100 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2102 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2105 /* conversion helper for CLSIDFromString/IIDFromString */
2106 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2110 if (!s
|| s
[0]!='{') {
2111 memset( id
, 0, sizeof (CLSID
) );
2116 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2118 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2121 for (i
= 1; i
< 9; i
++) {
2122 if (!is_valid_hex(s
[i
])) return FALSE
;
2123 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2125 if (s
[9]!='-') return FALSE
;
2128 for (i
= 10; i
< 14; i
++) {
2129 if (!is_valid_hex(s
[i
])) return FALSE
;
2130 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2132 if (s
[14]!='-') return FALSE
;
2135 for (i
= 15; i
< 19; i
++) {
2136 if (!is_valid_hex(s
[i
])) return FALSE
;
2137 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2139 if (s
[19]!='-') return FALSE
;
2141 for (i
= 20; i
< 37; i
+=2) {
2143 if (s
[i
]!='-') return FALSE
;
2146 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2147 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2150 if (s
[37] == '}' && s
[38] == '\0')
2156 /*****************************************************************************/
2158 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2160 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2161 WCHAR buf2
[CHARS_IN_GUID
];
2162 LONG buf2len
= sizeof(buf2
);
2166 memset(clsid
, 0, sizeof(*clsid
));
2167 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2168 if (!buf
) return E_OUTOFMEMORY
;
2169 strcpyW( buf
, progid
);
2170 strcatW( buf
, clsidW
);
2171 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2173 HeapFree(GetProcessHeap(),0,buf
);
2174 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2175 return CO_E_CLASSSTRING
;
2177 HeapFree(GetProcessHeap(),0,buf
);
2179 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2182 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2183 return CO_E_CLASSSTRING
;
2186 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2189 /******************************************************************************
2190 * CLSIDFromString [OLE32.@]
2192 * Converts a unique identifier from its string representation into
2196 * idstr [I] The string representation of the GUID.
2197 * id [O] GUID converted from the string.
2201 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2206 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2208 HRESULT ret
= CO_E_CLASSSTRING
;
2212 return E_INVALIDARG
;
2214 if (guid_from_string(idstr
, id
))
2217 /* It appears a ProgID is also valid */
2218 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2225 /******************************************************************************
2226 * IIDFromString [OLE32.@]
2228 * Converts an interface identifier from its string representation to
2232 * idstr [I] The string representation of the GUID.
2233 * id [O] IID converted from the string.
2237 * CO_E_IIDSTRING if idstr is not a valid IID
2242 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2244 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2248 memset(iid
, 0, sizeof(*iid
));
2252 /* length mismatch is a special case */
2253 if (strlenW(s
) + 1 != CHARS_IN_GUID
)
2254 return E_INVALIDARG
;
2257 return CO_E_IIDSTRING
;
2259 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2262 /******************************************************************************
2263 * StringFromCLSID [OLE32.@]
2264 * StringFromIID [OLE32.@]
2266 * Converts a GUID into the respective string representation.
2267 * The target string is allocated using the OLE IMalloc.
2270 * id [I] the GUID to be converted.
2271 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2278 * StringFromGUID2, CLSIDFromString
2280 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2282 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2283 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2287 /******************************************************************************
2288 * StringFromGUID2 [OLE32.@]
2290 * Modified version of StringFromCLSID that allows you to specify max
2294 * id [I] GUID to convert to string.
2295 * str [O] Buffer where the result will be stored.
2296 * cmax [I] Size of the buffer in characters.
2299 * Success: The length of the resulting string in characters.
2302 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2304 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2305 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2306 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2307 '%','0','2','X','%','0','2','X','}',0 };
2308 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2309 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2310 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2311 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2312 return CHARS_IN_GUID
;
2315 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2316 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2318 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2319 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2323 strcpyW(path
, wszCLSIDSlash
);
2324 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2325 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2326 if (res
== ERROR_FILE_NOT_FOUND
)
2327 return REGDB_E_CLASSNOTREG
;
2328 else if (res
!= ERROR_SUCCESS
)
2329 return REGDB_E_READREGDB
;
2337 res
= open_classes_key(key
, keyname
, access
, subkey
);
2339 if (res
== ERROR_FILE_NOT_FOUND
)
2340 return REGDB_E_KEYMISSING
;
2341 else if (res
!= ERROR_SUCCESS
)
2342 return REGDB_E_READREGDB
;
2347 /* open HKCR\\AppId\\{string form of appid clsid} key */
2348 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2350 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2351 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2353 WCHAR buf
[CHARS_IN_GUID
];
2354 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2360 /* read the AppID value under the class's key */
2361 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2366 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2368 if (res
== ERROR_FILE_NOT_FOUND
)
2369 return REGDB_E_KEYMISSING
;
2370 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2371 return REGDB_E_READREGDB
;
2373 strcpyW(keyname
, szAppIdKey
);
2374 strcatW(keyname
, buf
);
2375 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2376 if (res
== ERROR_FILE_NOT_FOUND
)
2377 return REGDB_E_KEYMISSING
;
2378 else if (res
!= ERROR_SUCCESS
)
2379 return REGDB_E_READREGDB
;
2384 /******************************************************************************
2385 * ProgIDFromCLSID [OLE32.@]
2387 * Converts a class id into the respective program ID.
2390 * clsid [I] Class ID, as found in registry.
2391 * ppszProgID [O] Associated ProgID.
2396 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2398 HRESULT WINAPI DECLSPEC_HOTPATCH
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2400 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2401 ACTCTX_SECTION_KEYED_DATA data
;
2407 return E_INVALIDARG
;
2411 data
.cbSize
= sizeof(data
);
2412 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2415 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2416 if (comclass
->progid_len
)
2420 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2421 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2423 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2424 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2428 return REGDB_E_CLASSNOTREG
;
2431 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2435 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2436 ret
= REGDB_E_CLASSNOTREG
;
2440 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2443 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2444 ret
= REGDB_E_CLASSNOTREG
;
2445 CoTaskMemFree(*ppszProgID
);
2450 ret
= E_OUTOFMEMORY
;
2457 /******************************************************************************
2458 * CLSIDFromProgID [OLE32.@]
2460 * Converts a program id into the respective GUID.
2463 * progid [I] Unicode program ID, as found in registry.
2464 * clsid [O] Associated CLSID.
2468 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2470 HRESULT WINAPI DECLSPEC_HOTPATCH
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2472 ACTCTX_SECTION_KEYED_DATA data
;
2474 if (!progid
|| !clsid
)
2475 return E_INVALIDARG
;
2477 data
.cbSize
= sizeof(data
);
2478 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2481 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2482 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2487 return clsid_from_string_reg(progid
, clsid
);
2490 /******************************************************************************
2491 * CLSIDFromProgIDEx [OLE32.@]
2493 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2495 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2497 return CLSIDFromProgID(progid
, clsid
);
2500 static HRESULT
get_ps_clsid_from_registry(const WCHAR
* path
, REGSAM access
, CLSID
*pclsid
)
2503 WCHAR value
[CHARS_IN_GUID
];
2508 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, access
, &hkey
))
2509 return REGDB_E_IIDNOTREG
;
2511 len
= sizeof(value
);
2512 if (ERROR_SUCCESS
!= RegQueryValueExW(hkey
, NULL
, NULL
, NULL
, (BYTE
*)value
, &len
))
2513 return REGDB_E_IIDNOTREG
;
2516 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2517 return REGDB_E_IIDNOTREG
;
2522 /*****************************************************************************
2523 * CoGetPSClsid [OLE32.@]
2525 * Retrieves the CLSID of the proxy/stub factory that implements
2526 * IPSFactoryBuffer for the specified interface.
2529 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2530 * pclsid [O] Where to store returned proxy/stub CLSID.
2535 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2539 * The standard marshaller activates the object with the CLSID
2540 * returned and uses the CreateProxy and CreateStub methods on its
2541 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2544 * CoGetPSClsid determines this CLSID by searching the
2545 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2546 * in the registry and any interface id registered by
2547 * CoRegisterPSClsid within the current process.
2551 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2552 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2553 * considered a bug in native unless an application depends on this (unlikely).
2556 * CoRegisterPSClsid.
2558 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2560 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2561 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2562 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2563 APARTMENT
*apt
= COM_CurrentApt();
2564 struct registered_psclsid
*registered_psclsid
;
2565 ACTCTX_SECTION_KEYED_DATA data
;
2567 REGSAM opposite
= (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
;
2570 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2574 ERR("apartment not initialised\n");
2575 return CO_E_NOTINITIALIZED
;
2579 return E_INVALIDARG
;
2581 EnterCriticalSection(&apt
->cs
);
2583 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2584 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2586 *pclsid
= registered_psclsid
->clsid
;
2587 LeaveCriticalSection(&apt
->cs
);
2591 LeaveCriticalSection(&apt
->cs
);
2593 data
.cbSize
= sizeof(data
);
2594 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2597 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2598 *pclsid
= ifaceps
->iid
;
2602 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2603 strcpyW(path
, wszInterface
);
2604 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2605 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2607 hr
= get_ps_clsid_from_registry(path
, 0, pclsid
);
2608 if (FAILED(hr
) && (opposite
== KEY_WOW64_32KEY
||
2609 (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)))
2610 hr
= get_ps_clsid_from_registry(path
, opposite
, pclsid
);
2613 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2615 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2620 /*****************************************************************************
2621 * CoRegisterPSClsid [OLE32.@]
2623 * Register a proxy/stub CLSID for the given interface in the current process
2627 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2628 * rclsid [I] CLSID of the proxy/stub.
2632 * Failure: E_OUTOFMEMORY
2636 * This function does not add anything to the registry and the effects are
2637 * limited to the lifetime of the current process.
2642 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2644 APARTMENT
*apt
= COM_CurrentApt();
2645 struct registered_psclsid
*registered_psclsid
;
2647 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2651 ERR("apartment not initialised\n");
2652 return CO_E_NOTINITIALIZED
;
2655 EnterCriticalSection(&apt
->cs
);
2657 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2658 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2660 registered_psclsid
->clsid
= *rclsid
;
2661 LeaveCriticalSection(&apt
->cs
);
2665 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2666 if (!registered_psclsid
)
2668 LeaveCriticalSection(&apt
->cs
);
2669 return E_OUTOFMEMORY
;
2672 registered_psclsid
->iid
= *riid
;
2673 registered_psclsid
->clsid
= *rclsid
;
2674 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
2676 LeaveCriticalSection(&apt
->cs
);
2683 * COM_GetRegisteredClassObject
2685 * This internal method is used to scan the registered class list to
2686 * find a class object.
2689 * rclsid Class ID of the class to find.
2690 * dwClsContext Class context to match.
2691 * ppv [out] returns a pointer to the class object. Complying
2692 * to normal COM usage, this method will increase the
2693 * reference count on this object.
2695 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2696 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2698 HRESULT hr
= S_FALSE
;
2699 RegisteredClass
*curClass
;
2701 EnterCriticalSection( &csRegisteredClassList
);
2703 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2706 * Check if we have a match on the class ID and context.
2708 if ((apt
->oxid
== curClass
->apartment_id
) &&
2709 (dwClsContext
& curClass
->runContext
) &&
2710 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2713 * We have a match, return the pointer to the class object.
2715 *ppUnk
= curClass
->classObject
;
2717 IUnknown_AddRef(curClass
->classObject
);
2724 LeaveCriticalSection( &csRegisteredClassList
);
2729 /******************************************************************************
2730 * CoRegisterClassObject [OLE32.@]
2732 * Registers the class object for a given class ID. Servers housed in EXE
2733 * files use this method instead of exporting DllGetClassObject to allow
2734 * other code to connect to their objects.
2737 * rclsid [I] CLSID of the object to register.
2738 * pUnk [I] IUnknown of the object.
2739 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2740 * flags [I] REGCLS flags indicating how connections are made.
2741 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2745 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2746 * CO_E_OBJISREG if the object is already registered. We should not return this.
2749 * CoRevokeClassObject, CoGetClassObject
2752 * In-process objects are only registered for the current apartment.
2753 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2754 * in other apartments.
2757 * MSDN claims that multiple interface registrations are legal, but we
2758 * can't do that with our current implementation.
2760 HRESULT WINAPI
CoRegisterClassObject(
2765 LPDWORD lpdwRegister
)
2767 static LONG next_cookie
;
2768 RegisteredClass
* newClass
;
2769 LPUNKNOWN foundObject
;
2773 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2774 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2776 if ( (lpdwRegister
==0) || (pUnk
==0) )
2777 return E_INVALIDARG
;
2779 apt
= COM_CurrentApt();
2782 ERR("COM was not initialized\n");
2783 return CO_E_NOTINITIALIZED
;
2788 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2789 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2790 if (flags
& REGCLS_MULTIPLEUSE
)
2791 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2794 * First, check if the class is already registered.
2795 * If it is, this should cause an error.
2797 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2799 if (flags
& REGCLS_MULTIPLEUSE
) {
2800 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2801 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2802 IUnknown_Release(foundObject
);
2805 IUnknown_Release(foundObject
);
2806 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2807 return CO_E_OBJISREG
;
2810 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2811 if ( newClass
== NULL
)
2812 return E_OUTOFMEMORY
;
2814 newClass
->classIdentifier
= *rclsid
;
2815 newClass
->apartment_id
= apt
->oxid
;
2816 newClass
->runContext
= dwClsContext
;
2817 newClass
->connectFlags
= flags
;
2818 newClass
->RpcRegistration
= NULL
;
2820 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2821 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2824 * Since we're making a copy of the object pointer, we have to increase its
2827 newClass
->classObject
= pUnk
;
2828 IUnknown_AddRef(newClass
->classObject
);
2830 EnterCriticalSection( &csRegisteredClassList
);
2831 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2832 LeaveCriticalSection( &csRegisteredClassList
);
2834 *lpdwRegister
= newClass
->dwCookie
;
2836 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2837 IStream
*marshal_stream
;
2839 hr
= get_local_server_stream(apt
, &marshal_stream
);
2843 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2845 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2846 &newClass
->RpcRegistration
);
2847 IStream_Release(marshal_stream
);
2852 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2856 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2857 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2858 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2859 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2860 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2861 DWORD dwLength
= sizeof(threading_model
);
2865 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2866 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2867 threading_model
[0] = '\0';
2869 if (!strcmpiW(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2870 if (!strcmpiW(threading_model
, wszFree
)) return ThreadingModel_Free
;
2871 if (!strcmpiW(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2873 /* there's not specific handling for this case */
2874 if (threading_model
[0]) return ThreadingModel_Neutral
;
2875 return ThreadingModel_No
;
2878 return data
->u
.actctx
.data
->model
;
2881 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2882 REFCLSID rclsid
, REFIID riid
,
2883 BOOL hostifnecessary
, void **ppv
)
2885 WCHAR dllpath
[MAX_PATH
+1];
2886 BOOL apartment_threaded
;
2888 if (hostifnecessary
)
2890 enum comclass_threadingmodel model
= get_threading_model(regdata
);
2892 if (model
== ThreadingModel_Apartment
)
2894 apartment_threaded
= TRUE
;
2895 if (apt
->multi_threaded
)
2896 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2898 else if (model
== ThreadingModel_Free
)
2900 apartment_threaded
= FALSE
;
2901 if (!apt
->multi_threaded
)
2902 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2904 /* everything except "Apartment", "Free" and "Both" */
2905 else if (model
!= ThreadingModel_Both
)
2907 apartment_threaded
= TRUE
;
2908 /* everything else is main-threaded */
2909 if (model
!= ThreadingModel_No
)
2910 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
2912 if (apt
->multi_threaded
|| !apt
->main
)
2913 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
2916 apartment_threaded
= FALSE
;
2919 apartment_threaded
= !apt
->multi_threaded
;
2921 if (COM_RegReadPath(regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2923 /* failure: CLSID is not found in registry */
2924 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2925 return REGDB_E_CLASSNOTREG
;
2928 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2932 /***********************************************************************
2933 * CoGetClassObject [OLE32.@]
2935 * Creates an object of the specified class.
2938 * rclsid [I] Class ID to create an instance of.
2939 * dwClsContext [I] Flags to restrict the location of the created instance.
2940 * pServerInfo [I] Optional. Details for connecting to a remote server.
2941 * iid [I] The ID of the interface of the instance to return.
2942 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2946 * Failure: HRESULT code.
2949 * The dwClsContext parameter can be one or more of the following:
2950 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2951 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2952 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2953 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2956 * CoCreateInstance()
2958 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
2959 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2960 REFIID iid
, LPVOID
*ppv
)
2962 struct class_reg_data clsreg
;
2963 IUnknown
*regClassObject
;
2964 HRESULT hres
= E_UNEXPECTED
;
2966 BOOL release_apt
= FALSE
;
2968 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2971 return E_INVALIDARG
;
2975 if (!(apt
= COM_CurrentApt()))
2977 if (!(apt
= apartment_find_multi_threaded()))
2979 ERR("apartment not initialised\n");
2980 return CO_E_NOTINITIALIZED
;
2986 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2987 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2990 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2992 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
2994 if (release_apt
) apartment_release(apt
);
2995 return FTMarshalCF_Create(iid
, ppv
);
2999 if (CLSCTX_INPROC
& dwClsContext
)
3001 ACTCTX_SECTION_KEYED_DATA data
;
3003 data
.cbSize
= sizeof(data
);
3004 /* search activation context first */
3005 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
3006 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
3009 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
3011 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
3012 clsreg
.u
.actctx
.data
= data
.lpData
;
3013 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
3014 clsreg
.hkey
= FALSE
;
3016 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3017 ReleaseActCtx(data
.hActCtx
);
3018 if (release_apt
) apartment_release(apt
);
3024 * First, try and see if we can't match the class ID with one of the
3025 * registered classes.
3027 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
3030 /* Get the required interface from the retrieved pointer. */
3031 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3034 * Since QI got another reference on the pointer, we want to release the
3035 * one we already have. If QI was unsuccessful, this will release the object. This
3036 * is good since we are not returning it in the "out" parameter.
3038 IUnknown_Release(regClassObject
);
3039 if (release_apt
) apartment_release(apt
);
3043 /* First try in-process server */
3044 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3046 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3049 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3052 if (hres
== REGDB_E_CLASSNOTREG
)
3053 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3054 else if (hres
== REGDB_E_KEYMISSING
)
3056 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3057 hres
= REGDB_E_CLASSNOTREG
;
3061 if (SUCCEEDED(hres
))
3063 clsreg
.u
.hkey
= hkey
;
3066 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3070 /* return if we got a class, otherwise fall through to one of the
3072 if (SUCCEEDED(hres
))
3074 if (release_apt
) apartment_release(apt
);
3079 /* Next try in-process handler */
3080 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3082 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3085 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3088 if (hres
== REGDB_E_CLASSNOTREG
)
3089 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3090 else if (hres
== REGDB_E_KEYMISSING
)
3092 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3093 hres
= REGDB_E_CLASSNOTREG
;
3097 if (SUCCEEDED(hres
))
3099 clsreg
.u
.hkey
= hkey
;
3102 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3106 /* return if we got a class, otherwise fall through to one of the
3108 if (SUCCEEDED(hres
))
3110 if (release_apt
) apartment_release(apt
);
3114 if (release_apt
) apartment_release(apt
);
3116 /* Next try out of process */
3117 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3119 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3120 if (SUCCEEDED(hres
))
3124 /* Finally try remote: this requires networked DCOM (a lot of work) */
3125 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3127 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3128 hres
= REGDB_E_CLASSNOTREG
;
3132 ERR("no class object %s could be created for context 0x%x\n",
3133 debugstr_guid(rclsid
), dwClsContext
);
3137 /***********************************************************************
3138 * CoResumeClassObjects (OLE32.@)
3140 * Resumes all class objects registered with REGCLS_SUSPENDED.
3144 * Failure: HRESULT code.
3146 HRESULT WINAPI
CoResumeClassObjects(void)
3152 /***********************************************************************
3153 * CoCreateInstance [OLE32.@]
3155 * Creates an instance of the specified class.
3158 * rclsid [I] Class ID to create an instance of.
3159 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3160 * dwClsContext [I] Flags to restrict the location of the created instance.
3161 * iid [I] The ID of the interface of the instance to return.
3162 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3166 * Failure: HRESULT code.
3169 * The dwClsContext parameter can be one or more of the following:
3170 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3171 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3172 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3173 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3175 * Aggregation is the concept of deferring the IUnknown of an object to another
3176 * object. This allows a separate object to behave as though it was part of
3177 * the object and to allow this the pUnkOuter parameter can be set. Note that
3178 * not all objects support having an outer of unknown.
3181 * CoGetClassObject()
3183 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3185 LPUNKNOWN pUnkOuter
,
3190 MULTI_QI multi_qi
= { iid
};
3193 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3194 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3199 hres
= CoCreateInstanceEx(rclsid
, pUnkOuter
, dwClsContext
, NULL
, 1, &multi_qi
);
3200 *ppv
= multi_qi
.pItf
;
3204 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
)
3208 for (i
= 0; i
< count
; i
++)
3211 mqi
[i
].hr
= E_NOINTERFACE
;
3215 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
, BOOL include_unk
)
3217 ULONG index
= 0, fetched
= 0;
3223 index
= fetched
= 1;
3226 for (; index
< count
; index
++)
3228 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3229 if (mqi
[index
].hr
== S_OK
)
3234 IUnknown_Release(unk
);
3237 return E_NOINTERFACE
;
3239 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3242 /***********************************************************************
3243 * CoCreateInstanceEx [OLE32.@]
3245 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstanceEx(
3247 LPUNKNOWN pUnkOuter
,
3249 COSERVERINFO
* pServerInfo
,
3253 IUnknown
*unk
= NULL
;
3259 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid
), pUnkOuter
, dwClsContext
, pServerInfo
, cmq
, pResults
);
3261 if (!cmq
|| !pResults
)
3262 return E_INVALIDARG
;
3265 FIXME("() non-NULL pServerInfo not supported!\n");
3267 init_multi_qi(cmq
, pResults
);
3269 hres
= CoGetTreatAsClass(rclsid
, &clsid
);
3273 if (!(apt
= COM_CurrentApt()))
3275 if (!(apt
= apartment_find_multi_threaded()))
3277 ERR("apartment not initialised\n");
3278 return CO_E_NOTINITIALIZED
;
3280 apartment_release(apt
);
3284 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3286 if (IsEqualIID(&clsid
, &CLSID_StdGlobalInterfaceTable
))
3288 IGlobalInterfaceTable
*git
= get_std_git();
3289 TRACE("Retrieving GIT\n");
3290 return return_multi_qi((IUnknown
*)git
, cmq
, pResults
, FALSE
);
3293 if (IsEqualCLSID(&clsid
, &CLSID_ManualResetEvent
)) {
3294 hres
= ManualResetEvent_Construct(pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3297 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3301 * Get a class factory to construct the object we want.
3303 hres
= CoGetClassObject(&clsid
, dwClsContext
, NULL
, &IID_IClassFactory
, (void**)&cf
);
3308 * Create the object and don't forget to release the factory
3310 hres
= IClassFactory_CreateInstance(cf
, pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3311 IClassFactory_Release(cf
);
3314 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3315 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid
));
3317 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3318 debugstr_guid(pResults
[0].pIID
),
3319 debugstr_guid(&clsid
),hres
);
3323 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3326 /***********************************************************************
3327 * CoGetInstanceFromFile [OLE32.@]
3329 HRESULT WINAPI
CoGetInstanceFromFile(
3330 COSERVERINFO
*server_info
,
3340 IPersistFile
*pf
= NULL
;
3341 IUnknown
* unk
= NULL
;
3345 if (count
== 0 || !results
)
3346 return E_INVALIDARG
;
3349 FIXME("() non-NULL server_info not supported\n");
3351 init_multi_qi(count
, results
);
3353 /* optionally get CLSID from a file */
3356 hr
= GetClassFile(filename
, &clsid
);
3359 ERR("failed to get CLSID from a file\n");
3366 hr
= CoCreateInstance(rclsid
,
3375 /* init from file */
3376 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3378 ERR("failed to get IPersistFile\n");
3382 IPersistFile_Load(pf
, filename
, grfmode
);
3383 IPersistFile_Release(pf
);
3386 return return_multi_qi(unk
, count
, results
, FALSE
);
3389 /***********************************************************************
3390 * CoGetInstanceFromIStorage [OLE32.@]
3392 HRESULT WINAPI
CoGetInstanceFromIStorage(
3393 COSERVERINFO
*server_info
,
3402 IPersistStorage
*ps
= NULL
;
3403 IUnknown
* unk
= NULL
;
3407 if (count
== 0 || !results
|| !storage
)
3408 return E_INVALIDARG
;
3411 FIXME("() non-NULL server_info not supported\n");
3413 init_multi_qi(count
, results
);
3415 /* optionally get CLSID from a file */
3418 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3419 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3422 ERR("failed to get CLSID from a file\n");
3426 rclsid
= &stat
.clsid
;
3429 hr
= CoCreateInstance(rclsid
,
3438 /* init from IStorage */
3439 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3441 ERR("failed to get IPersistStorage\n");
3445 IPersistStorage_Load(ps
, storage
);
3446 IPersistStorage_Release(ps
);
3449 return return_multi_qi(unk
, count
, results
, FALSE
);
3452 /***********************************************************************
3453 * CoLoadLibrary (OLE32.@)
3458 * lpszLibName [I] Path to library.
3459 * bAutoFree [I] Whether the library should automatically be freed.
3462 * Success: Handle to loaded library.
3466 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3468 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3470 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3472 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3475 /***********************************************************************
3476 * CoFreeLibrary [OLE32.@]
3478 * Unloads a library from memory.
3481 * hLibrary [I] Handle to library to unload.
3487 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3489 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3491 FreeLibrary(hLibrary
);
3495 /***********************************************************************
3496 * CoFreeAllLibraries [OLE32.@]
3498 * Function for backwards compatibility only. Does nothing.
3504 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3506 void WINAPI
CoFreeAllLibraries(void)
3511 /***********************************************************************
3512 * CoFreeUnusedLibrariesEx [OLE32.@]
3514 * Frees any previously unused libraries whose delay has expired and marks
3515 * currently unused libraries for unloading. Unused are identified as those that
3516 * return S_OK from their DllCanUnloadNow function.
3519 * dwUnloadDelay [I] Unload delay in milliseconds.
3520 * dwReserved [I] Reserved. Set to 0.
3526 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3528 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3530 struct apartment
*apt
= COM_CurrentApt();
3533 ERR("apartment not initialised\n");
3537 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3540 /***********************************************************************
3541 * CoFreeUnusedLibraries [OLE32.@]
3543 * Frees any unused libraries. Unused are identified as those that return
3544 * S_OK from their DllCanUnloadNow function.
3550 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3552 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibraries(void)
3554 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3557 /***********************************************************************
3558 * CoFileTimeNow [OLE32.@]
3560 * Retrieves the current time in FILETIME format.
3563 * lpFileTime [O] The current time.
3568 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3570 GetSystemTimeAsFileTime( lpFileTime
);
3574 /******************************************************************************
3575 * CoLockObjectExternal [OLE32.@]
3577 * Increments or decrements the external reference count of a stub object.
3580 * pUnk [I] Stub object.
3581 * fLock [I] If TRUE then increments the external ref-count,
3582 * otherwise decrements.
3583 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3584 * calling CoDisconnectObject.
3588 * Failure: HRESULT code.
3591 * If fLock is TRUE and an object is passed in that doesn't have a stub
3592 * manager then a new stub manager is created for the object.
3594 HRESULT WINAPI
CoLockObjectExternal(
3597 BOOL fLastUnlockReleases
)
3599 struct stub_manager
*stubmgr
;
3600 struct apartment
*apt
;
3602 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3603 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3605 apt
= COM_CurrentApt();
3606 if (!apt
) return CO_E_NOTINITIALIZED
;
3608 stubmgr
= get_stub_manager_from_object(apt
, pUnk
, fLock
);
3611 WARN("stub object not found %p\n", pUnk
);
3612 /* Note: native is pretty broken here because it just silently
3613 * fails, without returning an appropriate error code, making apps
3614 * think that the object was disconnected, when it actually wasn't */
3619 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3621 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3623 stub_manager_int_release(stubmgr
);
3627 /***********************************************************************
3628 * CoInitializeWOW (OLE32.@)
3630 * WOW equivalent of CoInitialize?
3639 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3641 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3645 /***********************************************************************
3646 * CoGetState [OLE32.@]
3648 * Retrieves the thread state object previously stored by CoSetState().
3651 * ppv [I] Address where pointer to object will be stored.
3655 * Failure: E_OUTOFMEMORY.
3658 * Crashes on all invalid ppv addresses, including NULL.
3659 * If the function returns a non-NULL object then the caller must release its
3660 * reference on the object when the object is no longer required.
3665 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3667 struct oletls
*info
= COM_CurrentInfo();
3668 if (!info
) return E_OUTOFMEMORY
;
3674 IUnknown_AddRef(info
->state
);
3676 TRACE("apt->state=%p\n", info
->state
);
3682 /***********************************************************************
3683 * CoSetState [OLE32.@]
3685 * Sets the thread state object.
3688 * pv [I] Pointer to state object to be stored.
3691 * The system keeps a reference on the object while the object stored.
3695 * Failure: E_OUTOFMEMORY.
3697 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3699 struct oletls
*info
= COM_CurrentInfo();
3700 if (!info
) return E_OUTOFMEMORY
;
3702 if (pv
) IUnknown_AddRef(pv
);
3706 TRACE("-- release %p now\n", info
->state
);
3707 IUnknown_Release(info
->state
);
3716 /******************************************************************************
3717 * CoTreatAsClass [OLE32.@]
3719 * Sets the TreatAs value of a class.
3722 * clsidOld [I] Class to set TreatAs value on.
3723 * clsidNew [I] The class the clsidOld should be treated as.
3727 * Failure: HRESULT code.
3732 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3734 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3735 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3737 WCHAR szClsidNew
[CHARS_IN_GUID
];
3739 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3740 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3743 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3747 if (IsEqualGUID( clsidOld
, clsidNew
))
3749 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3750 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3752 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3754 res
= REGDB_E_WRITEREGDB
;
3760 if(RegDeleteKeyW(hkey
, wszTreatAs
))
3761 res
= REGDB_E_WRITEREGDB
;
3767 if(IsEqualGUID(clsidNew
, &CLSID_NULL
)){
3768 RegDeleteKeyW(hkey
, wszTreatAs
);
3770 if(!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
))){
3771 WARN("StringFromGUID2 failed\n");
3776 if(RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)) != ERROR_SUCCESS
){
3777 WARN("RegSetValue failed\n");
3778 res
= REGDB_E_WRITEREGDB
;
3785 if (hkey
) RegCloseKey(hkey
);
3789 /******************************************************************************
3790 * CoGetTreatAsClass [OLE32.@]
3792 * Gets the TreatAs value of a class.
3795 * clsidOld [I] Class to get the TreatAs value of.
3796 * clsidNew [I] The class the clsidOld should be treated as.
3800 * Failure: HRESULT code.
3805 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3807 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3809 WCHAR szClsidNew
[CHARS_IN_GUID
];
3811 LONG len
= sizeof(szClsidNew
);
3813 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3814 *clsidNew
= *clsidOld
; /* copy over old value */
3816 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3822 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3827 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3829 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3831 if (hkey
) RegCloseKey(hkey
);
3835 /******************************************************************************
3836 * CoGetCurrentProcess [OLE32.@]
3838 * Gets the current process ID.
3841 * The current process ID.
3844 * Is DWORD really the correct return type for this function?
3846 DWORD WINAPI
CoGetCurrentProcess(void)
3848 return GetCurrentProcessId();
3851 /******************************************************************************
3852 * CoRegisterMessageFilter [OLE32.@]
3854 * Registers a message filter.
3857 * lpMessageFilter [I] Pointer to interface.
3858 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3862 * Failure: HRESULT code.
3865 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3866 * lpMessageFilter removes the message filter.
3868 * If lplpMessageFilter is not NULL the previous message filter will be
3869 * returned in the memory pointer to this parameter and the caller is
3870 * responsible for releasing the object.
3872 * The current thread be in an apartment otherwise the function will crash.
3874 HRESULT WINAPI
CoRegisterMessageFilter(
3875 LPMESSAGEFILTER lpMessageFilter
,
3876 LPMESSAGEFILTER
*lplpMessageFilter
)
3878 struct apartment
*apt
;
3879 IMessageFilter
*lpOldMessageFilter
;
3881 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3883 apt
= COM_CurrentApt();
3885 /* can't set a message filter in a multi-threaded apartment */
3886 if (!apt
|| apt
->multi_threaded
)
3888 WARN("can't set message filter in MTA or uninitialized apt\n");
3889 return CO_E_NOT_SUPPORTED
;
3892 if (lpMessageFilter
)
3893 IMessageFilter_AddRef(lpMessageFilter
);
3895 EnterCriticalSection(&apt
->cs
);
3897 lpOldMessageFilter
= apt
->filter
;
3898 apt
->filter
= lpMessageFilter
;
3900 LeaveCriticalSection(&apt
->cs
);
3902 if (lplpMessageFilter
)
3903 *lplpMessageFilter
= lpOldMessageFilter
;
3904 else if (lpOldMessageFilter
)
3905 IMessageFilter_Release(lpOldMessageFilter
);
3910 /***********************************************************************
3911 * CoIsOle1Class [OLE32.@]
3913 * Determines whether the specified class an OLE v1 class.
3916 * clsid [I] Class to test.
3919 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3921 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3923 FIXME("%s\n", debugstr_guid(clsid
));
3927 /***********************************************************************
3928 * IsEqualGUID [OLE32.@]
3930 * Compares two Unique Identifiers.
3933 * rguid1 [I] The first GUID to compare.
3934 * rguid2 [I] The other GUID to compare.
3940 BOOL WINAPI
IsEqualGUID(
3944 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3947 /***********************************************************************
3948 * CoInitializeSecurity [OLE32.@]
3950 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3951 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3952 void* pReserved1
, DWORD dwAuthnLevel
,
3953 DWORD dwImpLevel
, void* pReserved2
,
3954 DWORD dwCapabilities
, void* pReserved3
)
3956 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3957 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3958 dwCapabilities
, pReserved3
);
3962 /***********************************************************************
3963 * CoSuspendClassObjects [OLE32.@]
3965 * Suspends all registered class objects to prevent further requests coming in
3966 * for those objects.
3970 * Failure: HRESULT code.
3972 HRESULT WINAPI
CoSuspendClassObjects(void)
3978 /***********************************************************************
3979 * CoAddRefServerProcess [OLE32.@]
3981 * Helper function for incrementing the reference count of a local-server
3985 * New reference count.
3988 * CoReleaseServerProcess().
3990 ULONG WINAPI
CoAddRefServerProcess(void)
3996 EnterCriticalSection(&csRegisteredClassList
);
3997 refs
= ++s_COMServerProcessReferences
;
3998 LeaveCriticalSection(&csRegisteredClassList
);
4000 TRACE("refs before: %d\n", refs
- 1);
4005 /***********************************************************************
4006 * CoReleaseServerProcess [OLE32.@]
4008 * Helper function for decrementing the reference count of a local-server
4012 * New reference count.
4015 * When reference count reaches 0, this function suspends all registered
4016 * classes so no new connections are accepted.
4019 * CoAddRefServerProcess(), CoSuspendClassObjects().
4021 ULONG WINAPI
CoReleaseServerProcess(void)
4027 EnterCriticalSection(&csRegisteredClassList
);
4029 refs
= --s_COMServerProcessReferences
;
4030 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4032 LeaveCriticalSection(&csRegisteredClassList
);
4034 TRACE("refs after: %d\n", refs
);
4039 /***********************************************************************
4040 * CoIsHandlerConnected [OLE32.@]
4042 * Determines whether a proxy is connected to a remote stub.
4045 * pUnk [I] Pointer to object that may or may not be connected.
4048 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4051 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4053 FIXME("%p\n", pUnk
);
4058 /***********************************************************************
4059 * CoAllowSetForegroundWindow [OLE32.@]
4062 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4064 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4068 /***********************************************************************
4069 * CoQueryProxyBlanket [OLE32.@]
4071 * Retrieves the security settings being used by a proxy.
4074 * pProxy [I] Pointer to the proxy object.
4075 * pAuthnSvc [O] The type of authentication service.
4076 * pAuthzSvc [O] The type of authorization service.
4077 * ppServerPrincName [O] Optional. The server prinicple name.
4078 * pAuthnLevel [O] The authentication level.
4079 * pImpLevel [O] The impersonation level.
4080 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4081 * pCapabilities [O] Flags affecting the security behaviour.
4085 * Failure: HRESULT code.
4088 * CoCopyProxy, CoSetProxyBlanket.
4090 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4091 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4092 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4094 IClientSecurity
*pCliSec
;
4097 TRACE("%p\n", pProxy
);
4099 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4102 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4103 pAuthzSvc
, ppServerPrincName
,
4104 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4106 IClientSecurity_Release(pCliSec
);
4109 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4113 /***********************************************************************
4114 * CoSetProxyBlanket [OLE32.@]
4116 * Sets the security settings for a proxy.
4119 * pProxy [I] Pointer to the proxy object.
4120 * AuthnSvc [I] The type of authentication service.
4121 * AuthzSvc [I] The type of authorization service.
4122 * pServerPrincName [I] The server prinicple name.
4123 * AuthnLevel [I] The authentication level.
4124 * ImpLevel [I] The impersonation level.
4125 * pAuthInfo [I] Information specific to the authorization/authentication service.
4126 * Capabilities [I] Flags affecting the security behaviour.
4130 * Failure: HRESULT code.
4133 * CoQueryProxyBlanket, CoCopyProxy.
4135 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4136 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4137 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4139 IClientSecurity
*pCliSec
;
4142 TRACE("%p\n", pProxy
);
4144 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4147 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4148 AuthzSvc
, pServerPrincName
,
4149 AuthnLevel
, ImpLevel
, pAuthInfo
,
4151 IClientSecurity_Release(pCliSec
);
4154 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4158 /***********************************************************************
4159 * CoCopyProxy [OLE32.@]
4164 * pProxy [I] Pointer to the proxy object.
4165 * ppCopy [O] Copy of the proxy.
4169 * Failure: HRESULT code.
4172 * CoQueryProxyBlanket, CoSetProxyBlanket.
4174 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4176 IClientSecurity
*pCliSec
;
4179 TRACE("%p\n", pProxy
);
4181 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4184 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4185 IClientSecurity_Release(pCliSec
);
4188 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4193 /***********************************************************************
4194 * CoGetCallContext [OLE32.@]
4196 * Gets the context of the currently executing server call in the current
4200 * riid [I] Context interface to return.
4201 * ppv [O] Pointer to memory that will receive the context on return.
4205 * Failure: HRESULT code.
4207 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4209 struct oletls
*info
= COM_CurrentInfo();
4211 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4214 return E_OUTOFMEMORY
;
4216 if (!info
->call_state
)
4217 return RPC_E_CALL_COMPLETE
;
4219 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4222 /***********************************************************************
4223 * CoSwitchCallContext [OLE32.@]
4225 * Switches the context of the currently executing server call in the current
4229 * pObject [I] Pointer to new context object
4230 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4234 * Failure: HRESULT code.
4236 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4238 struct oletls
*info
= COM_CurrentInfo();
4240 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4243 return E_OUTOFMEMORY
;
4245 *ppOldObject
= info
->call_state
;
4246 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4251 /***********************************************************************
4252 * CoQueryClientBlanket [OLE32.@]
4254 * Retrieves the authentication information about the client of the currently
4255 * executing server call in the current thread.
4258 * pAuthnSvc [O] Optional. The type of authentication service.
4259 * pAuthzSvc [O] Optional. The type of authorization service.
4260 * pServerPrincName [O] Optional. The server prinicple name.
4261 * pAuthnLevel [O] Optional. The authentication level.
4262 * pImpLevel [O] Optional. The impersonation level.
4263 * pPrivs [O] Optional. Information about the privileges of the client.
4264 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4268 * Failure: HRESULT code.
4271 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4273 HRESULT WINAPI
CoQueryClientBlanket(
4276 OLECHAR
**pServerPrincName
,
4279 RPC_AUTHZ_HANDLE
*pPrivs
,
4280 DWORD
*pCapabilities
)
4282 IServerSecurity
*pSrvSec
;
4285 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4286 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4287 pPrivs
, pCapabilities
);
4289 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4292 hr
= IServerSecurity_QueryBlanket(
4293 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4294 pImpLevel
, pPrivs
, pCapabilities
);
4295 IServerSecurity_Release(pSrvSec
);
4301 /***********************************************************************
4302 * CoImpersonateClient [OLE32.@]
4304 * Impersonates the client of the currently executing server call in the
4312 * Failure: HRESULT code.
4315 * If this function fails then the current thread will not be impersonating
4316 * the client and all actions will take place on behalf of the server.
4317 * Therefore, it is important to check the return value from this function.
4320 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4322 HRESULT WINAPI
CoImpersonateClient(void)
4324 IServerSecurity
*pSrvSec
;
4329 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4332 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4333 IServerSecurity_Release(pSrvSec
);
4339 /***********************************************************************
4340 * CoRevertToSelf [OLE32.@]
4342 * Ends the impersonation of the client of the currently executing server
4343 * call in the current thread.
4350 * Failure: HRESULT code.
4353 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4355 HRESULT WINAPI
CoRevertToSelf(void)
4357 IServerSecurity
*pSrvSec
;
4362 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4365 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4366 IServerSecurity_Release(pSrvSec
);
4372 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4374 /* first try to retrieve messages for incoming COM calls to the apartment window */
4375 return (apt
->win
&& PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
)) ||
4376 /* next retrieve other messages necessary for the app to remain responsive */
4377 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4378 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4381 /***********************************************************************
4382 * CoWaitForMultipleHandles [OLE32.@]
4384 * Waits for one or more handles to become signaled.
4387 * dwFlags [I] Flags. See notes.
4388 * dwTimeout [I] Timeout in milliseconds.
4389 * cHandles [I] Number of handles pointed to by pHandles.
4390 * pHandles [I] Handles to wait for.
4391 * lpdwindex [O] Index of handle that was signaled.
4395 * Failure: RPC_S_CALLPENDING on timeout.
4399 * The dwFlags parameter can be zero or more of the following:
4400 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4401 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4404 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4406 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4407 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4410 DWORD start_time
= GetTickCount();
4411 APARTMENT
*apt
= COM_CurrentApt();
4412 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4413 BOOL check_apc
= (dwFlags
& COWAIT_ALERTABLE
) != 0;
4415 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4416 pHandles
, lpdwindex
);
4419 return E_INVALIDARG
;
4424 return E_INVALIDARG
;
4427 return RPC_E_NO_SYNC
;
4431 DWORD now
= GetTickCount();
4434 if (now
- start_time
> dwTimeout
)
4436 hr
= RPC_S_CALLPENDING
;
4442 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4443 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4445 TRACE("waiting for rpc completion or window message\n");
4451 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
4452 (dwFlags
& COWAIT_WAITALL
) != 0, 0, TRUE
);
4456 if (res
== WAIT_TIMEOUT
)
4457 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4458 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4459 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4461 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4466 /* call message filter */
4468 if (COM_CurrentApt()->filter
)
4470 PENDINGTYPE pendingtype
=
4471 COM_CurrentInfo()->pending_call_count_server
?
4472 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4473 DWORD be_handled
= IMessageFilter_MessagePending(
4474 COM_CurrentApt()->filter
, 0 /* FIXME */,
4475 now
- start_time
, pendingtype
);
4476 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4479 case PENDINGMSG_CANCELCALL
:
4480 WARN("call canceled\n");
4481 hr
= RPC_E_CALL_CANCELED
;
4483 case PENDINGMSG_WAITNOPROCESS
:
4484 case PENDINGMSG_WAITDEFPROCESS
:
4486 /* FIXME: MSDN is very vague about the difference
4487 * between WAITNOPROCESS and WAITDEFPROCESS - there
4488 * appears to be none, so it is possibly a left-over
4489 * from the 16-bit world. */
4494 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4495 * so after processing 100 messages we go back to checking the wait handles */
4496 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4498 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4499 TranslateMessage(&msg
);
4500 DispatchMessageW(&msg
);
4501 if (msg
.message
== WM_QUIT
)
4503 TRACE("resending WM_QUIT to outer message loop\n");
4504 PostQuitMessage(msg
.wParam
);
4505 /* no longer need to process messages */
4506 message_loop
= FALSE
;
4515 TRACE("waiting for rpc completion\n");
4517 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4518 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4519 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4525 hr
= RPC_S_CALLPENDING
;
4528 hr
= HRESULT_FROM_WIN32( GetLastError() );
4536 TRACE("-- 0x%08x\n", hr
);
4541 /***********************************************************************
4542 * CoGetObject [OLE32.@]
4544 * Gets the object named by converting the name to a moniker and binding to it.
4547 * pszName [I] String representing the object.
4548 * pBindOptions [I] Parameters affecting the binding to the named object.
4549 * riid [I] Interface to bind to on the objecct.
4550 * ppv [O] On output, the interface riid of the object represented
4555 * Failure: HRESULT code.
4558 * MkParseDisplayName.
4560 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4561 REFIID riid
, void **ppv
)
4568 hr
= CreateBindCtx(0, &pbc
);
4572 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4579 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4582 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4583 IMoniker_Release(pmk
);
4587 IBindCtx_Release(pbc
);
4592 /***********************************************************************
4593 * CoRegisterChannelHook [OLE32.@]
4595 * Registers a process-wide hook that is called during ORPC calls.
4598 * guidExtension [I] GUID of the channel hook to register.
4599 * pChannelHook [I] Channel hook object to register.
4603 * Failure: HRESULT code.
4605 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4607 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4609 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4612 typedef struct Context
4614 IComThreadingInfo IComThreadingInfo_iface
;
4615 IContextCallback IContextCallback_iface
;
4616 IObjContext IObjContext_iface
;
4621 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4623 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4626 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4628 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4631 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4633 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4636 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4640 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4641 IsEqualIID(riid
, &IID_IUnknown
))
4643 *ppv
= &iface
->IComThreadingInfo_iface
;
4645 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4647 *ppv
= &iface
->IContextCallback_iface
;
4649 else if (IsEqualIID(riid
, &IID_IObjContext
))
4651 *ppv
= &iface
->IObjContext_iface
;
4656 IUnknown_AddRef((IUnknown
*)*ppv
);
4660 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4661 return E_NOINTERFACE
;
4664 static ULONG
Context_AddRef(Context
*This
)
4666 return InterlockedIncrement(&This
->refs
);
4669 static ULONG
Context_Release(Context
*This
)
4671 ULONG refs
= InterlockedDecrement(&This
->refs
);
4673 HeapFree(GetProcessHeap(), 0, This
);
4677 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4679 Context
*This
= impl_from_IComThreadingInfo(iface
);
4680 return Context_QueryInterface(This
, riid
, ppv
);
4683 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4685 Context
*This
= impl_from_IComThreadingInfo(iface
);
4686 return Context_AddRef(This
);
4689 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4691 Context
*This
= impl_from_IComThreadingInfo(iface
);
4692 return Context_Release(This
);
4695 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4697 Context
*This
= impl_from_IComThreadingInfo(iface
);
4699 TRACE("(%p)\n", apttype
);
4701 *apttype
= This
->apttype
;
4705 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4707 Context
*This
= impl_from_IComThreadingInfo(iface
);
4709 TRACE("(%p)\n", thdtype
);
4711 switch (This
->apttype
)
4714 case APTTYPE_MAINSTA
:
4715 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4718 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4724 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4726 FIXME("(%p): stub\n", logical_thread_id
);
4730 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4732 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4736 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4738 Context_CTI_QueryInterface
,
4740 Context_CTI_Release
,
4741 Context_CTI_GetCurrentApartmentType
,
4742 Context_CTI_GetCurrentThreadType
,
4743 Context_CTI_GetCurrentLogicalThreadId
,
4744 Context_CTI_SetCurrentLogicalThreadId
4747 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4749 Context
*This
= impl_from_IContextCallback(iface
);
4750 return Context_QueryInterface(This
, riid
, ppv
);
4753 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4755 Context
*This
= impl_from_IContextCallback(iface
);
4756 return Context_AddRef(This
);
4759 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4761 Context
*This
= impl_from_IContextCallback(iface
);
4762 return Context_Release(This
);
4765 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4766 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4768 Context
*This
= impl_from_IContextCallback(iface
);
4770 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4774 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4776 Context_CC_QueryInterface
,
4779 Context_CC_ContextCallback
4782 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4784 Context
*This
= impl_from_IObjContext(iface
);
4785 return Context_QueryInterface(This
, riid
, ppv
);
4788 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4790 Context
*This
= impl_from_IObjContext(iface
);
4791 return Context_AddRef(This
);
4794 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4796 Context
*This
= impl_from_IObjContext(iface
);
4797 return Context_Release(This
);
4800 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4802 Context
*This
= impl_from_IObjContext(iface
);
4804 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4808 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4810 Context
*This
= impl_from_IObjContext(iface
);
4812 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4816 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4818 Context
*This
= impl_from_IObjContext(iface
);
4820 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4824 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4826 Context
*This
= impl_from_IObjContext(iface
);
4828 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4832 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4834 Context
*This
= impl_from_IObjContext(iface
);
4835 FIXME("(%p/%p)\n", This
, iface
);
4838 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4840 Context
*This
= impl_from_IObjContext(iface
);
4841 FIXME("(%p/%p)\n", This
, iface
);
4844 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4846 Context
*This
= impl_from_IObjContext(iface
);
4847 FIXME("(%p/%p)\n", This
, iface
);
4850 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4852 Context
*This
= impl_from_IObjContext(iface
);
4853 FIXME("(%p/%p)\n", This
, iface
);
4856 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4858 Context
*This
= impl_from_IObjContext(iface
);
4859 FIXME("(%p/%p)\n", This
, iface
);
4862 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4864 Context
*This
= impl_from_IObjContext(iface
);
4865 FIXME("(%p/%p)\n", This
, iface
);
4868 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4870 Context
*This
= impl_from_IObjContext(iface
);
4871 FIXME("(%p/%p)\n", This
, iface
);
4874 static const IObjContextVtbl Context_Object_Vtbl
=
4876 Context_OC_QueryInterface
,
4879 Context_OC_SetProperty
,
4880 Context_OC_RemoveProperty
,
4881 Context_OC_GetProperty
,
4882 Context_OC_EnumContextProps
,
4883 Context_OC_Reserved1
,
4884 Context_OC_Reserved2
,
4885 Context_OC_Reserved3
,
4886 Context_OC_Reserved4
,
4887 Context_OC_Reserved5
,
4888 Context_OC_Reserved6
,
4889 Context_OC_Reserved7
4892 /***********************************************************************
4893 * CoGetObjectContext [OLE32.@]
4895 * Retrieves an object associated with the current context (i.e. apartment).
4898 * riid [I] ID of the interface of the object to retrieve.
4899 * ppv [O] Address where object will be stored on return.
4903 * Failure: HRESULT code.
4905 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4907 APARTMENT
*apt
= COM_CurrentApt();
4911 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4916 if (!(apt
= apartment_find_multi_threaded()))
4918 ERR("apartment not initialised\n");
4919 return CO_E_NOTINITIALIZED
;
4921 apartment_release(apt
);
4924 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4926 return E_OUTOFMEMORY
;
4928 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
4929 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
4930 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
4932 if (apt
->multi_threaded
)
4933 context
->apttype
= APTTYPE_MTA
;
4935 context
->apttype
= APTTYPE_MAINSTA
;
4937 context
->apttype
= APTTYPE_STA
;
4939 hr
= IComThreadingInfo_QueryInterface(&context
->IComThreadingInfo_iface
, riid
, ppv
);
4940 IComThreadingInfo_Release(&context
->IComThreadingInfo_iface
);
4946 /***********************************************************************
4947 * CoGetContextToken [OLE32.@]
4949 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4951 struct oletls
*info
= COM_CurrentInfo();
4953 TRACE("(%p)\n", token
);
4956 return E_OUTOFMEMORY
;
4961 if (!(apt
= apartment_find_multi_threaded()))
4963 ERR("apartment not initialised\n");
4964 return CO_E_NOTINITIALIZED
;
4966 apartment_release(apt
);
4972 if (!info
->context_token
)
4977 hr
= CoGetObjectContext(&IID_IObjContext
, (void **)&ctx
);
4978 if (FAILED(hr
)) return hr
;
4979 info
->context_token
= ctx
;
4982 *token
= (ULONG_PTR
)info
->context_token
;
4983 TRACE("apt->context_token=%p\n", info
->context_token
);
4988 /***********************************************************************
4989 * CoGetDefaultContext [OLE32.@]
4991 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
4993 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
4994 return E_NOINTERFACE
;
4997 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
4999 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5003 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
5004 if (SUCCEEDED(hres
))
5006 struct class_reg_data regdata
;
5007 WCHAR dllpath
[MAX_PATH
+1];
5009 regdata
.u
.hkey
= hkey
;
5010 regdata
.hkey
= TRUE
;
5012 if (COM_RegReadPath(®data
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
5014 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
5015 if (!strcmpiW(dllpath
, wszOle32
))
5018 return HandlerCF_Create(rclsid
, riid
, ppv
);
5022 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
5026 return CLASS_E_CLASSNOTAVAILABLE
;
5029 /***********************************************************************
5032 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
5034 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
5037 case DLL_PROCESS_ATTACH
:
5038 hProxyDll
= hinstDLL
;
5041 case DLL_PROCESS_DETACH
:
5042 if (reserved
) break;
5044 UnregisterClassW( wszAptWinClass
, hProxyDll
);
5045 RPC_UnregisterAllChannelHooks();
5046 COMPOBJ_DllList_Free();
5047 DeleteCriticalSection(&csRegisteredClassList
);
5048 DeleteCriticalSection(&csApartment
);
5051 case DLL_THREAD_DETACH
:
5058 /***********************************************************************
5059 * DllRegisterServer (OLE32.@)
5061 HRESULT WINAPI
DllRegisterServer(void)
5063 return OLE32_DllRegisterServer();
5066 /***********************************************************************
5067 * DllUnregisterServer (OLE32.@)
5069 HRESULT WINAPI
DllUnregisterServer(void)
5071 return OLE32_DllUnregisterServer();