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
119 ULONG clrdata_offset
;
121 DWORD miscstatuscontent
;
122 DWORD miscstatusthumbnail
;
123 DWORD miscstatusicon
;
124 DWORD miscstatusdocprint
;
127 struct ifacepsredirect_data
139 struct progidredirect_data
146 enum class_reg_data_origin
152 struct class_reg_data
154 enum class_reg_data_origin origin
;
159 const WCHAR
*module_name
;
160 DWORD threading_model
;
167 struct registered_psclsid
174 static struct list registered_psclsid_list
= LIST_INIT(registered_psclsid_list
);
176 static CRITICAL_SECTION cs_registered_psclsid_list
;
177 static CRITICAL_SECTION_DEBUG psclsid_cs_debug
=
179 0, 0, &cs_registered_psclsid_list
,
180 { &psclsid_cs_debug
.ProcessLocksList
, &psclsid_cs_debug
.ProcessLocksList
},
181 0, 0, { (DWORD_PTR
)(__FILE__
": cs_registered_psclsid_list") }
183 static CRITICAL_SECTION cs_registered_psclsid_list
= { &psclsid_cs_debug
, -1, 0, 0, 0, 0 };
186 * This is a marshallable object exposing registered local servers.
187 * IServiceProvider is used only because it happens meet requirements
188 * and already has proxy/stub code. If more functionality is needed,
189 * a custom interface may be used instead.
193 IServiceProvider IServiceProvider_iface
;
196 IStream
*marshal_stream
;
200 * This lock count counts the number of times CoInitialize is called. It is
201 * decreased every time CoUninitialize is called. When it hits 0, the COM
202 * libraries are freed
204 static LONG s_COMLockCount
= 0;
205 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
206 static LONG s_COMServerProcessReferences
= 0;
209 * This linked list contains the list of registered class objects. These
210 * are mostly used to register the factories for out-of-proc servers of OLE
213 * TODO: Make this data structure aware of inter-process communication. This
214 * means that parts of this will be exported to rpcss.
216 typedef struct tagRegisteredClass
219 CLSID classIdentifier
;
221 LPUNKNOWN classObject
;
225 void *RpcRegistration
;
228 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
230 static CRITICAL_SECTION csRegisteredClassList
;
231 static CRITICAL_SECTION_DEBUG class_cs_debug
=
233 0, 0, &csRegisteredClassList
,
234 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
235 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
237 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
239 static inline enum comclass_miscfields
dvaspect_to_miscfields(DWORD aspect
)
243 case DVASPECT_CONTENT
:
244 return MiscStatusContent
;
245 case DVASPECT_THUMBNAIL
:
246 return MiscStatusThumbnail
;
248 return MiscStatusIcon
;
249 case DVASPECT_DOCPRINT
:
250 return MiscStatusDocPrint
;
256 BOOL
actctx_get_miscstatus(const CLSID
*clsid
, DWORD aspect
, DWORD
*status
)
258 ACTCTX_SECTION_KEYED_DATA data
;
260 data
.cbSize
= sizeof(data
);
261 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
264 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
265 enum comclass_miscfields misc
= dvaspect_to_miscfields(aspect
);
266 ULONG miscmask
= (comclass
->flags
>> 8) & 0xff;
268 if (!(miscmask
& misc
))
270 if (!(miscmask
& MiscStatus
))
281 *status
= comclass
->miscstatus
;
284 *status
= comclass
->miscstatusicon
;
286 case MiscStatusContent
:
287 *status
= comclass
->miscstatuscontent
;
289 case MiscStatusThumbnail
:
290 *status
= comclass
->miscstatusthumbnail
;
292 case MiscStatusDocPrint
:
293 *status
= comclass
->miscstatusdocprint
;
305 /* wrapper for NtCreateKey that creates the key recursively if necessary */
306 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
308 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
310 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
312 HANDLE subkey
, root
= attr
->RootDirectory
;
313 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
314 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
317 while (i
< len
&& buffer
[i
] != '\\') i
++;
318 if (i
== len
) return status
;
320 attrs
= attr
->Attributes
;
321 attr
->ObjectName
= &str
;
325 str
.Buffer
= buffer
+ pos
;
326 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
327 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
328 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
329 if (status
) return status
;
330 attr
->RootDirectory
= subkey
;
331 while (i
< len
&& buffer
[i
] == '\\') i
++;
333 while (i
< len
&& buffer
[i
] != '\\') i
++;
335 str
.Buffer
= buffer
+ pos
;
336 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
337 attr
->Attributes
= attrs
;
338 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
339 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
344 static const WCHAR classes_rootW
[] =
345 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
346 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
348 static HKEY classes_root_hkey
;
350 /* create the special HKEY_CLASSES_ROOT key */
351 static HKEY
create_classes_root_hkey(DWORD access
)
354 OBJECT_ATTRIBUTES attr
;
357 attr
.Length
= sizeof(attr
);
358 attr
.RootDirectory
= 0;
359 attr
.ObjectName
= &name
;
361 attr
.SecurityDescriptor
= NULL
;
362 attr
.SecurityQualityOfService
= NULL
;
363 RtlInitUnicodeString( &name
, classes_rootW
);
364 if (create_key( &hkey
, access
, &attr
)) return 0;
365 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
367 if (!(access
& KEY_WOW64_64KEY
))
369 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
372 NtClose( hkey
); /* somebody beat us to it */
379 /* map the hkey from special root to normal key if necessary */
380 static inline HKEY
get_classes_root_hkey( HKEY hkey
, REGSAM access
)
383 const BOOL is_win64
= sizeof(void*) > sizeof(int);
384 const BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
386 if (hkey
== HKEY_CLASSES_ROOT
&&
387 ((access
& KEY_WOW64_64KEY
) || !(ret
= classes_root_hkey
)))
388 ret
= create_classes_root_hkey(MAXIMUM_ALLOWED
| (access
& KEY_WOW64_64KEY
));
389 if (force_wow32
&& ret
&& ret
== classes_root_hkey
)
391 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
392 access
&= ~KEY_WOW64_32KEY
;
393 if (create_classes_key(classes_root_hkey
, wow6432nodeW
, access
, &hkey
))
401 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
403 OBJECT_ATTRIBUTES attr
;
404 UNICODE_STRING nameW
;
406 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
408 attr
.Length
= sizeof(attr
);
409 attr
.RootDirectory
= hkey
;
410 attr
.ObjectName
= &nameW
;
412 attr
.SecurityDescriptor
= NULL
;
413 attr
.SecurityQualityOfService
= NULL
;
414 RtlInitUnicodeString( &nameW
, name
);
416 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
419 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
421 OBJECT_ATTRIBUTES attr
;
422 UNICODE_STRING nameW
;
424 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
426 attr
.Length
= sizeof(attr
);
427 attr
.RootDirectory
= hkey
;
428 attr
.ObjectName
= &nameW
;
430 attr
.SecurityDescriptor
= NULL
;
431 attr
.SecurityQualityOfService
= NULL
;
432 RtlInitUnicodeString( &nameW
, name
);
434 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
437 /*****************************************************************************
438 * This section contains OpenDllList definitions
440 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
441 * other functions that do LoadLibrary _without_ giving back a HMODULE.
442 * Without this list these handles would never be freed.
444 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
445 * next unload-call but not before 600 sec.
448 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
449 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
451 typedef struct tagOpenDll
456 DllGetClassObjectFunc DllGetClassObject
;
457 DllCanUnloadNowFunc DllCanUnloadNow
;
461 static struct list openDllList
= LIST_INIT(openDllList
);
463 static CRITICAL_SECTION csOpenDllList
;
464 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
466 0, 0, &csOpenDllList
,
467 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
468 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
470 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
472 struct apartment_loaded_dll
480 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};
482 static ATOM apt_win_class
;
484 /*****************************************************************************
485 * This section contains OpenDllList implementation
488 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
492 EnterCriticalSection(&csOpenDllList
);
493 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
495 if (!wcsicmp(library_name
, ptr
->library_name
) &&
496 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
502 LeaveCriticalSection(&csOpenDllList
);
506 /* caller must ensure that library_name is not already in the open dll list */
507 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
513 DllCanUnloadNowFunc DllCanUnloadNow
;
514 DllGetClassObjectFunc DllGetClassObject
;
516 TRACE("%s\n", debugstr_w(library_name
));
518 *ret
= COMPOBJ_DllList_Get(library_name
);
519 if (*ret
) return S_OK
;
521 /* do this outside the csOpenDllList to avoid creating a lock dependency on
523 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
526 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
527 /* failure: DLL could not be loaded */
528 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
531 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
532 /* Note: failing to find DllCanUnloadNow is not a failure */
533 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
534 if (!DllGetClassObject
)
536 /* failure: the dll did not export DllGetClassObject */
537 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
538 FreeLibrary(hLibrary
);
539 return CO_E_DLLNOTFOUND
;
542 EnterCriticalSection( &csOpenDllList
);
544 *ret
= COMPOBJ_DllList_Get(library_name
);
547 /* another caller to this function already added the dll while we
548 * weren't in the critical section */
549 FreeLibrary(hLibrary
);
553 len
= lstrlenW(library_name
);
554 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
556 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
557 if (entry
&& entry
->library_name
)
559 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
560 entry
->library
= hLibrary
;
562 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
563 entry
->DllGetClassObject
= DllGetClassObject
;
564 list_add_tail(&openDllList
, &entry
->entry
);
569 HeapFree(GetProcessHeap(), 0, entry
);
571 FreeLibrary(hLibrary
);
575 LeaveCriticalSection( &csOpenDllList
);
580 /* pass FALSE for free_entry to release a reference without destroying the
581 * entry if it reaches zero or TRUE otherwise */
582 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
584 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
586 EnterCriticalSection(&csOpenDllList
);
587 list_remove(&entry
->entry
);
588 LeaveCriticalSection(&csOpenDllList
);
590 TRACE("freeing %p\n", entry
->library
);
591 FreeLibrary(entry
->library
);
593 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
594 HeapFree(GetProcessHeap(), 0, entry
);
598 /* frees memory associated with active dll list */
599 static void COMPOBJ_DllList_Free(void)
601 OpenDll
*entry
, *cursor2
;
602 EnterCriticalSection(&csOpenDllList
);
603 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
605 list_remove(&entry
->entry
);
607 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
608 HeapFree(GetProcessHeap(), 0, entry
);
610 LeaveCriticalSection(&csOpenDllList
);
611 DeleteCriticalSection(&csOpenDllList
);
614 /******************************************************************************
618 static DWORD
apartment_addref(struct apartment
*apt
)
620 DWORD refs
= InterlockedIncrement(&apt
->refs
);
621 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
625 /* allocates memory and fills in the necessary fields for a new apartment
626 * object. must be called inside apartment cs */
627 static APARTMENT
*apartment_construct(DWORD model
)
631 TRACE("creating new apartment, model=%d\n", model
);
633 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
634 apt
->tid
= GetCurrentThreadId();
636 list_init(&apt
->proxies
);
637 list_init(&apt
->stubmgrs
);
638 list_init(&apt
->loaded_dlls
);
639 list_init(&apt
->usage_cookies
);
642 apt
->remunk_exported
= FALSE
;
644 InitializeCriticalSection(&apt
->cs
);
645 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
647 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
649 if (apt
->multi_threaded
)
651 /* FIXME: should be randomly generated by in an RPC call to rpcss */
652 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
656 /* FIXME: should be randomly generated by in an RPC call to rpcss */
657 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
660 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
662 list_add_head(&apts
, &apt
->entry
);
667 /* gets and existing apartment if one exists or otherwise creates an apartment
668 * structure which stores OLE apartment-local information and stores a pointer
669 * to it in the thread-local storage */
670 static APARTMENT
*apartment_get_or_create(DWORD model
)
672 APARTMENT
*apt
= COM_CurrentApt();
676 if (model
& COINIT_APARTMENTTHREADED
)
678 EnterCriticalSection(&csApartment
);
680 apt
= apartment_construct(model
);
685 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
688 LeaveCriticalSection(&csApartment
);
691 apartment_createwindowifneeded(apt
);
695 EnterCriticalSection(&csApartment
);
697 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
698 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
702 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
703 apartment_addref(MTA
);
706 MTA
= apartment_construct(model
);
710 LeaveCriticalSection(&csApartment
);
712 COM_CurrentInfo()->apt
= apt
;
718 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
720 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
723 /* gets the multi-threaded apartment if it exists. The caller must
724 * release the reference from the apartment as soon as the apartment pointer
725 * is no longer required. */
726 static APARTMENT
*apartment_find_mta(void)
730 EnterCriticalSection(&csApartment
);
733 apartment_addref(apt
);
735 LeaveCriticalSection(&csApartment
);
740 /* Return the current apartment if it exists, or, failing that, the MTA. Caller
741 * must free the returned apartment in either case. */
742 APARTMENT
*apartment_get_current_or_mta(void)
744 APARTMENT
*apt
= COM_CurrentApt();
747 apartment_addref(apt
);
750 return apartment_find_mta();
753 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
755 list_remove(&curClass
->entry
);
757 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
758 RPC_StopLocalServer(curClass
->RpcRegistration
);
760 IUnknown_Release(curClass
->classObject
);
761 HeapFree(GetProcessHeap(), 0, curClass
);
764 static void COM_RevokeAllClasses(const struct apartment
*apt
)
766 RegisteredClass
*curClass
, *cursor
;
768 EnterCriticalSection( &csRegisteredClassList
);
770 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
772 if (curClass
->apartment_id
== apt
->oxid
)
773 COM_RevokeRegisteredClassObject(curClass
);
776 LeaveCriticalSection( &csRegisteredClassList
);
779 static void revoke_registered_psclsids(void)
781 struct registered_psclsid
*psclsid
, *psclsid2
;
783 EnterCriticalSection( &cs_registered_psclsid_list
);
785 LIST_FOR_EACH_ENTRY_SAFE(psclsid
, psclsid2
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
787 list_remove(&psclsid
->entry
);
788 HeapFree(GetProcessHeap(), 0, psclsid
);
791 LeaveCriticalSection( &cs_registered_psclsid_list
);
794 /******************************************************************************
795 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
798 typedef struct ManualResetEvent
{
799 ISynchronize ISynchronize_iface
;
800 ISynchronizeHandle ISynchronizeHandle_iface
;
805 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
807 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
810 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
812 MREImpl
*This
= impl_from_ISynchronize(iface
);
814 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
816 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
817 *ppv
= &This
->ISynchronize_iface
;
818 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
819 *ppv
= &This
->ISynchronizeHandle_iface
;
821 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
823 return E_NOINTERFACE
;
826 IUnknown_AddRef((IUnknown
*)*ppv
);
830 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
832 MREImpl
*This
= impl_from_ISynchronize(iface
);
833 LONG ref
= InterlockedIncrement(&This
->ref
);
834 TRACE("%p - ref %d\n", This
, ref
);
839 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
841 MREImpl
*This
= impl_from_ISynchronize(iface
);
842 LONG ref
= InterlockedDecrement(&This
->ref
);
843 TRACE("%p - ref %d\n", This
, ref
);
847 CloseHandle(This
->event
);
848 HeapFree(GetProcessHeap(), 0, This
);
854 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
856 MREImpl
*This
= impl_from_ISynchronize(iface
);
858 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
859 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
862 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
864 MREImpl
*This
= impl_from_ISynchronize(iface
);
866 SetEvent(This
->event
);
870 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
872 MREImpl
*This
= impl_from_ISynchronize(iface
);
874 ResetEvent(This
->event
);
878 static ISynchronizeVtbl vt_ISynchronize
= {
879 ISynchronize_fnQueryInterface
,
880 ISynchronize_fnAddRef
,
881 ISynchronize_fnRelease
,
883 ISynchronize_fnSignal
,
887 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
889 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
892 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
894 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
895 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
898 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
900 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
901 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
904 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
906 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
907 return ISynchronize_Release(&This
->ISynchronize_iface
);
910 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
912 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
918 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
919 SynchronizeHandle_QueryInterface
,
920 SynchronizeHandle_AddRef
,
921 SynchronizeHandle_Release
,
922 SynchronizeHandle_GetHandle
925 HRESULT WINAPI
ManualResetEvent_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID iid
, void **ppv
)
927 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
931 FIXME("Aggregation not implemented.\n");
934 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
935 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
936 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
938 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
939 ISynchronize_Release(&This
->ISynchronize_iface
);
943 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
945 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
948 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
950 LocalServer
*This
= impl_from_IServiceProvider(iface
);
952 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
954 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
955 *ppv
= &This
->IServiceProvider_iface
;
958 return E_NOINTERFACE
;
961 IUnknown_AddRef((IUnknown
*)*ppv
);
965 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
967 LocalServer
*This
= impl_from_IServiceProvider(iface
);
968 LONG ref
= InterlockedIncrement(&This
->ref
);
970 TRACE("(%p) ref=%d\n", This
, ref
);
975 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
977 LocalServer
*This
= impl_from_IServiceProvider(iface
);
978 LONG ref
= InterlockedDecrement(&This
->ref
);
980 TRACE("(%p) ref=%d\n", This
, ref
);
984 HeapFree(GetProcessHeap(), 0, This
);
990 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
992 LocalServer
*This
= impl_from_IServiceProvider(iface
);
993 APARTMENT
*apt
= COM_CurrentApt();
994 RegisteredClass
*iter
;
995 HRESULT hres
= E_FAIL
;
997 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
1000 return E_UNEXPECTED
;
1002 EnterCriticalSection(&csRegisteredClassList
);
1004 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
1005 if(iter
->apartment_id
== apt
->oxid
1006 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
1007 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
1008 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
1013 LeaveCriticalSection( &csRegisteredClassList
);
1018 static const IServiceProviderVtbl LocalServerVtbl
= {
1019 LocalServer_QueryInterface
,
1021 LocalServer_Release
,
1022 LocalServer_QueryService
1025 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
1027 HRESULT hres
= S_OK
;
1029 EnterCriticalSection(&apt
->cs
);
1031 if(!apt
->local_server
) {
1034 obj
= heap_alloc(sizeof(*obj
));
1036 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
1040 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
1041 if(SUCCEEDED(hres
)) {
1042 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
1043 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1045 IStream_Release(obj
->marshal_stream
);
1049 apt
->local_server
= obj
;
1053 hres
= E_OUTOFMEMORY
;
1058 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
1060 LeaveCriticalSection(&apt
->cs
);
1063 ERR("Failed: %08x\n", hres
);
1067 /***********************************************************************
1068 * CoRevokeClassObject [OLE32.@]
1070 * Removes a class object from the class registry.
1073 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1077 * Failure: HRESULT code.
1080 * Must be called from the same apartment that called CoRegisterClassObject(),
1081 * otherwise it will fail with RPC_E_WRONG_THREAD.
1084 * CoRegisterClassObject
1086 HRESULT WINAPI DECLSPEC_HOTPATCH
CoRevokeClassObject(
1089 HRESULT hr
= E_INVALIDARG
;
1090 RegisteredClass
*curClass
;
1093 TRACE("(%08x)\n",dwRegister
);
1095 if (!(apt
= apartment_get_current_or_mta()))
1097 ERR("COM was not initialized\n");
1098 return CO_E_NOTINITIALIZED
;
1101 EnterCriticalSection( &csRegisteredClassList
);
1103 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1106 * Check if we have a match on the cookie.
1108 if (curClass
->dwCookie
== dwRegister
)
1110 if (curClass
->apartment_id
== apt
->oxid
)
1112 COM_RevokeRegisteredClassObject(curClass
);
1117 ERR("called from wrong apartment, should be called from %s\n",
1118 wine_dbgstr_longlong(curClass
->apartment_id
));
1119 hr
= RPC_E_WRONG_THREAD
;
1125 LeaveCriticalSection( &csRegisteredClassList
);
1126 apartment_release(apt
);
1130 /* frees unused libraries loaded by apartment_getclassobject by calling the
1131 * DLL's DllCanUnloadNow entry point */
1132 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
1134 struct apartment_loaded_dll
*entry
, *next
;
1135 EnterCriticalSection(&apt
->cs
);
1136 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1138 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
1140 DWORD real_delay
= delay
;
1142 if (real_delay
== INFINITE
)
1144 /* DLLs that return multi-threaded objects aren't unloaded
1145 * straight away to cope for programs that have races between
1146 * last object destruction and threads in the DLLs that haven't
1147 * finished, despite DllCanUnloadNow returning S_OK */
1148 if (entry
->multi_threaded
)
1149 real_delay
= 10 * 60 * 1000; /* 10 minutes */
1154 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
1156 list_remove(&entry
->entry
);
1157 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
1158 HeapFree(GetProcessHeap(), 0, entry
);
1162 entry
->unload_time
= GetTickCount() + real_delay
;
1163 if (!entry
->unload_time
) entry
->unload_time
= 1;
1166 else if (entry
->unload_time
)
1167 entry
->unload_time
= 0;
1169 LeaveCriticalSection(&apt
->cs
);
1172 DWORD
apartment_release(struct apartment
*apt
)
1176 EnterCriticalSection(&csApartment
);
1178 ret
= InterlockedDecrement(&apt
->refs
);
1179 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
1181 if (apt
->being_destroyed
)
1183 LeaveCriticalSection(&csApartment
);
1187 /* destruction stuff that needs to happen under csApartment CS */
1190 apt
->being_destroyed
= TRUE
;
1191 if (apt
== MTA
) MTA
= NULL
;
1192 else if (apt
== MainApartment
) MainApartment
= NULL
;
1193 list_remove(&apt
->entry
);
1196 LeaveCriticalSection(&csApartment
);
1200 struct list
*cursor
, *cursor2
;
1202 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
1204 if(apt
->local_server
) {
1205 LocalServer
*local_server
= apt
->local_server
;
1208 memset(&zero
, 0, sizeof(zero
));
1209 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
1210 CoReleaseMarshalData(local_server
->marshal_stream
);
1211 IStream_Release(local_server
->marshal_stream
);
1212 local_server
->marshal_stream
= NULL
;
1214 apt
->local_server
= NULL
;
1215 local_server
->apt
= NULL
;
1216 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
1219 /* Release the references to the registered class objects */
1220 COM_RevokeAllClasses(apt
);
1222 /* no locking is needed for this apartment, because no other thread
1223 * can access it at this point */
1225 apartment_disconnectproxies(apt
);
1227 if (apt
->win
) DestroyWindow(apt
->win
);
1228 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
1230 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
1232 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
1233 /* release the implicit reference given by the fact that the
1234 * stub has external references (it must do since it is in the
1235 * stub manager list in the apartment and all non-apartment users
1236 * must have a ref on the apartment and so it cannot be destroyed).
1238 stub_manager_int_release(stubmgr
);
1241 /* if this assert fires, then another thread took a reference to a
1242 * stub manager without taking a reference to the containing
1243 * apartment, which it must do. */
1244 assert(list_empty(&apt
->stubmgrs
));
1246 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1248 /* free as many unused libraries as possible... */
1249 apartment_freeunusedlibraries(apt
, 0);
1251 /* ... and free the memory for the apartment loaded dll entry and
1252 * release the dll list reference without freeing the library for the
1254 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1256 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1257 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1258 list_remove(cursor
);
1259 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1262 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1263 DeleteCriticalSection(&apt
->cs
);
1265 HeapFree(GetProcessHeap(), 0, apt
);
1271 /* The given OXID must be local to this process:
1273 * The ref parameter is here mostly to ensure people remember that
1274 * they get one, you should normally take a ref for thread safety.
1276 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1278 APARTMENT
*result
= NULL
;
1279 struct list
*cursor
;
1281 EnterCriticalSection(&csApartment
);
1282 LIST_FOR_EACH( cursor
, &apts
)
1284 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1285 if (apt
->oxid
== oxid
)
1288 if (ref
) apartment_addref(result
);
1292 LeaveCriticalSection(&csApartment
);
1297 /* gets the apartment which has a given creator thread ID. The caller must
1298 * release the reference from the apartment as soon as the apartment pointer
1299 * is no longer required. */
1300 APARTMENT
*apartment_findfromtid(DWORD tid
)
1302 APARTMENT
*result
= NULL
;
1303 struct list
*cursor
;
1305 EnterCriticalSection(&csApartment
);
1306 LIST_FOR_EACH( cursor
, &apts
)
1308 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1309 if (apt
->tid
== tid
)
1312 apartment_addref(result
);
1316 LeaveCriticalSection(&csApartment
);
1321 /* gets the main apartment if it exists. The caller must
1322 * release the reference from the apartment as soon as the apartment pointer
1323 * is no longer required. */
1324 static APARTMENT
*apartment_findmain(void)
1328 EnterCriticalSection(&csApartment
);
1330 result
= MainApartment
;
1331 if (result
) apartment_addref(result
);
1333 LeaveCriticalSection(&csApartment
);
1338 /* gets the specified class object by loading the appropriate DLL, if
1339 * necessary and calls the DllGetClassObject function for the DLL */
1340 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1341 BOOL apartment_threaded
,
1342 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1344 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1347 struct apartment_loaded_dll
*apartment_loaded_dll
;
1349 if (!wcsicmp(dllpath
, wszOle32
))
1351 /* we don't need to control the lifetime of this dll, so use the local
1352 * implementation of DllGetClassObject directly */
1353 TRACE("calling ole32!DllGetClassObject\n");
1354 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1357 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr
, debugstr_w(dllpath
));
1362 EnterCriticalSection(&apt
->cs
);
1364 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1365 if (!wcsicmp(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1367 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1374 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1375 if (!apartment_loaded_dll
)
1379 apartment_loaded_dll
->unload_time
= 0;
1380 apartment_loaded_dll
->multi_threaded
= FALSE
;
1381 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1383 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1387 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1388 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1392 LeaveCriticalSection(&apt
->cs
);
1396 /* one component being multi-threaded overrides any number of
1397 * apartment-threaded components */
1398 if (!apartment_threaded
)
1399 apartment_loaded_dll
->multi_threaded
= TRUE
;
1401 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1402 /* OK: get the ClassObject */
1403 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1406 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr
, debugstr_w(dllpath
));
1412 /* Returns expanded dll path from the registry or activation context. */
1413 static BOOL
get_object_dll_path(const struct class_reg_data
*regdata
, WCHAR
*dst
, DWORD dstlen
)
1417 if (regdata
->origin
== CLASS_REG_REGISTRY
)
1420 WCHAR src
[MAX_PATH
];
1421 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1423 if( (ret
= RegQueryValueExW(regdata
->u
.hkey
, NULL
, NULL
, &keytype
, (BYTE
*)src
, &dwLength
)) == ERROR_SUCCESS
) {
1424 if (keytype
== REG_EXPAND_SZ
) {
1425 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1427 const WCHAR
*quote_start
;
1428 quote_start
= wcschr(src
, '\"');
1430 const WCHAR
*quote_end
= wcschr(quote_start
+ 1, '\"');
1432 memmove(src
, quote_start
+ 1,
1433 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1434 src
[quote_end
- quote_start
- 1] = '\0';
1437 lstrcpynW(dst
, src
, dstlen
);
1444 static const WCHAR dllW
[] = {'.','d','l','l',0};
1448 ActivateActCtx(regdata
->u
.actctx
.hactctx
, &cookie
);
1449 ret
= SearchPathW(NULL
, regdata
->u
.actctx
.module_name
, dllW
, dstlen
, dst
, NULL
);
1450 DeactivateActCtx(0, cookie
);
1455 struct host_object_params
1457 struct class_reg_data regdata
;
1458 CLSID clsid
; /* clsid of object to marshal */
1459 IID iid
; /* interface to marshal */
1460 HANDLE event
; /* event signalling when ready for multi-threaded case */
1461 HRESULT hr
; /* result for multi-threaded case */
1462 IStream
*stream
; /* stream that the object will be marshaled into */
1463 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1466 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1467 const struct host_object_params
*params
)
1471 static const LARGE_INTEGER llZero
;
1472 WCHAR dllpath
[MAX_PATH
+1];
1474 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1476 if (!get_object_dll_path(¶ms
->regdata
, dllpath
, ARRAY_SIZE(dllpath
)))
1478 /* failure: CLSID is not found in registry */
1479 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1480 return REGDB_E_CLASSNOTREG
;
1483 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1484 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1488 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1490 IUnknown_Release(object
);
1491 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1496 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1501 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1504 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1506 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1510 struct host_thread_params
1512 COINIT threading_model
;
1514 HWND apartment_hwnd
;
1517 /* thread for hosting an object to allow an object to appear to be created in
1518 * an apartment with an incompatible threading model */
1519 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1521 struct host_thread_params
*params
= p
;
1524 struct apartment
*apt
;
1528 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1529 if (FAILED(hr
)) return hr
;
1531 apt
= COM_CurrentApt();
1532 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1534 apartment_createwindowifneeded(apt
);
1535 params
->apartment_hwnd
= apartment_getwindow(apt
);
1538 params
->apartment_hwnd
= NULL
;
1540 /* force the message queue to be created before signaling parent thread */
1541 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1543 SetEvent(params
->ready_event
);
1544 params
= NULL
; /* can't touch params after here as it may be invalid */
1546 while (GetMessageW(&msg
, NULL
, 0, 0))
1548 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1550 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1551 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1552 SetEvent(obj_params
->event
);
1556 TranslateMessage(&msg
);
1557 DispatchMessageW(&msg
);
1568 /* finds or creates a host apartment, creates the object inside it and returns
1569 * a proxy to it so that the object can be used in the apartment of the
1570 * caller of this function */
1571 static HRESULT
apartment_hostobject_in_hostapt(
1572 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1573 const struct class_reg_data
*regdata
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1575 struct host_object_params params
;
1576 HWND apartment_hwnd
= NULL
;
1577 DWORD apartment_tid
= 0;
1580 if (!multi_threaded
&& main_apartment
)
1582 APARTMENT
*host_apt
= apartment_findmain();
1585 apartment_hwnd
= apartment_getwindow(host_apt
);
1586 apartment_release(host_apt
);
1590 if (!apartment_hwnd
)
1592 EnterCriticalSection(&apt
->cs
);
1594 if (!apt
->host_apt_tid
)
1596 struct host_thread_params thread_params
;
1600 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1601 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1602 thread_params
.apartment_hwnd
= NULL
;
1603 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1606 CloseHandle(handles
[0]);
1607 LeaveCriticalSection(&apt
->cs
);
1608 return E_OUTOFMEMORY
;
1610 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1611 CloseHandle(handles
[0]);
1612 CloseHandle(handles
[1]);
1613 if (wait_value
== WAIT_OBJECT_0
)
1614 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1617 LeaveCriticalSection(&apt
->cs
);
1618 return E_OUTOFMEMORY
;
1622 if (multi_threaded
|| !main_apartment
)
1624 apartment_hwnd
= apt
->host_apt_hwnd
;
1625 apartment_tid
= apt
->host_apt_tid
;
1628 LeaveCriticalSection(&apt
->cs
);
1631 /* another thread may have become the main apartment in the time it took
1632 * us to create the thread for the host apartment */
1633 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1635 APARTMENT
*host_apt
= apartment_findmain();
1638 apartment_hwnd
= apartment_getwindow(host_apt
);
1639 apartment_release(host_apt
);
1643 params
.regdata
= *regdata
;
1644 params
.clsid
= *rclsid
;
1646 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1649 params
.apartment_threaded
= !multi_threaded
;
1653 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1654 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1658 WaitForSingleObject(params
.event
, INFINITE
);
1661 CloseHandle(params
.event
);
1665 if (!apartment_hwnd
)
1667 ERR("host apartment didn't create window\n");
1671 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1674 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1675 IStream_Release(params
.stream
);
1679 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1683 /* Dispatching to the correct thread in an apartment is done through
1684 * window messages rather than RPC transports. When an interface is
1685 * marshalled into another apartment in the same process, a window of the
1686 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1687 * application) is responsible for pumping the message loop in that thread.
1688 * The WM_USER messages which point to the RPCs are then dispatched to
1689 * apartment_wndproc by the user's code from the apartment in which the
1690 * interface was unmarshalled.
1692 memset(&wclass
, 0, sizeof(wclass
));
1693 wclass
.lpfnWndProc
= apartment_wndproc
;
1694 wclass
.hInstance
= hProxyDll
;
1695 wclass
.lpszClassName
= wszAptWinClass
;
1696 apt_win_class
= RegisterClassW(&wclass
);
1700 /* create a window for the apartment or return the current one if one has
1701 * already been created */
1702 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1704 static INIT_ONCE class_init_once
= INIT_ONCE_STATIC_INIT
;
1706 if (apt
->multi_threaded
)
1713 InitOnceExecuteOnce( &class_init_once
, register_class
, NULL
, NULL
);
1715 hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0, 0, 0, 0, 0,
1716 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1719 ERR("CreateWindow failed with error %d\n", GetLastError());
1720 return HRESULT_FROM_WIN32(GetLastError());
1722 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1723 /* someone beat us to it */
1724 DestroyWindow(hwnd
);
1730 /* retrieves the window for the main- or apartment-threaded apartment */
1731 HWND
apartment_getwindow(const struct apartment
*apt
)
1733 assert(!apt
->multi_threaded
);
1737 static void COM_TlsDestroy(void)
1739 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1742 struct init_spy
*cursor
, *cursor2
;
1744 if (info
->apt
) apartment_release(info
->apt
);
1745 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1746 if (info
->state
) IUnknown_Release(info
->state
);
1748 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &info
->spies
, struct init_spy
, entry
)
1750 list_remove(&cursor
->entry
);
1751 if (cursor
->spy
) IInitializeSpy_Release(cursor
->spy
);
1755 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1757 HeapFree(GetProcessHeap(), 0, info
);
1758 NtCurrentTeb()->ReservedForOle
= NULL
;
1762 /******************************************************************************
1763 * CoBuildVersion [OLE32.@]
1765 * Gets the build version of the DLL.
1770 * Current build version, hiword is majornumber, loword is minornumber
1772 DWORD WINAPI
CoBuildVersion(void)
1774 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1775 return (rmm
<<16)+rup
;
1778 static struct init_spy
*get_spy_entry(struct oletls
*info
, unsigned int id
)
1780 struct init_spy
*spy
;
1782 LIST_FOR_EACH_ENTRY(spy
, &info
->spies
, struct init_spy
, entry
)
1784 if (id
== spy
->id
&& spy
->spy
)
1792 * When locked, don't modify list (unless we add a new head), so that it's
1793 * safe to iterate it. Freeing of list entries is delayed and done on unlock.
1795 static inline void lock_init_spies(struct oletls
*info
)
1800 static void unlock_init_spies(struct oletls
*info
)
1802 struct init_spy
*spy
, *next
;
1804 if (--info
->spies_lock
) return;
1806 LIST_FOR_EACH_ENTRY_SAFE(spy
, next
, &info
->spies
, struct init_spy
, entry
)
1808 if (spy
->spy
) continue;
1809 list_remove(&spy
->entry
);
1814 /******************************************************************************
1815 * CoRegisterInitializeSpy [OLE32.@]
1817 * Add a Spy that watches CoInitializeEx calls
1820 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1821 * cookie [II] cookie receiver
1824 * Success: S_OK if not already initialized, S_FALSE otherwise.
1825 * Failure: HRESULT code.
1830 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1832 struct oletls
*info
= COM_CurrentInfo();
1833 struct init_spy
*entry
;
1837 TRACE("(%p, %p)\n", spy
, cookie
);
1839 if (!spy
|| !cookie
|| !info
)
1842 WARN("Could not allocate tls\n");
1843 return E_INVALIDARG
;
1846 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **)&spy
);
1850 entry
= heap_alloc(sizeof(*entry
));
1853 IInitializeSpy_Release(spy
);
1854 return E_OUTOFMEMORY
;
1860 while (get_spy_entry(info
, id
) != NULL
)
1866 list_add_head(&info
->spies
, &entry
->entry
);
1868 cookie
->HighPart
= GetCurrentThreadId();
1869 cookie
->LowPart
= entry
->id
;
1874 /******************************************************************************
1875 * CoRevokeInitializeSpy [OLE32.@]
1877 * Remove a spy that previously watched CoInitializeEx calls
1880 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1883 * Success: S_OK if a spy is removed
1884 * Failure: E_INVALIDARG
1889 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1891 struct oletls
*info
= COM_CurrentInfo();
1892 struct init_spy
*spy
;
1894 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1896 if (!info
|| cookie
.HighPart
!= GetCurrentThreadId())
1897 return E_INVALIDARG
;
1899 if (!(spy
= get_spy_entry(info
, cookie
.LowPart
))) return E_INVALIDARG
;
1901 IInitializeSpy_Release(spy
->spy
);
1903 if (!info
->spies_lock
)
1905 list_remove(&spy
->entry
);
1911 HRESULT
enter_apartment( struct oletls
*info
, DWORD model
)
1917 if (!apartment_get_or_create( model
))
1918 return E_OUTOFMEMORY
;
1920 else if (!apartment_is_model( info
->apt
, model
))
1922 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1923 info
->apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1924 model
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded" );
1925 return RPC_E_CHANGED_MODE
;
1935 void leave_apartment( struct oletls
*info
)
1939 if (info
->ole_inits
)
1940 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1941 apartment_release( info
->apt
);
1946 /******************************************************************************
1947 * CoInitialize [OLE32.@]
1949 * Initializes the COM libraries by calling CoInitializeEx with
1950 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1953 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1956 * Success: S_OK if not already initialized, S_FALSE otherwise.
1957 * Failure: HRESULT code.
1962 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1965 * Just delegate to the newer method.
1967 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1970 /******************************************************************************
1971 * CoInitializeEx [OLE32.@]
1973 * Initializes the COM libraries.
1976 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1977 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1980 * S_OK if successful,
1981 * S_FALSE if this function was called already.
1982 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1987 * The behavior used to set the IMalloc used for memory management is
1989 * The dwCoInit parameter must specify one of the following apartment
1991 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1992 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1993 * The parameter may also specify zero or more of the following flags:
1994 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1995 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
2000 HRESULT WINAPI DECLSPEC_HOTPATCH
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
2002 struct oletls
*info
= COM_CurrentInfo();
2003 struct init_spy
*cursor
;
2006 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
2008 if (lpReserved
!=NULL
)
2010 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
2014 * Check the lock count. If this is the first time going through the initialize
2015 * process, we have to initialize the libraries.
2017 * And crank-up that lock count.
2019 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
2022 * Initialize the various COM libraries and data structures.
2024 TRACE("() - Initializing the COM libraries\n");
2026 /* we may need to defer this until after apartment initialisation */
2027 RunningObjectTableImpl_Initialize();
2030 lock_init_spies(info
);
2031 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2033 if (cursor
->spy
) IInitializeSpy_PreInitialize(cursor
->spy
, dwCoInit
, info
->inits
);
2035 unlock_init_spies(info
);
2037 hr
= enter_apartment( info
, dwCoInit
);
2039 lock_init_spies(info
);
2040 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2042 if (cursor
->spy
) hr
= IInitializeSpy_PostInitialize(cursor
->spy
, hr
, dwCoInit
, info
->inits
);
2044 unlock_init_spies(info
);
2049 /***********************************************************************
2050 * CoUninitialize [OLE32.@]
2052 * This method will decrement the refcount on the current apartment, freeing
2053 * the resources associated with it if it is the last thread in the apartment.
2054 * If the last apartment is freed, the function will additionally release
2055 * any COM resources associated with the process.
2065 void WINAPI DECLSPEC_HOTPATCH
CoUninitialize(void)
2067 struct oletls
* info
= COM_CurrentInfo();
2068 struct init_spy
*cursor
, *next
;
2073 /* will only happen on OOM */
2076 lock_init_spies(info
);
2077 LIST_FOR_EACH_ENTRY_SAFE(cursor
, next
, &info
->spies
, struct init_spy
, entry
)
2079 if (cursor
->spy
) IInitializeSpy_PreUninitialize(cursor
->spy
, info
->inits
);
2081 unlock_init_spies(info
);
2086 ERR("Mismatched CoUninitialize\n");
2088 lock_init_spies(info
);
2089 LIST_FOR_EACH_ENTRY_SAFE(cursor
, next
, &info
->spies
, struct init_spy
, entry
)
2091 if (cursor
->spy
) IInitializeSpy_PostUninitialize(cursor
->spy
, info
->inits
);
2093 unlock_init_spies(info
);
2098 leave_apartment( info
);
2101 * Decrease the reference count.
2102 * If we are back to 0 locks on the COM library, make sure we free
2103 * all the associated data structures.
2105 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
2108 TRACE("() - Releasing the COM libraries\n");
2110 revoke_registered_psclsids();
2111 RunningObjectTableImpl_UnInitialize();
2113 else if (lCOMRefCnt
<1) {
2114 ERR( "CoUninitialize() - not CoInitialized.\n" );
2115 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
2118 lock_init_spies(info
);
2119 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2121 if (cursor
->spy
) IInitializeSpy_PostUninitialize(cursor
->spy
, info
->inits
);
2123 unlock_init_spies(info
);
2126 /******************************************************************************
2127 * CoDisconnectObject [OLE32.@]
2129 * Disconnects all connections to this object from remote processes. Dispatches
2130 * pending RPCs while blocking new RPCs from occurring, and then calls
2131 * IMarshal::DisconnectObject on the given object.
2133 * Typically called when the object server is forced to shut down, for instance by
2137 * lpUnk [I] The object whose stub should be disconnected.
2138 * reserved [I] Reserved. Should be set to 0.
2142 * Failure: HRESULT code.
2145 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2147 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2149 struct stub_manager
*manager
;
2154 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2156 if (!lpUnk
) return E_INVALIDARG
;
2158 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2161 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2162 IMarshal_Release(marshal
);
2166 if (!(apt
= apartment_get_current_or_mta()))
2168 ERR("apartment not initialised\n");
2169 return CO_E_NOTINITIALIZED
;
2172 manager
= get_stub_manager_from_object(apt
, lpUnk
, FALSE
);
2174 stub_manager_disconnect(manager
);
2175 /* Release stub manager twice, to remove the apartment reference. */
2176 stub_manager_int_release(manager
);
2177 stub_manager_int_release(manager
);
2180 /* Note: native is pretty broken here because it just silently
2181 * fails, without returning an appropriate error code if the object was
2182 * not found, making apps think that the object was disconnected, when
2183 * it actually wasn't */
2185 apartment_release(apt
);
2189 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2190 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2192 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2193 WCHAR path
[CHARS_IN_GUID
+ ARRAY_SIZE(wszCLSIDSlash
) - 1];
2197 lstrcpyW(path
, wszCLSIDSlash
);
2198 StringFromGUID2(clsid
, path
+ lstrlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2199 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2200 if (res
== ERROR_FILE_NOT_FOUND
)
2201 return REGDB_E_CLASSNOTREG
;
2202 else if (res
!= ERROR_SUCCESS
)
2203 return REGDB_E_READREGDB
;
2211 res
= open_classes_key(key
, keyname
, access
, subkey
);
2213 if (res
== ERROR_FILE_NOT_FOUND
)
2214 return REGDB_E_KEYMISSING
;
2215 else if (res
!= ERROR_SUCCESS
)
2216 return REGDB_E_READREGDB
;
2221 /* open HKCR\\AppId\\{string form of appid clsid} key */
2222 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2224 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2225 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2227 WCHAR buf
[CHARS_IN_GUID
];
2228 WCHAR keyname
[ARRAY_SIZE(szAppIdKey
) + CHARS_IN_GUID
];
2234 /* read the AppID value under the class's key */
2235 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2240 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2242 if (res
== ERROR_FILE_NOT_FOUND
)
2243 return REGDB_E_KEYMISSING
;
2244 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2245 return REGDB_E_READREGDB
;
2247 lstrcpyW(keyname
, szAppIdKey
);
2248 lstrcatW(keyname
, buf
);
2249 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2250 if (res
== ERROR_FILE_NOT_FOUND
)
2251 return REGDB_E_KEYMISSING
;
2252 else if (res
!= ERROR_SUCCESS
)
2253 return REGDB_E_READREGDB
;
2258 static HRESULT
get_ps_clsid_from_registry(const WCHAR
* path
, REGSAM access
, CLSID
*pclsid
)
2261 WCHAR value
[CHARS_IN_GUID
];
2266 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, access
, &hkey
))
2267 return REGDB_E_IIDNOTREG
;
2269 len
= sizeof(value
);
2270 if (ERROR_SUCCESS
!= RegQueryValueExW(hkey
, NULL
, NULL
, NULL
, (BYTE
*)value
, &len
))
2271 return REGDB_E_IIDNOTREG
;
2274 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2275 return REGDB_E_IIDNOTREG
;
2280 /*****************************************************************************
2281 * CoGetPSClsid [OLE32.@]
2283 * Retrieves the CLSID of the proxy/stub factory that implements
2284 * IPSFactoryBuffer for the specified interface.
2287 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2288 * pclsid [O] Where to store returned proxy/stub CLSID.
2293 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2297 * The standard marshaller activates the object with the CLSID
2298 * returned and uses the CreateProxy and CreateStub methods on its
2299 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2302 * CoGetPSClsid determines this CLSID by searching the
2303 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2304 * in the registry and any interface id registered by
2305 * CoRegisterPSClsid within the current process.
2309 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2310 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2311 * considered a bug in native unless an application depends on this (unlikely).
2314 * CoRegisterPSClsid.
2316 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2318 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2319 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2320 WCHAR path
[ARRAY_SIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAY_SIZE(wszPSC
)];
2322 struct registered_psclsid
*registered_psclsid
;
2323 ACTCTX_SECTION_KEYED_DATA data
;
2325 REGSAM opposite
= (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
;
2328 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2330 if (!(apt
= apartment_get_current_or_mta()))
2332 ERR("apartment not initialised\n");
2333 return CO_E_NOTINITIALIZED
;
2335 apartment_release(apt
);
2338 return E_INVALIDARG
;
2340 EnterCriticalSection(&cs_registered_psclsid_list
);
2342 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2343 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2345 *pclsid
= registered_psclsid
->clsid
;
2346 LeaveCriticalSection(&cs_registered_psclsid_list
);
2350 LeaveCriticalSection(&cs_registered_psclsid_list
);
2352 data
.cbSize
= sizeof(data
);
2353 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2356 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2357 *pclsid
= ifaceps
->iid
;
2361 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2362 lstrcpyW(path
, wszInterface
);
2363 StringFromGUID2(riid
, path
+ ARRAY_SIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2364 lstrcpyW(path
+ ARRAY_SIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2366 hr
= get_ps_clsid_from_registry(path
, 0, pclsid
);
2367 if (FAILED(hr
) && (opposite
== KEY_WOW64_32KEY
||
2368 (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)))
2369 hr
= get_ps_clsid_from_registry(path
, opposite
, pclsid
);
2372 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2374 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2379 /*****************************************************************************
2380 * CoRegisterPSClsid [OLE32.@]
2382 * Register a proxy/stub CLSID for the given interface in the current process
2386 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2387 * rclsid [I] CLSID of the proxy/stub.
2391 * Failure: E_OUTOFMEMORY
2395 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2396 * will be returned from other apartments in the same process.
2398 * This function does not add anything to the registry and the effects are
2399 * limited to the lifetime of the current process.
2404 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2407 struct registered_psclsid
*registered_psclsid
;
2409 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2411 if (!(apt
= apartment_get_current_or_mta()))
2413 ERR("apartment not initialised\n");
2414 return CO_E_NOTINITIALIZED
;
2416 apartment_release(apt
);
2418 EnterCriticalSection(&cs_registered_psclsid_list
);
2420 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2421 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2423 registered_psclsid
->clsid
= *rclsid
;
2424 LeaveCriticalSection(&cs_registered_psclsid_list
);
2428 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2429 if (!registered_psclsid
)
2431 LeaveCriticalSection(&cs_registered_psclsid_list
);
2432 return E_OUTOFMEMORY
;
2435 registered_psclsid
->iid
= *riid
;
2436 registered_psclsid
->clsid
= *rclsid
;
2437 list_add_head(®istered_psclsid_list
, ®istered_psclsid
->entry
);
2439 LeaveCriticalSection(&cs_registered_psclsid_list
);
2446 * COM_GetRegisteredClassObject
2448 * This internal method is used to scan the registered class list to
2449 * find a class object.
2452 * rclsid Class ID of the class to find.
2453 * dwClsContext Class context to match.
2454 * ppv [out] returns a pointer to the class object. Complying
2455 * to normal COM usage, this method will increase the
2456 * reference count on this object.
2458 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2459 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2461 HRESULT hr
= S_FALSE
;
2462 RegisteredClass
*curClass
;
2464 EnterCriticalSection( &csRegisteredClassList
);
2466 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2469 * Check if we have a match on the class ID and context.
2471 if ((apt
->oxid
== curClass
->apartment_id
) &&
2472 (dwClsContext
& curClass
->runContext
) &&
2473 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2476 * We have a match, return the pointer to the class object.
2478 *ppUnk
= curClass
->classObject
;
2480 IUnknown_AddRef(curClass
->classObject
);
2487 LeaveCriticalSection( &csRegisteredClassList
);
2492 /******************************************************************************
2493 * CoRegisterClassObject [OLE32.@]
2495 * Registers the class object for a given class ID. Servers housed in EXE
2496 * files use this method instead of exporting DllGetClassObject to allow
2497 * other code to connect to their objects.
2500 * rclsid [I] CLSID of the object to register.
2501 * pUnk [I] IUnknown of the object.
2502 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2503 * flags [I] REGCLS flags indicating how connections are made.
2504 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2508 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2509 * CO_E_OBJISREG if the object is already registered. We should not return this.
2512 * CoRevokeClassObject, CoGetClassObject
2515 * In-process objects are only registered for the current apartment.
2516 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2517 * in other apartments.
2520 * MSDN claims that multiple interface registrations are legal, but we
2521 * can't do that with our current implementation.
2523 HRESULT WINAPI
CoRegisterClassObject(
2528 LPDWORD lpdwRegister
)
2530 static LONG next_cookie
;
2531 RegisteredClass
* newClass
;
2532 LPUNKNOWN foundObject
;
2536 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2537 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2539 if ( (lpdwRegister
==0) || (pUnk
==0) )
2540 return E_INVALIDARG
;
2542 if (!(apt
= apartment_get_current_or_mta()))
2544 ERR("COM was not initialized\n");
2545 return CO_E_NOTINITIALIZED
;
2550 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2551 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2552 if (flags
& REGCLS_MULTIPLEUSE
)
2553 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2556 * First, check if the class is already registered.
2557 * If it is, this should cause an error.
2559 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2561 if (flags
& REGCLS_MULTIPLEUSE
) {
2562 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2563 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2564 IUnknown_Release(foundObject
);
2565 apartment_release(apt
);
2568 IUnknown_Release(foundObject
);
2569 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2570 apartment_release(apt
);
2571 return CO_E_OBJISREG
;
2574 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2575 if ( newClass
== NULL
)
2577 apartment_release(apt
);
2578 return E_OUTOFMEMORY
;
2581 newClass
->classIdentifier
= *rclsid
;
2582 newClass
->apartment_id
= apt
->oxid
;
2583 newClass
->runContext
= dwClsContext
;
2584 newClass
->connectFlags
= flags
;
2585 newClass
->RpcRegistration
= NULL
;
2587 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2588 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2591 * Since we're making a copy of the object pointer, we have to increase its
2594 newClass
->classObject
= pUnk
;
2595 IUnknown_AddRef(newClass
->classObject
);
2597 EnterCriticalSection( &csRegisteredClassList
);
2598 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2599 LeaveCriticalSection( &csRegisteredClassList
);
2601 *lpdwRegister
= newClass
->dwCookie
;
2603 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2604 IStream
*marshal_stream
;
2606 hr
= get_local_server_stream(apt
, &marshal_stream
);
2609 apartment_release(apt
);
2613 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2615 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2616 &newClass
->RpcRegistration
);
2617 IStream_Release(marshal_stream
);
2619 apartment_release(apt
);
2623 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2625 if (data
->origin
== CLASS_REG_REGISTRY
)
2627 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2628 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2629 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2630 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2631 WCHAR threading_model
[10 /* lstrlenW(L"apartment")+1 */];
2632 DWORD dwLength
= sizeof(threading_model
);
2636 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2637 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2638 threading_model
[0] = '\0';
2640 if (!wcsicmp(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2641 if (!wcsicmp(threading_model
, wszFree
)) return ThreadingModel_Free
;
2642 if (!wcsicmp(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2644 /* there's not specific handling for this case */
2645 if (threading_model
[0]) return ThreadingModel_Neutral
;
2646 return ThreadingModel_No
;
2649 return data
->u
.actctx
.threading_model
;
2652 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2653 REFCLSID rclsid
, REFIID riid
,
2654 BOOL hostifnecessary
, void **ppv
)
2656 WCHAR dllpath
[MAX_PATH
+1];
2657 BOOL apartment_threaded
;
2659 if (hostifnecessary
)
2661 enum comclass_threadingmodel model
= get_threading_model(regdata
);
2663 if (model
== ThreadingModel_Apartment
)
2665 apartment_threaded
= TRUE
;
2666 if (apt
->multi_threaded
)
2667 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2669 else if (model
== ThreadingModel_Free
)
2671 apartment_threaded
= FALSE
;
2672 if (!apt
->multi_threaded
)
2673 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2675 /* everything except "Apartment", "Free" and "Both" */
2676 else if (model
!= ThreadingModel_Both
)
2678 apartment_threaded
= TRUE
;
2679 /* everything else is main-threaded */
2680 if (model
!= ThreadingModel_No
)
2681 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
2683 if (apt
->multi_threaded
|| !apt
->main
)
2684 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
2687 apartment_threaded
= FALSE
;
2690 apartment_threaded
= !apt
->multi_threaded
;
2692 if (!get_object_dll_path(regdata
, dllpath
, ARRAY_SIZE(dllpath
)))
2694 /* failure: CLSID is not found in registry */
2695 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2696 return REGDB_E_CLASSNOTREG
;
2699 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2703 /***********************************************************************
2704 * CoGetClassObject [OLE32.@]
2706 * Creates an object of the specified class.
2709 * rclsid [I] Class ID to create an instance of.
2710 * dwClsContext [I] Flags to restrict the location of the created instance.
2711 * pServerInfo [I] Optional. Details for connecting to a remote server.
2712 * iid [I] The ID of the interface of the instance to return.
2713 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2717 * Failure: HRESULT code.
2720 * The dwClsContext parameter can be one or more of the following:
2721 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2722 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2723 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2724 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2727 * CoCreateInstance()
2729 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
2730 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2731 REFIID iid
, LPVOID
*ppv
)
2733 struct class_reg_data clsreg
= { 0 };
2734 IUnknown
*regClassObject
;
2735 HRESULT hres
= E_UNEXPECTED
;
2738 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2741 return E_INVALIDARG
;
2745 if (!(apt
= apartment_get_current_or_mta()))
2747 ERR("apartment not initialised\n");
2748 return CO_E_NOTINITIALIZED
;
2752 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2753 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2756 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2758 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
) ||
2759 IsEqualCLSID(rclsid
, &CLSID_GlobalOptions
) ||
2760 IsEqualCLSID(rclsid
, &CLSID_ManualResetEvent
) ||
2761 IsEqualCLSID(rclsid
, &CLSID_StdGlobalInterfaceTable
))
2763 apartment_release(apt
);
2764 return Ole32DllGetClassObject(rclsid
, iid
, ppv
);
2768 if (CLSCTX_INPROC
& dwClsContext
)
2770 ACTCTX_SECTION_KEYED_DATA data
;
2772 data
.cbSize
= sizeof(data
);
2773 /* search activation context first */
2774 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
2775 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2778 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2780 clsreg
.u
.actctx
.module_name
= (WCHAR
*)((BYTE
*)data
.lpSectionBase
+ comclass
->name_offset
);
2781 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
2782 clsreg
.u
.actctx
.threading_model
= comclass
->model
;
2783 clsreg
.origin
= CLASS_REG_ACTCTX
;
2785 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2786 ReleaseActCtx(data
.hActCtx
);
2787 apartment_release(apt
);
2793 * First, try and see if we can't match the class ID with one of the
2794 * registered classes.
2796 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
2799 /* Get the required interface from the retrieved pointer. */
2800 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
2803 * Since QI got another reference on the pointer, we want to release the
2804 * one we already have. If QI was unsuccessful, this will release the object. This
2805 * is good since we are not returning it in the "out" parameter.
2807 IUnknown_Release(regClassObject
);
2808 apartment_release(apt
);
2812 /* First try in-process server */
2813 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2815 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2818 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
2821 if (hres
== REGDB_E_CLASSNOTREG
)
2822 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2823 else if (hres
== REGDB_E_KEYMISSING
)
2825 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
2826 hres
= REGDB_E_CLASSNOTREG
;
2830 if (SUCCEEDED(hres
))
2832 clsreg
.u
.hkey
= hkey
;
2833 clsreg
.origin
= CLASS_REG_REGISTRY
;
2835 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2839 /* return if we got a class, otherwise fall through to one of the
2841 if (SUCCEEDED(hres
))
2843 apartment_release(apt
);
2848 /* Next try in-process handler */
2849 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
2851 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2854 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
2857 if (hres
== REGDB_E_CLASSNOTREG
)
2858 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2859 else if (hres
== REGDB_E_KEYMISSING
)
2861 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
2862 hres
= REGDB_E_CLASSNOTREG
;
2866 if (SUCCEEDED(hres
))
2868 clsreg
.u
.hkey
= hkey
;
2869 clsreg
.origin
= CLASS_REG_REGISTRY
;
2871 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2875 /* return if we got a class, otherwise fall through to one of the
2877 if (SUCCEEDED(hres
))
2879 apartment_release(apt
);
2883 apartment_release(apt
);
2885 /* Next try out of process */
2886 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
2888 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
2889 if (SUCCEEDED(hres
))
2893 /* Finally try remote: this requires networked DCOM (a lot of work) */
2894 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
2896 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2897 hres
= REGDB_E_CLASSNOTREG
;
2901 ERR("no class object %s could be created for context 0x%x\n",
2902 debugstr_guid(rclsid
), dwClsContext
);
2906 /***********************************************************************
2907 * CoResumeClassObjects (OLE32.@)
2909 * Resumes all class objects registered with REGCLS_SUSPENDED.
2913 * Failure: HRESULT code.
2915 HRESULT WINAPI
CoResumeClassObjects(void)
2921 /***********************************************************************
2922 * CoLoadLibrary (OLE32.@)
2927 * lpszLibName [I] Path to library.
2928 * bAutoFree [I] Whether the library should automatically be freed.
2931 * Success: Handle to loaded library.
2935 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2937 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
2939 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
2941 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
2944 /***********************************************************************
2945 * CoFreeLibrary [OLE32.@]
2947 * Unloads a library from memory.
2950 * hLibrary [I] Handle to library to unload.
2956 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2958 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
2960 FreeLibrary(hLibrary
);
2964 /***********************************************************************
2965 * CoFreeAllLibraries [OLE32.@]
2967 * Function for backwards compatibility only. Does nothing.
2973 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2975 void WINAPI
CoFreeAllLibraries(void)
2980 /***********************************************************************
2981 * CoFreeUnusedLibrariesEx [OLE32.@]
2983 * Frees any previously unused libraries whose delay has expired and marks
2984 * currently unused libraries for unloading. Unused are identified as those that
2985 * return S_OK from their DllCanUnloadNow function.
2988 * dwUnloadDelay [I] Unload delay in milliseconds.
2989 * dwReserved [I] Reserved. Set to 0.
2995 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2997 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
2999 struct apartment
*apt
= COM_CurrentApt();
3002 ERR("apartment not initialised\n");
3006 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3009 /******************************************************************************
3010 * CoLockObjectExternal [OLE32.@]
3012 * Increments or decrements the external reference count of a stub object.
3015 * pUnk [I] Stub object.
3016 * fLock [I] If TRUE then increments the external ref-count,
3017 * otherwise decrements.
3018 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3019 * calling CoDisconnectObject.
3023 * Failure: HRESULT code.
3026 * If fLock is TRUE and an object is passed in that doesn't have a stub
3027 * manager then a new stub manager is created for the object.
3029 HRESULT WINAPI
CoLockObjectExternal(
3032 BOOL fLastUnlockReleases
)
3034 struct stub_manager
*stubmgr
;
3035 struct apartment
*apt
;
3037 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3038 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3040 if (!(apt
= apartment_get_current_or_mta()))
3042 ERR("apartment not initialised\n");
3043 return CO_E_NOTINITIALIZED
;
3046 stubmgr
= get_stub_manager_from_object(apt
, pUnk
, fLock
);
3049 WARN("stub object not found %p\n", pUnk
);
3050 /* Note: native is pretty broken here because it just silently
3051 * fails, without returning an appropriate error code, making apps
3052 * think that the object was disconnected, when it actually wasn't */
3053 apartment_release(apt
);
3058 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3060 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3062 stub_manager_int_release(stubmgr
);
3063 apartment_release(apt
);
3067 /***********************************************************************
3068 * CoInitializeWOW (OLE32.@)
3070 * WOW equivalent of CoInitialize?
3079 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3081 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3085 /***********************************************************************
3086 * CoGetState [OLE32.@]
3088 * Retrieves the thread state object previously stored by CoSetState().
3091 * ppv [I] Address where pointer to object will be stored.
3095 * Failure: E_OUTOFMEMORY.
3098 * Crashes on all invalid ppv addresses, including NULL.
3099 * If the function returns a non-NULL object then the caller must release its
3100 * reference on the object when the object is no longer required.
3105 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3107 struct oletls
*info
= COM_CurrentInfo();
3108 if (!info
) return E_OUTOFMEMORY
;
3114 IUnknown_AddRef(info
->state
);
3116 TRACE("apt->state=%p\n", info
->state
);
3122 /***********************************************************************
3123 * CoSetState [OLE32.@]
3125 * Sets the thread state object.
3128 * pv [I] Pointer to state object to be stored.
3131 * The system keeps a reference on the object while the object stored.
3135 * Failure: E_OUTOFMEMORY.
3137 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3139 struct oletls
*info
= COM_CurrentInfo();
3140 if (!info
) return E_OUTOFMEMORY
;
3142 if (pv
) IUnknown_AddRef(pv
);
3146 TRACE("-- release %p now\n", info
->state
);
3147 IUnknown_Release(info
->state
);
3156 /******************************************************************************
3157 * CoTreatAsClass [OLE32.@]
3159 * Sets the TreatAs value of a class.
3162 * clsidOld [I] Class to set TreatAs value on.
3163 * clsidNew [I] The class the clsidOld should be treated as.
3167 * Failure: HRESULT code.
3172 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3174 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3175 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3177 WCHAR szClsidNew
[CHARS_IN_GUID
];
3179 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3180 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3183 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3187 if (IsEqualGUID( clsidOld
, clsidNew
))
3189 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3190 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3192 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3194 res
= REGDB_E_WRITEREGDB
;
3200 if(RegDeleteKeyW(hkey
, wszTreatAs
))
3201 res
= REGDB_E_WRITEREGDB
;
3207 if(IsEqualGUID(clsidNew
, &CLSID_NULL
)){
3208 RegDeleteKeyW(hkey
, wszTreatAs
);
3210 if(!StringFromGUID2(clsidNew
, szClsidNew
, ARRAY_SIZE(szClsidNew
))){
3211 WARN("StringFromGUID2 failed\n");
3216 if(RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)) != ERROR_SUCCESS
){
3217 WARN("RegSetValue failed\n");
3218 res
= REGDB_E_WRITEREGDB
;
3225 if (hkey
) RegCloseKey(hkey
);
3229 /******************************************************************************
3230 * CoGetCurrentProcess [OLE32.@]
3232 DWORD WINAPI
CoGetCurrentProcess(void)
3234 struct oletls
*info
= COM_CurrentInfo();
3239 if (!info
->thread_seqid
)
3240 info
->thread_seqid
= rpcss_get_next_seqid();
3242 return info
->thread_seqid
;
3245 /***********************************************************************
3246 * CoGetCurrentLogicalThreadId [OLE32.@]
3248 HRESULT WINAPI
CoGetCurrentLogicalThreadId(GUID
*id
)
3250 TRACE("(%p)\n", id
);
3253 return E_INVALIDARG
;
3255 *id
= COM_CurrentCausalityId();
3259 /******************************************************************************
3260 * CoRegisterMessageFilter [OLE32.@]
3262 * Registers a message filter.
3265 * lpMessageFilter [I] Pointer to interface.
3266 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3270 * Failure: HRESULT code.
3273 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3274 * lpMessageFilter removes the message filter.
3276 * If lplpMessageFilter is not NULL the previous message filter will be
3277 * returned in the memory pointer to this parameter and the caller is
3278 * responsible for releasing the object.
3280 * The current thread be in an apartment otherwise the function will crash.
3282 HRESULT WINAPI
CoRegisterMessageFilter(
3283 LPMESSAGEFILTER lpMessageFilter
,
3284 LPMESSAGEFILTER
*lplpMessageFilter
)
3286 struct apartment
*apt
;
3287 IMessageFilter
*lpOldMessageFilter
;
3289 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3291 apt
= COM_CurrentApt();
3293 /* can't set a message filter in a multi-threaded apartment */
3294 if (!apt
|| apt
->multi_threaded
)
3296 WARN("can't set message filter in MTA or uninitialized apt\n");
3297 return CO_E_NOT_SUPPORTED
;
3300 if (lpMessageFilter
)
3301 IMessageFilter_AddRef(lpMessageFilter
);
3303 EnterCriticalSection(&apt
->cs
);
3305 lpOldMessageFilter
= apt
->filter
;
3306 apt
->filter
= lpMessageFilter
;
3308 LeaveCriticalSection(&apt
->cs
);
3310 if (lplpMessageFilter
)
3311 *lplpMessageFilter
= lpOldMessageFilter
;
3312 else if (lpOldMessageFilter
)
3313 IMessageFilter_Release(lpOldMessageFilter
);
3318 /***********************************************************************
3319 * CoIsOle1Class [OLE32.@]
3321 * Determines whether the specified class an OLE v1 class.
3324 * clsid [I] Class to test.
3327 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3329 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3331 FIXME("%s\n", debugstr_guid(clsid
));
3335 /***********************************************************************
3336 * IsEqualGUID [OLE32.@]
3338 * Compares two Unique Identifiers.
3341 * rguid1 [I] The first GUID to compare.
3342 * rguid2 [I] The other GUID to compare.
3348 BOOL WINAPI
IsEqualGUID(
3352 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3355 /***********************************************************************
3356 * CoInitializeSecurity [OLE32.@]
3358 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3359 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3360 void* pReserved1
, DWORD dwAuthnLevel
,
3361 DWORD dwImpLevel
, void* pReserved2
,
3362 DWORD dwCapabilities
, void* pReserved3
)
3364 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3365 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3366 dwCapabilities
, pReserved3
);
3370 /***********************************************************************
3371 * CoSuspendClassObjects [OLE32.@]
3373 * Suspends all registered class objects to prevent further requests coming in
3374 * for those objects.
3378 * Failure: HRESULT code.
3380 HRESULT WINAPI
CoSuspendClassObjects(void)
3386 /***********************************************************************
3387 * CoAddRefServerProcess [OLE32.@]
3389 * Helper function for incrementing the reference count of a local-server
3393 * New reference count.
3396 * CoReleaseServerProcess().
3398 ULONG WINAPI
CoAddRefServerProcess(void)
3404 EnterCriticalSection(&csRegisteredClassList
);
3405 refs
= ++s_COMServerProcessReferences
;
3406 LeaveCriticalSection(&csRegisteredClassList
);
3408 TRACE("refs before: %d\n", refs
- 1);
3413 /***********************************************************************
3414 * CoReleaseServerProcess [OLE32.@]
3416 * Helper function for decrementing the reference count of a local-server
3420 * New reference count.
3423 * When reference count reaches 0, this function suspends all registered
3424 * classes so no new connections are accepted.
3427 * CoAddRefServerProcess(), CoSuspendClassObjects().
3429 ULONG WINAPI
CoReleaseServerProcess(void)
3435 EnterCriticalSection(&csRegisteredClassList
);
3437 refs
= --s_COMServerProcessReferences
;
3438 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3440 LeaveCriticalSection(&csRegisteredClassList
);
3442 TRACE("refs after: %d\n", refs
);
3447 /***********************************************************************
3448 * CoIsHandlerConnected [OLE32.@]
3450 * Determines whether a proxy is connected to a remote stub.
3453 * pUnk [I] Pointer to object that may or may not be connected.
3456 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3459 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
3461 FIXME("%p\n", pUnk
);
3466 /***********************************************************************
3467 * CoAllowSetForegroundWindow [OLE32.@]
3470 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
3472 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
3476 /***********************************************************************
3477 * CoGetCallContext [OLE32.@]
3479 * Gets the context of the currently executing server call in the current
3483 * riid [I] Context interface to return.
3484 * ppv [O] Pointer to memory that will receive the context on return.
3488 * Failure: HRESULT code.
3490 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
3492 struct oletls
*info
= COM_CurrentInfo();
3494 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
3497 return E_OUTOFMEMORY
;
3499 if (!info
->call_state
)
3500 return RPC_E_CALL_COMPLETE
;
3502 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
3505 /***********************************************************************
3506 * CoSwitchCallContext [OLE32.@]
3508 * Switches the context of the currently executing server call in the current
3512 * pObject [I] Pointer to new context object
3513 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3517 * Failure: HRESULT code.
3519 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
3521 struct oletls
*info
= COM_CurrentInfo();
3523 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
3526 return E_OUTOFMEMORY
;
3528 *ppOldObject
= info
->call_state
;
3529 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
3534 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
3536 /* first try to retrieve messages for incoming COM calls to the apartment window */
3537 return (apt
->win
&& PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
)) ||
3538 /* next retrieve other messages necessary for the app to remain responsive */
3539 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
3540 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
3543 /***********************************************************************
3544 * CoWaitForMultipleHandles [OLE32.@]
3546 * Waits for one or more handles to become signaled.
3549 * dwFlags [I] Flags. See notes.
3550 * dwTimeout [I] Timeout in milliseconds.
3551 * cHandles [I] Number of handles pointed to by pHandles.
3552 * pHandles [I] Handles to wait for.
3553 * lpdwindex [O] Index of handle that was signaled.
3557 * Failure: RPC_S_CALLPENDING on timeout.
3561 * The dwFlags parameter can be zero or more of the following:
3562 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3563 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3566 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3568 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
3569 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
3572 DWORD start_time
= GetTickCount();
3573 APARTMENT
*apt
= COM_CurrentApt();
3574 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
3575 BOOL check_apc
= (dwFlags
& COWAIT_ALERTABLE
) != 0;
3576 BOOL post_quit
= FALSE
;
3579 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
3580 pHandles
, lpdwindex
);
3583 return E_INVALIDARG
;
3588 return E_INVALIDARG
;
3591 return RPC_E_NO_SYNC
;
3595 DWORD now
= GetTickCount();
3598 if (now
- start_time
> dwTimeout
)
3600 hr
= RPC_S_CALLPENDING
;
3606 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
3607 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
3609 TRACE("waiting for rpc completion or window message\n");
3615 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
3616 (dwFlags
& COWAIT_WAITALL
) != 0, 0, TRUE
);
3620 if (res
== WAIT_TIMEOUT
)
3621 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
3622 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
3623 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
3625 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
3630 /* call message filter */
3632 if (COM_CurrentApt()->filter
)
3634 PENDINGTYPE pendingtype
=
3635 COM_CurrentInfo()->pending_call_count_server
?
3636 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
3637 DWORD be_handled
= IMessageFilter_MessagePending(
3638 COM_CurrentApt()->filter
, 0 /* FIXME */,
3639 now
- start_time
, pendingtype
);
3640 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
3643 case PENDINGMSG_CANCELCALL
:
3644 WARN("call canceled\n");
3645 hr
= RPC_E_CALL_CANCELED
;
3647 case PENDINGMSG_WAITNOPROCESS
:
3648 case PENDINGMSG_WAITDEFPROCESS
:
3650 /* FIXME: MSDN is very vague about the difference
3651 * between WAITNOPROCESS and WAITDEFPROCESS - there
3652 * appears to be none, so it is possibly a left-over
3653 * from the 16-bit world. */
3660 /* If window is NULL on apartment, peek at messages so that it will not trigger
3661 * MsgWaitForMultipleObjects next time. */
3662 PeekMessageW(NULL
, NULL
, 0, 0, PM_QS_POSTMESSAGE
| PM_NOREMOVE
| PM_NOYIELD
);
3664 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
3665 * so after processing 100 messages we go back to checking the wait handles */
3666 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
3668 if (msg
.message
== WM_QUIT
)
3670 TRACE("received WM_QUIT message\n");
3672 exit_code
= msg
.wParam
;
3676 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
3677 TranslateMessage(&msg
);
3678 DispatchMessageW(&msg
);
3686 TRACE("waiting for rpc completion\n");
3688 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
3689 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
3690 (dwFlags
& COWAIT_ALERTABLE
) != 0);
3696 hr
= RPC_S_CALLPENDING
;
3699 hr
= HRESULT_FROM_WIN32( GetLastError() );
3707 if (post_quit
) PostQuitMessage(exit_code
);
3708 TRACE("-- 0x%08x\n", hr
);
3713 /***********************************************************************
3714 * CoGetObject [OLE32.@]
3716 * Gets the object named by converting the name to a moniker and binding to it.
3719 * pszName [I] String representing the object.
3720 * pBindOptions [I] Parameters affecting the binding to the named object.
3721 * riid [I] Interface to bind to on the object.
3722 * ppv [O] On output, the interface riid of the object represented
3727 * Failure: HRESULT code.
3730 * MkParseDisplayName.
3732 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
3733 REFIID riid
, void **ppv
)
3740 hr
= CreateBindCtx(0, &pbc
);
3744 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
3751 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
3754 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
3755 IMoniker_Release(pmk
);
3759 IBindCtx_Release(pbc
);
3764 /***********************************************************************
3765 * CoRegisterChannelHook [OLE32.@]
3767 * Registers a process-wide hook that is called during ORPC calls.
3770 * guidExtension [I] GUID of the channel hook to register.
3771 * pChannelHook [I] Channel hook object to register.
3775 * Failure: HRESULT code.
3777 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
3779 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
3781 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
3784 typedef struct Context
3786 IComThreadingInfo IComThreadingInfo_iface
;
3787 IContextCallback IContextCallback_iface
;
3788 IObjContext IObjContext_iface
;
3792 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
3794 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
3797 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
3799 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
3802 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
3804 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
3807 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
3811 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
3812 IsEqualIID(riid
, &IID_IUnknown
))
3814 *ppv
= &iface
->IComThreadingInfo_iface
;
3816 else if (IsEqualIID(riid
, &IID_IContextCallback
))
3818 *ppv
= &iface
->IContextCallback_iface
;
3820 else if (IsEqualIID(riid
, &IID_IObjContext
))
3822 *ppv
= &iface
->IObjContext_iface
;
3827 IUnknown_AddRef((IUnknown
*)*ppv
);
3831 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
3832 return E_NOINTERFACE
;
3835 static ULONG
Context_AddRef(Context
*This
)
3837 return InterlockedIncrement(&This
->refs
);
3840 static ULONG
Context_Release(Context
*This
)
3842 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
3843 releasing context while refcount is at 0 destroys it. */
3846 HeapFree(GetProcessHeap(), 0, This
);
3850 return InterlockedDecrement(&This
->refs
);
3853 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
3855 Context
*This
= impl_from_IComThreadingInfo(iface
);
3856 return Context_QueryInterface(This
, riid
, ppv
);
3859 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
3861 Context
*This
= impl_from_IComThreadingInfo(iface
);
3862 return Context_AddRef(This
);
3865 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
3867 Context
*This
= impl_from_IComThreadingInfo(iface
);
3868 return Context_Release(This
);
3871 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
3873 APTTYPEQUALIFIER qualifier
;
3875 TRACE("(%p)\n", apttype
);
3877 return CoGetApartmentType(apttype
, &qualifier
);
3880 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
3882 APTTYPEQUALIFIER qualifier
;
3886 hr
= CoGetApartmentType(&apttype
, &qualifier
);
3890 TRACE("(%p)\n", thdtype
);
3895 case APTTYPE_MAINSTA
:
3896 *thdtype
= THDTYPE_PROCESSMESSAGES
;
3899 *thdtype
= THDTYPE_BLOCKMESSAGES
;
3905 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
3907 TRACE("(%p)\n", logical_thread_id
);
3908 return CoGetCurrentLogicalThreadId(logical_thread_id
);
3911 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
3913 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
3917 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
3919 Context_CTI_QueryInterface
,
3921 Context_CTI_Release
,
3922 Context_CTI_GetCurrentApartmentType
,
3923 Context_CTI_GetCurrentThreadType
,
3924 Context_CTI_GetCurrentLogicalThreadId
,
3925 Context_CTI_SetCurrentLogicalThreadId
3928 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
3930 Context
*This
= impl_from_IContextCallback(iface
);
3931 return Context_QueryInterface(This
, riid
, ppv
);
3934 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
3936 Context
*This
= impl_from_IContextCallback(iface
);
3937 return Context_AddRef(This
);
3940 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
3942 Context
*This
= impl_from_IContextCallback(iface
);
3943 return Context_Release(This
);
3946 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
3947 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
3949 Context
*This
= impl_from_IContextCallback(iface
);
3951 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
3955 static const IContextCallbackVtbl Context_Callback_Vtbl
=
3957 Context_CC_QueryInterface
,
3960 Context_CC_ContextCallback
3963 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
3965 Context
*This
= impl_from_IObjContext(iface
);
3966 return Context_QueryInterface(This
, riid
, ppv
);
3969 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
3971 Context
*This
= impl_from_IObjContext(iface
);
3972 return Context_AddRef(This
);
3975 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
3977 Context
*This
= impl_from_IObjContext(iface
);
3978 return Context_Release(This
);
3981 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
3983 Context
*This
= impl_from_IObjContext(iface
);
3985 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
3989 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
3991 Context
*This
= impl_from_IObjContext(iface
);
3993 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
3997 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
3999 Context
*This
= impl_from_IObjContext(iface
);
4001 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4005 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4007 Context
*This
= impl_from_IObjContext(iface
);
4009 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4013 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4015 Context
*This
= impl_from_IObjContext(iface
);
4016 FIXME("(%p/%p)\n", This
, iface
);
4019 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4021 Context
*This
= impl_from_IObjContext(iface
);
4022 FIXME("(%p/%p)\n", This
, iface
);
4025 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4027 Context
*This
= impl_from_IObjContext(iface
);
4028 FIXME("(%p/%p)\n", This
, iface
);
4031 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4033 Context
*This
= impl_from_IObjContext(iface
);
4034 FIXME("(%p/%p)\n", This
, iface
);
4037 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4039 Context
*This
= impl_from_IObjContext(iface
);
4040 FIXME("(%p/%p)\n", This
, iface
);
4043 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4045 Context
*This
= impl_from_IObjContext(iface
);
4046 FIXME("(%p/%p)\n", This
, iface
);
4049 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4051 Context
*This
= impl_from_IObjContext(iface
);
4052 FIXME("(%p/%p)\n", This
, iface
);
4055 static const IObjContextVtbl Context_Object_Vtbl
=
4057 Context_OC_QueryInterface
,
4060 Context_OC_SetProperty
,
4061 Context_OC_RemoveProperty
,
4062 Context_OC_GetProperty
,
4063 Context_OC_EnumContextProps
,
4064 Context_OC_Reserved1
,
4065 Context_OC_Reserved2
,
4066 Context_OC_Reserved3
,
4067 Context_OC_Reserved4
,
4068 Context_OC_Reserved5
,
4069 Context_OC_Reserved6
,
4070 Context_OC_Reserved7
4073 /***********************************************************************
4074 * CoGetContextToken [OLE32.@]
4076 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4078 struct oletls
*info
= COM_CurrentInfo();
4081 TRACE("(%p)\n", token
);
4084 return E_OUTOFMEMORY
;
4086 if (!(apt
= apartment_get_current_or_mta()))
4088 ERR("apartment not initialised\n");
4089 return CO_E_NOTINITIALIZED
;
4091 apartment_release(apt
);
4096 if (!info
->context_token
)
4100 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4102 return E_OUTOFMEMORY
;
4104 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
4105 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
4106 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
4107 /* Context token does not take a reference, it's always zero until the
4108 interface is explicitly requested with CoGetObjectContext(). */
4111 info
->context_token
= &context
->IObjContext_iface
;
4114 *token
= (ULONG_PTR
)info
->context_token
;
4115 TRACE("context_token=%p\n", info
->context_token
);
4120 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
4122 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4126 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
4127 if (SUCCEEDED(hres
))
4129 struct class_reg_data regdata
;
4130 WCHAR dllpath
[MAX_PATH
+1];
4132 regdata
.u
.hkey
= hkey
;
4133 regdata
.origin
= CLASS_REG_REGISTRY
;
4135 if (get_object_dll_path(®data
, dllpath
, ARRAY_SIZE(dllpath
)))
4137 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
4138 if (!wcsicmp(dllpath
, wszOle32
))
4141 return HandlerCF_Create(rclsid
, riid
, ppv
);
4145 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
4149 return CLASS_E_CLASSNOTAVAILABLE
;
4152 /***********************************************************************
4153 * CoGetApartmentType [OLE32.@]
4155 HRESULT WINAPI
CoGetApartmentType(APTTYPE
*type
, APTTYPEQUALIFIER
*qualifier
)
4157 struct oletls
*info
= COM_CurrentInfo();
4160 TRACE("(%p, %p)\n", type
, qualifier
);
4162 if (!type
|| !qualifier
)
4163 return E_INVALIDARG
;
4166 return E_OUTOFMEMORY
;
4169 *type
= APTTYPE_CURRENT
;
4170 else if (info
->apt
->multi_threaded
)
4171 *type
= APTTYPE_MTA
;
4172 else if (info
->apt
->main
)
4173 *type
= APTTYPE_MAINSTA
;
4175 *type
= APTTYPE_STA
;
4177 *qualifier
= APTTYPEQUALIFIER_NONE
;
4179 if (!info
->apt
&& (apt
= apartment_find_mta()))
4181 apartment_release(apt
);
4182 *type
= APTTYPE_MTA
;
4183 *qualifier
= APTTYPEQUALIFIER_IMPLICIT_MTA
;
4187 return info
->apt
? S_OK
: CO_E_NOTINITIALIZED
;
4195 /***********************************************************************
4196 * CoIncrementMTAUsage [OLE32.@]
4198 HRESULT WINAPI
CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE
*cookie
)
4200 struct mta_cookie
*mta_cookie
;
4202 TRACE("%p\n", cookie
);
4206 if (!(mta_cookie
= heap_alloc(sizeof(*mta_cookie
))))
4207 return E_OUTOFMEMORY
;
4209 EnterCriticalSection(&csApartment
);
4212 apartment_addref(MTA
);
4214 MTA
= apartment_construct(COINIT_MULTITHREADED
);
4215 list_add_head(&MTA
->usage_cookies
, &mta_cookie
->entry
);
4217 LeaveCriticalSection(&csApartment
);
4219 *cookie
= (CO_MTA_USAGE_COOKIE
)mta_cookie
;
4224 /***********************************************************************
4225 * CoDecrementMTAUsage [OLE32.@]
4227 HRESULT WINAPI
CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie
)
4229 struct mta_cookie
*mta_cookie
= (struct mta_cookie
*)cookie
;
4231 TRACE("%p\n", cookie
);
4233 EnterCriticalSection(&csApartment
);
4237 struct mta_cookie
*cur
;
4239 LIST_FOR_EACH_ENTRY(cur
, &MTA
->usage_cookies
, struct mta_cookie
, entry
)
4241 if (mta_cookie
== cur
)
4243 list_remove(&cur
->entry
);
4245 apartment_release(MTA
);
4251 LeaveCriticalSection(&csApartment
);
4256 /***********************************************************************
4257 * CoDisableCallCancellation [OLE32.@]
4259 HRESULT WINAPI
CoDisableCallCancellation(void *reserved
)
4261 FIXME("(%p): stub\n", reserved
);
4266 /***********************************************************************
4267 * CoEnableCallCancellation [OLE32.@]
4269 HRESULT WINAPI
CoEnableCallCancellation(void *reserved
)
4271 FIXME("(%p): stub\n", reserved
);
4276 /***********************************************************************
4277 * CoRegisterSurrogate [OLE32.@]
4279 HRESULT WINAPI
CoRegisterSurrogate(ISurrogate
*surrogate
)
4281 FIXME("(%p): stub\n", surrogate
);
4286 /***********************************************************************
4287 * CoRegisterSurrogateEx [OLE32.@]
4289 HRESULT WINAPI
CoRegisterSurrogateEx(REFGUID guid
, void *reserved
)
4291 FIXME("(%s %p): stub\n", debugstr_guid(guid
), reserved
);
4297 IGlobalOptions IGlobalOptions_iface
;
4301 static inline GlobalOptions
*impl_from_IGlobalOptions(IGlobalOptions
*iface
)
4303 return CONTAINING_RECORD(iface
, GlobalOptions
, IGlobalOptions_iface
);
4306 static HRESULT WINAPI
GlobalOptions_QueryInterface(IGlobalOptions
*iface
, REFIID riid
, void **ppv
)
4308 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
4310 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
4312 if (IsEqualGUID(&IID_IGlobalOptions
, riid
) || IsEqualGUID(&IID_IUnknown
, riid
))
4319 return E_NOINTERFACE
;
4322 IUnknown_AddRef((IUnknown
*)*ppv
);
4326 static ULONG WINAPI
GlobalOptions_AddRef(IGlobalOptions
*iface
)
4328 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
4329 LONG ref
= InterlockedIncrement(&This
->ref
);
4331 TRACE("(%p) ref=%d\n", This
, ref
);
4336 static ULONG WINAPI
GlobalOptions_Release(IGlobalOptions
*iface
)
4338 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
4339 LONG ref
= InterlockedDecrement(&This
->ref
);
4341 TRACE("(%p) ref=%d\n", This
, ref
);
4349 static HRESULT WINAPI
GlobalOptions_Set(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR value
)
4351 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
4352 FIXME("(%p)->(%u %lx)\n", This
, property
, value
);
4356 static HRESULT WINAPI
GlobalOptions_Query(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR
*value
)
4358 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
4359 FIXME("(%p)->(%u %p)\n", This
, property
, value
);
4363 static const IGlobalOptionsVtbl GlobalOptionsVtbl
= {
4364 GlobalOptions_QueryInterface
,
4365 GlobalOptions_AddRef
,
4366 GlobalOptions_Release
,
4371 HRESULT WINAPI
GlobalOptions_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **ppv
)
4373 GlobalOptions
*global_options
;
4376 TRACE("(%p %s %p)\n", outer
, debugstr_guid(riid
), ppv
);
4379 return E_INVALIDARG
;
4381 global_options
= heap_alloc(sizeof(*global_options
));
4382 if (!global_options
)
4383 return E_OUTOFMEMORY
;
4384 global_options
->IGlobalOptions_iface
.lpVtbl
= &GlobalOptionsVtbl
;
4385 global_options
->ref
= 1;
4387 hres
= IGlobalOptions_QueryInterface(&global_options
->IGlobalOptions_iface
, riid
, ppv
);
4388 IGlobalOptions_Release(&global_options
->IGlobalOptions_iface
);
4392 /***********************************************************************
4395 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
4397 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
4400 case DLL_PROCESS_ATTACH
:
4401 hProxyDll
= hinstDLL
;
4404 case DLL_PROCESS_DETACH
:
4405 if (reserved
) break;
4408 UnregisterClassW( (const WCHAR
*)MAKEINTATOM(apt_win_class
), hProxyDll
);
4409 RPC_UnregisterAllChannelHooks();
4410 COMPOBJ_DllList_Free();
4411 DeleteCriticalSection(&csRegisteredClassList
);
4412 DeleteCriticalSection(&csApartment
);
4415 case DLL_THREAD_DETACH
:
4422 /***********************************************************************
4423 * DllRegisterServer (OLE32.@)
4425 HRESULT WINAPI
DllRegisterServer(void)
4427 return OLE32_DllRegisterServer();
4430 /***********************************************************************
4431 * DllUnregisterServer (OLE32.@)
4433 HRESULT WINAPI
DllUnregisterServer(void)
4435 return OLE32_DllUnregisterServer();