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
45 #define NONAMELESSUNION
48 #define WIN32_NO_STATUS
54 #define USE_COM_CONTEXT_DEF
63 #include "compobj_private.h"
66 #include "wine/debug.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
70 /****************************************************************************
71 * This section defines variables internal to the COM module.
74 static APARTMENT
*MTA
; /* protected by csApartment */
75 static APARTMENT
*MainApartment
; /* the first STA apartment */
76 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
78 static CRITICAL_SECTION csApartment
;
79 static CRITICAL_SECTION_DEBUG critsect_debug
=
82 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
83 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
85 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
87 enum comclass_threadingmodel
89 ThreadingModel_Apartment
= 1,
90 ThreadingModel_Free
= 2,
91 ThreadingModel_No
= 3,
92 ThreadingModel_Both
= 4,
93 ThreadingModel_Neutral
= 5
96 enum comclass_miscfields
100 MiscStatusContent
= 4,
101 MiscStatusThumbnail
= 8,
102 MiscStatusDocPrint
= 16
105 struct comclassredirect_data
121 ULONG clrdata_offset
;
123 DWORD miscstatuscontent
;
124 DWORD miscstatusthumbnail
;
125 DWORD miscstatusicon
;
126 DWORD miscstatusdocprint
;
129 struct ifacepsredirect_data
141 struct progidredirect_data
148 struct class_reg_data
154 struct comclassredirect_data
*data
;
163 struct registered_psclsid
170 static struct list registered_psclsid_list
= LIST_INIT(registered_psclsid_list
);
172 static CRITICAL_SECTION cs_registered_psclsid_list
;
173 static CRITICAL_SECTION_DEBUG psclsid_cs_debug
=
175 0, 0, &cs_registered_psclsid_list
,
176 { &psclsid_cs_debug
.ProcessLocksList
, &psclsid_cs_debug
.ProcessLocksList
},
177 0, 0, { (DWORD_PTR
)(__FILE__
": cs_registered_psclsid_list") }
179 static CRITICAL_SECTION cs_registered_psclsid_list
= { &psclsid_cs_debug
, -1, 0, 0, 0, 0 };
182 * This is a marshallable object exposing registered local servers.
183 * IServiceProvider is used only because it happens meet requirements
184 * and already has proxy/stub code. If more functionality is needed,
185 * a custom interface may be used instead.
189 IServiceProvider IServiceProvider_iface
;
192 IStream
*marshal_stream
;
196 * This lock count counts the number of times CoInitialize is called. It is
197 * decreased every time CoUninitialize is called. When it hits 0, the COM
198 * libraries are freed
200 static LONG s_COMLockCount
= 0;
201 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
202 static LONG s_COMServerProcessReferences
= 0;
205 * This linked list contains the list of registered class objects. These
206 * are mostly used to register the factories for out-of-proc servers of OLE
209 * TODO: Make this data structure aware of inter-process communication. This
210 * means that parts of this will be exported to rpcss.
212 typedef struct tagRegisteredClass
215 CLSID classIdentifier
;
217 LPUNKNOWN classObject
;
221 void *RpcRegistration
;
224 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
226 static CRITICAL_SECTION csRegisteredClassList
;
227 static CRITICAL_SECTION_DEBUG class_cs_debug
=
229 0, 0, &csRegisteredClassList
,
230 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
231 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
233 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
235 static inline enum comclass_miscfields
dvaspect_to_miscfields(DWORD aspect
)
239 case DVASPECT_CONTENT
:
240 return MiscStatusContent
;
241 case DVASPECT_THUMBNAIL
:
242 return MiscStatusThumbnail
;
244 return MiscStatusIcon
;
245 case DVASPECT_DOCPRINT
:
246 return MiscStatusDocPrint
;
252 BOOL
actctx_get_miscstatus(const CLSID
*clsid
, DWORD aspect
, DWORD
*status
)
254 ACTCTX_SECTION_KEYED_DATA data
;
256 data
.cbSize
= sizeof(data
);
257 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
260 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
261 enum comclass_miscfields misc
= dvaspect_to_miscfields(aspect
);
263 if (!(comclass
->miscmask
& misc
))
265 if (!(comclass
->miscmask
& MiscStatus
))
276 *status
= comclass
->miscstatus
;
279 *status
= comclass
->miscstatusicon
;
281 case MiscStatusContent
:
282 *status
= comclass
->miscstatuscontent
;
284 case MiscStatusThumbnail
:
285 *status
= comclass
->miscstatusthumbnail
;
287 case MiscStatusDocPrint
:
288 *status
= comclass
->miscstatusdocprint
;
300 /* wrapper for NtCreateKey that creates the key recursively if necessary */
301 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
303 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
305 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
307 HANDLE subkey
, root
= attr
->RootDirectory
;
308 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
309 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
312 while (i
< len
&& buffer
[i
] != '\\') i
++;
313 if (i
== len
) return status
;
315 attrs
= attr
->Attributes
;
316 attr
->ObjectName
= &str
;
320 str
.Buffer
= buffer
+ pos
;
321 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
322 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
323 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
324 if (status
) return status
;
325 attr
->RootDirectory
= subkey
;
326 while (i
< len
&& buffer
[i
] == '\\') i
++;
328 while (i
< len
&& buffer
[i
] != '\\') i
++;
330 str
.Buffer
= buffer
+ pos
;
331 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
332 attr
->Attributes
= attrs
;
333 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
334 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
339 static const WCHAR classes_rootW
[] =
340 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
341 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
343 static HKEY classes_root_hkey
;
345 /* create the special HKEY_CLASSES_ROOT key */
346 static HKEY
create_classes_root_hkey(DWORD access
)
349 OBJECT_ATTRIBUTES attr
;
352 attr
.Length
= sizeof(attr
);
353 attr
.RootDirectory
= 0;
354 attr
.ObjectName
= &name
;
356 attr
.SecurityDescriptor
= NULL
;
357 attr
.SecurityQualityOfService
= NULL
;
358 RtlInitUnicodeString( &name
, classes_rootW
);
359 if (create_key( &hkey
, access
, &attr
)) return 0;
360 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
362 if (!(access
& KEY_WOW64_64KEY
))
364 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
367 NtClose( hkey
); /* somebody beat us to it */
374 /* map the hkey from special root to normal key if necessary */
375 static inline HKEY
get_classes_root_hkey( HKEY hkey
, REGSAM access
)
378 const BOOL is_win64
= sizeof(void*) > sizeof(int);
379 const BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
381 if (hkey
== HKEY_CLASSES_ROOT
&&
382 ((access
& KEY_WOW64_64KEY
) || !(ret
= classes_root_hkey
)))
383 ret
= create_classes_root_hkey(MAXIMUM_ALLOWED
| (access
& KEY_WOW64_64KEY
));
384 if (force_wow32
&& ret
&& ret
== classes_root_hkey
)
386 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
387 access
&= ~KEY_WOW64_32KEY
;
388 if (create_classes_key(classes_root_hkey
, wow6432nodeW
, access
, &hkey
))
396 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
398 OBJECT_ATTRIBUTES attr
;
399 UNICODE_STRING nameW
;
401 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
403 attr
.Length
= sizeof(attr
);
404 attr
.RootDirectory
= hkey
;
405 attr
.ObjectName
= &nameW
;
407 attr
.SecurityDescriptor
= NULL
;
408 attr
.SecurityQualityOfService
= NULL
;
409 RtlInitUnicodeString( &nameW
, name
);
411 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
414 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
416 OBJECT_ATTRIBUTES attr
;
417 UNICODE_STRING nameW
;
419 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
421 attr
.Length
= sizeof(attr
);
422 attr
.RootDirectory
= hkey
;
423 attr
.ObjectName
= &nameW
;
425 attr
.SecurityDescriptor
= NULL
;
426 attr
.SecurityQualityOfService
= NULL
;
427 RtlInitUnicodeString( &nameW
, name
);
429 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
432 /*****************************************************************************
433 * This section contains OpenDllList definitions
435 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
436 * other functions that do LoadLibrary _without_ giving back a HMODULE.
437 * Without this list these handles would never be freed.
439 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
440 * next unload-call but not before 600 sec.
443 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
444 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
446 typedef struct tagOpenDll
451 DllGetClassObjectFunc DllGetClassObject
;
452 DllCanUnloadNowFunc DllCanUnloadNow
;
456 static struct list openDllList
= LIST_INIT(openDllList
);
458 static CRITICAL_SECTION csOpenDllList
;
459 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
461 0, 0, &csOpenDllList
,
462 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
463 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
465 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
467 struct apartment_loaded_dll
475 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',0};
477 static ATOM apt_win_class
;
479 /*****************************************************************************
480 * This section contains OpenDllList implementation
483 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
487 EnterCriticalSection(&csOpenDllList
);
488 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
490 if (!wcsicmp(library_name
, ptr
->library_name
) &&
491 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
497 LeaveCriticalSection(&csOpenDllList
);
501 /* caller must ensure that library_name is not already in the open dll list */
502 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
508 DllCanUnloadNowFunc DllCanUnloadNow
;
509 DllGetClassObjectFunc DllGetClassObject
;
511 TRACE("%s\n", debugstr_w(library_name
));
513 *ret
= COMPOBJ_DllList_Get(library_name
);
514 if (*ret
) return S_OK
;
516 /* do this outside the csOpenDllList to avoid creating a lock dependency on
518 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
521 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
522 /* failure: DLL could not be loaded */
523 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
526 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
527 /* Note: failing to find DllCanUnloadNow is not a failure */
528 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
529 if (!DllGetClassObject
)
531 /* failure: the dll did not export DllGetClassObject */
532 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
533 FreeLibrary(hLibrary
);
534 return CO_E_DLLNOTFOUND
;
537 EnterCriticalSection( &csOpenDllList
);
539 *ret
= COMPOBJ_DllList_Get(library_name
);
542 /* another caller to this function already added the dll while we
543 * weren't in the critical section */
544 FreeLibrary(hLibrary
);
548 len
= lstrlenW(library_name
);
549 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
551 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
552 if (entry
&& entry
->library_name
)
554 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
555 entry
->library
= hLibrary
;
557 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
558 entry
->DllGetClassObject
= DllGetClassObject
;
559 list_add_tail(&openDllList
, &entry
->entry
);
564 HeapFree(GetProcessHeap(), 0, entry
);
566 FreeLibrary(hLibrary
);
570 LeaveCriticalSection( &csOpenDllList
);
575 /* pass FALSE for free_entry to release a reference without destroying the
576 * entry if it reaches zero or TRUE otherwise */
577 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
579 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
581 EnterCriticalSection(&csOpenDllList
);
582 list_remove(&entry
->entry
);
583 LeaveCriticalSection(&csOpenDllList
);
585 TRACE("freeing %p\n", entry
->library
);
586 FreeLibrary(entry
->library
);
588 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
589 HeapFree(GetProcessHeap(), 0, entry
);
593 /* frees memory associated with active dll list */
594 static void COMPOBJ_DllList_Free(void)
596 OpenDll
*entry
, *cursor2
;
597 EnterCriticalSection(&csOpenDllList
);
598 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
600 list_remove(&entry
->entry
);
602 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
603 HeapFree(GetProcessHeap(), 0, entry
);
605 LeaveCriticalSection(&csOpenDllList
);
606 DeleteCriticalSection(&csOpenDllList
);
609 /******************************************************************************
613 static DWORD
apartment_addref(struct apartment
*apt
)
615 DWORD refs
= InterlockedIncrement(&apt
->refs
);
616 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
620 /* allocates memory and fills in the necessary fields for a new apartment
621 * object. must be called inside apartment cs */
622 static APARTMENT
*apartment_construct(DWORD model
)
626 TRACE("creating new apartment, model=%d\n", model
);
628 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
629 apt
->tid
= GetCurrentThreadId();
631 list_init(&apt
->proxies
);
632 list_init(&apt
->stubmgrs
);
633 list_init(&apt
->loaded_dlls
);
636 apt
->remunk_exported
= FALSE
;
638 InitializeCriticalSection(&apt
->cs
);
639 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
641 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
643 if (apt
->multi_threaded
)
645 /* FIXME: should be randomly generated by in an RPC call to rpcss */
646 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
650 /* FIXME: should be randomly generated by in an RPC call to rpcss */
651 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
654 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
656 list_add_head(&apts
, &apt
->entry
);
661 /* gets and existing apartment if one exists or otherwise creates an apartment
662 * structure which stores OLE apartment-local information and stores a pointer
663 * to it in the thread-local storage */
664 static APARTMENT
*apartment_get_or_create(DWORD model
)
666 APARTMENT
*apt
= COM_CurrentApt();
670 if (model
& COINIT_APARTMENTTHREADED
)
672 EnterCriticalSection(&csApartment
);
674 apt
= apartment_construct(model
);
679 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
682 LeaveCriticalSection(&csApartment
);
685 apartment_createwindowifneeded(apt
);
689 EnterCriticalSection(&csApartment
);
691 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
692 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
696 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
697 apartment_addref(MTA
);
700 MTA
= apartment_construct(model
);
704 LeaveCriticalSection(&csApartment
);
706 COM_CurrentInfo()->apt
= apt
;
712 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
714 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
717 /* gets the multi-threaded apartment if it exists. The caller must
718 * release the reference from the apartment as soon as the apartment pointer
719 * is no longer required. */
720 static APARTMENT
*apartment_find_mta(void)
724 EnterCriticalSection(&csApartment
);
727 apartment_addref(apt
);
729 LeaveCriticalSection(&csApartment
);
734 /* Return the current apartment if it exists, or, failing that, the MTA. Caller
735 * must free the returned apartment in either case. */
736 APARTMENT
*apartment_get_current_or_mta(void)
738 APARTMENT
*apt
= COM_CurrentApt();
741 apartment_addref(apt
);
744 return apartment_find_mta();
747 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
749 list_remove(&curClass
->entry
);
751 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
752 RPC_StopLocalServer(curClass
->RpcRegistration
);
754 IUnknown_Release(curClass
->classObject
);
755 HeapFree(GetProcessHeap(), 0, curClass
);
758 static void COM_RevokeAllClasses(const struct apartment
*apt
)
760 RegisteredClass
*curClass
, *cursor
;
762 EnterCriticalSection( &csRegisteredClassList
);
764 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
766 if (curClass
->apartment_id
== apt
->oxid
)
767 COM_RevokeRegisteredClassObject(curClass
);
770 LeaveCriticalSection( &csRegisteredClassList
);
773 static void revoke_registered_psclsids(void)
775 struct registered_psclsid
*psclsid
, *psclsid2
;
777 EnterCriticalSection( &cs_registered_psclsid_list
);
779 LIST_FOR_EACH_ENTRY_SAFE(psclsid
, psclsid2
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
781 list_remove(&psclsid
->entry
);
782 HeapFree(GetProcessHeap(), 0, psclsid
);
785 LeaveCriticalSection( &cs_registered_psclsid_list
);
788 /******************************************************************************
789 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
792 typedef struct ManualResetEvent
{
793 ISynchronize ISynchronize_iface
;
794 ISynchronizeHandle ISynchronizeHandle_iface
;
799 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
801 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
804 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
806 MREImpl
*This
= impl_from_ISynchronize(iface
);
808 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
810 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
811 *ppv
= &This
->ISynchronize_iface
;
812 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
813 *ppv
= &This
->ISynchronizeHandle_iface
;
815 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
817 return E_NOINTERFACE
;
820 IUnknown_AddRef((IUnknown
*)*ppv
);
824 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
826 MREImpl
*This
= impl_from_ISynchronize(iface
);
827 LONG ref
= InterlockedIncrement(&This
->ref
);
828 TRACE("%p - ref %d\n", This
, ref
);
833 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
835 MREImpl
*This
= impl_from_ISynchronize(iface
);
836 LONG ref
= InterlockedDecrement(&This
->ref
);
837 TRACE("%p - ref %d\n", This
, ref
);
841 CloseHandle(This
->event
);
842 HeapFree(GetProcessHeap(), 0, This
);
848 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
850 MREImpl
*This
= impl_from_ISynchronize(iface
);
852 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
853 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
856 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
858 MREImpl
*This
= impl_from_ISynchronize(iface
);
860 SetEvent(This
->event
);
864 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
866 MREImpl
*This
= impl_from_ISynchronize(iface
);
868 ResetEvent(This
->event
);
872 static ISynchronizeVtbl vt_ISynchronize
= {
873 ISynchronize_fnQueryInterface
,
874 ISynchronize_fnAddRef
,
875 ISynchronize_fnRelease
,
877 ISynchronize_fnSignal
,
881 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
883 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
886 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
888 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
889 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
892 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
894 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
895 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
898 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
900 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
901 return ISynchronize_Release(&This
->ISynchronize_iface
);
904 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
906 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
912 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
913 SynchronizeHandle_QueryInterface
,
914 SynchronizeHandle_AddRef
,
915 SynchronizeHandle_Release
,
916 SynchronizeHandle_GetHandle
919 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
921 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
925 FIXME("Aggregation not implemented.\n");
928 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
929 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
930 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
932 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
933 ISynchronize_Release(&This
->ISynchronize_iface
);
937 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
939 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
942 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
944 LocalServer
*This
= impl_from_IServiceProvider(iface
);
946 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
948 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
949 *ppv
= &This
->IServiceProvider_iface
;
952 return E_NOINTERFACE
;
955 IUnknown_AddRef((IUnknown
*)*ppv
);
959 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
961 LocalServer
*This
= impl_from_IServiceProvider(iface
);
962 LONG ref
= InterlockedIncrement(&This
->ref
);
964 TRACE("(%p) ref=%d\n", This
, ref
);
969 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
971 LocalServer
*This
= impl_from_IServiceProvider(iface
);
972 LONG ref
= InterlockedDecrement(&This
->ref
);
974 TRACE("(%p) ref=%d\n", This
, ref
);
978 HeapFree(GetProcessHeap(), 0, This
);
984 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
986 LocalServer
*This
= impl_from_IServiceProvider(iface
);
987 APARTMENT
*apt
= COM_CurrentApt();
988 RegisteredClass
*iter
;
989 HRESULT hres
= E_FAIL
;
991 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
996 EnterCriticalSection(&csRegisteredClassList
);
998 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
999 if(iter
->apartment_id
== apt
->oxid
1000 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
1001 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
1002 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
1007 LeaveCriticalSection( &csRegisteredClassList
);
1012 static const IServiceProviderVtbl LocalServerVtbl
= {
1013 LocalServer_QueryInterface
,
1015 LocalServer_Release
,
1016 LocalServer_QueryService
1019 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
1021 HRESULT hres
= S_OK
;
1023 EnterCriticalSection(&apt
->cs
);
1025 if(!apt
->local_server
) {
1028 obj
= heap_alloc(sizeof(*obj
));
1030 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
1034 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
1035 if(SUCCEEDED(hres
)) {
1036 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
1037 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1039 IStream_Release(obj
->marshal_stream
);
1043 apt
->local_server
= obj
;
1047 hres
= E_OUTOFMEMORY
;
1052 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
1054 LeaveCriticalSection(&apt
->cs
);
1057 ERR("Failed: %08x\n", hres
);
1061 /***********************************************************************
1062 * CoRevokeClassObject [OLE32.@]
1064 * Removes a class object from the class registry.
1067 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1071 * Failure: HRESULT code.
1074 * Must be called from the same apartment that called CoRegisterClassObject(),
1075 * otherwise it will fail with RPC_E_WRONG_THREAD.
1078 * CoRegisterClassObject
1080 HRESULT WINAPI DECLSPEC_HOTPATCH
CoRevokeClassObject(
1083 HRESULT hr
= E_INVALIDARG
;
1084 RegisteredClass
*curClass
;
1087 TRACE("(%08x)\n",dwRegister
);
1089 if (!(apt
= apartment_get_current_or_mta()))
1091 ERR("COM was not initialized\n");
1092 return CO_E_NOTINITIALIZED
;
1095 EnterCriticalSection( &csRegisteredClassList
);
1097 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1100 * Check if we have a match on the cookie.
1102 if (curClass
->dwCookie
== dwRegister
)
1104 if (curClass
->apartment_id
== apt
->oxid
)
1106 COM_RevokeRegisteredClassObject(curClass
);
1111 ERR("called from wrong apartment, should be called from %s\n",
1112 wine_dbgstr_longlong(curClass
->apartment_id
));
1113 hr
= RPC_E_WRONG_THREAD
;
1119 LeaveCriticalSection( &csRegisteredClassList
);
1120 apartment_release(apt
);
1124 /* frees unused libraries loaded by apartment_getclassobject by calling the
1125 * DLL's DllCanUnloadNow entry point */
1126 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
1128 struct apartment_loaded_dll
*entry
, *next
;
1129 EnterCriticalSection(&apt
->cs
);
1130 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1132 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
1134 DWORD real_delay
= delay
;
1136 if (real_delay
== INFINITE
)
1138 /* DLLs that return multi-threaded objects aren't unloaded
1139 * straight away to cope for programs that have races between
1140 * last object destruction and threads in the DLLs that haven't
1141 * finished, despite DllCanUnloadNow returning S_OK */
1142 if (entry
->multi_threaded
)
1143 real_delay
= 10 * 60 * 1000; /* 10 minutes */
1148 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
1150 list_remove(&entry
->entry
);
1151 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
1152 HeapFree(GetProcessHeap(), 0, entry
);
1156 entry
->unload_time
= GetTickCount() + real_delay
;
1157 if (!entry
->unload_time
) entry
->unload_time
= 1;
1160 else if (entry
->unload_time
)
1161 entry
->unload_time
= 0;
1163 LeaveCriticalSection(&apt
->cs
);
1166 DWORD
apartment_release(struct apartment
*apt
)
1170 EnterCriticalSection(&csApartment
);
1172 ret
= InterlockedDecrement(&apt
->refs
);
1173 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
1175 if (apt
->being_destroyed
)
1177 LeaveCriticalSection(&csApartment
);
1181 /* destruction stuff that needs to happen under csApartment CS */
1184 apt
->being_destroyed
= TRUE
;
1185 if (apt
== MTA
) MTA
= NULL
;
1186 else if (apt
== MainApartment
) MainApartment
= NULL
;
1187 list_remove(&apt
->entry
);
1190 LeaveCriticalSection(&csApartment
);
1194 struct list
*cursor
, *cursor2
;
1196 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
1198 if(apt
->local_server
) {
1199 LocalServer
*local_server
= apt
->local_server
;
1202 memset(&zero
, 0, sizeof(zero
));
1203 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
1204 CoReleaseMarshalData(local_server
->marshal_stream
);
1205 IStream_Release(local_server
->marshal_stream
);
1206 local_server
->marshal_stream
= NULL
;
1208 apt
->local_server
= NULL
;
1209 local_server
->apt
= NULL
;
1210 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
1213 /* Release the references to the registered class objects */
1214 COM_RevokeAllClasses(apt
);
1216 /* no locking is needed for this apartment, because no other thread
1217 * can access it at this point */
1219 apartment_disconnectproxies(apt
);
1221 if (apt
->win
) DestroyWindow(apt
->win
);
1222 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
1224 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
1226 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
1227 /* release the implicit reference given by the fact that the
1228 * stub has external references (it must do since it is in the
1229 * stub manager list in the apartment and all non-apartment users
1230 * must have a ref on the apartment and so it cannot be destroyed).
1232 stub_manager_int_release(stubmgr
);
1235 /* if this assert fires, then another thread took a reference to a
1236 * stub manager without taking a reference to the containing
1237 * apartment, which it must do. */
1238 assert(list_empty(&apt
->stubmgrs
));
1240 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1242 /* free as many unused libraries as possible... */
1243 apartment_freeunusedlibraries(apt
, 0);
1245 /* ... and free the memory for the apartment loaded dll entry and
1246 * release the dll list reference without freeing the library for the
1248 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1250 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1251 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1252 list_remove(cursor
);
1253 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1256 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1257 DeleteCriticalSection(&apt
->cs
);
1259 HeapFree(GetProcessHeap(), 0, apt
);
1265 /* The given OXID must be local to this process:
1267 * The ref parameter is here mostly to ensure people remember that
1268 * they get one, you should normally take a ref for thread safety.
1270 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1272 APARTMENT
*result
= NULL
;
1273 struct list
*cursor
;
1275 EnterCriticalSection(&csApartment
);
1276 LIST_FOR_EACH( cursor
, &apts
)
1278 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1279 if (apt
->oxid
== oxid
)
1282 if (ref
) apartment_addref(result
);
1286 LeaveCriticalSection(&csApartment
);
1291 /* gets the apartment which has a given creator thread ID. The caller must
1292 * release the reference from the apartment as soon as the apartment pointer
1293 * is no longer required. */
1294 APARTMENT
*apartment_findfromtid(DWORD tid
)
1296 APARTMENT
*result
= NULL
;
1297 struct list
*cursor
;
1299 EnterCriticalSection(&csApartment
);
1300 LIST_FOR_EACH( cursor
, &apts
)
1302 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1303 if (apt
->tid
== tid
)
1306 apartment_addref(result
);
1310 LeaveCriticalSection(&csApartment
);
1315 /* gets the main apartment if it exists. The caller must
1316 * release the reference from the apartment as soon as the apartment pointer
1317 * is no longer required. */
1318 static APARTMENT
*apartment_findmain(void)
1322 EnterCriticalSection(&csApartment
);
1324 result
= MainApartment
;
1325 if (result
) apartment_addref(result
);
1327 LeaveCriticalSection(&csApartment
);
1332 /* gets the specified class object by loading the appropriate DLL, if
1333 * necessary and calls the DllGetClassObject function for the DLL */
1334 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1335 BOOL apartment_threaded
,
1336 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1338 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1341 struct apartment_loaded_dll
*apartment_loaded_dll
;
1343 if (!wcsicmp(dllpath
, wszOle32
))
1345 /* we don't need to control the lifetime of this dll, so use the local
1346 * implementation of DllGetClassObject directly */
1347 TRACE("calling ole32!DllGetClassObject\n");
1348 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1351 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr
, debugstr_w(dllpath
));
1356 EnterCriticalSection(&apt
->cs
);
1358 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1359 if (!wcsicmp(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1361 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1368 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1369 if (!apartment_loaded_dll
)
1373 apartment_loaded_dll
->unload_time
= 0;
1374 apartment_loaded_dll
->multi_threaded
= FALSE
;
1375 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1377 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1381 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1382 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1386 LeaveCriticalSection(&apt
->cs
);
1390 /* one component being multi-threaded overrides any number of
1391 * apartment-threaded components */
1392 if (!apartment_threaded
)
1393 apartment_loaded_dll
->multi_threaded
= TRUE
;
1395 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1396 /* OK: get the ClassObject */
1397 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1400 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr
, debugstr_w(dllpath
));
1406 /* Returns expanded dll path from the registry or activation context. */
1407 static BOOL
get_object_dll_path(const struct class_reg_data
*regdata
, WCHAR
*dst
, DWORD dstlen
)
1414 WCHAR src
[MAX_PATH
];
1415 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1417 if( (ret
= RegQueryValueExW(regdata
->u
.hkey
, NULL
, NULL
, &keytype
, (BYTE
*)src
, &dwLength
)) == ERROR_SUCCESS
) {
1418 if (keytype
== REG_EXPAND_SZ
) {
1419 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1421 const WCHAR
*quote_start
;
1422 quote_start
= wcschr(src
, '\"');
1424 const WCHAR
*quote_end
= wcschr(quote_start
+ 1, '\"');
1426 memmove(src
, quote_start
+ 1,
1427 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1428 src
[quote_end
- quote_start
- 1] = '\0';
1431 lstrcpynW(dst
, src
, dstlen
);
1438 static const WCHAR dllW
[] = {'.','d','l','l',0};
1443 nameW
= (WCHAR
*)((BYTE
*)regdata
->u
.actctx
.section
+ regdata
->u
.actctx
.data
->name_offset
);
1444 ActivateActCtx(regdata
->u
.actctx
.hactctx
, &cookie
);
1445 ret
= SearchPathW(NULL
, nameW
, dllW
, dstlen
, dst
, NULL
);
1446 DeactivateActCtx(0, cookie
);
1451 struct host_object_params
1453 struct class_reg_data regdata
;
1454 CLSID clsid
; /* clsid of object to marshal */
1455 IID iid
; /* interface to marshal */
1456 HANDLE event
; /* event signalling when ready for multi-threaded case */
1457 HRESULT hr
; /* result for multi-threaded case */
1458 IStream
*stream
; /* stream that the object will be marshaled into */
1459 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1462 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1463 const struct host_object_params
*params
)
1467 static const LARGE_INTEGER llZero
;
1468 WCHAR dllpath
[MAX_PATH
+1];
1470 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1472 if (!get_object_dll_path(¶ms
->regdata
, dllpath
, ARRAY_SIZE(dllpath
)))
1474 /* failure: CLSID is not found in registry */
1475 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1476 return REGDB_E_CLASSNOTREG
;
1479 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1480 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1484 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1486 IUnknown_Release(object
);
1487 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1492 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1497 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1500 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1502 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1506 struct host_thread_params
1508 COINIT threading_model
;
1510 HWND apartment_hwnd
;
1513 /* thread for hosting an object to allow an object to appear to be created in
1514 * an apartment with an incompatible threading model */
1515 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1517 struct host_thread_params
*params
= p
;
1520 struct apartment
*apt
;
1524 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1525 if (FAILED(hr
)) return hr
;
1527 apt
= COM_CurrentApt();
1528 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1530 apartment_createwindowifneeded(apt
);
1531 params
->apartment_hwnd
= apartment_getwindow(apt
);
1534 params
->apartment_hwnd
= NULL
;
1536 /* force the message queue to be created before signaling parent thread */
1537 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1539 SetEvent(params
->ready_event
);
1540 params
= NULL
; /* can't touch params after here as it may be invalid */
1542 while (GetMessageW(&msg
, NULL
, 0, 0))
1544 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1546 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1547 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1548 SetEvent(obj_params
->event
);
1552 TranslateMessage(&msg
);
1553 DispatchMessageW(&msg
);
1564 /* finds or creates a host apartment, creates the object inside it and returns
1565 * a proxy to it so that the object can be used in the apartment of the
1566 * caller of this function */
1567 static HRESULT
apartment_hostobject_in_hostapt(
1568 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1569 const struct class_reg_data
*regdata
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1571 struct host_object_params params
;
1572 HWND apartment_hwnd
= NULL
;
1573 DWORD apartment_tid
= 0;
1576 if (!multi_threaded
&& main_apartment
)
1578 APARTMENT
*host_apt
= apartment_findmain();
1581 apartment_hwnd
= apartment_getwindow(host_apt
);
1582 apartment_release(host_apt
);
1586 if (!apartment_hwnd
)
1588 EnterCriticalSection(&apt
->cs
);
1590 if (!apt
->host_apt_tid
)
1592 struct host_thread_params thread_params
;
1596 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1597 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1598 thread_params
.apartment_hwnd
= NULL
;
1599 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1602 CloseHandle(handles
[0]);
1603 LeaveCriticalSection(&apt
->cs
);
1604 return E_OUTOFMEMORY
;
1606 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1607 CloseHandle(handles
[0]);
1608 CloseHandle(handles
[1]);
1609 if (wait_value
== WAIT_OBJECT_0
)
1610 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1613 LeaveCriticalSection(&apt
->cs
);
1614 return E_OUTOFMEMORY
;
1618 if (multi_threaded
|| !main_apartment
)
1620 apartment_hwnd
= apt
->host_apt_hwnd
;
1621 apartment_tid
= apt
->host_apt_tid
;
1624 LeaveCriticalSection(&apt
->cs
);
1627 /* another thread may have become the main apartment in the time it took
1628 * us to create the thread for the host apartment */
1629 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1631 APARTMENT
*host_apt
= apartment_findmain();
1634 apartment_hwnd
= apartment_getwindow(host_apt
);
1635 apartment_release(host_apt
);
1639 params
.regdata
= *regdata
;
1640 params
.clsid
= *rclsid
;
1642 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1645 params
.apartment_threaded
= !multi_threaded
;
1649 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1650 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1654 WaitForSingleObject(params
.event
, INFINITE
);
1657 CloseHandle(params
.event
);
1661 if (!apartment_hwnd
)
1663 ERR("host apartment didn't create window\n");
1667 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1670 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1671 IStream_Release(params
.stream
);
1675 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1679 /* Dispatching to the correct thread in an apartment is done through
1680 * window messages rather than RPC transports. When an interface is
1681 * marshalled into another apartment in the same process, a window of the
1682 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1683 * application) is responsible for pumping the message loop in that thread.
1684 * The WM_USER messages which point to the RPCs are then dispatched to
1685 * apartment_wndproc by the user's code from the apartment in which the
1686 * interface was unmarshalled.
1688 memset(&wclass
, 0, sizeof(wclass
));
1689 wclass
.lpfnWndProc
= apartment_wndproc
;
1690 wclass
.hInstance
= hProxyDll
;
1691 wclass
.lpszClassName
= wszAptWinClass
;
1692 apt_win_class
= RegisterClassW(&wclass
);
1696 /* create a window for the apartment or return the current one if one has
1697 * already been created */
1698 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1700 static INIT_ONCE class_init_once
= INIT_ONCE_STATIC_INIT
;
1702 if (apt
->multi_threaded
)
1709 InitOnceExecuteOnce( &class_init_once
, register_class
, NULL
, NULL
);
1711 hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0, 0, 0, 0, 0,
1712 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1715 ERR("CreateWindow failed with error %d\n", GetLastError());
1716 return HRESULT_FROM_WIN32(GetLastError());
1718 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1719 /* someone beat us to it */
1720 DestroyWindow(hwnd
);
1726 /* retrieves the window for the main- or apartment-threaded apartment */
1727 HWND
apartment_getwindow(const struct apartment
*apt
)
1729 assert(!apt
->multi_threaded
);
1733 static void COM_TlsDestroy(void)
1735 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1738 struct init_spy
*cursor
, *cursor2
;
1740 if (info
->apt
) apartment_release(info
->apt
);
1741 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1742 if (info
->state
) IUnknown_Release(info
->state
);
1744 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &info
->spies
, struct init_spy
, entry
)
1746 list_remove(&cursor
->entry
);
1747 if (cursor
->spy
) IInitializeSpy_Release(cursor
->spy
);
1751 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1753 HeapFree(GetProcessHeap(), 0, info
);
1754 NtCurrentTeb()->ReservedForOle
= NULL
;
1758 /******************************************************************************
1759 * CoBuildVersion [OLE32.@]
1761 * Gets the build version of the DLL.
1766 * Current build version, hiword is majornumber, loword is minornumber
1768 DWORD WINAPI
CoBuildVersion(void)
1770 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1771 return (rmm
<<16)+rup
;
1774 static struct init_spy
*get_spy_entry(struct oletls
*info
, unsigned int id
)
1776 struct init_spy
*spy
;
1778 LIST_FOR_EACH_ENTRY(spy
, &info
->spies
, struct init_spy
, entry
)
1780 if (id
== spy
->id
&& spy
->spy
)
1788 * When locked, don't modify list (unless we add a new head), so that it's
1789 * safe to iterate it. Freeing of list entries is delayed and done on unlock.
1791 static inline void lock_init_spies(struct oletls
*info
)
1796 static void unlock_init_spies(struct oletls
*info
)
1798 struct init_spy
*spy
, *next
;
1800 if (--info
->spies_lock
) return;
1802 LIST_FOR_EACH_ENTRY_SAFE(spy
, next
, &info
->spies
, struct init_spy
, entry
)
1804 if (spy
->spy
) continue;
1805 list_remove(&spy
->entry
);
1810 /******************************************************************************
1811 * CoRegisterInitializeSpy [OLE32.@]
1813 * Add a Spy that watches CoInitializeEx calls
1816 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1817 * cookie [II] cookie receiver
1820 * Success: S_OK if not already initialized, S_FALSE otherwise.
1821 * Failure: HRESULT code.
1826 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1828 struct oletls
*info
= COM_CurrentInfo();
1829 struct init_spy
*entry
;
1833 TRACE("(%p, %p)\n", spy
, cookie
);
1835 if (!spy
|| !cookie
|| !info
)
1838 WARN("Could not allocate tls\n");
1839 return E_INVALIDARG
;
1842 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **)&spy
);
1846 entry
= heap_alloc(sizeof(*entry
));
1849 IInitializeSpy_Release(spy
);
1850 return E_OUTOFMEMORY
;
1856 while (get_spy_entry(info
, id
) != NULL
)
1862 list_add_head(&info
->spies
, &entry
->entry
);
1864 cookie
->HighPart
= GetCurrentThreadId();
1865 cookie
->LowPart
= entry
->id
;
1870 /******************************************************************************
1871 * CoRevokeInitializeSpy [OLE32.@]
1873 * Remove a spy that previously watched CoInitializeEx calls
1876 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1879 * Success: S_OK if a spy is removed
1880 * Failure: E_INVALIDARG
1885 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1887 struct oletls
*info
= COM_CurrentInfo();
1888 struct init_spy
*spy
;
1890 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1892 if (!info
|| cookie
.HighPart
!= GetCurrentThreadId())
1893 return E_INVALIDARG
;
1895 if (!(spy
= get_spy_entry(info
, cookie
.LowPart
))) return E_INVALIDARG
;
1897 IInitializeSpy_Release(spy
->spy
);
1899 if (!info
->spies_lock
)
1901 list_remove(&spy
->entry
);
1907 HRESULT
enter_apartment( struct oletls
*info
, DWORD model
)
1913 if (!apartment_get_or_create( model
))
1914 return E_OUTOFMEMORY
;
1916 else if (!apartment_is_model( info
->apt
, model
))
1918 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1919 info
->apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1920 model
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded" );
1921 return RPC_E_CHANGED_MODE
;
1931 void leave_apartment( struct oletls
*info
)
1935 if (info
->ole_inits
)
1936 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1937 apartment_release( info
->apt
);
1942 /******************************************************************************
1943 * CoInitialize [OLE32.@]
1945 * Initializes the COM libraries by calling CoInitializeEx with
1946 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1949 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1952 * Success: S_OK if not already initialized, S_FALSE otherwise.
1953 * Failure: HRESULT code.
1958 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1961 * Just delegate to the newer method.
1963 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1966 /******************************************************************************
1967 * CoInitializeEx [OLE32.@]
1969 * Initializes the COM libraries.
1972 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1973 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1976 * S_OK if successful,
1977 * S_FALSE if this function was called already.
1978 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1983 * The behavior used to set the IMalloc used for memory management is
1985 * The dwCoInit parameter must specify one of the following apartment
1987 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1988 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1989 * The parameter may also specify zero or more of the following flags:
1990 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1991 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1996 HRESULT WINAPI DECLSPEC_HOTPATCH
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1998 struct oletls
*info
= COM_CurrentInfo();
1999 struct init_spy
*cursor
;
2002 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
2004 if (lpReserved
!=NULL
)
2006 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
2010 * Check the lock count. If this is the first time going through the initialize
2011 * process, we have to initialize the libraries.
2013 * And crank-up that lock count.
2015 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
2018 * Initialize the various COM libraries and data structures.
2020 TRACE("() - Initializing the COM libraries\n");
2022 /* we may need to defer this until after apartment initialisation */
2023 RunningObjectTableImpl_Initialize();
2026 lock_init_spies(info
);
2027 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2029 if (cursor
->spy
) IInitializeSpy_PreInitialize(cursor
->spy
, dwCoInit
, info
->inits
);
2031 unlock_init_spies(info
);
2033 hr
= enter_apartment( info
, dwCoInit
);
2035 lock_init_spies(info
);
2036 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2038 if (cursor
->spy
) hr
= IInitializeSpy_PostInitialize(cursor
->spy
, hr
, dwCoInit
, info
->inits
);
2040 unlock_init_spies(info
);
2045 /***********************************************************************
2046 * CoUninitialize [OLE32.@]
2048 * This method will decrement the refcount on the current apartment, freeing
2049 * the resources associated with it if it is the last thread in the apartment.
2050 * If the last apartment is freed, the function will additionally release
2051 * any COM resources associated with the process.
2061 void WINAPI DECLSPEC_HOTPATCH
CoUninitialize(void)
2063 struct oletls
* info
= COM_CurrentInfo();
2064 struct init_spy
*cursor
, *next
;
2069 /* will only happen on OOM */
2072 lock_init_spies(info
);
2073 LIST_FOR_EACH_ENTRY_SAFE(cursor
, next
, &info
->spies
, struct init_spy
, entry
)
2075 if (cursor
->spy
) IInitializeSpy_PreUninitialize(cursor
->spy
, info
->inits
);
2077 unlock_init_spies(info
);
2082 ERR("Mismatched CoUninitialize\n");
2084 lock_init_spies(info
);
2085 LIST_FOR_EACH_ENTRY_SAFE(cursor
, next
, &info
->spies
, struct init_spy
, entry
)
2087 if (cursor
->spy
) IInitializeSpy_PostUninitialize(cursor
->spy
, info
->inits
);
2089 unlock_init_spies(info
);
2094 leave_apartment( info
);
2097 * Decrease the reference count.
2098 * If we are back to 0 locks on the COM library, make sure we free
2099 * all the associated data structures.
2101 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
2104 TRACE("() - Releasing the COM libraries\n");
2106 revoke_registered_psclsids();
2107 RunningObjectTableImpl_UnInitialize();
2109 else if (lCOMRefCnt
<1) {
2110 ERR( "CoUninitialize() - not CoInitialized.\n" );
2111 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
2114 lock_init_spies(info
);
2115 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2117 if (cursor
->spy
) IInitializeSpy_PostUninitialize(cursor
->spy
, info
->inits
);
2119 unlock_init_spies(info
);
2122 /******************************************************************************
2123 * CoDisconnectObject [OLE32.@]
2125 * Disconnects all connections to this object from remote processes. Dispatches
2126 * pending RPCs while blocking new RPCs from occurring, and then calls
2127 * IMarshal::DisconnectObject on the given object.
2129 * Typically called when the object server is forced to shut down, for instance by
2133 * lpUnk [I] The object whose stub should be disconnected.
2134 * reserved [I] Reserved. Should be set to 0.
2138 * Failure: HRESULT code.
2141 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2143 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2145 struct stub_manager
*manager
;
2150 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2152 if (!lpUnk
) return E_INVALIDARG
;
2154 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2157 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2158 IMarshal_Release(marshal
);
2162 if (!(apt
= apartment_get_current_or_mta()))
2164 ERR("apartment not initialised\n");
2165 return CO_E_NOTINITIALIZED
;
2168 manager
= get_stub_manager_from_object(apt
, lpUnk
, FALSE
);
2170 stub_manager_disconnect(manager
);
2171 /* Release stub manager twice, to remove the apartment reference. */
2172 stub_manager_int_release(manager
);
2173 stub_manager_int_release(manager
);
2176 /* Note: native is pretty broken here because it just silently
2177 * fails, without returning an appropriate error code if the object was
2178 * not found, making apps think that the object was disconnected, when
2179 * it actually wasn't */
2181 apartment_release(apt
);
2185 /******************************************************************************
2186 * CoCreateGuid [OLE32.@]
2188 * Simply forwards to UuidCreate in RPCRT4.
2191 * pguid [O] Points to the GUID to initialize.
2195 * Failure: HRESULT code.
2200 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
2204 if(!pguid
) return E_INVALIDARG
;
2206 status
= UuidCreate(pguid
);
2207 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2208 return HRESULT_FROM_WIN32( status
);
2211 static inline BOOL
is_valid_hex(WCHAR c
)
2213 if (!(((c
>= '0') && (c
<= '9')) ||
2214 ((c
>= 'a') && (c
<= 'f')) ||
2215 ((c
>= 'A') && (c
<= 'F'))))
2220 static const BYTE guid_conv_table
[256] =
2222 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2223 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2224 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2225 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2226 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2227 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2228 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2231 /* conversion helper for CLSIDFromString/IIDFromString */
2232 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2236 if (!s
|| s
[0]!='{') {
2237 memset( id
, 0, sizeof (CLSID
) );
2242 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2244 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2247 for (i
= 1; i
< 9; i
++) {
2248 if (!is_valid_hex(s
[i
])) return FALSE
;
2249 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2251 if (s
[9]!='-') return FALSE
;
2254 for (i
= 10; i
< 14; i
++) {
2255 if (!is_valid_hex(s
[i
])) return FALSE
;
2256 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2258 if (s
[14]!='-') return FALSE
;
2261 for (i
= 15; i
< 19; i
++) {
2262 if (!is_valid_hex(s
[i
])) return FALSE
;
2263 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2265 if (s
[19]!='-') return FALSE
;
2267 for (i
= 20; i
< 37; i
+=2) {
2269 if (s
[i
]!='-') return FALSE
;
2272 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2273 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2276 if (s
[37] == '}' && s
[38] == '\0')
2282 /*****************************************************************************/
2284 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2286 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2287 WCHAR buf2
[CHARS_IN_GUID
];
2288 LONG buf2len
= sizeof(buf2
);
2292 memset(clsid
, 0, sizeof(*clsid
));
2293 buf
= HeapAlloc( GetProcessHeap(),0,(lstrlenW(progid
)+8) * sizeof(WCHAR
) );
2294 if (!buf
) return E_OUTOFMEMORY
;
2295 lstrcpyW( buf
, progid
);
2296 lstrcatW( buf
, clsidW
);
2297 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2299 HeapFree(GetProcessHeap(),0,buf
);
2300 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2301 return CO_E_CLASSSTRING
;
2303 HeapFree(GetProcessHeap(),0,buf
);
2305 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2308 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2309 return CO_E_CLASSSTRING
;
2312 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2315 /******************************************************************************
2316 * CLSIDFromString [OLE32.@]
2318 * Converts a unique identifier from its string representation into
2322 * idstr [I] The string representation of the GUID.
2323 * id [O] GUID converted from the string.
2327 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2332 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2334 HRESULT ret
= CO_E_CLASSSTRING
;
2338 return E_INVALIDARG
;
2340 if (guid_from_string(idstr
, id
))
2343 /* It appears a ProgID is also valid */
2344 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2351 /******************************************************************************
2352 * IIDFromString [OLE32.@]
2354 * Converts an interface identifier from its string representation to
2358 * idstr [I] The string representation of the GUID.
2359 * id [O] IID converted from the string.
2363 * CO_E_IIDSTRING if idstr is not a valid IID
2368 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2370 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2374 memset(iid
, 0, sizeof(*iid
));
2378 /* length mismatch is a special case */
2379 if (lstrlenW(s
) + 1 != CHARS_IN_GUID
)
2380 return E_INVALIDARG
;
2383 return CO_E_IIDSTRING
;
2385 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2388 /******************************************************************************
2389 * StringFromCLSID [OLE32.@]
2390 * StringFromIID [OLE32.@]
2392 * Converts a GUID into the respective string representation.
2393 * The target string is allocated using the OLE IMalloc.
2396 * id [I] the GUID to be converted.
2397 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2404 * StringFromGUID2, CLSIDFromString
2406 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2408 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2409 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2413 /******************************************************************************
2414 * StringFromGUID2 [OLE32.@]
2416 * Modified version of StringFromCLSID that allows you to specify max
2420 * id [I] GUID to convert to string.
2421 * str [O] Buffer where the result will be stored.
2422 * cmax [I] Size of the buffer in characters.
2425 * Success: The length of the resulting string in characters.
2428 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2430 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2431 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2432 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2433 '%','0','2','X','%','0','2','X','}',0 };
2434 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2435 swprintf( str
, CHARS_IN_GUID
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2436 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2437 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2438 return CHARS_IN_GUID
;
2441 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2442 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2444 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2445 WCHAR path
[CHARS_IN_GUID
+ ARRAY_SIZE(wszCLSIDSlash
) - 1];
2449 lstrcpyW(path
, wszCLSIDSlash
);
2450 StringFromGUID2(clsid
, path
+ lstrlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2451 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2452 if (res
== ERROR_FILE_NOT_FOUND
)
2453 return REGDB_E_CLASSNOTREG
;
2454 else if (res
!= ERROR_SUCCESS
)
2455 return REGDB_E_READREGDB
;
2463 res
= open_classes_key(key
, keyname
, access
, subkey
);
2465 if (res
== ERROR_FILE_NOT_FOUND
)
2466 return REGDB_E_KEYMISSING
;
2467 else if (res
!= ERROR_SUCCESS
)
2468 return REGDB_E_READREGDB
;
2473 /* open HKCR\\AppId\\{string form of appid clsid} key */
2474 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2476 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2477 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2479 WCHAR buf
[CHARS_IN_GUID
];
2480 WCHAR keyname
[ARRAY_SIZE(szAppIdKey
) + CHARS_IN_GUID
];
2486 /* read the AppID value under the class's key */
2487 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2492 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2494 if (res
== ERROR_FILE_NOT_FOUND
)
2495 return REGDB_E_KEYMISSING
;
2496 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2497 return REGDB_E_READREGDB
;
2499 lstrcpyW(keyname
, szAppIdKey
);
2500 lstrcatW(keyname
, buf
);
2501 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2502 if (res
== ERROR_FILE_NOT_FOUND
)
2503 return REGDB_E_KEYMISSING
;
2504 else if (res
!= ERROR_SUCCESS
)
2505 return REGDB_E_READREGDB
;
2510 /******************************************************************************
2511 * ProgIDFromCLSID [OLE32.@]
2513 * Converts a class id into the respective program ID.
2516 * clsid [I] Class ID, as found in registry.
2517 * ppszProgID [O] Associated ProgID.
2522 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2524 HRESULT WINAPI DECLSPEC_HOTPATCH
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2526 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2527 ACTCTX_SECTION_KEYED_DATA data
;
2533 return E_INVALIDARG
;
2537 data
.cbSize
= sizeof(data
);
2538 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2541 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2542 if (comclass
->progid_len
)
2546 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2547 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2549 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2550 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2554 return REGDB_E_CLASSNOTREG
;
2557 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2561 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2562 ret
= REGDB_E_CLASSNOTREG
;
2566 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2569 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2570 ret
= REGDB_E_CLASSNOTREG
;
2571 CoTaskMemFree(*ppszProgID
);
2576 ret
= E_OUTOFMEMORY
;
2583 /******************************************************************************
2584 * CLSIDFromProgID [OLE32.@]
2586 * Converts a program id into the respective GUID.
2589 * progid [I] Unicode program ID, as found in registry.
2590 * clsid [O] Associated CLSID.
2594 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2596 HRESULT WINAPI DECLSPEC_HOTPATCH
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2598 ACTCTX_SECTION_KEYED_DATA data
;
2600 if (!progid
|| !clsid
)
2601 return E_INVALIDARG
;
2603 data
.cbSize
= sizeof(data
);
2604 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2607 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2608 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2613 return clsid_from_string_reg(progid
, clsid
);
2616 /******************************************************************************
2617 * CLSIDFromProgIDEx [OLE32.@]
2619 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2621 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2623 return CLSIDFromProgID(progid
, clsid
);
2626 static HRESULT
get_ps_clsid_from_registry(const WCHAR
* path
, REGSAM access
, CLSID
*pclsid
)
2629 WCHAR value
[CHARS_IN_GUID
];
2634 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, access
, &hkey
))
2635 return REGDB_E_IIDNOTREG
;
2637 len
= sizeof(value
);
2638 if (ERROR_SUCCESS
!= RegQueryValueExW(hkey
, NULL
, NULL
, NULL
, (BYTE
*)value
, &len
))
2639 return REGDB_E_IIDNOTREG
;
2642 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2643 return REGDB_E_IIDNOTREG
;
2648 /*****************************************************************************
2649 * CoGetPSClsid [OLE32.@]
2651 * Retrieves the CLSID of the proxy/stub factory that implements
2652 * IPSFactoryBuffer for the specified interface.
2655 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2656 * pclsid [O] Where to store returned proxy/stub CLSID.
2661 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2665 * The standard marshaller activates the object with the CLSID
2666 * returned and uses the CreateProxy and CreateStub methods on its
2667 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2670 * CoGetPSClsid determines this CLSID by searching the
2671 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2672 * in the registry and any interface id registered by
2673 * CoRegisterPSClsid within the current process.
2677 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2678 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2679 * considered a bug in native unless an application depends on this (unlikely).
2682 * CoRegisterPSClsid.
2684 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2686 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2687 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2688 WCHAR path
[ARRAY_SIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAY_SIZE(wszPSC
)];
2690 struct registered_psclsid
*registered_psclsid
;
2691 ACTCTX_SECTION_KEYED_DATA data
;
2693 REGSAM opposite
= (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
;
2696 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2698 if (!(apt
= apartment_get_current_or_mta()))
2700 ERR("apartment not initialised\n");
2701 return CO_E_NOTINITIALIZED
;
2703 apartment_release(apt
);
2706 return E_INVALIDARG
;
2708 EnterCriticalSection(&cs_registered_psclsid_list
);
2710 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2711 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2713 *pclsid
= registered_psclsid
->clsid
;
2714 LeaveCriticalSection(&cs_registered_psclsid_list
);
2718 LeaveCriticalSection(&cs_registered_psclsid_list
);
2720 data
.cbSize
= sizeof(data
);
2721 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2724 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2725 *pclsid
= ifaceps
->iid
;
2729 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2730 lstrcpyW(path
, wszInterface
);
2731 StringFromGUID2(riid
, path
+ ARRAY_SIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2732 lstrcpyW(path
+ ARRAY_SIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2734 hr
= get_ps_clsid_from_registry(path
, 0, pclsid
);
2735 if (FAILED(hr
) && (opposite
== KEY_WOW64_32KEY
||
2736 (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)))
2737 hr
= get_ps_clsid_from_registry(path
, opposite
, pclsid
);
2740 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2742 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2747 /*****************************************************************************
2748 * CoRegisterPSClsid [OLE32.@]
2750 * Register a proxy/stub CLSID for the given interface in the current process
2754 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2755 * rclsid [I] CLSID of the proxy/stub.
2759 * Failure: E_OUTOFMEMORY
2763 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2764 * will be returned from other apartments in the same process.
2766 * This function does not add anything to the registry and the effects are
2767 * limited to the lifetime of the current process.
2772 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2775 struct registered_psclsid
*registered_psclsid
;
2777 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2779 if (!(apt
= apartment_get_current_or_mta()))
2781 ERR("apartment not initialised\n");
2782 return CO_E_NOTINITIALIZED
;
2784 apartment_release(apt
);
2786 EnterCriticalSection(&cs_registered_psclsid_list
);
2788 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2789 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2791 registered_psclsid
->clsid
= *rclsid
;
2792 LeaveCriticalSection(&cs_registered_psclsid_list
);
2796 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2797 if (!registered_psclsid
)
2799 LeaveCriticalSection(&cs_registered_psclsid_list
);
2800 return E_OUTOFMEMORY
;
2803 registered_psclsid
->iid
= *riid
;
2804 registered_psclsid
->clsid
= *rclsid
;
2805 list_add_head(®istered_psclsid_list
, ®istered_psclsid
->entry
);
2807 LeaveCriticalSection(&cs_registered_psclsid_list
);
2814 * COM_GetRegisteredClassObject
2816 * This internal method is used to scan the registered class list to
2817 * find a class object.
2820 * rclsid Class ID of the class to find.
2821 * dwClsContext Class context to match.
2822 * ppv [out] returns a pointer to the class object. Complying
2823 * to normal COM usage, this method will increase the
2824 * reference count on this object.
2826 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2827 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2829 HRESULT hr
= S_FALSE
;
2830 RegisteredClass
*curClass
;
2832 EnterCriticalSection( &csRegisteredClassList
);
2834 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2837 * Check if we have a match on the class ID and context.
2839 if ((apt
->oxid
== curClass
->apartment_id
) &&
2840 (dwClsContext
& curClass
->runContext
) &&
2841 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2844 * We have a match, return the pointer to the class object.
2846 *ppUnk
= curClass
->classObject
;
2848 IUnknown_AddRef(curClass
->classObject
);
2855 LeaveCriticalSection( &csRegisteredClassList
);
2860 /******************************************************************************
2861 * CoRegisterClassObject [OLE32.@]
2863 * Registers the class object for a given class ID. Servers housed in EXE
2864 * files use this method instead of exporting DllGetClassObject to allow
2865 * other code to connect to their objects.
2868 * rclsid [I] CLSID of the object to register.
2869 * pUnk [I] IUnknown of the object.
2870 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2871 * flags [I] REGCLS flags indicating how connections are made.
2872 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2876 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2877 * CO_E_OBJISREG if the object is already registered. We should not return this.
2880 * CoRevokeClassObject, CoGetClassObject
2883 * In-process objects are only registered for the current apartment.
2884 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2885 * in other apartments.
2888 * MSDN claims that multiple interface registrations are legal, but we
2889 * can't do that with our current implementation.
2891 HRESULT WINAPI
CoRegisterClassObject(
2896 LPDWORD lpdwRegister
)
2898 static LONG next_cookie
;
2899 RegisteredClass
* newClass
;
2900 LPUNKNOWN foundObject
;
2904 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2905 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2907 if ( (lpdwRegister
==0) || (pUnk
==0) )
2908 return E_INVALIDARG
;
2910 if (!(apt
= apartment_get_current_or_mta()))
2912 ERR("COM was not initialized\n");
2913 return CO_E_NOTINITIALIZED
;
2918 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2919 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2920 if (flags
& REGCLS_MULTIPLEUSE
)
2921 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2924 * First, check if the class is already registered.
2925 * If it is, this should cause an error.
2927 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2929 if (flags
& REGCLS_MULTIPLEUSE
) {
2930 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2931 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2932 IUnknown_Release(foundObject
);
2933 apartment_release(apt
);
2936 IUnknown_Release(foundObject
);
2937 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2938 apartment_release(apt
);
2939 return CO_E_OBJISREG
;
2942 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2943 if ( newClass
== NULL
)
2945 apartment_release(apt
);
2946 return E_OUTOFMEMORY
;
2949 newClass
->classIdentifier
= *rclsid
;
2950 newClass
->apartment_id
= apt
->oxid
;
2951 newClass
->runContext
= dwClsContext
;
2952 newClass
->connectFlags
= flags
;
2953 newClass
->RpcRegistration
= NULL
;
2955 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2956 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2959 * Since we're making a copy of the object pointer, we have to increase its
2962 newClass
->classObject
= pUnk
;
2963 IUnknown_AddRef(newClass
->classObject
);
2965 EnterCriticalSection( &csRegisteredClassList
);
2966 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2967 LeaveCriticalSection( &csRegisteredClassList
);
2969 *lpdwRegister
= newClass
->dwCookie
;
2971 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2972 IStream
*marshal_stream
;
2974 hr
= get_local_server_stream(apt
, &marshal_stream
);
2977 apartment_release(apt
);
2981 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2983 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2984 &newClass
->RpcRegistration
);
2985 IStream_Release(marshal_stream
);
2987 apartment_release(apt
);
2991 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2995 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2996 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2997 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2998 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2999 WCHAR threading_model
[10 /* lstrlenW(L"apartment")+1 */];
3000 DWORD dwLength
= sizeof(threading_model
);
3004 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
3005 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
3006 threading_model
[0] = '\0';
3008 if (!wcsicmp(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
3009 if (!wcsicmp(threading_model
, wszFree
)) return ThreadingModel_Free
;
3010 if (!wcsicmp(threading_model
, wszBoth
)) return ThreadingModel_Both
;
3012 /* there's not specific handling for this case */
3013 if (threading_model
[0]) return ThreadingModel_Neutral
;
3014 return ThreadingModel_No
;
3017 return data
->u
.actctx
.data
->model
;
3020 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
3021 REFCLSID rclsid
, REFIID riid
,
3022 BOOL hostifnecessary
, void **ppv
)
3024 WCHAR dllpath
[MAX_PATH
+1];
3025 BOOL apartment_threaded
;
3027 if (hostifnecessary
)
3029 enum comclass_threadingmodel model
= get_threading_model(regdata
);
3031 if (model
== ThreadingModel_Apartment
)
3033 apartment_threaded
= TRUE
;
3034 if (apt
->multi_threaded
)
3035 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
3037 else if (model
== ThreadingModel_Free
)
3039 apartment_threaded
= FALSE
;
3040 if (!apt
->multi_threaded
)
3041 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
3043 /* everything except "Apartment", "Free" and "Both" */
3044 else if (model
!= ThreadingModel_Both
)
3046 apartment_threaded
= TRUE
;
3047 /* everything else is main-threaded */
3048 if (model
!= ThreadingModel_No
)
3049 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
3051 if (apt
->multi_threaded
|| !apt
->main
)
3052 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
3055 apartment_threaded
= FALSE
;
3058 apartment_threaded
= !apt
->multi_threaded
;
3060 if (!get_object_dll_path(regdata
, dllpath
, ARRAY_SIZE(dllpath
)))
3062 /* failure: CLSID is not found in registry */
3063 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
3064 return REGDB_E_CLASSNOTREG
;
3067 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
3071 /***********************************************************************
3072 * CoGetClassObject [OLE32.@]
3074 * Creates an object of the specified class.
3077 * rclsid [I] Class ID to create an instance of.
3078 * dwClsContext [I] Flags to restrict the location of the created instance.
3079 * pServerInfo [I] Optional. Details for connecting to a remote server.
3080 * iid [I] The ID of the interface of the instance to return.
3081 * ppv [O] On returns, contains a pointer to the specified interface of the object.
3085 * Failure: HRESULT code.
3088 * The dwClsContext parameter can be one or more of the following:
3089 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3090 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3091 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3092 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3095 * CoCreateInstance()
3097 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
3098 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
3099 REFIID iid
, LPVOID
*ppv
)
3101 struct class_reg_data clsreg
;
3102 IUnknown
*regClassObject
;
3103 HRESULT hres
= E_UNEXPECTED
;
3106 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
3109 return E_INVALIDARG
;
3113 if (!(apt
= apartment_get_current_or_mta()))
3115 ERR("apartment not initialised\n");
3116 return CO_E_NOTINITIALIZED
;
3120 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3121 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
3124 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3126 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
3128 apartment_release(apt
);
3129 return FTMarshalCF_Create(iid
, ppv
);
3131 if (IsEqualCLSID(rclsid
, &CLSID_GlobalOptions
))
3132 return IClassFactory_QueryInterface(&GlobalOptionsCF
, iid
, ppv
);
3135 if (CLSCTX_INPROC
& dwClsContext
)
3137 ACTCTX_SECTION_KEYED_DATA data
;
3139 data
.cbSize
= sizeof(data
);
3140 /* search activation context first */
3141 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
3142 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
3145 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
3147 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
3148 clsreg
.u
.actctx
.data
= data
.lpData
;
3149 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
3150 clsreg
.hkey
= FALSE
;
3152 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3153 ReleaseActCtx(data
.hActCtx
);
3154 apartment_release(apt
);
3160 * First, try and see if we can't match the class ID with one of the
3161 * registered classes.
3163 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
3166 /* Get the required interface from the retrieved pointer. */
3167 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3170 * Since QI got another reference on the pointer, we want to release the
3171 * one we already have. If QI was unsuccessful, this will release the object. This
3172 * is good since we are not returning it in the "out" parameter.
3174 IUnknown_Release(regClassObject
);
3175 apartment_release(apt
);
3179 /* First try in-process server */
3180 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3182 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3185 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3188 if (hres
== REGDB_E_CLASSNOTREG
)
3189 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3190 else if (hres
== REGDB_E_KEYMISSING
)
3192 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3193 hres
= REGDB_E_CLASSNOTREG
;
3197 if (SUCCEEDED(hres
))
3199 clsreg
.u
.hkey
= hkey
;
3202 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3206 /* return if we got a class, otherwise fall through to one of the
3208 if (SUCCEEDED(hres
))
3210 apartment_release(apt
);
3215 /* Next try in-process handler */
3216 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3218 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3221 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3224 if (hres
== REGDB_E_CLASSNOTREG
)
3225 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3226 else if (hres
== REGDB_E_KEYMISSING
)
3228 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3229 hres
= REGDB_E_CLASSNOTREG
;
3233 if (SUCCEEDED(hres
))
3235 clsreg
.u
.hkey
= hkey
;
3238 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3242 /* return if we got a class, otherwise fall through to one of the
3244 if (SUCCEEDED(hres
))
3246 apartment_release(apt
);
3250 apartment_release(apt
);
3252 /* Next try out of process */
3253 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3255 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3256 if (SUCCEEDED(hres
))
3260 /* Finally try remote: this requires networked DCOM (a lot of work) */
3261 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3263 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3264 hres
= REGDB_E_CLASSNOTREG
;
3268 ERR("no class object %s could be created for context 0x%x\n",
3269 debugstr_guid(rclsid
), dwClsContext
);
3273 /***********************************************************************
3274 * CoResumeClassObjects (OLE32.@)
3276 * Resumes all class objects registered with REGCLS_SUSPENDED.
3280 * Failure: HRESULT code.
3282 HRESULT WINAPI
CoResumeClassObjects(void)
3288 /***********************************************************************
3289 * CoCreateInstance [OLE32.@]
3291 * Creates an instance of the specified class.
3294 * rclsid [I] Class ID to create an instance of.
3295 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3296 * dwClsContext [I] Flags to restrict the location of the created instance.
3297 * iid [I] The ID of the interface of the instance to return.
3298 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3302 * Failure: HRESULT code.
3305 * The dwClsContext parameter can be one or more of the following:
3306 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3307 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3308 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3309 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3311 * Aggregation is the concept of deferring the IUnknown of an object to another
3312 * object. This allows a separate object to behave as though it was part of
3313 * the object and to allow this the pUnkOuter parameter can be set. Note that
3314 * not all objects support having an outer of unknown.
3317 * CoGetClassObject()
3319 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3321 LPUNKNOWN pUnkOuter
,
3326 MULTI_QI multi_qi
= { iid
};
3329 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3330 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3335 hres
= CoCreateInstanceEx(rclsid
, pUnkOuter
, dwClsContext
, NULL
, 1, &multi_qi
);
3336 *ppv
= multi_qi
.pItf
;
3340 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
, HRESULT hr
)
3344 for (i
= 0; i
< count
; i
++)
3351 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
, BOOL include_unk
)
3353 ULONG index
= 0, fetched
= 0;
3359 index
= fetched
= 1;
3362 for (; index
< count
; index
++)
3364 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3365 if (mqi
[index
].hr
== S_OK
)
3370 IUnknown_Release(unk
);
3373 return E_NOINTERFACE
;
3375 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3378 /***********************************************************************
3379 * CoCreateInstanceEx [OLE32.@]
3381 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstanceEx(
3383 LPUNKNOWN pUnkOuter
,
3385 COSERVERINFO
* pServerInfo
,
3389 IUnknown
*unk
= NULL
;
3395 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid
), pUnkOuter
, dwClsContext
, pServerInfo
, cmq
, pResults
);
3397 if (!cmq
|| !pResults
)
3398 return E_INVALIDARG
;
3401 FIXME("() non-NULL pServerInfo not supported!\n");
3403 init_multi_qi(cmq
, pResults
, E_NOINTERFACE
);
3405 hres
= CoGetTreatAsClass(rclsid
, &clsid
);
3409 if (!(apt
= apartment_get_current_or_mta()))
3411 ERR("apartment not initialised\n");
3412 return CO_E_NOTINITIALIZED
;
3414 apartment_release(apt
);
3417 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3419 if (IsEqualIID(&clsid
, &CLSID_StdGlobalInterfaceTable
))
3421 IGlobalInterfaceTable
*git
= get_std_git();
3422 TRACE("Retrieving GIT\n");
3423 return return_multi_qi((IUnknown
*)git
, cmq
, pResults
, FALSE
);
3426 if (IsEqualCLSID(&clsid
, &CLSID_ManualResetEvent
)) {
3427 hres
= ManualResetEvent_Construct(pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3430 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3434 * Get a class factory to construct the object we want.
3436 hres
= CoGetClassObject(&clsid
, dwClsContext
, NULL
, &IID_IClassFactory
, (void**)&cf
);
3441 * Create the object and don't forget to release the factory
3443 hres
= IClassFactory_CreateInstance(cf
, pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3444 IClassFactory_Release(cf
);
3447 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3448 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid
));
3450 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3451 debugstr_guid(pResults
[0].pIID
),
3452 debugstr_guid(&clsid
),hres
);
3456 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3459 /***********************************************************************
3460 * CoGetInstanceFromFile [OLE32.@]
3462 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetInstanceFromFile(
3463 COSERVERINFO
*server_info
,
3473 IPersistFile
*pf
= NULL
;
3474 IUnknown
* unk
= NULL
;
3478 if (count
== 0 || !results
)
3479 return E_INVALIDARG
;
3482 FIXME("() non-NULL server_info not supported\n");
3484 init_multi_qi(count
, results
, E_NOINTERFACE
);
3486 /* optionally get CLSID from a file */
3489 hr
= GetClassFile(filename
, &clsid
);
3492 ERR("failed to get CLSID from a file\n");
3499 hr
= CoCreateInstance(rclsid
,
3507 init_multi_qi(count
, results
, hr
);
3511 /* init from file */
3512 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3515 init_multi_qi(count
, results
, hr
);
3516 IUnknown_Release(unk
);
3520 hr
= IPersistFile_Load(pf
, filename
, grfmode
);
3521 IPersistFile_Release(pf
);
3523 return return_multi_qi(unk
, count
, results
, FALSE
);
3526 init_multi_qi(count
, results
, hr
);
3527 IUnknown_Release(unk
);
3532 /***********************************************************************
3533 * CoGetInstanceFromIStorage [OLE32.@]
3535 HRESULT WINAPI
CoGetInstanceFromIStorage(
3536 COSERVERINFO
*server_info
,
3545 IPersistStorage
*ps
= NULL
;
3546 IUnknown
* unk
= NULL
;
3550 if (count
== 0 || !results
|| !storage
)
3551 return E_INVALIDARG
;
3554 FIXME("() non-NULL server_info not supported\n");
3556 init_multi_qi(count
, results
, E_NOINTERFACE
);
3558 /* optionally get CLSID from a file */
3561 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3562 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3565 ERR("failed to get CLSID from a file\n");
3569 rclsid
= &stat
.clsid
;
3572 hr
= CoCreateInstance(rclsid
,
3581 /* init from IStorage */
3582 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3584 ERR("failed to get IPersistStorage\n");
3588 IPersistStorage_Load(ps
, storage
);
3589 IPersistStorage_Release(ps
);
3592 return return_multi_qi(unk
, count
, results
, FALSE
);
3595 /***********************************************************************
3596 * CoLoadLibrary (OLE32.@)
3601 * lpszLibName [I] Path to library.
3602 * bAutoFree [I] Whether the library should automatically be freed.
3605 * Success: Handle to loaded library.
3609 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3611 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3613 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3615 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3618 /***********************************************************************
3619 * CoFreeLibrary [OLE32.@]
3621 * Unloads a library from memory.
3624 * hLibrary [I] Handle to library to unload.
3630 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3632 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3634 FreeLibrary(hLibrary
);
3638 /***********************************************************************
3639 * CoFreeAllLibraries [OLE32.@]
3641 * Function for backwards compatibility only. Does nothing.
3647 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3649 void WINAPI
CoFreeAllLibraries(void)
3654 /***********************************************************************
3655 * CoFreeUnusedLibrariesEx [OLE32.@]
3657 * Frees any previously unused libraries whose delay has expired and marks
3658 * currently unused libraries for unloading. Unused are identified as those that
3659 * return S_OK from their DllCanUnloadNow function.
3662 * dwUnloadDelay [I] Unload delay in milliseconds.
3663 * dwReserved [I] Reserved. Set to 0.
3669 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3671 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3673 struct apartment
*apt
= COM_CurrentApt();
3676 ERR("apartment not initialised\n");
3680 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3683 /***********************************************************************
3684 * CoFreeUnusedLibraries [OLE32.@]
3686 * Frees any unused libraries. Unused are identified as those that return
3687 * S_OK from their DllCanUnloadNow function.
3693 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3695 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibraries(void)
3697 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3700 /***********************************************************************
3701 * CoFileTimeNow [OLE32.@]
3703 * Retrieves the current time in FILETIME format.
3706 * lpFileTime [O] The current time.
3711 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3713 GetSystemTimeAsFileTime( lpFileTime
);
3717 /******************************************************************************
3718 * CoLockObjectExternal [OLE32.@]
3720 * Increments or decrements the external reference count of a stub object.
3723 * pUnk [I] Stub object.
3724 * fLock [I] If TRUE then increments the external ref-count,
3725 * otherwise decrements.
3726 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3727 * calling CoDisconnectObject.
3731 * Failure: HRESULT code.
3734 * If fLock is TRUE and an object is passed in that doesn't have a stub
3735 * manager then a new stub manager is created for the object.
3737 HRESULT WINAPI
CoLockObjectExternal(
3740 BOOL fLastUnlockReleases
)
3742 struct stub_manager
*stubmgr
;
3743 struct apartment
*apt
;
3745 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3746 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3748 if (!(apt
= apartment_get_current_or_mta()))
3750 ERR("apartment not initialised\n");
3751 return CO_E_NOTINITIALIZED
;
3754 stubmgr
= get_stub_manager_from_object(apt
, pUnk
, fLock
);
3757 WARN("stub object not found %p\n", pUnk
);
3758 /* Note: native is pretty broken here because it just silently
3759 * fails, without returning an appropriate error code, making apps
3760 * think that the object was disconnected, when it actually wasn't */
3761 apartment_release(apt
);
3766 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3768 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3770 stub_manager_int_release(stubmgr
);
3771 apartment_release(apt
);
3775 /***********************************************************************
3776 * CoInitializeWOW (OLE32.@)
3778 * WOW equivalent of CoInitialize?
3787 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3789 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3793 /***********************************************************************
3794 * CoGetState [OLE32.@]
3796 * Retrieves the thread state object previously stored by CoSetState().
3799 * ppv [I] Address where pointer to object will be stored.
3803 * Failure: E_OUTOFMEMORY.
3806 * Crashes on all invalid ppv addresses, including NULL.
3807 * If the function returns a non-NULL object then the caller must release its
3808 * reference on the object when the object is no longer required.
3813 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3815 struct oletls
*info
= COM_CurrentInfo();
3816 if (!info
) return E_OUTOFMEMORY
;
3822 IUnknown_AddRef(info
->state
);
3824 TRACE("apt->state=%p\n", info
->state
);
3830 /***********************************************************************
3831 * CoSetState [OLE32.@]
3833 * Sets the thread state object.
3836 * pv [I] Pointer to state object to be stored.
3839 * The system keeps a reference on the object while the object stored.
3843 * Failure: E_OUTOFMEMORY.
3845 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3847 struct oletls
*info
= COM_CurrentInfo();
3848 if (!info
) return E_OUTOFMEMORY
;
3850 if (pv
) IUnknown_AddRef(pv
);
3854 TRACE("-- release %p now\n", info
->state
);
3855 IUnknown_Release(info
->state
);
3864 /******************************************************************************
3865 * CoTreatAsClass [OLE32.@]
3867 * Sets the TreatAs value of a class.
3870 * clsidOld [I] Class to set TreatAs value on.
3871 * clsidNew [I] The class the clsidOld should be treated as.
3875 * Failure: HRESULT code.
3880 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3882 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3883 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3885 WCHAR szClsidNew
[CHARS_IN_GUID
];
3887 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3888 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3891 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3895 if (IsEqualGUID( clsidOld
, clsidNew
))
3897 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3898 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3900 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3902 res
= REGDB_E_WRITEREGDB
;
3908 if(RegDeleteKeyW(hkey
, wszTreatAs
))
3909 res
= REGDB_E_WRITEREGDB
;
3915 if(IsEqualGUID(clsidNew
, &CLSID_NULL
)){
3916 RegDeleteKeyW(hkey
, wszTreatAs
);
3918 if(!StringFromGUID2(clsidNew
, szClsidNew
, ARRAY_SIZE(szClsidNew
))){
3919 WARN("StringFromGUID2 failed\n");
3924 if(RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)) != ERROR_SUCCESS
){
3925 WARN("RegSetValue failed\n");
3926 res
= REGDB_E_WRITEREGDB
;
3933 if (hkey
) RegCloseKey(hkey
);
3937 /******************************************************************************
3938 * CoGetTreatAsClass [OLE32.@]
3940 * Gets the TreatAs value of a class.
3943 * clsidOld [I] Class to get the TreatAs value of.
3944 * clsidNew [I] The class the clsidOld should be treated as.
3948 * Failure: HRESULT code.
3953 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3955 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3957 WCHAR szClsidNew
[CHARS_IN_GUID
];
3959 LONG len
= sizeof(szClsidNew
);
3961 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3963 if (!clsidOld
|| !clsidNew
)
3964 return E_INVALIDARG
;
3966 *clsidNew
= *clsidOld
; /* copy over old value */
3968 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3974 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3979 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3981 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3983 if (hkey
) RegCloseKey(hkey
);
3987 /******************************************************************************
3988 * CoGetCurrentProcess [OLE32.@]
3990 * Gets the current process ID.
3993 * The current process ID.
3996 * Is DWORD really the correct return type for this function?
3998 DWORD WINAPI
CoGetCurrentProcess(void)
4000 return GetCurrentProcessId();
4003 /***********************************************************************
4004 * CoGetCurrentLogicalThreadId [OLE32.@]
4006 HRESULT WINAPI
CoGetCurrentLogicalThreadId(GUID
*id
)
4008 TRACE("(%p)\n", id
);
4011 return E_INVALIDARG
;
4013 *id
= COM_CurrentCausalityId();
4017 /******************************************************************************
4018 * CoRegisterMessageFilter [OLE32.@]
4020 * Registers a message filter.
4023 * lpMessageFilter [I] Pointer to interface.
4024 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
4028 * Failure: HRESULT code.
4031 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
4032 * lpMessageFilter removes the message filter.
4034 * If lplpMessageFilter is not NULL the previous message filter will be
4035 * returned in the memory pointer to this parameter and the caller is
4036 * responsible for releasing the object.
4038 * The current thread be in an apartment otherwise the function will crash.
4040 HRESULT WINAPI
CoRegisterMessageFilter(
4041 LPMESSAGEFILTER lpMessageFilter
,
4042 LPMESSAGEFILTER
*lplpMessageFilter
)
4044 struct apartment
*apt
;
4045 IMessageFilter
*lpOldMessageFilter
;
4047 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
4049 apt
= COM_CurrentApt();
4051 /* can't set a message filter in a multi-threaded apartment */
4052 if (!apt
|| apt
->multi_threaded
)
4054 WARN("can't set message filter in MTA or uninitialized apt\n");
4055 return CO_E_NOT_SUPPORTED
;
4058 if (lpMessageFilter
)
4059 IMessageFilter_AddRef(lpMessageFilter
);
4061 EnterCriticalSection(&apt
->cs
);
4063 lpOldMessageFilter
= apt
->filter
;
4064 apt
->filter
= lpMessageFilter
;
4066 LeaveCriticalSection(&apt
->cs
);
4068 if (lplpMessageFilter
)
4069 *lplpMessageFilter
= lpOldMessageFilter
;
4070 else if (lpOldMessageFilter
)
4071 IMessageFilter_Release(lpOldMessageFilter
);
4076 /***********************************************************************
4077 * CoIsOle1Class [OLE32.@]
4079 * Determines whether the specified class an OLE v1 class.
4082 * clsid [I] Class to test.
4085 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
4087 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
4089 FIXME("%s\n", debugstr_guid(clsid
));
4093 /***********************************************************************
4094 * IsEqualGUID [OLE32.@]
4096 * Compares two Unique Identifiers.
4099 * rguid1 [I] The first GUID to compare.
4100 * rguid2 [I] The other GUID to compare.
4106 BOOL WINAPI
IsEqualGUID(
4110 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
4113 /***********************************************************************
4114 * CoInitializeSecurity [OLE32.@]
4116 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
4117 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
4118 void* pReserved1
, DWORD dwAuthnLevel
,
4119 DWORD dwImpLevel
, void* pReserved2
,
4120 DWORD dwCapabilities
, void* pReserved3
)
4122 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
4123 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
4124 dwCapabilities
, pReserved3
);
4128 /***********************************************************************
4129 * CoSuspendClassObjects [OLE32.@]
4131 * Suspends all registered class objects to prevent further requests coming in
4132 * for those objects.
4136 * Failure: HRESULT code.
4138 HRESULT WINAPI
CoSuspendClassObjects(void)
4144 /***********************************************************************
4145 * CoAddRefServerProcess [OLE32.@]
4147 * Helper function for incrementing the reference count of a local-server
4151 * New reference count.
4154 * CoReleaseServerProcess().
4156 ULONG WINAPI
CoAddRefServerProcess(void)
4162 EnterCriticalSection(&csRegisteredClassList
);
4163 refs
= ++s_COMServerProcessReferences
;
4164 LeaveCriticalSection(&csRegisteredClassList
);
4166 TRACE("refs before: %d\n", refs
- 1);
4171 /***********************************************************************
4172 * CoReleaseServerProcess [OLE32.@]
4174 * Helper function for decrementing the reference count of a local-server
4178 * New reference count.
4181 * When reference count reaches 0, this function suspends all registered
4182 * classes so no new connections are accepted.
4185 * CoAddRefServerProcess(), CoSuspendClassObjects().
4187 ULONG WINAPI
CoReleaseServerProcess(void)
4193 EnterCriticalSection(&csRegisteredClassList
);
4195 refs
= --s_COMServerProcessReferences
;
4196 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4198 LeaveCriticalSection(&csRegisteredClassList
);
4200 TRACE("refs after: %d\n", refs
);
4205 /***********************************************************************
4206 * CoIsHandlerConnected [OLE32.@]
4208 * Determines whether a proxy is connected to a remote stub.
4211 * pUnk [I] Pointer to object that may or may not be connected.
4214 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4217 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4219 FIXME("%p\n", pUnk
);
4224 /***********************************************************************
4225 * CoAllowSetForegroundWindow [OLE32.@]
4228 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4230 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4234 /***********************************************************************
4235 * CoQueryProxyBlanket [OLE32.@]
4237 * Retrieves the security settings being used by a proxy.
4240 * pProxy [I] Pointer to the proxy object.
4241 * pAuthnSvc [O] The type of authentication service.
4242 * pAuthzSvc [O] The type of authorization service.
4243 * ppServerPrincName [O] Optional. The server prinicple name.
4244 * pAuthnLevel [O] The authentication level.
4245 * pImpLevel [O] The impersonation level.
4246 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4247 * pCapabilities [O] Flags affecting the security behaviour.
4251 * Failure: HRESULT code.
4254 * CoCopyProxy, CoSetProxyBlanket.
4256 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4257 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4258 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4260 IClientSecurity
*pCliSec
;
4263 TRACE("%p\n", pProxy
);
4265 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4268 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4269 pAuthzSvc
, ppServerPrincName
,
4270 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4272 IClientSecurity_Release(pCliSec
);
4275 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4279 /***********************************************************************
4280 * CoSetProxyBlanket [OLE32.@]
4282 * Sets the security settings for a proxy.
4285 * pProxy [I] Pointer to the proxy object.
4286 * AuthnSvc [I] The type of authentication service.
4287 * AuthzSvc [I] The type of authorization service.
4288 * pServerPrincName [I] The server prinicple name.
4289 * AuthnLevel [I] The authentication level.
4290 * ImpLevel [I] The impersonation level.
4291 * pAuthInfo [I] Information specific to the authorization/authentication service.
4292 * Capabilities [I] Flags affecting the security behaviour.
4296 * Failure: HRESULT code.
4299 * CoQueryProxyBlanket, CoCopyProxy.
4301 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4302 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4303 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4305 IClientSecurity
*pCliSec
;
4308 TRACE("%p\n", pProxy
);
4310 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4313 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4314 AuthzSvc
, pServerPrincName
,
4315 AuthnLevel
, ImpLevel
, pAuthInfo
,
4317 IClientSecurity_Release(pCliSec
);
4320 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4324 /***********************************************************************
4325 * CoCopyProxy [OLE32.@]
4330 * pProxy [I] Pointer to the proxy object.
4331 * ppCopy [O] Copy of the proxy.
4335 * Failure: HRESULT code.
4338 * CoQueryProxyBlanket, CoSetProxyBlanket.
4340 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4342 IClientSecurity
*pCliSec
;
4345 TRACE("%p\n", pProxy
);
4347 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4350 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4351 IClientSecurity_Release(pCliSec
);
4354 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4359 /***********************************************************************
4360 * CoGetCallContext [OLE32.@]
4362 * Gets the context of the currently executing server call in the current
4366 * riid [I] Context interface to return.
4367 * ppv [O] Pointer to memory that will receive the context on return.
4371 * Failure: HRESULT code.
4373 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4375 struct oletls
*info
= COM_CurrentInfo();
4377 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4380 return E_OUTOFMEMORY
;
4382 if (!info
->call_state
)
4383 return RPC_E_CALL_COMPLETE
;
4385 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4388 /***********************************************************************
4389 * CoSwitchCallContext [OLE32.@]
4391 * Switches the context of the currently executing server call in the current
4395 * pObject [I] Pointer to new context object
4396 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4400 * Failure: HRESULT code.
4402 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4404 struct oletls
*info
= COM_CurrentInfo();
4406 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4409 return E_OUTOFMEMORY
;
4411 *ppOldObject
= info
->call_state
;
4412 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4417 /***********************************************************************
4418 * CoQueryClientBlanket [OLE32.@]
4420 * Retrieves the authentication information about the client of the currently
4421 * executing server call in the current thread.
4424 * pAuthnSvc [O] Optional. The type of authentication service.
4425 * pAuthzSvc [O] Optional. The type of authorization service.
4426 * pServerPrincName [O] Optional. The server prinicple name.
4427 * pAuthnLevel [O] Optional. The authentication level.
4428 * pImpLevel [O] Optional. The impersonation level.
4429 * pPrivs [O] Optional. Information about the privileges of the client.
4430 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4434 * Failure: HRESULT code.
4437 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4439 HRESULT WINAPI
CoQueryClientBlanket(
4442 OLECHAR
**pServerPrincName
,
4445 RPC_AUTHZ_HANDLE
*pPrivs
,
4446 DWORD
*pCapabilities
)
4448 IServerSecurity
*pSrvSec
;
4451 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4452 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4453 pPrivs
, pCapabilities
);
4455 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4458 hr
= IServerSecurity_QueryBlanket(
4459 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4460 pImpLevel
, pPrivs
, pCapabilities
);
4461 IServerSecurity_Release(pSrvSec
);
4467 /***********************************************************************
4468 * CoImpersonateClient [OLE32.@]
4470 * Impersonates the client of the currently executing server call in the
4478 * Failure: HRESULT code.
4481 * If this function fails then the current thread will not be impersonating
4482 * the client and all actions will take place on behalf of the server.
4483 * Therefore, it is important to check the return value from this function.
4486 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4488 HRESULT WINAPI
CoImpersonateClient(void)
4490 IServerSecurity
*pSrvSec
;
4495 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4498 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4499 IServerSecurity_Release(pSrvSec
);
4505 /***********************************************************************
4506 * CoRevertToSelf [OLE32.@]
4508 * Ends the impersonation of the client of the currently executing server
4509 * call in the current thread.
4516 * Failure: HRESULT code.
4519 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4521 HRESULT WINAPI
CoRevertToSelf(void)
4523 IServerSecurity
*pSrvSec
;
4528 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4531 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4532 IServerSecurity_Release(pSrvSec
);
4538 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4540 /* first try to retrieve messages for incoming COM calls to the apartment window */
4541 return (apt
->win
&& PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
)) ||
4542 /* next retrieve other messages necessary for the app to remain responsive */
4543 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4544 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4547 /***********************************************************************
4548 * CoWaitForMultipleHandles [OLE32.@]
4550 * Waits for one or more handles to become signaled.
4553 * dwFlags [I] Flags. See notes.
4554 * dwTimeout [I] Timeout in milliseconds.
4555 * cHandles [I] Number of handles pointed to by pHandles.
4556 * pHandles [I] Handles to wait for.
4557 * lpdwindex [O] Index of handle that was signaled.
4561 * Failure: RPC_S_CALLPENDING on timeout.
4565 * The dwFlags parameter can be zero or more of the following:
4566 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4567 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4570 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4572 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4573 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4576 DWORD start_time
= GetTickCount();
4577 APARTMENT
*apt
= COM_CurrentApt();
4578 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4579 BOOL check_apc
= (dwFlags
& COWAIT_ALERTABLE
) != 0;
4580 BOOL post_quit
= FALSE
;
4583 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4584 pHandles
, lpdwindex
);
4587 return E_INVALIDARG
;
4592 return E_INVALIDARG
;
4595 return RPC_E_NO_SYNC
;
4599 DWORD now
= GetTickCount();
4602 if (now
- start_time
> dwTimeout
)
4604 hr
= RPC_S_CALLPENDING
;
4610 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4611 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4613 TRACE("waiting for rpc completion or window message\n");
4619 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
4620 (dwFlags
& COWAIT_WAITALL
) != 0, 0, TRUE
);
4624 if (res
== WAIT_TIMEOUT
)
4625 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4626 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4627 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4629 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4634 /* call message filter */
4636 if (COM_CurrentApt()->filter
)
4638 PENDINGTYPE pendingtype
=
4639 COM_CurrentInfo()->pending_call_count_server
?
4640 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4641 DWORD be_handled
= IMessageFilter_MessagePending(
4642 COM_CurrentApt()->filter
, 0 /* FIXME */,
4643 now
- start_time
, pendingtype
);
4644 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4647 case PENDINGMSG_CANCELCALL
:
4648 WARN("call canceled\n");
4649 hr
= RPC_E_CALL_CANCELED
;
4651 case PENDINGMSG_WAITNOPROCESS
:
4652 case PENDINGMSG_WAITDEFPROCESS
:
4654 /* FIXME: MSDN is very vague about the difference
4655 * between WAITNOPROCESS and WAITDEFPROCESS - there
4656 * appears to be none, so it is possibly a left-over
4657 * from the 16-bit world. */
4664 /* If window is NULL on apartment, peek at messages so that it will not trigger
4665 * MsgWaitForMultipleObjects next time. */
4666 PeekMessageW(NULL
, NULL
, 0, 0, PM_QS_POSTMESSAGE
| PM_NOREMOVE
| PM_NOYIELD
);
4668 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4669 * so after processing 100 messages we go back to checking the wait handles */
4670 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4672 if (msg
.message
== WM_QUIT
)
4674 TRACE("received WM_QUIT message\n");
4676 exit_code
= msg
.wParam
;
4680 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4681 TranslateMessage(&msg
);
4682 DispatchMessageW(&msg
);
4690 TRACE("waiting for rpc completion\n");
4692 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4693 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4694 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4700 hr
= RPC_S_CALLPENDING
;
4703 hr
= HRESULT_FROM_WIN32( GetLastError() );
4711 if (post_quit
) PostQuitMessage(exit_code
);
4712 TRACE("-- 0x%08x\n", hr
);
4717 /***********************************************************************
4718 * CoGetObject [OLE32.@]
4720 * Gets the object named by converting the name to a moniker and binding to it.
4723 * pszName [I] String representing the object.
4724 * pBindOptions [I] Parameters affecting the binding to the named object.
4725 * riid [I] Interface to bind to on the objecct.
4726 * ppv [O] On output, the interface riid of the object represented
4731 * Failure: HRESULT code.
4734 * MkParseDisplayName.
4736 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4737 REFIID riid
, void **ppv
)
4744 hr
= CreateBindCtx(0, &pbc
);
4748 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4755 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4758 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4759 IMoniker_Release(pmk
);
4763 IBindCtx_Release(pbc
);
4768 /***********************************************************************
4769 * CoRegisterChannelHook [OLE32.@]
4771 * Registers a process-wide hook that is called during ORPC calls.
4774 * guidExtension [I] GUID of the channel hook to register.
4775 * pChannelHook [I] Channel hook object to register.
4779 * Failure: HRESULT code.
4781 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4783 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4785 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4788 typedef struct Context
4790 IComThreadingInfo IComThreadingInfo_iface
;
4791 IContextCallback IContextCallback_iface
;
4792 IObjContext IObjContext_iface
;
4796 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4798 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4801 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4803 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4806 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4808 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4811 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4815 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4816 IsEqualIID(riid
, &IID_IUnknown
))
4818 *ppv
= &iface
->IComThreadingInfo_iface
;
4820 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4822 *ppv
= &iface
->IContextCallback_iface
;
4824 else if (IsEqualIID(riid
, &IID_IObjContext
))
4826 *ppv
= &iface
->IObjContext_iface
;
4831 IUnknown_AddRef((IUnknown
*)*ppv
);
4835 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4836 return E_NOINTERFACE
;
4839 static ULONG
Context_AddRef(Context
*This
)
4841 return InterlockedIncrement(&This
->refs
);
4844 static ULONG
Context_Release(Context
*This
)
4846 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4847 releasing context while refcount is at 0 destroys it. */
4850 HeapFree(GetProcessHeap(), 0, This
);
4854 return InterlockedDecrement(&This
->refs
);
4857 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4859 Context
*This
= impl_from_IComThreadingInfo(iface
);
4860 return Context_QueryInterface(This
, riid
, ppv
);
4863 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4865 Context
*This
= impl_from_IComThreadingInfo(iface
);
4866 return Context_AddRef(This
);
4869 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4871 Context
*This
= impl_from_IComThreadingInfo(iface
);
4872 return Context_Release(This
);
4875 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4877 APTTYPEQUALIFIER qualifier
;
4879 TRACE("(%p)\n", apttype
);
4881 return CoGetApartmentType(apttype
, &qualifier
);
4884 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4886 APTTYPEQUALIFIER qualifier
;
4890 hr
= CoGetApartmentType(&apttype
, &qualifier
);
4894 TRACE("(%p)\n", thdtype
);
4899 case APTTYPE_MAINSTA
:
4900 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4903 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4909 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4911 TRACE("(%p)\n", logical_thread_id
);
4912 return CoGetCurrentLogicalThreadId(logical_thread_id
);
4915 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4917 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4921 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4923 Context_CTI_QueryInterface
,
4925 Context_CTI_Release
,
4926 Context_CTI_GetCurrentApartmentType
,
4927 Context_CTI_GetCurrentThreadType
,
4928 Context_CTI_GetCurrentLogicalThreadId
,
4929 Context_CTI_SetCurrentLogicalThreadId
4932 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4934 Context
*This
= impl_from_IContextCallback(iface
);
4935 return Context_QueryInterface(This
, riid
, ppv
);
4938 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4940 Context
*This
= impl_from_IContextCallback(iface
);
4941 return Context_AddRef(This
);
4944 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4946 Context
*This
= impl_from_IContextCallback(iface
);
4947 return Context_Release(This
);
4950 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4951 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4953 Context
*This
= impl_from_IContextCallback(iface
);
4955 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4959 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4961 Context_CC_QueryInterface
,
4964 Context_CC_ContextCallback
4967 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4969 Context
*This
= impl_from_IObjContext(iface
);
4970 return Context_QueryInterface(This
, riid
, ppv
);
4973 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4975 Context
*This
= impl_from_IObjContext(iface
);
4976 return Context_AddRef(This
);
4979 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4981 Context
*This
= impl_from_IObjContext(iface
);
4982 return Context_Release(This
);
4985 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4987 Context
*This
= impl_from_IObjContext(iface
);
4989 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4993 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4995 Context
*This
= impl_from_IObjContext(iface
);
4997 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
5001 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
5003 Context
*This
= impl_from_IObjContext(iface
);
5005 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
5009 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
5011 Context
*This
= impl_from_IObjContext(iface
);
5013 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
5017 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
5019 Context
*This
= impl_from_IObjContext(iface
);
5020 FIXME("(%p/%p)\n", This
, iface
);
5023 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
5025 Context
*This
= impl_from_IObjContext(iface
);
5026 FIXME("(%p/%p)\n", This
, iface
);
5029 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
5031 Context
*This
= impl_from_IObjContext(iface
);
5032 FIXME("(%p/%p)\n", This
, iface
);
5035 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
5037 Context
*This
= impl_from_IObjContext(iface
);
5038 FIXME("(%p/%p)\n", This
, iface
);
5041 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
5043 Context
*This
= impl_from_IObjContext(iface
);
5044 FIXME("(%p/%p)\n", This
, iface
);
5047 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
5049 Context
*This
= impl_from_IObjContext(iface
);
5050 FIXME("(%p/%p)\n", This
, iface
);
5053 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
5055 Context
*This
= impl_from_IObjContext(iface
);
5056 FIXME("(%p/%p)\n", This
, iface
);
5059 static const IObjContextVtbl Context_Object_Vtbl
=
5061 Context_OC_QueryInterface
,
5064 Context_OC_SetProperty
,
5065 Context_OC_RemoveProperty
,
5066 Context_OC_GetProperty
,
5067 Context_OC_EnumContextProps
,
5068 Context_OC_Reserved1
,
5069 Context_OC_Reserved2
,
5070 Context_OC_Reserved3
,
5071 Context_OC_Reserved4
,
5072 Context_OC_Reserved5
,
5073 Context_OC_Reserved6
,
5074 Context_OC_Reserved7
5077 /***********************************************************************
5078 * CoGetObjectContext [OLE32.@]
5080 * Retrieves an object associated with the current context (i.e. apartment).
5083 * riid [I] ID of the interface of the object to retrieve.
5084 * ppv [O] Address where object will be stored on return.
5088 * Failure: HRESULT code.
5090 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
5092 IObjContext
*context
;
5095 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
5098 hr
= CoGetContextToken((ULONG_PTR
*)&context
);
5102 return IObjContext_QueryInterface(context
, riid
, ppv
);
5105 /***********************************************************************
5106 * CoGetContextToken [OLE32.@]
5108 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
5110 struct oletls
*info
= COM_CurrentInfo();
5113 TRACE("(%p)\n", token
);
5116 return E_OUTOFMEMORY
;
5118 if (!(apt
= apartment_get_current_or_mta()))
5120 ERR("apartment not initialised\n");
5121 return CO_E_NOTINITIALIZED
;
5123 apartment_release(apt
);
5128 if (!info
->context_token
)
5132 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
5134 return E_OUTOFMEMORY
;
5136 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
5137 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
5138 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
5139 /* Context token does not take a reference, it's always zero until the
5140 interface is explicitly requested with CoGetObjectContext(). */
5143 info
->context_token
= &context
->IObjContext_iface
;
5146 *token
= (ULONG_PTR
)info
->context_token
;
5147 TRACE("context_token=%p\n", info
->context_token
);
5152 /***********************************************************************
5153 * CoGetDefaultContext [OLE32.@]
5155 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
5157 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
5158 return E_NOINTERFACE
;
5161 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
5163 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5167 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
5168 if (SUCCEEDED(hres
))
5170 struct class_reg_data regdata
;
5171 WCHAR dllpath
[MAX_PATH
+1];
5173 regdata
.u
.hkey
= hkey
;
5174 regdata
.hkey
= TRUE
;
5176 if (get_object_dll_path(®data
, dllpath
, ARRAY_SIZE(dllpath
)))
5178 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
5179 if (!wcsicmp(dllpath
, wszOle32
))
5182 return HandlerCF_Create(rclsid
, riid
, ppv
);
5186 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
5190 return CLASS_E_CLASSNOTAVAILABLE
;
5193 /***********************************************************************
5194 * CoGetApartmentType [OLE32.@]
5196 HRESULT WINAPI
CoGetApartmentType(APTTYPE
*type
, APTTYPEQUALIFIER
*qualifier
)
5198 struct oletls
*info
= COM_CurrentInfo();
5201 TRACE("(%p, %p)\n", type
, qualifier
);
5203 if (!type
|| !qualifier
)
5204 return E_INVALIDARG
;
5207 return E_OUTOFMEMORY
;
5210 *type
= APTTYPE_CURRENT
;
5211 else if (info
->apt
->multi_threaded
)
5212 *type
= APTTYPE_MTA
;
5213 else if (info
->apt
->main
)
5214 *type
= APTTYPE_MAINSTA
;
5216 *type
= APTTYPE_STA
;
5218 *qualifier
= APTTYPEQUALIFIER_NONE
;
5220 if (!info
->apt
&& (apt
= apartment_find_mta()))
5222 apartment_release(apt
);
5223 *type
= APTTYPE_MTA
;
5224 *qualifier
= APTTYPEQUALIFIER_IMPLICIT_MTA
;
5227 return info
->apt
? S_OK
: CO_E_NOTINITIALIZED
;
5230 /***********************************************************************
5231 * CoDisableCallCancellation [OLE32.@]
5233 HRESULT WINAPI
CoDisableCallCancellation(void *reserved
)
5235 FIXME("(%p): stub\n", reserved
);
5240 /***********************************************************************
5241 * CoEnableCallCancellation [OLE32.@]
5243 HRESULT WINAPI
CoEnableCallCancellation(void *reserved
)
5245 FIXME("(%p): stub\n", reserved
);
5250 /***********************************************************************
5251 * CoRegisterSurrogate [OLE32.@]
5253 HRESULT WINAPI
CoRegisterSurrogate(ISurrogate
*surrogate
)
5255 FIXME("(%p): stub\n", surrogate
);
5260 /***********************************************************************
5261 * CoRegisterSurrogateEx [OLE32.@]
5263 HRESULT WINAPI
CoRegisterSurrogateEx(REFGUID guid
, void *reserved
)
5265 FIXME("(%s %p): stub\n", debugstr_guid(guid
), reserved
);
5271 IGlobalOptions IGlobalOptions_iface
;
5275 static inline GlobalOptions
*impl_from_IGlobalOptions(IGlobalOptions
*iface
)
5277 return CONTAINING_RECORD(iface
, GlobalOptions
, IGlobalOptions_iface
);
5280 static HRESULT WINAPI
GlobalOptions_QueryInterface(IGlobalOptions
*iface
, REFIID riid
, void **ppv
)
5282 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5284 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
5286 if (IsEqualGUID(&IID_IGlobalOptions
, riid
) || IsEqualGUID(&IID_IUnknown
, riid
))
5293 return E_NOINTERFACE
;
5296 IUnknown_AddRef((IUnknown
*)*ppv
);
5300 static ULONG WINAPI
GlobalOptions_AddRef(IGlobalOptions
*iface
)
5302 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5303 LONG ref
= InterlockedIncrement(&This
->ref
);
5305 TRACE("(%p) ref=%d\n", This
, ref
);
5310 static ULONG WINAPI
GlobalOptions_Release(IGlobalOptions
*iface
)
5312 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5313 LONG ref
= InterlockedDecrement(&This
->ref
);
5315 TRACE("(%p) ref=%d\n", This
, ref
);
5323 static HRESULT WINAPI
GlobalOptions_Set(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR value
)
5325 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5326 FIXME("(%p)->(%u %lx)\n", This
, property
, value
);
5330 static HRESULT WINAPI
GlobalOptions_Query(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR
*value
)
5332 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5333 FIXME("(%p)->(%u %p)\n", This
, property
, value
);
5337 static const IGlobalOptionsVtbl GlobalOptionsVtbl
= {
5338 GlobalOptions_QueryInterface
,
5339 GlobalOptions_AddRef
,
5340 GlobalOptions_Release
,
5345 HRESULT WINAPI
GlobalOptions_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **ppv
)
5347 GlobalOptions
*global_options
;
5350 TRACE("(%p %s %p)\n", outer
, debugstr_guid(riid
), ppv
);
5353 return E_INVALIDARG
;
5355 global_options
= heap_alloc(sizeof(*global_options
));
5356 if (!global_options
)
5357 return E_OUTOFMEMORY
;
5358 global_options
->IGlobalOptions_iface
.lpVtbl
= &GlobalOptionsVtbl
;
5359 global_options
->ref
= 1;
5361 hres
= IGlobalOptions_QueryInterface(&global_options
->IGlobalOptions_iface
, riid
, ppv
);
5362 IGlobalOptions_Release(&global_options
->IGlobalOptions_iface
);
5366 /***********************************************************************
5369 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
5371 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
5374 case DLL_PROCESS_ATTACH
:
5375 hProxyDll
= hinstDLL
;
5378 case DLL_PROCESS_DETACH
:
5379 if (reserved
) break;
5382 UnregisterClassW( (const WCHAR
*)MAKEINTATOM(apt_win_class
), hProxyDll
);
5383 RPC_UnregisterAllChannelHooks();
5384 COMPOBJ_DllList_Free();
5385 DeleteCriticalSection(&csRegisteredClassList
);
5386 DeleteCriticalSection(&csApartment
);
5389 case DLL_THREAD_DETACH
:
5396 /***********************************************************************
5397 * DllRegisterServer (OLE32.@)
5399 HRESULT WINAPI
DllRegisterServer(void)
5401 return OLE32_DllRegisterServer();
5404 /***********************************************************************
5405 * DllUnregisterServer (OLE32.@)
5407 HRESULT WINAPI
DllUnregisterServer(void)
5409 return OLE32_DllUnregisterServer();