kernel32: Fix typo in enum_locale_ex_proc.
[wine.git] / dlls / ole32 / compobj.c
blob7af3bb75628e6bac0c1ff5e9043b38d4428c983f
1 /*
2 * COMPOBJ library
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
26 * Note
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
39 #include "config.h"
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
46 #define COBJMACROS
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
50 #include "ntstatus.h"
51 #define WIN32_NO_STATUS
52 #include "windef.h"
53 #include "winbase.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "winuser.h"
57 #define USE_COM_CONTEXT_DEF
58 #include "objbase.h"
59 #include "ole2.h"
60 #include "ole2ver.h"
61 #include "ctxtcall.h"
62 #include "dde.h"
63 #include "servprov.h"
65 #include "initguid.h"
66 #include "compobj_private.h"
67 #include "moniker.h"
69 #include "wine/unicode.h"
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(ole);
74 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
76 /****************************************************************************
77 * This section defines variables internal to the COM module.
80 static APARTMENT *MTA; /* protected by csApartment */
81 static APARTMENT *MainApartment; /* the first STA apartment */
82 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
84 static CRITICAL_SECTION csApartment;
85 static CRITICAL_SECTION_DEBUG critsect_debug =
87 0, 0, &csApartment,
88 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
89 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
91 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
93 enum comclass_threadingmodel
95 ThreadingModel_Apartment = 1,
96 ThreadingModel_Free = 2,
97 ThreadingModel_No = 3,
98 ThreadingModel_Both = 4,
99 ThreadingModel_Neutral = 5
102 enum comclass_miscfields
104 MiscStatus = 1,
105 MiscStatusIcon = 2,
106 MiscStatusContent = 4,
107 MiscStatusThumbnail = 8,
108 MiscStatusDocPrint = 16
111 struct comclassredirect_data
113 ULONG size;
114 BYTE res;
115 BYTE miscmask;
116 BYTE res1[2];
117 DWORD model;
118 GUID clsid;
119 GUID alias;
120 GUID clsid2;
121 GUID tlbid;
122 ULONG name_len;
123 ULONG name_offset;
124 ULONG progid_len;
125 ULONG progid_offset;
126 ULONG clrdata_len;
127 ULONG clrdata_offset;
128 DWORD miscstatus;
129 DWORD miscstatuscontent;
130 DWORD miscstatusthumbnail;
131 DWORD miscstatusicon;
132 DWORD miscstatusdocprint;
135 struct ifacepsredirect_data
137 ULONG size;
138 DWORD mask;
139 GUID iid;
140 ULONG nummethods;
141 GUID tlbid;
142 GUID base;
143 ULONG name_len;
144 ULONG name_offset;
147 struct progidredirect_data
149 ULONG size;
150 DWORD reserved;
151 ULONG clsid_offset;
154 struct class_reg_data
156 union
158 struct
160 struct comclassredirect_data *data;
161 void *section;
162 HANDLE hactctx;
163 } actctx;
164 HKEY hkey;
165 } u;
166 BOOL hkey;
169 struct registered_psclsid
171 struct list entry;
172 IID iid;
173 CLSID clsid;
177 * This is a marshallable object exposing registered local servers.
178 * IServiceProvider is used only because it happens meet requirements
179 * and already has proxy/stub code. If more functionality is needed,
180 * a custom interface may be used instead.
182 struct LocalServer
184 IServiceProvider IServiceProvider_iface;
185 LONG ref;
186 APARTMENT *apt;
187 IStream *marshal_stream;
191 * This lock count counts the number of times CoInitialize is called. It is
192 * decreased every time CoUninitialize is called. When it hits 0, the COM
193 * libraries are freed
195 static LONG s_COMLockCount = 0;
196 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
197 static LONG s_COMServerProcessReferences = 0;
200 * This linked list contains the list of registered class objects. These
201 * are mostly used to register the factories for out-of-proc servers of OLE
202 * objects.
204 * TODO: Make this data structure aware of inter-process communication. This
205 * means that parts of this will be exported to rpcss.
207 typedef struct tagRegisteredClass
209 struct list entry;
210 CLSID classIdentifier;
211 OXID apartment_id;
212 LPUNKNOWN classObject;
213 DWORD runContext;
214 DWORD connectFlags;
215 DWORD dwCookie;
216 void *RpcRegistration;
217 } RegisteredClass;
219 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
221 static CRITICAL_SECTION csRegisteredClassList;
222 static CRITICAL_SECTION_DEBUG class_cs_debug =
224 0, 0, &csRegisteredClassList,
225 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
226 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
228 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
230 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
232 switch (aspect)
234 case DVASPECT_CONTENT:
235 return MiscStatusContent;
236 case DVASPECT_THUMBNAIL:
237 return MiscStatusThumbnail;
238 case DVASPECT_ICON:
239 return MiscStatusIcon;
240 case DVASPECT_DOCPRINT:
241 return MiscStatusDocPrint;
242 default:
243 return MiscStatus;
247 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
249 ACTCTX_SECTION_KEYED_DATA data;
251 data.cbSize = sizeof(data);
252 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
253 clsid, &data))
255 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
256 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
258 if (!(comclass->miscmask & misc))
260 if (!(comclass->miscmask & MiscStatus))
262 *status = 0;
263 return TRUE;
265 misc = MiscStatus;
268 switch (misc)
270 case MiscStatus:
271 *status = comclass->miscstatus;
272 break;
273 case MiscStatusIcon:
274 *status = comclass->miscstatusicon;
275 break;
276 case MiscStatusContent:
277 *status = comclass->miscstatuscontent;
278 break;
279 case MiscStatusThumbnail:
280 *status = comclass->miscstatusthumbnail;
281 break;
282 case MiscStatusDocPrint:
283 *status = comclass->miscstatusdocprint;
284 break;
285 default:
289 return TRUE;
291 else
292 return FALSE;
295 /* wrapper for NtCreateKey that creates the key recursively if necessary */
296 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
298 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
300 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
302 HANDLE subkey, root = attr->RootDirectory;
303 WCHAR *buffer = attr->ObjectName->Buffer;
304 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
305 UNICODE_STRING str;
307 while (i < len && buffer[i] != '\\') i++;
308 if (i == len) return status;
310 attrs = attr->Attributes;
311 attr->ObjectName = &str;
313 while (i < len)
315 str.Buffer = buffer + pos;
316 str.Length = (i - pos) * sizeof(WCHAR);
317 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
318 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
319 if (status) return status;
320 attr->RootDirectory = subkey;
321 while (i < len && buffer[i] == '\\') i++;
322 pos = i;
323 while (i < len && buffer[i] != '\\') i++;
325 str.Buffer = buffer + pos;
326 str.Length = (i - pos) * sizeof(WCHAR);
327 attr->Attributes = attrs;
328 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
329 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
331 return status;
334 static const WCHAR classes_rootW[] =
335 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
337 static HKEY classes_root_hkey;
339 /* create the special HKEY_CLASSES_ROOT key */
340 static HKEY create_classes_root_hkey(void)
342 HKEY hkey, ret = 0;
343 OBJECT_ATTRIBUTES attr;
344 UNICODE_STRING name;
346 attr.Length = sizeof(attr);
347 attr.RootDirectory = 0;
348 attr.ObjectName = &name;
349 attr.Attributes = 0;
350 attr.SecurityDescriptor = NULL;
351 attr.SecurityQualityOfService = NULL;
352 RtlInitUnicodeString( &name, classes_rootW );
353 if (create_key( &hkey, MAXIMUM_ALLOWED, &attr )) return 0;
354 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
356 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
357 ret = hkey;
358 else
359 NtClose( hkey ); /* somebody beat us to it */
360 return ret;
363 /* map the hkey from special root to normal key if necessary */
364 static inline HKEY get_classes_root_hkey( HKEY hkey )
366 HKEY ret = hkey;
368 if (hkey == HKEY_CLASSES_ROOT && !(ret = classes_root_hkey))
369 ret = create_classes_root_hkey();
371 return ret;
374 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
376 OBJECT_ATTRIBUTES attr;
377 UNICODE_STRING nameW;
379 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
381 attr.Length = sizeof(attr);
382 attr.RootDirectory = hkey;
383 attr.ObjectName = &nameW;
384 attr.Attributes = 0;
385 attr.SecurityDescriptor = NULL;
386 attr.SecurityQualityOfService = NULL;
387 RtlInitUnicodeString( &nameW, name );
389 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
392 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
394 OBJECT_ATTRIBUTES attr;
395 UNICODE_STRING nameW;
397 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
399 attr.Length = sizeof(attr);
400 attr.RootDirectory = hkey;
401 attr.ObjectName = &nameW;
402 attr.Attributes = 0;
403 attr.SecurityDescriptor = NULL;
404 attr.SecurityQualityOfService = NULL;
405 RtlInitUnicodeString( &nameW, name );
407 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
410 /*****************************************************************************
411 * This section contains OpenDllList definitions
413 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
414 * other functions that do LoadLibrary _without_ giving back a HMODULE.
415 * Without this list these handles would never be freed.
417 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
418 * next unload-call but not before 600 sec.
421 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
422 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
424 typedef struct tagOpenDll
426 LONG refs;
427 LPWSTR library_name;
428 HANDLE library;
429 DllGetClassObjectFunc DllGetClassObject;
430 DllCanUnloadNowFunc DllCanUnloadNow;
431 struct list entry;
432 } OpenDll;
434 static struct list openDllList = LIST_INIT(openDllList);
436 static CRITICAL_SECTION csOpenDllList;
437 static CRITICAL_SECTION_DEBUG dll_cs_debug =
439 0, 0, &csOpenDllList,
440 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
441 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
443 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
445 struct apartment_loaded_dll
447 struct list entry;
448 OpenDll *dll;
449 DWORD unload_time;
450 BOOL multi_threaded;
453 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',' ',
454 '0','x','#','#','#','#','#','#','#','#',' ',0};
456 /*****************************************************************************
457 * This section contains OpenDllList implementation
460 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
462 OpenDll *ptr;
463 OpenDll *ret = NULL;
464 EnterCriticalSection(&csOpenDllList);
465 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
467 if (!strcmpiW(library_name, ptr->library_name) &&
468 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
470 ret = ptr;
471 break;
474 LeaveCriticalSection(&csOpenDllList);
475 return ret;
478 /* caller must ensure that library_name is not already in the open dll list */
479 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
481 OpenDll *entry;
482 int len;
483 HRESULT hr = S_OK;
484 HANDLE hLibrary;
485 DllCanUnloadNowFunc DllCanUnloadNow;
486 DllGetClassObjectFunc DllGetClassObject;
488 TRACE("%s\n", debugstr_w(library_name));
490 *ret = COMPOBJ_DllList_Get(library_name);
491 if (*ret) return S_OK;
493 /* do this outside the csOpenDllList to avoid creating a lock dependency on
494 * the loader lock */
495 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
496 if (!hLibrary)
498 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
499 /* failure: DLL could not be loaded */
500 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
503 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
504 /* Note: failing to find DllCanUnloadNow is not a failure */
505 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
506 if (!DllGetClassObject)
508 /* failure: the dll did not export DllGetClassObject */
509 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
510 FreeLibrary(hLibrary);
511 return CO_E_DLLNOTFOUND;
514 EnterCriticalSection( &csOpenDllList );
516 *ret = COMPOBJ_DllList_Get(library_name);
517 if (*ret)
519 /* another caller to this function already added the dll while we
520 * weren't in the critical section */
521 FreeLibrary(hLibrary);
523 else
525 len = strlenW(library_name);
526 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
527 if (entry)
528 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
529 if (entry && entry->library_name)
531 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
532 entry->library = hLibrary;
533 entry->refs = 1;
534 entry->DllCanUnloadNow = DllCanUnloadNow;
535 entry->DllGetClassObject = DllGetClassObject;
536 list_add_tail(&openDllList, &entry->entry);
537 *ret = entry;
539 else
541 HeapFree(GetProcessHeap(), 0, entry);
542 hr = E_OUTOFMEMORY;
543 FreeLibrary(hLibrary);
547 LeaveCriticalSection( &csOpenDllList );
549 return hr;
552 /* pass FALSE for free_entry to release a reference without destroying the
553 * entry if it reaches zero or TRUE otherwise */
554 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
556 if (!InterlockedDecrement(&entry->refs) && free_entry)
558 EnterCriticalSection(&csOpenDllList);
559 list_remove(&entry->entry);
560 LeaveCriticalSection(&csOpenDllList);
562 TRACE("freeing %p\n", entry->library);
563 FreeLibrary(entry->library);
565 HeapFree(GetProcessHeap(), 0, entry->library_name);
566 HeapFree(GetProcessHeap(), 0, entry);
570 /* frees memory associated with active dll list */
571 static void COMPOBJ_DllList_Free(void)
573 OpenDll *entry, *cursor2;
574 EnterCriticalSection(&csOpenDllList);
575 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
577 list_remove(&entry->entry);
579 HeapFree(GetProcessHeap(), 0, entry->library_name);
580 HeapFree(GetProcessHeap(), 0, entry);
582 LeaveCriticalSection(&csOpenDllList);
583 DeleteCriticalSection(&csOpenDllList);
586 /******************************************************************************
587 * Manage apartments.
590 static DWORD apartment_addref(struct apartment *apt)
592 DWORD refs = InterlockedIncrement(&apt->refs);
593 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
594 return refs;
597 /* allocates memory and fills in the necessary fields for a new apartment
598 * object. must be called inside apartment cs */
599 static APARTMENT *apartment_construct(DWORD model)
601 APARTMENT *apt;
603 TRACE("creating new apartment, model=%d\n", model);
605 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
606 apt->tid = GetCurrentThreadId();
608 list_init(&apt->proxies);
609 list_init(&apt->stubmgrs);
610 list_init(&apt->psclsids);
611 list_init(&apt->loaded_dlls);
612 apt->ipidc = 0;
613 apt->refs = 1;
614 apt->remunk_exported = FALSE;
615 apt->oidc = 1;
616 InitializeCriticalSection(&apt->cs);
617 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
619 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
621 if (apt->multi_threaded)
623 /* FIXME: should be randomly generated by in an RPC call to rpcss */
624 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
626 else
628 /* FIXME: should be randomly generated by in an RPC call to rpcss */
629 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
632 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
634 list_add_head(&apts, &apt->entry);
636 return apt;
639 /* gets and existing apartment if one exists or otherwise creates an apartment
640 * structure which stores OLE apartment-local information and stores a pointer
641 * to it in the thread-local storage */
642 static APARTMENT *apartment_get_or_create(DWORD model)
644 APARTMENT *apt = COM_CurrentApt();
646 if (!apt)
648 if (model & COINIT_APARTMENTTHREADED)
650 EnterCriticalSection(&csApartment);
652 apt = apartment_construct(model);
653 if (!MainApartment)
655 MainApartment = apt;
656 apt->main = TRUE;
657 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
660 LeaveCriticalSection(&csApartment);
662 if (apt->main)
663 apartment_createwindowifneeded(apt);
665 else
667 EnterCriticalSection(&csApartment);
669 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
670 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
671 * in a process */
672 if (MTA)
674 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
675 apartment_addref(MTA);
677 else
678 MTA = apartment_construct(model);
680 apt = MTA;
682 LeaveCriticalSection(&csApartment);
684 COM_CurrentInfo()->apt = apt;
687 return apt;
690 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
692 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
695 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
697 list_remove(&curClass->entry);
699 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
700 RPC_StopLocalServer(curClass->RpcRegistration);
702 IUnknown_Release(curClass->classObject);
703 HeapFree(GetProcessHeap(), 0, curClass);
706 static void COM_RevokeAllClasses(const struct apartment *apt)
708 RegisteredClass *curClass, *cursor;
710 EnterCriticalSection( &csRegisteredClassList );
712 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
714 if (curClass->apartment_id == apt->oxid)
715 COM_RevokeRegisteredClassObject(curClass);
718 LeaveCriticalSection( &csRegisteredClassList );
721 /******************************************************************************
722 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
725 typedef struct ManualResetEvent {
726 ISynchronize ISynchronize_iface;
727 ISynchronizeHandle ISynchronizeHandle_iface;
728 LONG ref;
729 HANDLE event;
730 } MREImpl;
732 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
734 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
737 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
739 MREImpl *This = impl_from_ISynchronize(iface);
741 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
743 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
744 *ppv = &This->ISynchronize_iface;
745 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
746 *ppv = &This->ISynchronizeHandle_iface;
747 }else {
748 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
749 *ppv = NULL;
750 return E_NOINTERFACE;
753 IUnknown_AddRef((IUnknown*)*ppv);
754 return S_OK;
757 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
759 MREImpl *This = impl_from_ISynchronize(iface);
760 LONG ref = InterlockedIncrement(&This->ref);
761 TRACE("%p - ref %d\n", This, ref);
763 return ref;
766 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
768 MREImpl *This = impl_from_ISynchronize(iface);
769 LONG ref = InterlockedDecrement(&This->ref);
770 TRACE("%p - ref %d\n", This, ref);
772 if(!ref)
774 CloseHandle(This->event);
775 HeapFree(GetProcessHeap(), 0, This);
778 return ref;
781 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
783 MREImpl *This = impl_from_ISynchronize(iface);
784 UINT index;
785 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
786 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
789 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
791 MREImpl *This = impl_from_ISynchronize(iface);
792 TRACE("%p\n", This);
793 SetEvent(This->event);
794 return S_OK;
797 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
799 MREImpl *This = impl_from_ISynchronize(iface);
800 TRACE("%p\n", This);
801 ResetEvent(This->event);
802 return S_OK;
805 static ISynchronizeVtbl vt_ISynchronize = {
806 ISynchronize_fnQueryInterface,
807 ISynchronize_fnAddRef,
808 ISynchronize_fnRelease,
809 ISynchronize_fnWait,
810 ISynchronize_fnSignal,
811 ISynchronize_fnReset
814 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
816 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
819 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
821 MREImpl *This = impl_from_ISynchronizeHandle(iface);
822 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
825 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
827 MREImpl *This = impl_from_ISynchronizeHandle(iface);
828 return ISynchronize_AddRef(&This->ISynchronize_iface);
831 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
833 MREImpl *This = impl_from_ISynchronizeHandle(iface);
834 return ISynchronize_Release(&This->ISynchronize_iface);
837 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
839 MREImpl *This = impl_from_ISynchronizeHandle(iface);
841 *ph = This->event;
842 return S_OK;
845 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
846 SynchronizeHandle_QueryInterface,
847 SynchronizeHandle_AddRef,
848 SynchronizeHandle_Release,
849 SynchronizeHandle_GetHandle
852 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
854 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
855 HRESULT hr;
857 if(punkouter)
858 FIXME("Aggregation not implemented.\n");
860 This->ref = 1;
861 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
862 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
863 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
865 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
866 ISynchronize_Release(&This->ISynchronize_iface);
867 return hr;
870 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
872 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
875 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
877 LocalServer *This = impl_from_IServiceProvider(iface);
879 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
881 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
882 *ppv = &This->IServiceProvider_iface;
883 }else {
884 *ppv = NULL;
885 return E_NOINTERFACE;
888 IUnknown_AddRef((IUnknown*)*ppv);
889 return S_OK;
892 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
894 LocalServer *This = impl_from_IServiceProvider(iface);
895 LONG ref = InterlockedIncrement(&This->ref);
897 TRACE("(%p) ref=%d\n", This, ref);
899 return ref;
902 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
904 LocalServer *This = impl_from_IServiceProvider(iface);
905 LONG ref = InterlockedDecrement(&This->ref);
907 TRACE("(%p) ref=%d\n", This, ref);
909 if(!ref) {
910 assert(!This->apt);
911 HeapFree(GetProcessHeap(), 0, This);
914 return ref;
917 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
919 LocalServer *This = impl_from_IServiceProvider(iface);
920 APARTMENT *apt = COM_CurrentApt();
921 RegisteredClass *iter;
922 HRESULT hres = E_FAIL;
924 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
926 if(!This->apt)
927 return E_UNEXPECTED;
929 EnterCriticalSection(&csRegisteredClassList);
931 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
932 if(iter->apartment_id == apt->oxid
933 && (iter->runContext & CLSCTX_LOCAL_SERVER)
934 && IsEqualGUID(&iter->classIdentifier, guid)) {
935 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
936 break;
940 LeaveCriticalSection( &csRegisteredClassList );
942 return hres;
945 static const IServiceProviderVtbl LocalServerVtbl = {
946 LocalServer_QueryInterface,
947 LocalServer_AddRef,
948 LocalServer_Release,
949 LocalServer_QueryService
952 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
954 HRESULT hres = S_OK;
956 EnterCriticalSection(&apt->cs);
958 if(!apt->local_server) {
959 LocalServer *obj;
961 obj = heap_alloc(sizeof(*obj));
962 if(obj) {
963 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
964 obj->ref = 1;
965 obj->apt = apt;
967 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
968 if(SUCCEEDED(hres)) {
969 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
970 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
971 if(FAILED(hres))
972 IStream_Release(obj->marshal_stream);
975 if(SUCCEEDED(hres))
976 apt->local_server = obj;
977 else
978 heap_free(obj);
979 }else {
980 hres = E_OUTOFMEMORY;
984 if(SUCCEEDED(hres))
985 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
987 LeaveCriticalSection(&apt->cs);
989 if(FAILED(hres))
990 ERR("Failed: %08x\n", hres);
991 return hres;
994 /***********************************************************************
995 * CoRevokeClassObject [OLE32.@]
997 * Removes a class object from the class registry.
999 * PARAMS
1000 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1002 * RETURNS
1003 * Success: S_OK.
1004 * Failure: HRESULT code.
1006 * NOTES
1007 * Must be called from the same apartment that called CoRegisterClassObject(),
1008 * otherwise it will fail with RPC_E_WRONG_THREAD.
1010 * SEE ALSO
1011 * CoRegisterClassObject
1013 HRESULT WINAPI CoRevokeClassObject(
1014 DWORD dwRegister)
1016 HRESULT hr = E_INVALIDARG;
1017 RegisteredClass *curClass;
1018 APARTMENT *apt;
1020 TRACE("(%08x)\n",dwRegister);
1022 apt = COM_CurrentApt();
1023 if (!apt)
1025 ERR("COM was not initialized\n");
1026 return CO_E_NOTINITIALIZED;
1029 EnterCriticalSection( &csRegisteredClassList );
1031 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1034 * Check if we have a match on the cookie.
1036 if (curClass->dwCookie == dwRegister)
1038 if (curClass->apartment_id == apt->oxid)
1040 COM_RevokeRegisteredClassObject(curClass);
1041 hr = S_OK;
1043 else
1045 ERR("called from wrong apartment, should be called from %s\n",
1046 wine_dbgstr_longlong(curClass->apartment_id));
1047 hr = RPC_E_WRONG_THREAD;
1049 break;
1053 LeaveCriticalSection( &csRegisteredClassList );
1055 return hr;
1058 /* frees unused libraries loaded by apartment_getclassobject by calling the
1059 * DLL's DllCanUnloadNow entry point */
1060 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1062 struct apartment_loaded_dll *entry, *next;
1063 EnterCriticalSection(&apt->cs);
1064 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1066 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1068 DWORD real_delay = delay;
1070 if (real_delay == INFINITE)
1072 /* DLLs that return multi-threaded objects aren't unloaded
1073 * straight away to cope for programs that have races between
1074 * last object destruction and threads in the DLLs that haven't
1075 * finished, despite DllCanUnloadNow returning S_OK */
1076 if (entry->multi_threaded)
1077 real_delay = 10 * 60 * 1000; /* 10 minutes */
1078 else
1079 real_delay = 0;
1082 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1084 list_remove(&entry->entry);
1085 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1086 HeapFree(GetProcessHeap(), 0, entry);
1088 else
1090 entry->unload_time = GetTickCount() + real_delay;
1091 if (!entry->unload_time) entry->unload_time = 1;
1094 else if (entry->unload_time)
1095 entry->unload_time = 0;
1097 LeaveCriticalSection(&apt->cs);
1100 DWORD apartment_release(struct apartment *apt)
1102 DWORD ret;
1104 EnterCriticalSection(&csApartment);
1106 ret = InterlockedDecrement(&apt->refs);
1107 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1108 /* destruction stuff that needs to happen under csApartment CS */
1109 if (ret == 0)
1111 if (apt == MTA) MTA = NULL;
1112 else if (apt == MainApartment) MainApartment = NULL;
1113 list_remove(&apt->entry);
1116 LeaveCriticalSection(&csApartment);
1118 if (ret == 0)
1120 struct list *cursor, *cursor2;
1122 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1124 if(apt->local_server) {
1125 LocalServer *local_server = apt->local_server;
1126 LARGE_INTEGER zero;
1128 memset(&zero, 0, sizeof(zero));
1129 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1130 CoReleaseMarshalData(local_server->marshal_stream);
1131 IStream_Release(local_server->marshal_stream);
1132 local_server->marshal_stream = NULL;
1134 apt->local_server = NULL;
1135 local_server->apt = NULL;
1136 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1139 /* Release the references to the registered class objects */
1140 COM_RevokeAllClasses(apt);
1142 /* no locking is needed for this apartment, because no other thread
1143 * can access it at this point */
1145 apartment_disconnectproxies(apt);
1147 if (apt->win) DestroyWindow(apt->win);
1148 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1150 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1152 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1153 /* release the implicit reference given by the fact that the
1154 * stub has external references (it must do since it is in the
1155 * stub manager list in the apartment and all non-apartment users
1156 * must have a ref on the apartment and so it cannot be destroyed).
1158 stub_manager_int_release(stubmgr);
1161 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
1163 struct registered_psclsid *registered_psclsid =
1164 LIST_ENTRY(cursor, struct registered_psclsid, entry);
1166 list_remove(&registered_psclsid->entry);
1167 HeapFree(GetProcessHeap(), 0, registered_psclsid);
1170 /* if this assert fires, then another thread took a reference to a
1171 * stub manager without taking a reference to the containing
1172 * apartment, which it must do. */
1173 assert(list_empty(&apt->stubmgrs));
1175 if (apt->filter) IMessageFilter_Release(apt->filter);
1177 /* free as many unused libraries as possible... */
1178 apartment_freeunusedlibraries(apt, 0);
1180 /* ... and free the memory for the apartment loaded dll entry and
1181 * release the dll list reference without freeing the library for the
1182 * rest */
1183 while ((cursor = list_head(&apt->loaded_dlls)))
1185 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1186 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1187 list_remove(cursor);
1188 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1191 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1192 DeleteCriticalSection(&apt->cs);
1194 HeapFree(GetProcessHeap(), 0, apt);
1197 return ret;
1200 /* The given OXID must be local to this process:
1202 * The ref parameter is here mostly to ensure people remember that
1203 * they get one, you should normally take a ref for thread safety.
1205 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1207 APARTMENT *result = NULL;
1208 struct list *cursor;
1210 EnterCriticalSection(&csApartment);
1211 LIST_FOR_EACH( cursor, &apts )
1213 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1214 if (apt->oxid == oxid)
1216 result = apt;
1217 if (ref) apartment_addref(result);
1218 break;
1221 LeaveCriticalSection(&csApartment);
1223 return result;
1226 /* gets the apartment which has a given creator thread ID. The caller must
1227 * release the reference from the apartment as soon as the apartment pointer
1228 * is no longer required. */
1229 APARTMENT *apartment_findfromtid(DWORD tid)
1231 APARTMENT *result = NULL;
1232 struct list *cursor;
1234 EnterCriticalSection(&csApartment);
1235 LIST_FOR_EACH( cursor, &apts )
1237 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1238 if (apt->tid == tid)
1240 result = apt;
1241 apartment_addref(result);
1242 break;
1245 LeaveCriticalSection(&csApartment);
1247 return result;
1250 /* gets the main apartment if it exists. The caller must
1251 * release the reference from the apartment as soon as the apartment pointer
1252 * is no longer required. */
1253 static APARTMENT *apartment_findmain(void)
1255 APARTMENT *result;
1257 EnterCriticalSection(&csApartment);
1259 result = MainApartment;
1260 if (result) apartment_addref(result);
1262 LeaveCriticalSection(&csApartment);
1264 return result;
1267 /* gets the multi-threaded apartment if it exists. The caller must
1268 * release the reference from the apartment as soon as the apartment pointer
1269 * is no longer required. */
1270 static APARTMENT *apartment_find_multi_threaded(void)
1272 APARTMENT *result = NULL;
1273 struct list *cursor;
1275 EnterCriticalSection(&csApartment);
1277 LIST_FOR_EACH( cursor, &apts )
1279 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1280 if (apt->multi_threaded)
1282 result = apt;
1283 apartment_addref(result);
1284 break;
1288 LeaveCriticalSection(&csApartment);
1289 return result;
1292 /* gets the specified class object by loading the appropriate DLL, if
1293 * necessary and calls the DllGetClassObject function for the DLL */
1294 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1295 BOOL apartment_threaded,
1296 REFCLSID rclsid, REFIID riid, void **ppv)
1298 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1299 HRESULT hr = S_OK;
1300 BOOL found = FALSE;
1301 struct apartment_loaded_dll *apartment_loaded_dll;
1303 if (!strcmpiW(dllpath, wszOle32))
1305 /* we don't need to control the lifetime of this dll, so use the local
1306 * implementation of DllGetClassObject directly */
1307 TRACE("calling ole32!DllGetClassObject\n");
1308 hr = DllGetClassObject(rclsid, riid, ppv);
1310 if (hr != S_OK)
1311 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1313 return hr;
1316 EnterCriticalSection(&apt->cs);
1318 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1319 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1321 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1322 found = TRUE;
1323 break;
1326 if (!found)
1328 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1329 if (!apartment_loaded_dll)
1330 hr = E_OUTOFMEMORY;
1331 if (SUCCEEDED(hr))
1333 apartment_loaded_dll->unload_time = 0;
1334 apartment_loaded_dll->multi_threaded = FALSE;
1335 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1336 if (FAILED(hr))
1337 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1339 if (SUCCEEDED(hr))
1341 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1342 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1346 LeaveCriticalSection(&apt->cs);
1348 if (SUCCEEDED(hr))
1350 /* one component being multi-threaded overrides any number of
1351 * apartment-threaded components */
1352 if (!apartment_threaded)
1353 apartment_loaded_dll->multi_threaded = TRUE;
1355 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1356 /* OK: get the ClassObject */
1357 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1359 if (hr != S_OK)
1360 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1363 return hr;
1366 /***********************************************************************
1367 * COM_RegReadPath [internal]
1369 * Reads a registry value and expands it when necessary
1371 static DWORD COM_RegReadPath(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1373 DWORD ret;
1375 if (regdata->hkey)
1377 DWORD keytype;
1378 WCHAR src[MAX_PATH];
1379 DWORD dwLength = dstlen * sizeof(WCHAR);
1381 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1382 if (keytype == REG_EXPAND_SZ) {
1383 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1384 } else {
1385 const WCHAR *quote_start;
1386 quote_start = strchrW(src, '\"');
1387 if (quote_start) {
1388 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1389 if (quote_end) {
1390 memmove(src, quote_start + 1,
1391 (quote_end - quote_start - 1) * sizeof(WCHAR));
1392 src[quote_end - quote_start - 1] = '\0';
1395 lstrcpynW(dst, src, dstlen);
1398 return ret;
1400 else
1402 ULONG_PTR cookie;
1403 WCHAR *nameW;
1405 *dst = 0;
1406 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1407 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1408 ret = SearchPathW(NULL, nameW, NULL, dstlen, dst, NULL);
1409 DeactivateActCtx(0, cookie);
1410 return !*dst;
1414 struct host_object_params
1416 struct class_reg_data regdata;
1417 CLSID clsid; /* clsid of object to marshal */
1418 IID iid; /* interface to marshal */
1419 HANDLE event; /* event signalling when ready for multi-threaded case */
1420 HRESULT hr; /* result for multi-threaded case */
1421 IStream *stream; /* stream that the object will be marshaled into */
1422 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1425 static HRESULT apartment_hostobject(struct apartment *apt,
1426 const struct host_object_params *params)
1428 IUnknown *object;
1429 HRESULT hr;
1430 static const LARGE_INTEGER llZero;
1431 WCHAR dllpath[MAX_PATH+1];
1433 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1435 if (COM_RegReadPath(&params->regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1437 /* failure: CLSID is not found in registry */
1438 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1439 return REGDB_E_CLASSNOTREG;
1442 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1443 &params->clsid, &params->iid, (void **)&object);
1444 if (FAILED(hr))
1445 return hr;
1447 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1448 if (FAILED(hr))
1449 IUnknown_Release(object);
1450 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1452 return hr;
1455 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1457 switch (msg)
1459 case DM_EXECUTERPC:
1460 RPC_ExecuteCall((struct dispatch_params *)lParam);
1461 return 0;
1462 case DM_HOSTOBJECT:
1463 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1464 default:
1465 return DefWindowProcW(hWnd, msg, wParam, lParam);
1469 struct host_thread_params
1471 COINIT threading_model;
1472 HANDLE ready_event;
1473 HWND apartment_hwnd;
1476 /* thread for hosting an object to allow an object to appear to be created in
1477 * an apartment with an incompatible threading model */
1478 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1480 struct host_thread_params *params = p;
1481 MSG msg;
1482 HRESULT hr;
1483 struct apartment *apt;
1485 TRACE("\n");
1487 hr = CoInitializeEx(NULL, params->threading_model);
1488 if (FAILED(hr)) return hr;
1490 apt = COM_CurrentApt();
1491 if (params->threading_model == COINIT_APARTMENTTHREADED)
1493 apartment_createwindowifneeded(apt);
1494 params->apartment_hwnd = apartment_getwindow(apt);
1496 else
1497 params->apartment_hwnd = NULL;
1499 /* force the message queue to be created before signaling parent thread */
1500 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1502 SetEvent(params->ready_event);
1503 params = NULL; /* can't touch params after here as it may be invalid */
1505 while (GetMessageW(&msg, NULL, 0, 0))
1507 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1509 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1510 obj_params->hr = apartment_hostobject(apt, obj_params);
1511 SetEvent(obj_params->event);
1513 else
1515 TranslateMessage(&msg);
1516 DispatchMessageW(&msg);
1520 TRACE("exiting\n");
1522 CoUninitialize();
1524 return S_OK;
1527 /* finds or creates a host apartment, creates the object inside it and returns
1528 * a proxy to it so that the object can be used in the apartment of the
1529 * caller of this function */
1530 static HRESULT apartment_hostobject_in_hostapt(
1531 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1532 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1534 struct host_object_params params;
1535 HWND apartment_hwnd = NULL;
1536 DWORD apartment_tid = 0;
1537 HRESULT hr;
1539 if (!multi_threaded && main_apartment)
1541 APARTMENT *host_apt = apartment_findmain();
1542 if (host_apt)
1544 apartment_hwnd = apartment_getwindow(host_apt);
1545 apartment_release(host_apt);
1549 if (!apartment_hwnd)
1551 EnterCriticalSection(&apt->cs);
1553 if (!apt->host_apt_tid)
1555 struct host_thread_params thread_params;
1556 HANDLE handles[2];
1557 DWORD wait_value;
1559 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1560 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1561 thread_params.apartment_hwnd = NULL;
1562 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1563 if (!handles[1])
1565 CloseHandle(handles[0]);
1566 LeaveCriticalSection(&apt->cs);
1567 return E_OUTOFMEMORY;
1569 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1570 CloseHandle(handles[0]);
1571 CloseHandle(handles[1]);
1572 if (wait_value == WAIT_OBJECT_0)
1573 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1574 else
1576 LeaveCriticalSection(&apt->cs);
1577 return E_OUTOFMEMORY;
1581 if (multi_threaded || !main_apartment)
1583 apartment_hwnd = apt->host_apt_hwnd;
1584 apartment_tid = apt->host_apt_tid;
1587 LeaveCriticalSection(&apt->cs);
1590 /* another thread may have become the main apartment in the time it took
1591 * us to create the thread for the host apartment */
1592 if (!apartment_hwnd && !multi_threaded && main_apartment)
1594 APARTMENT *host_apt = apartment_findmain();
1595 if (host_apt)
1597 apartment_hwnd = apartment_getwindow(host_apt);
1598 apartment_release(host_apt);
1602 params.regdata = *regdata;
1603 params.clsid = *rclsid;
1604 params.iid = *riid;
1605 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1606 if (FAILED(hr))
1607 return hr;
1608 params.apartment_threaded = !multi_threaded;
1609 if (multi_threaded)
1611 params.hr = S_OK;
1612 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1613 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1614 hr = E_OUTOFMEMORY;
1615 else
1617 WaitForSingleObject(params.event, INFINITE);
1618 hr = params.hr;
1620 CloseHandle(params.event);
1622 else
1624 if (!apartment_hwnd)
1626 ERR("host apartment didn't create window\n");
1627 hr = E_OUTOFMEMORY;
1629 else
1630 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1632 if (SUCCEEDED(hr))
1633 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1634 IStream_Release(params.stream);
1635 return hr;
1638 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1640 WNDCLASSW wclass;
1642 /* Dispatching to the correct thread in an apartment is done through
1643 * window messages rather than RPC transports. When an interface is
1644 * marshalled into another apartment in the same process, a window of the
1645 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1646 * application) is responsible for pumping the message loop in that thread.
1647 * The WM_USER messages which point to the RPCs are then dispatched to
1648 * apartment_wndproc by the user's code from the apartment in which the
1649 * interface was unmarshalled.
1651 memset(&wclass, 0, sizeof(wclass));
1652 wclass.lpfnWndProc = apartment_wndproc;
1653 wclass.hInstance = hProxyDll;
1654 wclass.lpszClassName = wszAptWinClass;
1655 RegisterClassW(&wclass);
1656 return TRUE;
1659 /* create a window for the apartment or return the current one if one has
1660 * already been created */
1661 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1663 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1665 if (apt->multi_threaded)
1666 return S_OK;
1668 if (!apt->win)
1670 HWND hwnd;
1672 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1674 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1675 HWND_MESSAGE, 0, hProxyDll, NULL);
1676 if (!hwnd)
1678 ERR("CreateWindow failed with error %d\n", GetLastError());
1679 return HRESULT_FROM_WIN32(GetLastError());
1681 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1682 /* someone beat us to it */
1683 DestroyWindow(hwnd);
1686 return S_OK;
1689 /* retrieves the window for the main- or apartment-threaded apartment */
1690 HWND apartment_getwindow(const struct apartment *apt)
1692 assert(!apt->multi_threaded);
1693 return apt->win;
1696 void apartment_joinmta(void)
1698 apartment_addref(MTA);
1699 COM_CurrentInfo()->apt = MTA;
1702 static void COM_TlsDestroy(void)
1704 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1705 if (info)
1707 if (info->apt) apartment_release(info->apt);
1708 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1709 if (info->state) IUnknown_Release(info->state);
1710 if (info->spy) IInitializeSpy_Release(info->spy);
1711 if (info->context_token) IObjContext_Release(info->context_token);
1712 HeapFree(GetProcessHeap(), 0, info);
1713 NtCurrentTeb()->ReservedForOle = NULL;
1717 /******************************************************************************
1718 * CoBuildVersion [OLE32.@]
1720 * Gets the build version of the DLL.
1722 * PARAMS
1724 * RETURNS
1725 * Current build version, hiword is majornumber, loword is minornumber
1727 DWORD WINAPI CoBuildVersion(void)
1729 TRACE("Returning version %d, build %d.\n", rmm, rup);
1730 return (rmm<<16)+rup;
1733 /******************************************************************************
1734 * CoRegisterInitializeSpy [OLE32.@]
1736 * Add a Spy that watches CoInitializeEx calls
1738 * PARAMS
1739 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1740 * cookie [II] cookie receiver
1742 * RETURNS
1743 * Success: S_OK if not already initialized, S_FALSE otherwise.
1744 * Failure: HRESULT code.
1746 * SEE ALSO
1747 * CoInitializeEx
1749 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1751 struct oletls *info = COM_CurrentInfo();
1752 HRESULT hr;
1754 TRACE("(%p, %p)\n", spy, cookie);
1756 if (!spy || !cookie || !info)
1758 if (!info)
1759 WARN("Could not allocate tls\n");
1760 return E_INVALIDARG;
1763 if (info->spy)
1765 FIXME("Already registered?\n");
1766 return E_UNEXPECTED;
1769 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1770 if (SUCCEEDED(hr))
1772 cookie->QuadPart = (DWORD_PTR)spy;
1773 return S_OK;
1775 return hr;
1778 /******************************************************************************
1779 * CoRevokeInitializeSpy [OLE32.@]
1781 * Remove a spy that previously watched CoInitializeEx calls
1783 * PARAMS
1784 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1786 * RETURNS
1787 * Success: S_OK if a spy is removed
1788 * Failure: E_INVALIDARG
1790 * SEE ALSO
1791 * CoInitializeEx
1793 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1795 struct oletls *info = COM_CurrentInfo();
1796 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1798 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1799 return E_INVALIDARG;
1801 IInitializeSpy_Release(info->spy);
1802 info->spy = NULL;
1803 return S_OK;
1807 /******************************************************************************
1808 * CoInitialize [OLE32.@]
1810 * Initializes the COM libraries by calling CoInitializeEx with
1811 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1813 * PARAMS
1814 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1816 * RETURNS
1817 * Success: S_OK if not already initialized, S_FALSE otherwise.
1818 * Failure: HRESULT code.
1820 * SEE ALSO
1821 * CoInitializeEx
1823 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1826 * Just delegate to the newer method.
1828 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1831 /******************************************************************************
1832 * CoInitializeEx [OLE32.@]
1834 * Initializes the COM libraries.
1836 * PARAMS
1837 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1838 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1840 * RETURNS
1841 * S_OK if successful,
1842 * S_FALSE if this function was called already.
1843 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1844 * threading model.
1846 * NOTES
1848 * The behavior used to set the IMalloc used for memory management is
1849 * obsolete.
1850 * The dwCoInit parameter must specify one of the following apartment
1851 * threading models:
1852 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1853 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1854 * The parameter may also specify zero or more of the following flags:
1855 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1856 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1858 * SEE ALSO
1859 * CoUninitialize
1861 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1863 struct oletls *info = COM_CurrentInfo();
1864 HRESULT hr = S_OK;
1865 APARTMENT *apt;
1867 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1869 if (lpReserved!=NULL)
1871 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1875 * Check the lock count. If this is the first time going through the initialize
1876 * process, we have to initialize the libraries.
1878 * And crank-up that lock count.
1880 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1883 * Initialize the various COM libraries and data structures.
1885 TRACE("() - Initializing the COM libraries\n");
1887 /* we may need to defer this until after apartment initialisation */
1888 RunningObjectTableImpl_Initialize();
1891 if (info->spy)
1892 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1894 if (!(apt = info->apt))
1896 apt = apartment_get_or_create(dwCoInit);
1897 if (!apt) return E_OUTOFMEMORY;
1899 else if (!apartment_is_model(apt, dwCoInit))
1901 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1902 code then we are probably using the wrong threading model to implement that API. */
1903 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1904 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1905 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1906 return RPC_E_CHANGED_MODE;
1908 else
1909 hr = S_FALSE;
1911 info->inits++;
1913 if (info->spy)
1914 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1916 return hr;
1919 /***********************************************************************
1920 * CoUninitialize [OLE32.@]
1922 * This method will decrement the refcount on the current apartment, freeing
1923 * the resources associated with it if it is the last thread in the apartment.
1924 * If the last apartment is freed, the function will additionally release
1925 * any COM resources associated with the process.
1927 * PARAMS
1929 * RETURNS
1930 * Nothing.
1932 * SEE ALSO
1933 * CoInitializeEx
1935 void WINAPI CoUninitialize(void)
1937 struct oletls * info = COM_CurrentInfo();
1938 LONG lCOMRefCnt;
1940 TRACE("()\n");
1942 /* will only happen on OOM */
1943 if (!info) return;
1945 if (info->spy)
1946 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1948 /* sanity check */
1949 if (!info->inits)
1951 ERR("Mismatched CoUninitialize\n");
1953 if (info->spy)
1954 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1955 return;
1958 if (!--info->inits)
1960 apartment_release(info->apt);
1961 info->apt = NULL;
1965 * Decrease the reference count.
1966 * If we are back to 0 locks on the COM library, make sure we free
1967 * all the associated data structures.
1969 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1970 if (lCOMRefCnt==1)
1972 TRACE("() - Releasing the COM libraries\n");
1974 RunningObjectTableImpl_UnInitialize();
1976 else if (lCOMRefCnt<1) {
1977 ERR( "CoUninitialize() - not CoInitialized.\n" );
1978 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1980 if (info->spy)
1981 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1984 /******************************************************************************
1985 * CoDisconnectObject [OLE32.@]
1987 * Disconnects all connections to this object from remote processes. Dispatches
1988 * pending RPCs while blocking new RPCs from occurring, and then calls
1989 * IMarshal::DisconnectObject on the given object.
1991 * Typically called when the object server is forced to shut down, for instance by
1992 * the user.
1994 * PARAMS
1995 * lpUnk [I] The object whose stub should be disconnected.
1996 * reserved [I] Reserved. Should be set to 0.
1998 * RETURNS
1999 * Success: S_OK.
2000 * Failure: HRESULT code.
2002 * SEE ALSO
2003 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2005 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2007 HRESULT hr;
2008 IMarshal *marshal;
2009 APARTMENT *apt;
2011 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2013 if (!lpUnk) return E_INVALIDARG;
2015 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2016 if (hr == S_OK)
2018 hr = IMarshal_DisconnectObject(marshal, reserved);
2019 IMarshal_Release(marshal);
2020 return hr;
2023 apt = COM_CurrentApt();
2024 if (!apt)
2025 return CO_E_NOTINITIALIZED;
2027 apartment_disconnectobject(apt, lpUnk);
2029 /* Note: native is pretty broken here because it just silently
2030 * fails, without returning an appropriate error code if the object was
2031 * not found, making apps think that the object was disconnected, when
2032 * it actually wasn't */
2034 return S_OK;
2037 /******************************************************************************
2038 * CoCreateGuid [OLE32.@]
2040 * Simply forwards to UuidCreate in RPCRT4.
2042 * PARAMS
2043 * pguid [O] Points to the GUID to initialize.
2045 * RETURNS
2046 * Success: S_OK.
2047 * Failure: HRESULT code.
2049 * SEE ALSO
2050 * UuidCreate
2052 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2054 DWORD status;
2056 if(!pguid) return E_INVALIDARG;
2058 status = UuidCreate(pguid);
2059 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2060 return HRESULT_FROM_WIN32( status );
2063 static inline BOOL is_valid_hex(WCHAR c)
2065 if (!(((c >= '0') && (c <= '9')) ||
2066 ((c >= 'a') && (c <= 'f')) ||
2067 ((c >= 'A') && (c <= 'F'))))
2068 return FALSE;
2069 return TRUE;
2072 static const BYTE guid_conv_table[256] =
2074 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2075 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2076 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2077 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2078 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2079 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2080 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2083 /* conversion helper for CLSIDFromString/IIDFromString */
2084 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2086 int i;
2088 if (!s || s[0]!='{') {
2089 memset( id, 0, sizeof (CLSID) );
2090 if(!s) return TRUE;
2091 return FALSE;
2094 TRACE("%s -> %p\n", debugstr_w(s), id);
2096 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2098 id->Data1 = 0;
2099 for (i = 1; i < 9; i++) {
2100 if (!is_valid_hex(s[i])) return FALSE;
2101 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2103 if (s[9]!='-') return FALSE;
2105 id->Data2 = 0;
2106 for (i = 10; i < 14; i++) {
2107 if (!is_valid_hex(s[i])) return FALSE;
2108 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2110 if (s[14]!='-') return FALSE;
2112 id->Data3 = 0;
2113 for (i = 15; i < 19; i++) {
2114 if (!is_valid_hex(s[i])) return FALSE;
2115 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2117 if (s[19]!='-') return FALSE;
2119 for (i = 20; i < 37; i+=2) {
2120 if (i == 24) {
2121 if (s[i]!='-') return FALSE;
2122 i++;
2124 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2125 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2128 if (s[37] == '}' && s[38] == '\0')
2129 return TRUE;
2131 return FALSE;
2134 /*****************************************************************************/
2136 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2138 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2139 WCHAR buf2[CHARS_IN_GUID];
2140 LONG buf2len = sizeof(buf2);
2141 HKEY xhkey;
2142 WCHAR *buf;
2144 memset(clsid, 0, sizeof(*clsid));
2145 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2146 if (!buf) return E_OUTOFMEMORY;
2147 strcpyW( buf, progid );
2148 strcatW( buf, clsidW );
2149 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2151 HeapFree(GetProcessHeap(),0,buf);
2152 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2153 return CO_E_CLASSSTRING;
2155 HeapFree(GetProcessHeap(),0,buf);
2157 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2159 RegCloseKey(xhkey);
2160 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2161 return CO_E_CLASSSTRING;
2163 RegCloseKey(xhkey);
2164 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2167 /******************************************************************************
2168 * CLSIDFromString [OLE32.@]
2170 * Converts a unique identifier from its string representation into
2171 * the GUID struct.
2173 * PARAMS
2174 * idstr [I] The string representation of the GUID.
2175 * id [O] GUID converted from the string.
2177 * RETURNS
2178 * S_OK on success
2179 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2181 * SEE ALSO
2182 * StringFromCLSID
2184 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2186 HRESULT ret = CO_E_CLASSSTRING;
2187 CLSID tmp_id;
2189 if (!id)
2190 return E_INVALIDARG;
2192 if (guid_from_string(idstr, id))
2193 return S_OK;
2195 /* It appears a ProgID is also valid */
2196 ret = clsid_from_string_reg(idstr, &tmp_id);
2197 if(SUCCEEDED(ret))
2198 *id = tmp_id;
2200 return ret;
2203 /******************************************************************************
2204 * IIDFromString [OLE32.@]
2206 * Converts a interface identifier from its string representation into
2207 * the IID struct.
2209 * PARAMS
2210 * idstr [I] The string representation of the GUID.
2211 * id [O] IID converted from the string.
2213 * RETURNS
2214 * S_OK on success
2215 * CO_E_IIDSTRING if idstr is not a valid IID
2217 * SEE ALSO
2218 * StringFromIID
2220 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2222 TRACE("%s -> %p\n", debugstr_w(s), iid);
2224 if (!s)
2226 memset(iid, 0, sizeof(*iid));
2227 return S_OK;
2230 /* length mismatch is a special case */
2231 if (strlenW(s) + 1 != CHARS_IN_GUID)
2232 return E_INVALIDARG;
2234 if (s[0] != '{')
2235 return CO_E_IIDSTRING;
2237 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2240 /******************************************************************************
2241 * StringFromCLSID [OLE32.@]
2242 * StringFromIID [OLE32.@]
2244 * Converts a GUID into the respective string representation.
2245 * The target string is allocated using the OLE IMalloc.
2247 * PARAMS
2248 * id [I] the GUID to be converted.
2249 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2251 * RETURNS
2252 * S_OK
2253 * E_FAIL
2255 * SEE ALSO
2256 * StringFromGUID2, CLSIDFromString
2258 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2260 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2261 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2262 return S_OK;
2265 /******************************************************************************
2266 * StringFromGUID2 [OLE32.@]
2268 * Modified version of StringFromCLSID that allows you to specify max
2269 * buffer size.
2271 * PARAMS
2272 * id [I] GUID to convert to string.
2273 * str [O] Buffer where the result will be stored.
2274 * cmax [I] Size of the buffer in characters.
2276 * RETURNS
2277 * Success: The length of the resulting string in characters.
2278 * Failure: 0.
2280 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2282 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2283 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2284 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2285 '%','0','2','X','%','0','2','X','}',0 };
2286 if (!id || cmax < CHARS_IN_GUID) return 0;
2287 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2288 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2289 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2290 return CHARS_IN_GUID;
2293 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2294 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2296 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2297 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2298 LONG res;
2299 HKEY key;
2301 strcpyW(path, wszCLSIDSlash);
2302 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2303 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2304 if (res == ERROR_FILE_NOT_FOUND)
2305 return REGDB_E_CLASSNOTREG;
2306 else if (res != ERROR_SUCCESS)
2307 return REGDB_E_READREGDB;
2309 if (!keyname)
2311 *subkey = key;
2312 return S_OK;
2315 res = open_classes_key(key, keyname, access, subkey);
2316 RegCloseKey(key);
2317 if (res == ERROR_FILE_NOT_FOUND)
2318 return REGDB_E_KEYMISSING;
2319 else if (res != ERROR_SUCCESS)
2320 return REGDB_E_READREGDB;
2322 return S_OK;
2325 /* open HKCR\\AppId\\{string form of appid clsid} key */
2326 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2328 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2329 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2330 DWORD res;
2331 WCHAR buf[CHARS_IN_GUID];
2332 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2333 DWORD size;
2334 HKEY hkey;
2335 DWORD type;
2336 HRESULT hr;
2338 /* read the AppID value under the class's key */
2339 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2340 if (FAILED(hr))
2341 return hr;
2343 size = sizeof(buf);
2344 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2345 RegCloseKey(hkey);
2346 if (res == ERROR_FILE_NOT_FOUND)
2347 return REGDB_E_KEYMISSING;
2348 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2349 return REGDB_E_READREGDB;
2351 strcpyW(keyname, szAppIdKey);
2352 strcatW(keyname, buf);
2353 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2354 if (res == ERROR_FILE_NOT_FOUND)
2355 return REGDB_E_KEYMISSING;
2356 else if (res != ERROR_SUCCESS)
2357 return REGDB_E_READREGDB;
2359 return S_OK;
2362 /******************************************************************************
2363 * ProgIDFromCLSID [OLE32.@]
2365 * Converts a class id into the respective program ID.
2367 * PARAMS
2368 * clsid [I] Class ID, as found in registry.
2369 * ppszProgID [O] Associated ProgID.
2371 * RETURNS
2372 * S_OK
2373 * E_OUTOFMEMORY
2374 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2376 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2378 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2379 ACTCTX_SECTION_KEYED_DATA data;
2380 HKEY hkey;
2381 HRESULT ret;
2382 LONG progidlen = 0;
2384 if (!ppszProgID)
2385 return E_INVALIDARG;
2387 *ppszProgID = NULL;
2389 data.cbSize = sizeof(data);
2390 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2391 clsid, &data))
2393 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2394 if (comclass->progid_len)
2396 WCHAR *ptrW;
2398 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2399 if (!*ppszProgID) return E_OUTOFMEMORY;
2401 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2402 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2403 return S_OK;
2405 else
2406 return REGDB_E_CLASSNOTREG;
2409 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2410 if (FAILED(ret))
2411 return ret;
2413 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2414 ret = REGDB_E_CLASSNOTREG;
2416 if (ret == S_OK)
2418 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2419 if (*ppszProgID)
2421 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2422 ret = REGDB_E_CLASSNOTREG;
2423 CoTaskMemFree(*ppszProgID);
2424 *ppszProgID = NULL;
2427 else
2428 ret = E_OUTOFMEMORY;
2431 RegCloseKey(hkey);
2432 return ret;
2435 /******************************************************************************
2436 * CLSIDFromProgID [OLE32.@]
2438 * Converts a program id into the respective GUID.
2440 * PARAMS
2441 * progid [I] Unicode program ID, as found in registry.
2442 * clsid [O] Associated CLSID.
2444 * RETURNS
2445 * Success: S_OK
2446 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2448 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2450 ACTCTX_SECTION_KEYED_DATA data;
2452 if (!progid || !clsid)
2453 return E_INVALIDARG;
2455 data.cbSize = sizeof(data);
2456 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2457 progid, &data))
2459 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2460 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2461 *clsid = *alias;
2462 return S_OK;
2465 return clsid_from_string_reg(progid, clsid);
2468 /******************************************************************************
2469 * CLSIDFromProgIDEx [OLE32.@]
2471 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2473 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2475 return CLSIDFromProgID(progid, clsid);
2478 /*****************************************************************************
2479 * CoGetPSClsid [OLE32.@]
2481 * Retrieves the CLSID of the proxy/stub factory that implements
2482 * IPSFactoryBuffer for the specified interface.
2484 * PARAMS
2485 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2486 * pclsid [O] Where to store returned proxy/stub CLSID.
2488 * RETURNS
2489 * S_OK
2490 * E_OUTOFMEMORY
2491 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2493 * NOTES
2495 * The standard marshaller activates the object with the CLSID
2496 * returned and uses the CreateProxy and CreateStub methods on its
2497 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2498 * given object.
2500 * CoGetPSClsid determines this CLSID by searching the
2501 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2502 * in the registry and any interface id registered by
2503 * CoRegisterPSClsid within the current process.
2505 * BUGS
2507 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2508 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2509 * considered a bug in native unless an application depends on this (unlikely).
2511 * SEE ALSO
2512 * CoRegisterPSClsid.
2514 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2516 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2517 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2518 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2519 WCHAR value[CHARS_IN_GUID];
2520 LONG len;
2521 HKEY hkey;
2522 APARTMENT *apt = COM_CurrentApt();
2523 struct registered_psclsid *registered_psclsid;
2524 ACTCTX_SECTION_KEYED_DATA data;
2526 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2528 if (!apt)
2530 ERR("apartment not initialised\n");
2531 return CO_E_NOTINITIALIZED;
2534 if (!pclsid)
2535 return E_INVALIDARG;
2537 EnterCriticalSection(&apt->cs);
2539 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2540 if (IsEqualIID(&registered_psclsid->iid, riid))
2542 *pclsid = registered_psclsid->clsid;
2543 LeaveCriticalSection(&apt->cs);
2544 return S_OK;
2547 LeaveCriticalSection(&apt->cs);
2549 data.cbSize = sizeof(data);
2550 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2551 riid, &data))
2553 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2554 *pclsid = ifaceps->iid;
2555 return S_OK;
2558 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2559 strcpyW(path, wszInterface);
2560 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2561 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2563 /* Open the key.. */
2564 if (open_classes_key(HKEY_CLASSES_ROOT, path, KEY_READ, &hkey))
2566 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2567 return REGDB_E_IIDNOTREG;
2570 /* ... Once we have the key, query the registry to get the
2571 value of CLSID as a string, and convert it into a
2572 proper CLSID structure to be passed back to the app */
2573 len = sizeof(value);
2574 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
2576 RegCloseKey(hkey);
2577 return REGDB_E_IIDNOTREG;
2579 RegCloseKey(hkey);
2581 /* We have the CLSID we want back from the registry as a string, so
2582 let's convert it into a CLSID structure */
2583 if (CLSIDFromString(value, pclsid) != NOERROR)
2584 return REGDB_E_IIDNOTREG;
2586 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2587 return S_OK;
2590 /*****************************************************************************
2591 * CoRegisterPSClsid [OLE32.@]
2593 * Register a proxy/stub CLSID for the given interface in the current process
2594 * only.
2596 * PARAMS
2597 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2598 * rclsid [I] CLSID of the proxy/stub.
2600 * RETURNS
2601 * Success: S_OK
2602 * Failure: E_OUTOFMEMORY
2604 * NOTES
2606 * This function does not add anything to the registry and the effects are
2607 * limited to the lifetime of the current process.
2609 * SEE ALSO
2610 * CoGetPSClsid.
2612 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2614 APARTMENT *apt = COM_CurrentApt();
2615 struct registered_psclsid *registered_psclsid;
2617 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2619 if (!apt)
2621 ERR("apartment not initialised\n");
2622 return CO_E_NOTINITIALIZED;
2625 EnterCriticalSection(&apt->cs);
2627 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2628 if (IsEqualIID(&registered_psclsid->iid, riid))
2630 registered_psclsid->clsid = *rclsid;
2631 LeaveCriticalSection(&apt->cs);
2632 return S_OK;
2635 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2636 if (!registered_psclsid)
2638 LeaveCriticalSection(&apt->cs);
2639 return E_OUTOFMEMORY;
2642 registered_psclsid->iid = *riid;
2643 registered_psclsid->clsid = *rclsid;
2644 list_add_head(&apt->psclsids, &registered_psclsid->entry);
2646 LeaveCriticalSection(&apt->cs);
2648 return S_OK;
2652 /***
2653 * COM_GetRegisteredClassObject
2655 * This internal method is used to scan the registered class list to
2656 * find a class object.
2658 * Params:
2659 * rclsid Class ID of the class to find.
2660 * dwClsContext Class context to match.
2661 * ppv [out] returns a pointer to the class object. Complying
2662 * to normal COM usage, this method will increase the
2663 * reference count on this object.
2665 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2666 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2668 HRESULT hr = S_FALSE;
2669 RegisteredClass *curClass;
2671 EnterCriticalSection( &csRegisteredClassList );
2673 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2676 * Check if we have a match on the class ID and context.
2678 if ((apt->oxid == curClass->apartment_id) &&
2679 (dwClsContext & curClass->runContext) &&
2680 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2683 * We have a match, return the pointer to the class object.
2685 *ppUnk = curClass->classObject;
2687 IUnknown_AddRef(curClass->classObject);
2689 hr = S_OK;
2690 break;
2694 LeaveCriticalSection( &csRegisteredClassList );
2696 return hr;
2699 /******************************************************************************
2700 * CoRegisterClassObject [OLE32.@]
2702 * Registers the class object for a given class ID. Servers housed in EXE
2703 * files use this method instead of exporting DllGetClassObject to allow
2704 * other code to connect to their objects.
2706 * PARAMS
2707 * rclsid [I] CLSID of the object to register.
2708 * pUnk [I] IUnknown of the object.
2709 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2710 * flags [I] REGCLS flags indicating how connections are made.
2711 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2713 * RETURNS
2714 * S_OK on success,
2715 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2716 * CO_E_OBJISREG if the object is already registered. We should not return this.
2718 * SEE ALSO
2719 * CoRevokeClassObject, CoGetClassObject
2721 * NOTES
2722 * In-process objects are only registered for the current apartment.
2723 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2724 * in other apartments.
2726 * BUGS
2727 * MSDN claims that multiple interface registrations are legal, but we
2728 * can't do that with our current implementation.
2730 HRESULT WINAPI CoRegisterClassObject(
2731 REFCLSID rclsid,
2732 LPUNKNOWN pUnk,
2733 DWORD dwClsContext,
2734 DWORD flags,
2735 LPDWORD lpdwRegister)
2737 static LONG next_cookie;
2738 RegisteredClass* newClass;
2739 LPUNKNOWN foundObject;
2740 HRESULT hr;
2741 APARTMENT *apt;
2743 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2744 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2746 if ( (lpdwRegister==0) || (pUnk==0) )
2747 return E_INVALIDARG;
2749 apt = COM_CurrentApt();
2750 if (!apt)
2752 ERR("COM was not initialized\n");
2753 return CO_E_NOTINITIALIZED;
2756 *lpdwRegister = 0;
2758 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2759 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2760 if (flags & REGCLS_MULTIPLEUSE)
2761 dwClsContext |= CLSCTX_INPROC_SERVER;
2764 * First, check if the class is already registered.
2765 * If it is, this should cause an error.
2767 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2768 if (hr == S_OK) {
2769 if (flags & REGCLS_MULTIPLEUSE) {
2770 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2771 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2772 IUnknown_Release(foundObject);
2773 return hr;
2775 IUnknown_Release(foundObject);
2776 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2777 return CO_E_OBJISREG;
2780 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2781 if ( newClass == NULL )
2782 return E_OUTOFMEMORY;
2784 newClass->classIdentifier = *rclsid;
2785 newClass->apartment_id = apt->oxid;
2786 newClass->runContext = dwClsContext;
2787 newClass->connectFlags = flags;
2788 newClass->RpcRegistration = NULL;
2790 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2791 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2794 * Since we're making a copy of the object pointer, we have to increase its
2795 * reference count.
2797 newClass->classObject = pUnk;
2798 IUnknown_AddRef(newClass->classObject);
2800 EnterCriticalSection( &csRegisteredClassList );
2801 list_add_tail(&RegisteredClassList, &newClass->entry);
2802 LeaveCriticalSection( &csRegisteredClassList );
2804 *lpdwRegister = newClass->dwCookie;
2806 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2807 IStream *marshal_stream;
2809 hr = get_local_server_stream(apt, &marshal_stream);
2810 if(FAILED(hr))
2811 return hr;
2813 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2814 marshal_stream,
2815 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2816 &newClass->RpcRegistration);
2817 IStream_Release(marshal_stream);
2819 return S_OK;
2822 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2824 if (data->hkey)
2826 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2827 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2828 static const WCHAR wszFree[] = {'F','r','e','e',0};
2829 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2830 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2831 DWORD dwLength = sizeof(threading_model);
2832 DWORD keytype;
2833 DWORD ret;
2835 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2836 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2837 threading_model[0] = '\0';
2839 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2840 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2841 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2843 /* there's not specific handling for this case */
2844 if (threading_model[0]) return ThreadingModel_Neutral;
2845 return ThreadingModel_No;
2847 else
2848 return data->u.actctx.data->model;
2851 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2852 REFCLSID rclsid, REFIID riid,
2853 BOOL hostifnecessary, void **ppv)
2855 WCHAR dllpath[MAX_PATH+1];
2856 BOOL apartment_threaded;
2858 if (hostifnecessary)
2860 enum comclass_threadingmodel model = get_threading_model(regdata);
2862 if (model == ThreadingModel_Apartment)
2864 apartment_threaded = TRUE;
2865 if (apt->multi_threaded)
2866 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2868 else if (model == ThreadingModel_Free)
2870 apartment_threaded = FALSE;
2871 if (!apt->multi_threaded)
2872 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2874 /* everything except "Apartment", "Free" and "Both" */
2875 else if (model != ThreadingModel_Both)
2877 apartment_threaded = TRUE;
2878 /* everything else is main-threaded */
2879 if (model != ThreadingModel_No)
2880 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2882 if (apt->multi_threaded || !apt->main)
2883 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2885 else
2886 apartment_threaded = FALSE;
2888 else
2889 apartment_threaded = !apt->multi_threaded;
2891 if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2893 /* failure: CLSID is not found in registry */
2894 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2895 return REGDB_E_CLASSNOTREG;
2898 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2899 rclsid, riid, ppv);
2902 /***********************************************************************
2903 * CoGetClassObject [OLE32.@]
2905 * Creates an object of the specified class.
2907 * PARAMS
2908 * rclsid [I] Class ID to create an instance of.
2909 * dwClsContext [I] Flags to restrict the location of the created instance.
2910 * pServerInfo [I] Optional. Details for connecting to a remote server.
2911 * iid [I] The ID of the interface of the instance to return.
2912 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2914 * RETURNS
2915 * Success: S_OK
2916 * Failure: HRESULT code.
2918 * NOTES
2919 * The dwClsContext parameter can be one or more of the following:
2920 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2921 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2922 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2923 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2925 * SEE ALSO
2926 * CoCreateInstance()
2928 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2929 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2930 REFIID iid, LPVOID *ppv)
2932 struct class_reg_data clsreg;
2933 IUnknown *regClassObject;
2934 HRESULT hres = E_UNEXPECTED;
2935 APARTMENT *apt;
2936 BOOL release_apt = FALSE;
2938 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2940 if (!ppv)
2941 return E_INVALIDARG;
2943 *ppv = NULL;
2945 if (!(apt = COM_CurrentApt()))
2947 if (!(apt = apartment_find_multi_threaded()))
2949 ERR("apartment not initialised\n");
2950 return CO_E_NOTINITIALIZED;
2952 release_apt = TRUE;
2955 if (pServerInfo) {
2956 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2957 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2960 if (CLSCTX_INPROC_SERVER & dwClsContext)
2962 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2964 if (release_apt) apartment_release(apt);
2965 return FTMarshalCF_Create(iid, ppv);
2969 if (CLSCTX_INPROC & dwClsContext)
2971 ACTCTX_SECTION_KEYED_DATA data;
2973 data.cbSize = sizeof(data);
2974 /* search activation context first */
2975 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2976 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2977 rclsid, &data))
2979 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2981 clsreg.u.actctx.hactctx = data.hActCtx;
2982 clsreg.u.actctx.data = data.lpData;
2983 clsreg.u.actctx.section = data.lpSectionBase;
2984 clsreg.hkey = FALSE;
2986 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2987 ReleaseActCtx(data.hActCtx);
2988 if (release_apt) apartment_release(apt);
2989 return hres;
2994 * First, try and see if we can't match the class ID with one of the
2995 * registered classes.
2997 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2998 &regClassObject))
3000 /* Get the required interface from the retrieved pointer. */
3001 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3004 * Since QI got another reference on the pointer, we want to release the
3005 * one we already have. If QI was unsuccessful, this will release the object. This
3006 * is good since we are not returning it in the "out" parameter.
3008 IUnknown_Release(regClassObject);
3009 if (release_apt) apartment_release(apt);
3010 return hres;
3013 /* First try in-process server */
3014 if (CLSCTX_INPROC_SERVER & dwClsContext)
3016 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3017 HKEY hkey;
3019 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3020 if (FAILED(hres))
3022 if (hres == REGDB_E_CLASSNOTREG)
3023 ERR("class %s not registered\n", debugstr_guid(rclsid));
3024 else if (hres == REGDB_E_KEYMISSING)
3026 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3027 hres = REGDB_E_CLASSNOTREG;
3031 if (SUCCEEDED(hres))
3033 clsreg.u.hkey = hkey;
3034 clsreg.hkey = TRUE;
3036 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3037 RegCloseKey(hkey);
3040 /* return if we got a class, otherwise fall through to one of the
3041 * other types */
3042 if (SUCCEEDED(hres))
3044 if (release_apt) apartment_release(apt);
3045 return hres;
3049 /* Next try in-process handler */
3050 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3052 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3053 HKEY hkey;
3055 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3056 if (FAILED(hres))
3058 if (hres == REGDB_E_CLASSNOTREG)
3059 ERR("class %s not registered\n", debugstr_guid(rclsid));
3060 else if (hres == REGDB_E_KEYMISSING)
3062 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3063 hres = REGDB_E_CLASSNOTREG;
3067 if (SUCCEEDED(hres))
3069 clsreg.u.hkey = hkey;
3070 clsreg.hkey = TRUE;
3072 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3073 RegCloseKey(hkey);
3076 /* return if we got a class, otherwise fall through to one of the
3077 * other types */
3078 if (SUCCEEDED(hres))
3080 if (release_apt) apartment_release(apt);
3081 return hres;
3084 if (release_apt) apartment_release(apt);
3086 /* Next try out of process */
3087 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3089 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3090 if (SUCCEEDED(hres))
3091 return hres;
3094 /* Finally try remote: this requires networked DCOM (a lot of work) */
3095 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3097 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3098 hres = REGDB_E_CLASSNOTREG;
3101 if (FAILED(hres))
3102 ERR("no class object %s could be created for context 0x%x\n",
3103 debugstr_guid(rclsid), dwClsContext);
3104 return hres;
3107 /***********************************************************************
3108 * CoResumeClassObjects (OLE32.@)
3110 * Resumes all class objects registered with REGCLS_SUSPENDED.
3112 * RETURNS
3113 * Success: S_OK.
3114 * Failure: HRESULT code.
3116 HRESULT WINAPI CoResumeClassObjects(void)
3118 FIXME("stub\n");
3119 return S_OK;
3122 /***********************************************************************
3123 * CoCreateInstance [OLE32.@]
3125 * Creates an instance of the specified class.
3127 * PARAMS
3128 * rclsid [I] Class ID to create an instance of.
3129 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3130 * dwClsContext [I] Flags to restrict the location of the created instance.
3131 * iid [I] The ID of the interface of the instance to return.
3132 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3134 * RETURNS
3135 * Success: S_OK
3136 * Failure: HRESULT code.
3138 * NOTES
3139 * The dwClsContext parameter can be one or more of the following:
3140 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3141 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3142 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3143 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3145 * Aggregation is the concept of deferring the IUnknown of an object to another
3146 * object. This allows a separate object to behave as though it was part of
3147 * the object and to allow this the pUnkOuter parameter can be set. Note that
3148 * not all objects support having an outer of unknown.
3150 * SEE ALSO
3151 * CoGetClassObject()
3153 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3154 REFCLSID rclsid,
3155 LPUNKNOWN pUnkOuter,
3156 DWORD dwClsContext,
3157 REFIID iid,
3158 LPVOID *ppv)
3160 HRESULT hres;
3161 LPCLASSFACTORY lpclf = 0;
3162 APARTMENT *apt;
3163 CLSID clsid;
3165 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3166 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3168 if (ppv==0)
3169 return E_POINTER;
3171 hres = CoGetTreatAsClass(rclsid, &clsid);
3172 if(FAILED(hres))
3173 clsid = *rclsid;
3175 *ppv = 0;
3177 if (!(apt = COM_CurrentApt()))
3179 if (!(apt = apartment_find_multi_threaded()))
3181 ERR("apartment not initialised\n");
3182 return CO_E_NOTINITIALIZED;
3184 apartment_release(apt);
3188 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3190 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3192 IGlobalInterfaceTable *git = get_std_git();
3193 hres = IGlobalInterfaceTable_QueryInterface(git, iid, ppv);
3194 if (hres != S_OK) return hres;
3196 TRACE("Retrieved GIT (%p)\n", *ppv);
3197 return S_OK;
3200 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent))
3201 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
3204 * Get a class factory to construct the object we want.
3206 hres = CoGetClassObject(&clsid,
3207 dwClsContext,
3208 NULL,
3209 &IID_IClassFactory,
3210 (LPVOID)&lpclf);
3212 if (FAILED(hres))
3213 return hres;
3216 * Create the object and don't forget to release the factory
3218 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
3219 IClassFactory_Release(lpclf);
3220 if (FAILED(hres))
3222 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3223 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3224 else
3225 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3226 debugstr_guid(iid),
3227 debugstr_guid(&clsid),hres);
3230 return hres;
3233 static void init_multi_qi(DWORD count, MULTI_QI *mqi)
3235 ULONG i;
3237 for (i = 0; i < count; i++)
3239 mqi[i].pItf = NULL;
3240 mqi[i].hr = E_NOINTERFACE;
3244 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi)
3246 ULONG index, fetched = 0;
3248 for (index = 0; index < count; index++)
3250 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3251 if (mqi[index].hr == S_OK)
3252 fetched++;
3255 IUnknown_Release(unk);
3257 if (fetched == 0)
3258 return E_NOINTERFACE;
3260 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3263 /***********************************************************************
3264 * CoCreateInstanceEx [OLE32.@]
3266 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3267 REFCLSID rclsid,
3268 LPUNKNOWN pUnkOuter,
3269 DWORD dwClsContext,
3270 COSERVERINFO* pServerInfo,
3271 ULONG cmq,
3272 MULTI_QI* pResults)
3274 IUnknown* pUnk = NULL;
3275 HRESULT hr;
3278 * Sanity check
3280 if ( (cmq==0) || (pResults==NULL))
3281 return E_INVALIDARG;
3283 if (pServerInfo!=NULL)
3284 FIXME("() non-NULL pServerInfo not supported!\n");
3286 init_multi_qi(cmq, pResults);
3289 * Get the object and get its IUnknown pointer.
3291 hr = CoCreateInstance(rclsid,
3292 pUnkOuter,
3293 dwClsContext,
3294 &IID_IUnknown,
3295 (VOID**)&pUnk);
3297 if (hr != S_OK)
3298 return hr;
3300 return return_multi_qi(pUnk, cmq, pResults);
3303 /***********************************************************************
3304 * CoGetInstanceFromFile [OLE32.@]
3306 HRESULT WINAPI CoGetInstanceFromFile(
3307 COSERVERINFO *server_info,
3308 CLSID *rclsid,
3309 IUnknown *outer,
3310 DWORD cls_context,
3311 DWORD grfmode,
3312 OLECHAR *filename,
3313 DWORD count,
3314 MULTI_QI *results
3317 IPersistFile *pf = NULL;
3318 IUnknown* unk = NULL;
3319 CLSID clsid;
3320 HRESULT hr;
3322 if (count == 0 || !results)
3323 return E_INVALIDARG;
3325 if (server_info)
3326 FIXME("() non-NULL server_info not supported\n");
3328 init_multi_qi(count, results);
3330 /* optionally get CLSID from a file */
3331 if (!rclsid)
3333 hr = GetClassFile(filename, &clsid);
3334 if (FAILED(hr))
3336 ERR("failed to get CLSID from a file\n");
3337 return hr;
3340 rclsid = &clsid;
3343 hr = CoCreateInstance(rclsid,
3344 outer,
3345 cls_context,
3346 &IID_IUnknown,
3347 (void**)&unk);
3349 if (hr != S_OK)
3350 return hr;
3352 /* init from file */
3353 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3354 if (FAILED(hr))
3355 ERR("failed to get IPersistFile\n");
3357 if (pf)
3359 IPersistFile_Load(pf, filename, grfmode);
3360 IPersistFile_Release(pf);
3363 return return_multi_qi(unk, count, results);
3366 /***********************************************************************
3367 * CoGetInstanceFromIStorage [OLE32.@]
3369 HRESULT WINAPI CoGetInstanceFromIStorage(
3370 COSERVERINFO *server_info,
3371 CLSID *rclsid,
3372 IUnknown *outer,
3373 DWORD cls_context,
3374 IStorage *storage,
3375 DWORD count,
3376 MULTI_QI *results
3379 IPersistStorage *ps = NULL;
3380 IUnknown* unk = NULL;
3381 STATSTG stat;
3382 HRESULT hr;
3384 if (count == 0 || !results || !storage)
3385 return E_INVALIDARG;
3387 if (server_info)
3388 FIXME("() non-NULL server_info not supported\n");
3390 init_multi_qi(count, results);
3392 /* optionally get CLSID from a file */
3393 if (!rclsid)
3395 memset(&stat.clsid, 0, sizeof(stat.clsid));
3396 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3397 if (FAILED(hr))
3399 ERR("failed to get CLSID from a file\n");
3400 return hr;
3403 rclsid = &stat.clsid;
3406 hr = CoCreateInstance(rclsid,
3407 outer,
3408 cls_context,
3409 &IID_IUnknown,
3410 (void**)&unk);
3412 if (hr != S_OK)
3413 return hr;
3415 /* init from IStorage */
3416 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3417 if (FAILED(hr))
3418 ERR("failed to get IPersistStorage\n");
3420 if (ps)
3422 IPersistStorage_Load(ps, storage);
3423 IPersistStorage_Release(ps);
3426 return return_multi_qi(unk, count, results);
3429 /***********************************************************************
3430 * CoLoadLibrary (OLE32.@)
3432 * Loads a library.
3434 * PARAMS
3435 * lpszLibName [I] Path to library.
3436 * bAutoFree [I] Whether the library should automatically be freed.
3438 * RETURNS
3439 * Success: Handle to loaded library.
3440 * Failure: NULL.
3442 * SEE ALSO
3443 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3445 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3447 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3449 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3452 /***********************************************************************
3453 * CoFreeLibrary [OLE32.@]
3455 * Unloads a library from memory.
3457 * PARAMS
3458 * hLibrary [I] Handle to library to unload.
3460 * RETURNS
3461 * Nothing
3463 * SEE ALSO
3464 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3466 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3468 FreeLibrary(hLibrary);
3472 /***********************************************************************
3473 * CoFreeAllLibraries [OLE32.@]
3475 * Function for backwards compatibility only. Does nothing.
3477 * RETURNS
3478 * Nothing.
3480 * SEE ALSO
3481 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3483 void WINAPI CoFreeAllLibraries(void)
3485 /* NOP */
3488 /***********************************************************************
3489 * CoFreeUnusedLibrariesEx [OLE32.@]
3491 * Frees any previously unused libraries whose delay has expired and marks
3492 * currently unused libraries for unloading. Unused are identified as those that
3493 * return S_OK from their DllCanUnloadNow function.
3495 * PARAMS
3496 * dwUnloadDelay [I] Unload delay in milliseconds.
3497 * dwReserved [I] Reserved. Set to 0.
3499 * RETURNS
3500 * Nothing.
3502 * SEE ALSO
3503 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3505 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3507 struct apartment *apt = COM_CurrentApt();
3508 if (!apt)
3510 ERR("apartment not initialised\n");
3511 return;
3514 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3517 /***********************************************************************
3518 * CoFreeUnusedLibraries [OLE32.@]
3520 * Frees any unused libraries. Unused are identified as those that return
3521 * S_OK from their DllCanUnloadNow function.
3523 * RETURNS
3524 * Nothing.
3526 * SEE ALSO
3527 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3529 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3531 CoFreeUnusedLibrariesEx(INFINITE, 0);
3534 /***********************************************************************
3535 * CoFileTimeNow [OLE32.@]
3537 * Retrieves the current time in FILETIME format.
3539 * PARAMS
3540 * lpFileTime [O] The current time.
3542 * RETURNS
3543 * S_OK.
3545 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3547 GetSystemTimeAsFileTime( lpFileTime );
3548 return S_OK;
3551 /******************************************************************************
3552 * CoLockObjectExternal [OLE32.@]
3554 * Increments or decrements the external reference count of a stub object.
3556 * PARAMS
3557 * pUnk [I] Stub object.
3558 * fLock [I] If TRUE then increments the external ref-count,
3559 * otherwise decrements.
3560 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3561 * calling CoDisconnectObject.
3563 * RETURNS
3564 * Success: S_OK.
3565 * Failure: HRESULT code.
3567 * NOTES
3568 * If fLock is TRUE and an object is passed in that doesn't have a stub
3569 * manager then a new stub manager is created for the object.
3571 HRESULT WINAPI CoLockObjectExternal(
3572 LPUNKNOWN pUnk,
3573 BOOL fLock,
3574 BOOL fLastUnlockReleases)
3576 struct stub_manager *stubmgr;
3577 struct apartment *apt;
3579 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3580 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3582 apt = COM_CurrentApt();
3583 if (!apt) return CO_E_NOTINITIALIZED;
3585 stubmgr = get_stub_manager_from_object(apt, pUnk);
3587 if (stubmgr)
3589 if (fLock)
3590 stub_manager_ext_addref(stubmgr, 1, FALSE);
3591 else
3592 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3594 stub_manager_int_release(stubmgr);
3596 return S_OK;
3598 else if (fLock)
3600 stubmgr = new_stub_manager(apt, pUnk);
3602 if (stubmgr)
3604 stub_manager_ext_addref(stubmgr, 1, FALSE);
3605 stub_manager_int_release(stubmgr);
3608 return S_OK;
3610 else
3612 WARN("stub object not found %p\n", pUnk);
3613 /* Note: native is pretty broken here because it just silently
3614 * fails, without returning an appropriate error code, making apps
3615 * think that the object was disconnected, when it actually wasn't */
3616 return S_OK;
3620 /***********************************************************************
3621 * CoInitializeWOW (OLE32.@)
3623 * WOW equivalent of CoInitialize?
3625 * PARAMS
3626 * x [I] Unknown.
3627 * y [I] Unknown.
3629 * RETURNS
3630 * Unknown.
3632 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3634 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3635 return 0;
3638 /***********************************************************************
3639 * CoGetState [OLE32.@]
3641 * Retrieves the thread state object previously stored by CoSetState().
3643 * PARAMS
3644 * ppv [I] Address where pointer to object will be stored.
3646 * RETURNS
3647 * Success: S_OK.
3648 * Failure: E_OUTOFMEMORY.
3650 * NOTES
3651 * Crashes on all invalid ppv addresses, including NULL.
3652 * If the function returns a non-NULL object then the caller must release its
3653 * reference on the object when the object is no longer required.
3655 * SEE ALSO
3656 * CoSetState().
3658 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3660 struct oletls *info = COM_CurrentInfo();
3661 if (!info) return E_OUTOFMEMORY;
3663 *ppv = NULL;
3665 if (info->state)
3667 IUnknown_AddRef(info->state);
3668 *ppv = info->state;
3669 TRACE("apt->state=%p\n", info->state);
3672 return S_OK;
3675 /***********************************************************************
3676 * CoSetState [OLE32.@]
3678 * Sets the thread state object.
3680 * PARAMS
3681 * pv [I] Pointer to state object to be stored.
3683 * NOTES
3684 * The system keeps a reference on the object while the object stored.
3686 * RETURNS
3687 * Success: S_OK.
3688 * Failure: E_OUTOFMEMORY.
3690 HRESULT WINAPI CoSetState(IUnknown * pv)
3692 struct oletls *info = COM_CurrentInfo();
3693 if (!info) return E_OUTOFMEMORY;
3695 if (pv) IUnknown_AddRef(pv);
3697 if (info->state)
3699 TRACE("-- release %p now\n", info->state);
3700 IUnknown_Release(info->state);
3703 info->state = pv;
3705 return S_OK;
3709 /******************************************************************************
3710 * CoTreatAsClass [OLE32.@]
3712 * Sets the TreatAs value of a class.
3714 * PARAMS
3715 * clsidOld [I] Class to set TreatAs value on.
3716 * clsidNew [I] The class the clsidOld should be treated as.
3718 * RETURNS
3719 * Success: S_OK.
3720 * Failure: HRESULT code.
3722 * SEE ALSO
3723 * CoGetTreatAsClass
3725 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3727 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3728 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3729 HKEY hkey = NULL;
3730 WCHAR szClsidNew[CHARS_IN_GUID];
3731 HRESULT res = S_OK;
3732 WCHAR auto_treat_as[CHARS_IN_GUID];
3733 LONG auto_treat_as_size = sizeof(auto_treat_as);
3734 CLSID id;
3736 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3737 if (FAILED(res))
3738 goto done;
3740 if (IsEqualGUID( clsidOld, clsidNew ))
3742 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3743 CLSIDFromString(auto_treat_as, &id) == S_OK)
3745 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3747 res = REGDB_E_WRITEREGDB;
3748 goto done;
3751 else
3753 if(RegDeleteKeyW(hkey, wszTreatAs))
3754 res = REGDB_E_WRITEREGDB;
3755 goto done;
3758 else
3760 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3761 RegDeleteKeyW(hkey, wszTreatAs);
3762 }else{
3763 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
3764 WARN("StringFromGUID2 failed\n");
3765 res = E_FAIL;
3766 goto done;
3769 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3770 WARN("RegSetValue failed\n");
3771 res = REGDB_E_WRITEREGDB;
3772 goto done;
3777 done:
3778 if (hkey) RegCloseKey(hkey);
3779 return res;
3782 /******************************************************************************
3783 * CoGetTreatAsClass [OLE32.@]
3785 * Gets the TreatAs value of a class.
3787 * PARAMS
3788 * clsidOld [I] Class to get the TreatAs value of.
3789 * clsidNew [I] The class the clsidOld should be treated as.
3791 * RETURNS
3792 * Success: S_OK.
3793 * Failure: HRESULT code.
3795 * SEE ALSO
3796 * CoSetTreatAsClass
3798 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3800 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3801 HKEY hkey = NULL;
3802 WCHAR szClsidNew[CHARS_IN_GUID];
3803 HRESULT res = S_OK;
3804 LONG len = sizeof(szClsidNew);
3806 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3807 *clsidNew = *clsidOld; /* copy over old value */
3809 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3810 if (FAILED(res))
3812 res = S_FALSE;
3813 goto done;
3815 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3817 res = S_FALSE;
3818 goto done;
3820 res = CLSIDFromString(szClsidNew,clsidNew);
3821 if (FAILED(res))
3822 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3823 done:
3824 if (hkey) RegCloseKey(hkey);
3825 return res;
3828 /******************************************************************************
3829 * CoGetCurrentProcess [OLE32.@]
3831 * Gets the current process ID.
3833 * RETURNS
3834 * The current process ID.
3836 * NOTES
3837 * Is DWORD really the correct return type for this function?
3839 DWORD WINAPI CoGetCurrentProcess(void)
3841 return GetCurrentProcessId();
3844 /******************************************************************************
3845 * CoRegisterMessageFilter [OLE32.@]
3847 * Registers a message filter.
3849 * PARAMS
3850 * lpMessageFilter [I] Pointer to interface.
3851 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3853 * RETURNS
3854 * Success: S_OK.
3855 * Failure: HRESULT code.
3857 * NOTES
3858 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3859 * lpMessageFilter removes the message filter.
3861 * If lplpMessageFilter is not NULL the previous message filter will be
3862 * returned in the memory pointer to this parameter and the caller is
3863 * responsible for releasing the object.
3865 * The current thread be in an apartment otherwise the function will crash.
3867 HRESULT WINAPI CoRegisterMessageFilter(
3868 LPMESSAGEFILTER lpMessageFilter,
3869 LPMESSAGEFILTER *lplpMessageFilter)
3871 struct apartment *apt;
3872 IMessageFilter *lpOldMessageFilter;
3874 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3876 apt = COM_CurrentApt();
3878 /* can't set a message filter in a multi-threaded apartment */
3879 if (!apt || apt->multi_threaded)
3881 WARN("can't set message filter in MTA or uninitialized apt\n");
3882 return CO_E_NOT_SUPPORTED;
3885 if (lpMessageFilter)
3886 IMessageFilter_AddRef(lpMessageFilter);
3888 EnterCriticalSection(&apt->cs);
3890 lpOldMessageFilter = apt->filter;
3891 apt->filter = lpMessageFilter;
3893 LeaveCriticalSection(&apt->cs);
3895 if (lplpMessageFilter)
3896 *lplpMessageFilter = lpOldMessageFilter;
3897 else if (lpOldMessageFilter)
3898 IMessageFilter_Release(lpOldMessageFilter);
3900 return S_OK;
3903 /***********************************************************************
3904 * CoIsOle1Class [OLE32.@]
3906 * Determines whether the specified class an OLE v1 class.
3908 * PARAMS
3909 * clsid [I] Class to test.
3911 * RETURNS
3912 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3914 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3916 FIXME("%s\n", debugstr_guid(clsid));
3917 return FALSE;
3920 /***********************************************************************
3921 * IsEqualGUID [OLE32.@]
3923 * Compares two Unique Identifiers.
3925 * PARAMS
3926 * rguid1 [I] The first GUID to compare.
3927 * rguid2 [I] The other GUID to compare.
3929 * RETURNS
3930 * TRUE if equal
3932 #undef IsEqualGUID
3933 BOOL WINAPI IsEqualGUID(
3934 REFGUID rguid1,
3935 REFGUID rguid2)
3937 return !memcmp(rguid1,rguid2,sizeof(GUID));
3940 /***********************************************************************
3941 * CoInitializeSecurity [OLE32.@]
3943 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3944 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3945 void* pReserved1, DWORD dwAuthnLevel,
3946 DWORD dwImpLevel, void* pReserved2,
3947 DWORD dwCapabilities, void* pReserved3)
3949 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3950 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3951 dwCapabilities, pReserved3);
3952 return S_OK;
3955 /***********************************************************************
3956 * CoSuspendClassObjects [OLE32.@]
3958 * Suspends all registered class objects to prevent further requests coming in
3959 * for those objects.
3961 * RETURNS
3962 * Success: S_OK.
3963 * Failure: HRESULT code.
3965 HRESULT WINAPI CoSuspendClassObjects(void)
3967 FIXME("\n");
3968 return S_OK;
3971 /***********************************************************************
3972 * CoAddRefServerProcess [OLE32.@]
3974 * Helper function for incrementing the reference count of a local-server
3975 * process.
3977 * RETURNS
3978 * New reference count.
3980 * SEE ALSO
3981 * CoReleaseServerProcess().
3983 ULONG WINAPI CoAddRefServerProcess(void)
3985 ULONG refs;
3987 TRACE("\n");
3989 EnterCriticalSection(&csRegisteredClassList);
3990 refs = ++s_COMServerProcessReferences;
3991 LeaveCriticalSection(&csRegisteredClassList);
3993 TRACE("refs before: %d\n", refs - 1);
3995 return refs;
3998 /***********************************************************************
3999 * CoReleaseServerProcess [OLE32.@]
4001 * Helper function for decrementing the reference count of a local-server
4002 * process.
4004 * RETURNS
4005 * New reference count.
4007 * NOTES
4008 * When reference count reaches 0, this function suspends all registered
4009 * classes so no new connections are accepted.
4011 * SEE ALSO
4012 * CoAddRefServerProcess(), CoSuspendClassObjects().
4014 ULONG WINAPI CoReleaseServerProcess(void)
4016 ULONG refs;
4018 TRACE("\n");
4020 EnterCriticalSection(&csRegisteredClassList);
4022 refs = --s_COMServerProcessReferences;
4023 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4025 LeaveCriticalSection(&csRegisteredClassList);
4027 TRACE("refs after: %d\n", refs);
4029 return refs;
4032 /***********************************************************************
4033 * CoIsHandlerConnected [OLE32.@]
4035 * Determines whether a proxy is connected to a remote stub.
4037 * PARAMS
4038 * pUnk [I] Pointer to object that may or may not be connected.
4040 * RETURNS
4041 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4042 * FALSE otherwise.
4044 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4046 FIXME("%p\n", pUnk);
4048 return TRUE;
4051 /***********************************************************************
4052 * CoAllowSetForegroundWindow [OLE32.@]
4055 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4057 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4058 return S_OK;
4061 /***********************************************************************
4062 * CoQueryProxyBlanket [OLE32.@]
4064 * Retrieves the security settings being used by a proxy.
4066 * PARAMS
4067 * pProxy [I] Pointer to the proxy object.
4068 * pAuthnSvc [O] The type of authentication service.
4069 * pAuthzSvc [O] The type of authorization service.
4070 * ppServerPrincName [O] Optional. The server prinicple name.
4071 * pAuthnLevel [O] The authentication level.
4072 * pImpLevel [O] The impersonation level.
4073 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4074 * pCapabilities [O] Flags affecting the security behaviour.
4076 * RETURNS
4077 * Success: S_OK.
4078 * Failure: HRESULT code.
4080 * SEE ALSO
4081 * CoCopyProxy, CoSetProxyBlanket.
4083 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4084 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4085 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4087 IClientSecurity *pCliSec;
4088 HRESULT hr;
4090 TRACE("%p\n", pProxy);
4092 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4093 if (SUCCEEDED(hr))
4095 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4096 pAuthzSvc, ppServerPrincName,
4097 pAuthnLevel, pImpLevel, ppAuthInfo,
4098 pCapabilities);
4099 IClientSecurity_Release(pCliSec);
4102 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4103 return hr;
4106 /***********************************************************************
4107 * CoSetProxyBlanket [OLE32.@]
4109 * Sets the security settings for a proxy.
4111 * PARAMS
4112 * pProxy [I] Pointer to the proxy object.
4113 * AuthnSvc [I] The type of authentication service.
4114 * AuthzSvc [I] The type of authorization service.
4115 * pServerPrincName [I] The server prinicple name.
4116 * AuthnLevel [I] The authentication level.
4117 * ImpLevel [I] The impersonation level.
4118 * pAuthInfo [I] Information specific to the authorization/authentication service.
4119 * Capabilities [I] Flags affecting the security behaviour.
4121 * RETURNS
4122 * Success: S_OK.
4123 * Failure: HRESULT code.
4125 * SEE ALSO
4126 * CoQueryProxyBlanket, CoCopyProxy.
4128 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4129 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4130 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4132 IClientSecurity *pCliSec;
4133 HRESULT hr;
4135 TRACE("%p\n", pProxy);
4137 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4138 if (SUCCEEDED(hr))
4140 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4141 AuthzSvc, pServerPrincName,
4142 AuthnLevel, ImpLevel, pAuthInfo,
4143 Capabilities);
4144 IClientSecurity_Release(pCliSec);
4147 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4148 return hr;
4151 /***********************************************************************
4152 * CoCopyProxy [OLE32.@]
4154 * Copies a proxy.
4156 * PARAMS
4157 * pProxy [I] Pointer to the proxy object.
4158 * ppCopy [O] Copy of the proxy.
4160 * RETURNS
4161 * Success: S_OK.
4162 * Failure: HRESULT code.
4164 * SEE ALSO
4165 * CoQueryProxyBlanket, CoSetProxyBlanket.
4167 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4169 IClientSecurity *pCliSec;
4170 HRESULT hr;
4172 TRACE("%p\n", pProxy);
4174 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4175 if (SUCCEEDED(hr))
4177 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4178 IClientSecurity_Release(pCliSec);
4181 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4182 return hr;
4186 /***********************************************************************
4187 * CoGetCallContext [OLE32.@]
4189 * Gets the context of the currently executing server call in the current
4190 * thread.
4192 * PARAMS
4193 * riid [I] Context interface to return.
4194 * ppv [O] Pointer to memory that will receive the context on return.
4196 * RETURNS
4197 * Success: S_OK.
4198 * Failure: HRESULT code.
4200 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4202 struct oletls *info = COM_CurrentInfo();
4204 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4206 if (!info)
4207 return E_OUTOFMEMORY;
4209 if (!info->call_state)
4210 return RPC_E_CALL_COMPLETE;
4212 return IUnknown_QueryInterface(info->call_state, riid, ppv);
4215 /***********************************************************************
4216 * CoSwitchCallContext [OLE32.@]
4218 * Switches the context of the currently executing server call in the current
4219 * thread.
4221 * PARAMS
4222 * pObject [I] Pointer to new context object
4223 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4225 * RETURNS
4226 * Success: S_OK.
4227 * Failure: HRESULT code.
4229 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4231 struct oletls *info = COM_CurrentInfo();
4233 TRACE("(%p, %p)\n", pObject, ppOldObject);
4235 if (!info)
4236 return E_OUTOFMEMORY;
4238 *ppOldObject = info->call_state;
4239 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4241 return S_OK;
4244 /***********************************************************************
4245 * CoQueryClientBlanket [OLE32.@]
4247 * Retrieves the authentication information about the client of the currently
4248 * executing server call in the current thread.
4250 * PARAMS
4251 * pAuthnSvc [O] Optional. The type of authentication service.
4252 * pAuthzSvc [O] Optional. The type of authorization service.
4253 * pServerPrincName [O] Optional. The server prinicple name.
4254 * pAuthnLevel [O] Optional. The authentication level.
4255 * pImpLevel [O] Optional. The impersonation level.
4256 * pPrivs [O] Optional. Information about the privileges of the client.
4257 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4259 * RETURNS
4260 * Success: S_OK.
4261 * Failure: HRESULT code.
4263 * SEE ALSO
4264 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4266 HRESULT WINAPI CoQueryClientBlanket(
4267 DWORD *pAuthnSvc,
4268 DWORD *pAuthzSvc,
4269 OLECHAR **pServerPrincName,
4270 DWORD *pAuthnLevel,
4271 DWORD *pImpLevel,
4272 RPC_AUTHZ_HANDLE *pPrivs,
4273 DWORD *pCapabilities)
4275 IServerSecurity *pSrvSec;
4276 HRESULT hr;
4278 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4279 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4280 pPrivs, pCapabilities);
4282 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4283 if (SUCCEEDED(hr))
4285 hr = IServerSecurity_QueryBlanket(
4286 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4287 pImpLevel, pPrivs, pCapabilities);
4288 IServerSecurity_Release(pSrvSec);
4291 return hr;
4294 /***********************************************************************
4295 * CoImpersonateClient [OLE32.@]
4297 * Impersonates the client of the currently executing server call in the
4298 * current thread.
4300 * PARAMS
4301 * None.
4303 * RETURNS
4304 * Success: S_OK.
4305 * Failure: HRESULT code.
4307 * NOTES
4308 * If this function fails then the current thread will not be impersonating
4309 * the client and all actions will take place on behalf of the server.
4310 * Therefore, it is important to check the return value from this function.
4312 * SEE ALSO
4313 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4315 HRESULT WINAPI CoImpersonateClient(void)
4317 IServerSecurity *pSrvSec;
4318 HRESULT hr;
4320 TRACE("\n");
4322 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4323 if (SUCCEEDED(hr))
4325 hr = IServerSecurity_ImpersonateClient(pSrvSec);
4326 IServerSecurity_Release(pSrvSec);
4329 return hr;
4332 /***********************************************************************
4333 * CoRevertToSelf [OLE32.@]
4335 * Ends the impersonation of the client of the currently executing server
4336 * call in the current thread.
4338 * PARAMS
4339 * None.
4341 * RETURNS
4342 * Success: S_OK.
4343 * Failure: HRESULT code.
4345 * SEE ALSO
4346 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4348 HRESULT WINAPI CoRevertToSelf(void)
4350 IServerSecurity *pSrvSec;
4351 HRESULT hr;
4353 TRACE("\n");
4355 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4356 if (SUCCEEDED(hr))
4358 hr = IServerSecurity_RevertToSelf(pSrvSec);
4359 IServerSecurity_Release(pSrvSec);
4362 return hr;
4365 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4367 /* first try to retrieve messages for incoming COM calls to the apartment window */
4368 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
4369 /* next retrieve other messages necessary for the app to remain responsive */
4370 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4371 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4374 /***********************************************************************
4375 * CoWaitForMultipleHandles [OLE32.@]
4377 * Waits for one or more handles to become signaled.
4379 * PARAMS
4380 * dwFlags [I] Flags. See notes.
4381 * dwTimeout [I] Timeout in milliseconds.
4382 * cHandles [I] Number of handles pointed to by pHandles.
4383 * pHandles [I] Handles to wait for.
4384 * lpdwindex [O] Index of handle that was signaled.
4386 * RETURNS
4387 * Success: S_OK.
4388 * Failure: RPC_S_CALLPENDING on timeout.
4390 * NOTES
4392 * The dwFlags parameter can be zero or more of the following:
4393 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4394 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4396 * SEE ALSO
4397 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4399 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4400 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4402 HRESULT hr = S_OK;
4403 DWORD start_time = GetTickCount();
4404 APARTMENT *apt = COM_CurrentApt();
4405 BOOL message_loop = apt && !apt->multi_threaded;
4407 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4408 pHandles, lpdwindex);
4410 while (TRUE)
4412 DWORD now = GetTickCount();
4413 DWORD res;
4415 if (now - start_time > dwTimeout)
4417 hr = RPC_S_CALLPENDING;
4418 break;
4421 if (message_loop)
4423 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4424 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4426 TRACE("waiting for rpc completion or window message\n");
4428 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4429 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4430 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4432 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4434 MSG msg;
4435 int count = 0;
4437 /* call message filter */
4439 if (COM_CurrentApt()->filter)
4441 PENDINGTYPE pendingtype =
4442 COM_CurrentInfo()->pending_call_count_server ?
4443 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4444 DWORD be_handled = IMessageFilter_MessagePending(
4445 COM_CurrentApt()->filter, 0 /* FIXME */,
4446 now - start_time, pendingtype);
4447 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4448 switch (be_handled)
4450 case PENDINGMSG_CANCELCALL:
4451 WARN("call canceled\n");
4452 hr = RPC_E_CALL_CANCELED;
4453 break;
4454 case PENDINGMSG_WAITNOPROCESS:
4455 case PENDINGMSG_WAITDEFPROCESS:
4456 default:
4457 /* FIXME: MSDN is very vague about the difference
4458 * between WAITNOPROCESS and WAITDEFPROCESS - there
4459 * appears to be none, so it is possibly a left-over
4460 * from the 16-bit world. */
4461 break;
4465 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4466 * so after processing 100 messages we go back to checking the wait handles */
4467 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4469 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4470 TranslateMessage(&msg);
4471 DispatchMessageW(&msg);
4472 if (msg.message == WM_QUIT)
4474 TRACE("resending WM_QUIT to outer message loop\n");
4475 PostQuitMessage(msg.wParam);
4476 /* no longer need to process messages */
4477 message_loop = FALSE;
4478 break;
4481 continue;
4484 else
4486 TRACE("waiting for rpc completion\n");
4488 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4489 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4490 (dwFlags & COWAIT_ALERTABLE) != 0);
4493 switch (res)
4495 case WAIT_TIMEOUT:
4496 hr = RPC_S_CALLPENDING;
4497 break;
4498 case WAIT_FAILED:
4499 hr = HRESULT_FROM_WIN32( GetLastError() );
4500 break;
4501 default:
4502 *lpdwindex = res;
4503 break;
4505 break;
4507 TRACE("-- 0x%08x\n", hr);
4508 return hr;
4512 /***********************************************************************
4513 * CoGetObject [OLE32.@]
4515 * Gets the object named by converting the name to a moniker and binding to it.
4517 * PARAMS
4518 * pszName [I] String representing the object.
4519 * pBindOptions [I] Parameters affecting the binding to the named object.
4520 * riid [I] Interface to bind to on the objecct.
4521 * ppv [O] On output, the interface riid of the object represented
4522 * by pszName.
4524 * RETURNS
4525 * Success: S_OK.
4526 * Failure: HRESULT code.
4528 * SEE ALSO
4529 * MkParseDisplayName.
4531 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4532 REFIID riid, void **ppv)
4534 IBindCtx *pbc;
4535 HRESULT hr;
4537 *ppv = NULL;
4539 hr = CreateBindCtx(0, &pbc);
4540 if (SUCCEEDED(hr))
4542 if (pBindOptions)
4543 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4545 if (SUCCEEDED(hr))
4547 ULONG chEaten;
4548 IMoniker *pmk;
4550 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4551 if (SUCCEEDED(hr))
4553 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4554 IMoniker_Release(pmk);
4558 IBindCtx_Release(pbc);
4560 return hr;
4563 /***********************************************************************
4564 * CoRegisterChannelHook [OLE32.@]
4566 * Registers a process-wide hook that is called during ORPC calls.
4568 * PARAMS
4569 * guidExtension [I] GUID of the channel hook to register.
4570 * pChannelHook [I] Channel hook object to register.
4572 * RETURNS
4573 * Success: S_OK.
4574 * Failure: HRESULT code.
4576 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4578 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4580 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4583 typedef struct Context
4585 IComThreadingInfo IComThreadingInfo_iface;
4586 IContextCallback IContextCallback_iface;
4587 IObjContext IObjContext_iface;
4588 LONG refs;
4589 APTTYPE apttype;
4590 } Context;
4592 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4594 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4597 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4599 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4602 static inline Context *impl_from_IObjContext( IObjContext *iface )
4604 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4607 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4609 *ppv = NULL;
4611 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4612 IsEqualIID(riid, &IID_IUnknown))
4614 *ppv = &iface->IComThreadingInfo_iface;
4616 else if (IsEqualIID(riid, &IID_IContextCallback))
4618 *ppv = &iface->IContextCallback_iface;
4620 else if (IsEqualIID(riid, &IID_IObjContext))
4622 *ppv = &iface->IObjContext_iface;
4625 if (*ppv)
4627 IUnknown_AddRef((IUnknown*)*ppv);
4628 return S_OK;
4631 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4632 return E_NOINTERFACE;
4635 static ULONG Context_AddRef(Context *This)
4637 return InterlockedIncrement(&This->refs);
4640 static ULONG Context_Release(Context *This)
4642 ULONG refs = InterlockedDecrement(&This->refs);
4643 if (!refs)
4644 HeapFree(GetProcessHeap(), 0, This);
4645 return refs;
4648 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4650 Context *This = impl_from_IComThreadingInfo(iface);
4651 return Context_QueryInterface(This, riid, ppv);
4654 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4656 Context *This = impl_from_IComThreadingInfo(iface);
4657 return Context_AddRef(This);
4660 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4662 Context *This = impl_from_IComThreadingInfo(iface);
4663 return Context_Release(This);
4666 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4668 Context *This = impl_from_IComThreadingInfo(iface);
4670 TRACE("(%p)\n", apttype);
4672 *apttype = This->apttype;
4673 return S_OK;
4676 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4678 Context *This = impl_from_IComThreadingInfo(iface);
4680 TRACE("(%p)\n", thdtype);
4682 switch (This->apttype)
4684 case APTTYPE_STA:
4685 case APTTYPE_MAINSTA:
4686 *thdtype = THDTYPE_PROCESSMESSAGES;
4687 break;
4688 default:
4689 *thdtype = THDTYPE_BLOCKMESSAGES;
4690 break;
4692 return S_OK;
4695 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4697 FIXME("(%p): stub\n", logical_thread_id);
4698 return E_NOTIMPL;
4701 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4703 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4704 return E_NOTIMPL;
4707 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4709 Context_CTI_QueryInterface,
4710 Context_CTI_AddRef,
4711 Context_CTI_Release,
4712 Context_CTI_GetCurrentApartmentType,
4713 Context_CTI_GetCurrentThreadType,
4714 Context_CTI_GetCurrentLogicalThreadId,
4715 Context_CTI_SetCurrentLogicalThreadId
4718 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4720 Context *This = impl_from_IContextCallback(iface);
4721 return Context_QueryInterface(This, riid, ppv);
4724 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4726 Context *This = impl_from_IContextCallback(iface);
4727 return Context_AddRef(This);
4730 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4732 Context *This = impl_from_IContextCallback(iface);
4733 return Context_Release(This);
4736 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4737 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4739 Context *This = impl_from_IContextCallback(iface);
4741 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4742 return E_NOTIMPL;
4745 static const IContextCallbackVtbl Context_Callback_Vtbl =
4747 Context_CC_QueryInterface,
4748 Context_CC_AddRef,
4749 Context_CC_Release,
4750 Context_CC_ContextCallback
4753 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4755 Context *This = impl_from_IObjContext(iface);
4756 return Context_QueryInterface(This, riid, ppv);
4759 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4761 Context *This = impl_from_IObjContext(iface);
4762 return Context_AddRef(This);
4765 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4767 Context *This = impl_from_IObjContext(iface);
4768 return Context_Release(This);
4771 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4773 Context *This = impl_from_IObjContext(iface);
4775 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4776 return E_NOTIMPL;
4779 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4781 Context *This = impl_from_IObjContext(iface);
4783 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4784 return E_NOTIMPL;
4787 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4789 Context *This = impl_from_IObjContext(iface);
4791 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4792 return E_NOTIMPL;
4795 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4797 Context *This = impl_from_IObjContext(iface);
4799 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4800 return E_NOTIMPL;
4803 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4805 Context *This = impl_from_IObjContext(iface);
4806 FIXME("(%p/%p)\n", This, iface);
4809 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4811 Context *This = impl_from_IObjContext(iface);
4812 FIXME("(%p/%p)\n", This, iface);
4815 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4817 Context *This = impl_from_IObjContext(iface);
4818 FIXME("(%p/%p)\n", This, iface);
4821 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4823 Context *This = impl_from_IObjContext(iface);
4824 FIXME("(%p/%p)\n", This, iface);
4827 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4829 Context *This = impl_from_IObjContext(iface);
4830 FIXME("(%p/%p)\n", This, iface);
4833 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4835 Context *This = impl_from_IObjContext(iface);
4836 FIXME("(%p/%p)\n", This, iface);
4839 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4841 Context *This = impl_from_IObjContext(iface);
4842 FIXME("(%p/%p)\n", This, iface);
4845 static const IObjContextVtbl Context_Object_Vtbl =
4847 Context_OC_QueryInterface,
4848 Context_OC_AddRef,
4849 Context_OC_Release,
4850 Context_OC_SetProperty,
4851 Context_OC_RemoveProperty,
4852 Context_OC_GetProperty,
4853 Context_OC_EnumContextProps,
4854 Context_OC_Reserved1,
4855 Context_OC_Reserved2,
4856 Context_OC_Reserved3,
4857 Context_OC_Reserved4,
4858 Context_OC_Reserved5,
4859 Context_OC_Reserved6,
4860 Context_OC_Reserved7
4863 /***********************************************************************
4864 * CoGetObjectContext [OLE32.@]
4866 * Retrieves an object associated with the current context (i.e. apartment).
4868 * PARAMS
4869 * riid [I] ID of the interface of the object to retrieve.
4870 * ppv [O] Address where object will be stored on return.
4872 * RETURNS
4873 * Success: S_OK.
4874 * Failure: HRESULT code.
4876 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4878 APARTMENT *apt = COM_CurrentApt();
4879 Context *context;
4880 HRESULT hr;
4882 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4884 *ppv = NULL;
4885 if (!apt)
4887 if (!(apt = apartment_find_multi_threaded()))
4889 ERR("apartment not initialised\n");
4890 return CO_E_NOTINITIALIZED;
4892 apartment_release(apt);
4895 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4896 if (!context)
4897 return E_OUTOFMEMORY;
4899 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4900 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4901 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4902 context->refs = 1;
4903 if (apt->multi_threaded)
4904 context->apttype = APTTYPE_MTA;
4905 else if (apt->main)
4906 context->apttype = APTTYPE_MAINSTA;
4907 else
4908 context->apttype = APTTYPE_STA;
4910 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4911 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4913 return hr;
4917 /***********************************************************************
4918 * CoGetContextToken [OLE32.@]
4920 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4922 struct oletls *info = COM_CurrentInfo();
4924 TRACE("(%p)\n", token);
4926 if (!info)
4927 return E_OUTOFMEMORY;
4929 if (!info->apt)
4931 APARTMENT *apt;
4932 if (!(apt = apartment_find_multi_threaded()))
4934 ERR("apartment not initialised\n");
4935 return CO_E_NOTINITIALIZED;
4937 apartment_release(apt);
4940 if (!token)
4941 return E_POINTER;
4943 if (!info->context_token)
4945 HRESULT hr;
4946 IObjContext *ctx;
4948 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4949 if (FAILED(hr)) return hr;
4950 info->context_token = ctx;
4953 *token = (ULONG_PTR)info->context_token;
4954 TRACE("apt->context_token=%p\n", info->context_token);
4956 return S_OK;
4959 /***********************************************************************
4960 * CoGetDefaultContext [OLE32.@]
4962 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
4964 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
4965 return E_NOINTERFACE;
4968 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4970 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4971 HKEY hkey;
4972 HRESULT hres;
4974 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4975 if (SUCCEEDED(hres))
4977 struct class_reg_data regdata;
4978 WCHAR dllpath[MAX_PATH+1];
4980 regdata.u.hkey = hkey;
4981 regdata.hkey = TRUE;
4983 if (COM_RegReadPath(&regdata, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4985 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4986 if (!strcmpiW(dllpath, wszOle32))
4988 RegCloseKey(hkey);
4989 return HandlerCF_Create(rclsid, riid, ppv);
4992 else
4993 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4994 RegCloseKey(hkey);
4997 return CLASS_E_CLASSNOTAVAILABLE;
5000 /***********************************************************************
5001 * DllMain (OLE32.@)
5003 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5005 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5007 switch(fdwReason) {
5008 case DLL_PROCESS_ATTACH:
5009 hProxyDll = hinstDLL;
5010 break;
5012 case DLL_PROCESS_DETACH:
5013 if (reserved) break;
5014 release_std_git();
5015 UnregisterClassW( wszAptWinClass, hProxyDll );
5016 RPC_UnregisterAllChannelHooks();
5017 COMPOBJ_DllList_Free();
5018 DeleteCriticalSection(&csRegisteredClassList);
5019 DeleteCriticalSection(&csApartment);
5020 break;
5022 case DLL_THREAD_DETACH:
5023 COM_TlsDestroy();
5024 break;
5026 return TRUE;
5029 /***********************************************************************
5030 * DllRegisterServer (OLE32.@)
5032 HRESULT WINAPI DllRegisterServer(void)
5034 return OLE32_DllRegisterServer();
5037 /***********************************************************************
5038 * DllUnregisterServer (OLE32.@)
5040 HRESULT WINAPI DllUnregisterServer(void)
5042 return OLE32_DllUnregisterServer();