wined3d: Use a separate STATE_TRANSFORM(WINED3D_TS_VIEW) state handler in the GLSL...
[wine/multimedia.git] / dlls / ole32 / compobj.c
blobe2efe58a839eb8d96826ee4bd9878162ac571286
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
49 #include "ntstatus.h"
50 #define WIN32_NO_STATUS
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winerror.h"
54 #include "winreg.h"
55 #include "winuser.h"
56 #define USE_COM_CONTEXT_DEF
57 #include "objbase.h"
58 #include "ole2.h"
59 #include "ole2ver.h"
60 #include "ctxtcall.h"
61 #include "dde.h"
62 #include "servprov.h"
64 #include "initguid.h"
65 #include "compobj_private.h"
66 #include "moniker.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole);
73 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
75 /****************************************************************************
76 * This section defines variables internal to the COM module.
79 static APARTMENT *MTA; /* protected by csApartment */
80 static APARTMENT *MainApartment; /* the first STA apartment */
81 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
86 0, 0, &csApartment,
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
92 enum comclass_threadingmodel
94 ThreadingModel_Apartment = 1,
95 ThreadingModel_Free = 2,
96 ThreadingModel_No = 3,
97 ThreadingModel_Both = 4,
98 ThreadingModel_Neutral = 5
101 enum comclass_miscfields
103 MiscStatus = 1,
104 MiscStatusIcon = 2,
105 MiscStatusContent = 4,
106 MiscStatusThumbnail = 8,
107 MiscStatusDocPrint = 16
110 struct comclassredirect_data
112 ULONG size;
113 BYTE res;
114 BYTE miscmask;
115 BYTE res1[2];
116 DWORD model;
117 GUID clsid;
118 GUID alias;
119 GUID clsid2;
120 GUID tlbid;
121 ULONG name_len;
122 ULONG name_offset;
123 ULONG progid_len;
124 ULONG progid_offset;
125 ULONG clrdata_len;
126 ULONG clrdata_offset;
127 DWORD miscstatus;
128 DWORD miscstatuscontent;
129 DWORD miscstatusthumbnail;
130 DWORD miscstatusicon;
131 DWORD miscstatusdocprint;
134 struct ifacepsredirect_data
136 ULONG size;
137 DWORD mask;
138 GUID iid;
139 ULONG nummethods;
140 GUID tlbid;
141 GUID base;
142 ULONG name_len;
143 ULONG name_offset;
146 struct progidredirect_data
148 ULONG size;
149 DWORD reserved;
150 ULONG clsid_offset;
153 struct class_reg_data
155 union
157 struct
159 struct comclassredirect_data *data;
160 void *section;
161 HANDLE hactctx;
162 } actctx;
163 HKEY hkey;
164 } u;
165 BOOL hkey;
168 struct registered_psclsid
170 struct list entry;
171 IID iid;
172 CLSID clsid;
176 * This is a marshallable object exposing registered local servers.
177 * IServiceProvider is used only because it happens meet requirements
178 * and already has proxy/stub code. If more functionality is needed,
179 * a custom interface may be used instead.
181 struct LocalServer
183 IServiceProvider IServiceProvider_iface;
184 LONG ref;
185 APARTMENT *apt;
186 IStream *marshal_stream;
190 * This lock count counts the number of times CoInitialize is called. It is
191 * decreased every time CoUninitialize is called. When it hits 0, the COM
192 * libraries are freed
194 static LONG s_COMLockCount = 0;
195 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
196 static LONG s_COMServerProcessReferences = 0;
199 * This linked list contains the list of registered class objects. These
200 * are mostly used to register the factories for out-of-proc servers of OLE
201 * objects.
203 * TODO: Make this data structure aware of inter-process communication. This
204 * means that parts of this will be exported to rpcss.
206 typedef struct tagRegisteredClass
208 struct list entry;
209 CLSID classIdentifier;
210 OXID apartment_id;
211 LPUNKNOWN classObject;
212 DWORD runContext;
213 DWORD connectFlags;
214 DWORD dwCookie;
215 void *RpcRegistration;
216 } RegisteredClass;
218 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
220 static CRITICAL_SECTION csRegisteredClassList;
221 static CRITICAL_SECTION_DEBUG class_cs_debug =
223 0, 0, &csRegisteredClassList,
224 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
225 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
227 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
229 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
231 switch (aspect)
233 case DVASPECT_CONTENT:
234 return MiscStatusContent;
235 case DVASPECT_THUMBNAIL:
236 return MiscStatusThumbnail;
237 case DVASPECT_ICON:
238 return MiscStatusIcon;
239 case DVASPECT_DOCPRINT:
240 return MiscStatusDocPrint;
241 default:
242 return MiscStatus;
246 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
248 ACTCTX_SECTION_KEYED_DATA data;
250 data.cbSize = sizeof(data);
251 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
252 clsid, &data))
254 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
255 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
257 if (!(comclass->miscmask & misc))
259 if (!(comclass->miscmask & MiscStatus))
261 *status = 0;
262 return TRUE;
264 misc = MiscStatus;
267 switch (misc)
269 case MiscStatus:
270 *status = comclass->miscstatus;
271 break;
272 case MiscStatusIcon:
273 *status = comclass->miscstatusicon;
274 break;
275 case MiscStatusContent:
276 *status = comclass->miscstatuscontent;
277 break;
278 case MiscStatusThumbnail:
279 *status = comclass->miscstatusthumbnail;
280 break;
281 case MiscStatusDocPrint:
282 *status = comclass->miscstatusdocprint;
283 break;
284 default:
288 return TRUE;
290 else
291 return FALSE;
294 /* wrapper for NtCreateKey that creates the key recursively if necessary */
295 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
297 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
299 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
301 HANDLE subkey, root = attr->RootDirectory;
302 WCHAR *buffer = attr->ObjectName->Buffer;
303 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
304 UNICODE_STRING str;
306 while (i < len && buffer[i] != '\\') i++;
307 if (i == len) return status;
309 attrs = attr->Attributes;
310 attr->ObjectName = &str;
312 while (i < len)
314 str.Buffer = buffer + pos;
315 str.Length = (i - pos) * sizeof(WCHAR);
316 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
317 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
318 if (status) return status;
319 attr->RootDirectory = subkey;
320 while (i < len && buffer[i] == '\\') i++;
321 pos = i;
322 while (i < len && buffer[i] != '\\') i++;
324 str.Buffer = buffer + pos;
325 str.Length = (i - pos) * sizeof(WCHAR);
326 attr->Attributes = attrs;
327 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
328 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
330 return status;
333 static const WCHAR classes_rootW[] =
334 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
336 static HKEY classes_root_hkey;
338 /* create the special HKEY_CLASSES_ROOT key */
339 static HKEY create_classes_root_hkey(DWORD access)
341 HKEY hkey, ret = 0;
342 OBJECT_ATTRIBUTES attr;
343 UNICODE_STRING name;
345 attr.Length = sizeof(attr);
346 attr.RootDirectory = 0;
347 attr.ObjectName = &name;
348 attr.Attributes = 0;
349 attr.SecurityDescriptor = NULL;
350 attr.SecurityQualityOfService = NULL;
351 RtlInitUnicodeString( &name, classes_rootW );
352 if (create_key( &hkey, access, &attr )) return 0;
353 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
355 if (!(access & KEY_WOW64_64KEY))
357 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
358 ret = hkey;
359 else
360 NtClose( hkey ); /* somebody beat us to it */
362 else
363 ret = hkey;
364 return ret;
367 /* map the hkey from special root to normal key if necessary */
368 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
370 HKEY ret = hkey;
371 const BOOL is_win64 = sizeof(void*) > sizeof(int);
372 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
374 if (hkey == HKEY_CLASSES_ROOT &&
375 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
376 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
377 if (force_wow32 && ret && ret == classes_root_hkey)
379 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
380 access &= ~KEY_WOW64_32KEY;
381 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
382 return 0;
383 ret = hkey;
386 return ret;
389 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
391 OBJECT_ATTRIBUTES attr;
392 UNICODE_STRING nameW;
394 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
396 attr.Length = sizeof(attr);
397 attr.RootDirectory = hkey;
398 attr.ObjectName = &nameW;
399 attr.Attributes = 0;
400 attr.SecurityDescriptor = NULL;
401 attr.SecurityQualityOfService = NULL;
402 RtlInitUnicodeString( &nameW, name );
404 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
407 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
409 OBJECT_ATTRIBUTES attr;
410 UNICODE_STRING nameW;
412 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
414 attr.Length = sizeof(attr);
415 attr.RootDirectory = hkey;
416 attr.ObjectName = &nameW;
417 attr.Attributes = 0;
418 attr.SecurityDescriptor = NULL;
419 attr.SecurityQualityOfService = NULL;
420 RtlInitUnicodeString( &nameW, name );
422 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
425 /*****************************************************************************
426 * This section contains OpenDllList definitions
428 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
429 * other functions that do LoadLibrary _without_ giving back a HMODULE.
430 * Without this list these handles would never be freed.
432 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
433 * next unload-call but not before 600 sec.
436 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
437 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
439 typedef struct tagOpenDll
441 LONG refs;
442 LPWSTR library_name;
443 HANDLE library;
444 DllGetClassObjectFunc DllGetClassObject;
445 DllCanUnloadNowFunc DllCanUnloadNow;
446 struct list entry;
447 } OpenDll;
449 static struct list openDllList = LIST_INIT(openDllList);
451 static CRITICAL_SECTION csOpenDllList;
452 static CRITICAL_SECTION_DEBUG dll_cs_debug =
454 0, 0, &csOpenDllList,
455 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
456 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
458 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
460 struct apartment_loaded_dll
462 struct list entry;
463 OpenDll *dll;
464 DWORD unload_time;
465 BOOL multi_threaded;
468 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
469 '0','x','#','#','#','#','#','#','#','#',' ',0};
471 /*****************************************************************************
472 * This section contains OpenDllList implementation
475 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
477 OpenDll *ptr;
478 OpenDll *ret = NULL;
479 EnterCriticalSection(&csOpenDllList);
480 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
482 if (!strcmpiW(library_name, ptr->library_name) &&
483 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
485 ret = ptr;
486 break;
489 LeaveCriticalSection(&csOpenDllList);
490 return ret;
493 /* caller must ensure that library_name is not already in the open dll list */
494 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
496 OpenDll *entry;
497 int len;
498 HRESULT hr = S_OK;
499 HANDLE hLibrary;
500 DllCanUnloadNowFunc DllCanUnloadNow;
501 DllGetClassObjectFunc DllGetClassObject;
503 TRACE("%s\n", debugstr_w(library_name));
505 *ret = COMPOBJ_DllList_Get(library_name);
506 if (*ret) return S_OK;
508 /* do this outside the csOpenDllList to avoid creating a lock dependency on
509 * the loader lock */
510 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
511 if (!hLibrary)
513 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
514 /* failure: DLL could not be loaded */
515 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
518 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
519 /* Note: failing to find DllCanUnloadNow is not a failure */
520 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
521 if (!DllGetClassObject)
523 /* failure: the dll did not export DllGetClassObject */
524 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
525 FreeLibrary(hLibrary);
526 return CO_E_DLLNOTFOUND;
529 EnterCriticalSection( &csOpenDllList );
531 *ret = COMPOBJ_DllList_Get(library_name);
532 if (*ret)
534 /* another caller to this function already added the dll while we
535 * weren't in the critical section */
536 FreeLibrary(hLibrary);
538 else
540 len = strlenW(library_name);
541 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
542 if (entry)
543 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
544 if (entry && entry->library_name)
546 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
547 entry->library = hLibrary;
548 entry->refs = 1;
549 entry->DllCanUnloadNow = DllCanUnloadNow;
550 entry->DllGetClassObject = DllGetClassObject;
551 list_add_tail(&openDllList, &entry->entry);
552 *ret = entry;
554 else
556 HeapFree(GetProcessHeap(), 0, entry);
557 hr = E_OUTOFMEMORY;
558 FreeLibrary(hLibrary);
562 LeaveCriticalSection( &csOpenDllList );
564 return hr;
567 /* pass FALSE for free_entry to release a reference without destroying the
568 * entry if it reaches zero or TRUE otherwise */
569 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
571 if (!InterlockedDecrement(&entry->refs) && free_entry)
573 EnterCriticalSection(&csOpenDllList);
574 list_remove(&entry->entry);
575 LeaveCriticalSection(&csOpenDllList);
577 TRACE("freeing %p\n", entry->library);
578 FreeLibrary(entry->library);
580 HeapFree(GetProcessHeap(), 0, entry->library_name);
581 HeapFree(GetProcessHeap(), 0, entry);
585 /* frees memory associated with active dll list */
586 static void COMPOBJ_DllList_Free(void)
588 OpenDll *entry, *cursor2;
589 EnterCriticalSection(&csOpenDllList);
590 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
592 list_remove(&entry->entry);
594 HeapFree(GetProcessHeap(), 0, entry->library_name);
595 HeapFree(GetProcessHeap(), 0, entry);
597 LeaveCriticalSection(&csOpenDllList);
598 DeleteCriticalSection(&csOpenDllList);
601 /******************************************************************************
602 * Manage apartments.
605 static DWORD apartment_addref(struct apartment *apt)
607 DWORD refs = InterlockedIncrement(&apt->refs);
608 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
609 return refs;
612 /* allocates memory and fills in the necessary fields for a new apartment
613 * object. must be called inside apartment cs */
614 static APARTMENT *apartment_construct(DWORD model)
616 APARTMENT *apt;
618 TRACE("creating new apartment, model=%d\n", model);
620 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
621 apt->tid = GetCurrentThreadId();
623 list_init(&apt->proxies);
624 list_init(&apt->stubmgrs);
625 list_init(&apt->psclsids);
626 list_init(&apt->loaded_dlls);
627 apt->ipidc = 0;
628 apt->refs = 1;
629 apt->remunk_exported = FALSE;
630 apt->oidc = 1;
631 InitializeCriticalSection(&apt->cs);
632 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
634 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
636 if (apt->multi_threaded)
638 /* FIXME: should be randomly generated by in an RPC call to rpcss */
639 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
641 else
643 /* FIXME: should be randomly generated by in an RPC call to rpcss */
644 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
647 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
649 list_add_head(&apts, &apt->entry);
651 return apt;
654 /* gets and existing apartment if one exists or otherwise creates an apartment
655 * structure which stores OLE apartment-local information and stores a pointer
656 * to it in the thread-local storage */
657 static APARTMENT *apartment_get_or_create(DWORD model)
659 APARTMENT *apt = COM_CurrentApt();
661 if (!apt)
663 if (model & COINIT_APARTMENTTHREADED)
665 EnterCriticalSection(&csApartment);
667 apt = apartment_construct(model);
668 if (!MainApartment)
670 MainApartment = apt;
671 apt->main = TRUE;
672 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
675 LeaveCriticalSection(&csApartment);
677 if (apt->main)
678 apartment_createwindowifneeded(apt);
680 else
682 EnterCriticalSection(&csApartment);
684 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
685 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
686 * in a process */
687 if (MTA)
689 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
690 apartment_addref(MTA);
692 else
693 MTA = apartment_construct(model);
695 apt = MTA;
697 LeaveCriticalSection(&csApartment);
699 COM_CurrentInfo()->apt = apt;
702 return apt;
705 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
707 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
710 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
712 list_remove(&curClass->entry);
714 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
715 RPC_StopLocalServer(curClass->RpcRegistration);
717 IUnknown_Release(curClass->classObject);
718 HeapFree(GetProcessHeap(), 0, curClass);
721 static void COM_RevokeAllClasses(const struct apartment *apt)
723 RegisteredClass *curClass, *cursor;
725 EnterCriticalSection( &csRegisteredClassList );
727 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
729 if (curClass->apartment_id == apt->oxid)
730 COM_RevokeRegisteredClassObject(curClass);
733 LeaveCriticalSection( &csRegisteredClassList );
736 /******************************************************************************
737 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
740 typedef struct ManualResetEvent {
741 ISynchronize ISynchronize_iface;
742 ISynchronizeHandle ISynchronizeHandle_iface;
743 LONG ref;
744 HANDLE event;
745 } MREImpl;
747 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
749 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
752 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
754 MREImpl *This = impl_from_ISynchronize(iface);
756 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
758 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
759 *ppv = &This->ISynchronize_iface;
760 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
761 *ppv = &This->ISynchronizeHandle_iface;
762 }else {
763 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
764 *ppv = NULL;
765 return E_NOINTERFACE;
768 IUnknown_AddRef((IUnknown*)*ppv);
769 return S_OK;
772 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
774 MREImpl *This = impl_from_ISynchronize(iface);
775 LONG ref = InterlockedIncrement(&This->ref);
776 TRACE("%p - ref %d\n", This, ref);
778 return ref;
781 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
783 MREImpl *This = impl_from_ISynchronize(iface);
784 LONG ref = InterlockedDecrement(&This->ref);
785 TRACE("%p - ref %d\n", This, ref);
787 if(!ref)
789 CloseHandle(This->event);
790 HeapFree(GetProcessHeap(), 0, This);
793 return ref;
796 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
798 MREImpl *This = impl_from_ISynchronize(iface);
799 UINT index;
800 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
801 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
804 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
806 MREImpl *This = impl_from_ISynchronize(iface);
807 TRACE("%p\n", This);
808 SetEvent(This->event);
809 return S_OK;
812 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
814 MREImpl *This = impl_from_ISynchronize(iface);
815 TRACE("%p\n", This);
816 ResetEvent(This->event);
817 return S_OK;
820 static ISynchronizeVtbl vt_ISynchronize = {
821 ISynchronize_fnQueryInterface,
822 ISynchronize_fnAddRef,
823 ISynchronize_fnRelease,
824 ISynchronize_fnWait,
825 ISynchronize_fnSignal,
826 ISynchronize_fnReset
829 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
831 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
834 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
836 MREImpl *This = impl_from_ISynchronizeHandle(iface);
837 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
840 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
842 MREImpl *This = impl_from_ISynchronizeHandle(iface);
843 return ISynchronize_AddRef(&This->ISynchronize_iface);
846 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
848 MREImpl *This = impl_from_ISynchronizeHandle(iface);
849 return ISynchronize_Release(&This->ISynchronize_iface);
852 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
854 MREImpl *This = impl_from_ISynchronizeHandle(iface);
856 *ph = This->event;
857 return S_OK;
860 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
861 SynchronizeHandle_QueryInterface,
862 SynchronizeHandle_AddRef,
863 SynchronizeHandle_Release,
864 SynchronizeHandle_GetHandle
867 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
869 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
870 HRESULT hr;
872 if(punkouter)
873 FIXME("Aggregation not implemented.\n");
875 This->ref = 1;
876 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
877 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
878 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
880 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
881 ISynchronize_Release(&This->ISynchronize_iface);
882 return hr;
885 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
887 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
890 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
892 LocalServer *This = impl_from_IServiceProvider(iface);
894 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
896 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
897 *ppv = &This->IServiceProvider_iface;
898 }else {
899 *ppv = NULL;
900 return E_NOINTERFACE;
903 IUnknown_AddRef((IUnknown*)*ppv);
904 return S_OK;
907 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
909 LocalServer *This = impl_from_IServiceProvider(iface);
910 LONG ref = InterlockedIncrement(&This->ref);
912 TRACE("(%p) ref=%d\n", This, ref);
914 return ref;
917 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
919 LocalServer *This = impl_from_IServiceProvider(iface);
920 LONG ref = InterlockedDecrement(&This->ref);
922 TRACE("(%p) ref=%d\n", This, ref);
924 if(!ref) {
925 assert(!This->apt);
926 HeapFree(GetProcessHeap(), 0, This);
929 return ref;
932 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
934 LocalServer *This = impl_from_IServiceProvider(iface);
935 APARTMENT *apt = COM_CurrentApt();
936 RegisteredClass *iter;
937 HRESULT hres = E_FAIL;
939 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
941 if(!This->apt)
942 return E_UNEXPECTED;
944 EnterCriticalSection(&csRegisteredClassList);
946 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
947 if(iter->apartment_id == apt->oxid
948 && (iter->runContext & CLSCTX_LOCAL_SERVER)
949 && IsEqualGUID(&iter->classIdentifier, guid)) {
950 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
951 break;
955 LeaveCriticalSection( &csRegisteredClassList );
957 return hres;
960 static const IServiceProviderVtbl LocalServerVtbl = {
961 LocalServer_QueryInterface,
962 LocalServer_AddRef,
963 LocalServer_Release,
964 LocalServer_QueryService
967 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
969 HRESULT hres = S_OK;
971 EnterCriticalSection(&apt->cs);
973 if(!apt->local_server) {
974 LocalServer *obj;
976 obj = heap_alloc(sizeof(*obj));
977 if(obj) {
978 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
979 obj->ref = 1;
980 obj->apt = apt;
982 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
983 if(SUCCEEDED(hres)) {
984 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
985 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
986 if(FAILED(hres))
987 IStream_Release(obj->marshal_stream);
990 if(SUCCEEDED(hres))
991 apt->local_server = obj;
992 else
993 heap_free(obj);
994 }else {
995 hres = E_OUTOFMEMORY;
999 if(SUCCEEDED(hres))
1000 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1002 LeaveCriticalSection(&apt->cs);
1004 if(FAILED(hres))
1005 ERR("Failed: %08x\n", hres);
1006 return hres;
1009 /***********************************************************************
1010 * CoRevokeClassObject [OLE32.@]
1012 * Removes a class object from the class registry.
1014 * PARAMS
1015 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1017 * RETURNS
1018 * Success: S_OK.
1019 * Failure: HRESULT code.
1021 * NOTES
1022 * Must be called from the same apartment that called CoRegisterClassObject(),
1023 * otherwise it will fail with RPC_E_WRONG_THREAD.
1025 * SEE ALSO
1026 * CoRegisterClassObject
1028 HRESULT WINAPI CoRevokeClassObject(
1029 DWORD dwRegister)
1031 HRESULT hr = E_INVALIDARG;
1032 RegisteredClass *curClass;
1033 APARTMENT *apt;
1035 TRACE("(%08x)\n",dwRegister);
1037 apt = COM_CurrentApt();
1038 if (!apt)
1040 ERR("COM was not initialized\n");
1041 return CO_E_NOTINITIALIZED;
1044 EnterCriticalSection( &csRegisteredClassList );
1046 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1049 * Check if we have a match on the cookie.
1051 if (curClass->dwCookie == dwRegister)
1053 if (curClass->apartment_id == apt->oxid)
1055 COM_RevokeRegisteredClassObject(curClass);
1056 hr = S_OK;
1058 else
1060 ERR("called from wrong apartment, should be called from %s\n",
1061 wine_dbgstr_longlong(curClass->apartment_id));
1062 hr = RPC_E_WRONG_THREAD;
1064 break;
1068 LeaveCriticalSection( &csRegisteredClassList );
1070 return hr;
1073 /* frees unused libraries loaded by apartment_getclassobject by calling the
1074 * DLL's DllCanUnloadNow entry point */
1075 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1077 struct apartment_loaded_dll *entry, *next;
1078 EnterCriticalSection(&apt->cs);
1079 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1081 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1083 DWORD real_delay = delay;
1085 if (real_delay == INFINITE)
1087 /* DLLs that return multi-threaded objects aren't unloaded
1088 * straight away to cope for programs that have races between
1089 * last object destruction and threads in the DLLs that haven't
1090 * finished, despite DllCanUnloadNow returning S_OK */
1091 if (entry->multi_threaded)
1092 real_delay = 10 * 60 * 1000; /* 10 minutes */
1093 else
1094 real_delay = 0;
1097 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1099 list_remove(&entry->entry);
1100 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1101 HeapFree(GetProcessHeap(), 0, entry);
1103 else
1105 entry->unload_time = GetTickCount() + real_delay;
1106 if (!entry->unload_time) entry->unload_time = 1;
1109 else if (entry->unload_time)
1110 entry->unload_time = 0;
1112 LeaveCriticalSection(&apt->cs);
1115 DWORD apartment_release(struct apartment *apt)
1117 DWORD ret;
1119 EnterCriticalSection(&csApartment);
1121 ret = InterlockedDecrement(&apt->refs);
1122 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1123 /* destruction stuff that needs to happen under csApartment CS */
1124 if (ret == 0)
1126 if (apt == MTA) MTA = NULL;
1127 else if (apt == MainApartment) MainApartment = NULL;
1128 list_remove(&apt->entry);
1131 LeaveCriticalSection(&csApartment);
1133 if (ret == 0)
1135 struct list *cursor, *cursor2;
1137 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1139 if(apt->local_server) {
1140 LocalServer *local_server = apt->local_server;
1141 LARGE_INTEGER zero;
1143 memset(&zero, 0, sizeof(zero));
1144 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1145 CoReleaseMarshalData(local_server->marshal_stream);
1146 IStream_Release(local_server->marshal_stream);
1147 local_server->marshal_stream = NULL;
1149 apt->local_server = NULL;
1150 local_server->apt = NULL;
1151 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1154 /* Release the references to the registered class objects */
1155 COM_RevokeAllClasses(apt);
1157 /* no locking is needed for this apartment, because no other thread
1158 * can access it at this point */
1160 apartment_disconnectproxies(apt);
1162 if (apt->win) DestroyWindow(apt->win);
1163 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1165 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1167 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1168 /* release the implicit reference given by the fact that the
1169 * stub has external references (it must do since it is in the
1170 * stub manager list in the apartment and all non-apartment users
1171 * must have a ref on the apartment and so it cannot be destroyed).
1173 stub_manager_int_release(stubmgr);
1176 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
1178 struct registered_psclsid *registered_psclsid =
1179 LIST_ENTRY(cursor, struct registered_psclsid, entry);
1181 list_remove(&registered_psclsid->entry);
1182 HeapFree(GetProcessHeap(), 0, registered_psclsid);
1185 /* if this assert fires, then another thread took a reference to a
1186 * stub manager without taking a reference to the containing
1187 * apartment, which it must do. */
1188 assert(list_empty(&apt->stubmgrs));
1190 if (apt->filter) IMessageFilter_Release(apt->filter);
1192 /* free as many unused libraries as possible... */
1193 apartment_freeunusedlibraries(apt, 0);
1195 /* ... and free the memory for the apartment loaded dll entry and
1196 * release the dll list reference without freeing the library for the
1197 * rest */
1198 while ((cursor = list_head(&apt->loaded_dlls)))
1200 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1201 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1202 list_remove(cursor);
1203 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1206 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1207 DeleteCriticalSection(&apt->cs);
1209 HeapFree(GetProcessHeap(), 0, apt);
1212 return ret;
1215 /* The given OXID must be local to this process:
1217 * The ref parameter is here mostly to ensure people remember that
1218 * they get one, you should normally take a ref for thread safety.
1220 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1222 APARTMENT *result = NULL;
1223 struct list *cursor;
1225 EnterCriticalSection(&csApartment);
1226 LIST_FOR_EACH( cursor, &apts )
1228 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1229 if (apt->oxid == oxid)
1231 result = apt;
1232 if (ref) apartment_addref(result);
1233 break;
1236 LeaveCriticalSection(&csApartment);
1238 return result;
1241 /* gets the apartment which has a given creator thread ID. The caller must
1242 * release the reference from the apartment as soon as the apartment pointer
1243 * is no longer required. */
1244 APARTMENT *apartment_findfromtid(DWORD tid)
1246 APARTMENT *result = NULL;
1247 struct list *cursor;
1249 EnterCriticalSection(&csApartment);
1250 LIST_FOR_EACH( cursor, &apts )
1252 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1253 if (apt->tid == tid)
1255 result = apt;
1256 apartment_addref(result);
1257 break;
1260 LeaveCriticalSection(&csApartment);
1262 return result;
1265 /* gets the main apartment if it exists. The caller must
1266 * release the reference from the apartment as soon as the apartment pointer
1267 * is no longer required. */
1268 static APARTMENT *apartment_findmain(void)
1270 APARTMENT *result;
1272 EnterCriticalSection(&csApartment);
1274 result = MainApartment;
1275 if (result) apartment_addref(result);
1277 LeaveCriticalSection(&csApartment);
1279 return result;
1282 /* gets the multi-threaded apartment if it exists. The caller must
1283 * release the reference from the apartment as soon as the apartment pointer
1284 * is no longer required. */
1285 static APARTMENT *apartment_find_multi_threaded(void)
1287 APARTMENT *result = NULL;
1288 struct list *cursor;
1290 EnterCriticalSection(&csApartment);
1292 LIST_FOR_EACH( cursor, &apts )
1294 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1295 if (apt->multi_threaded)
1297 result = apt;
1298 apartment_addref(result);
1299 break;
1303 LeaveCriticalSection(&csApartment);
1304 return result;
1307 /* gets the specified class object by loading the appropriate DLL, if
1308 * necessary and calls the DllGetClassObject function for the DLL */
1309 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1310 BOOL apartment_threaded,
1311 REFCLSID rclsid, REFIID riid, void **ppv)
1313 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1314 HRESULT hr = S_OK;
1315 BOOL found = FALSE;
1316 struct apartment_loaded_dll *apartment_loaded_dll;
1318 if (!strcmpiW(dllpath, wszOle32))
1320 /* we don't need to control the lifetime of this dll, so use the local
1321 * implementation of DllGetClassObject directly */
1322 TRACE("calling ole32!DllGetClassObject\n");
1323 hr = DllGetClassObject(rclsid, riid, ppv);
1325 if (hr != S_OK)
1326 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1328 return hr;
1331 EnterCriticalSection(&apt->cs);
1333 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1334 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1336 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1337 found = TRUE;
1338 break;
1341 if (!found)
1343 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1344 if (!apartment_loaded_dll)
1345 hr = E_OUTOFMEMORY;
1346 if (SUCCEEDED(hr))
1348 apartment_loaded_dll->unload_time = 0;
1349 apartment_loaded_dll->multi_threaded = FALSE;
1350 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1351 if (FAILED(hr))
1352 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1354 if (SUCCEEDED(hr))
1356 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1357 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1361 LeaveCriticalSection(&apt->cs);
1363 if (SUCCEEDED(hr))
1365 /* one component being multi-threaded overrides any number of
1366 * apartment-threaded components */
1367 if (!apartment_threaded)
1368 apartment_loaded_dll->multi_threaded = TRUE;
1370 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1371 /* OK: get the ClassObject */
1372 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1374 if (hr != S_OK)
1375 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1378 return hr;
1381 /***********************************************************************
1382 * COM_RegReadPath [internal]
1384 * Reads a registry value and expands it when necessary
1386 static DWORD COM_RegReadPath(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1388 DWORD ret;
1390 if (regdata->hkey)
1392 DWORD keytype;
1393 WCHAR src[MAX_PATH];
1394 DWORD dwLength = dstlen * sizeof(WCHAR);
1396 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1397 if (keytype == REG_EXPAND_SZ) {
1398 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1399 } else {
1400 const WCHAR *quote_start;
1401 quote_start = strchrW(src, '\"');
1402 if (quote_start) {
1403 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1404 if (quote_end) {
1405 memmove(src, quote_start + 1,
1406 (quote_end - quote_start - 1) * sizeof(WCHAR));
1407 src[quote_end - quote_start - 1] = '\0';
1410 lstrcpynW(dst, src, dstlen);
1413 return ret;
1415 else
1417 ULONG_PTR cookie;
1418 WCHAR *nameW;
1420 *dst = 0;
1421 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1422 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1423 ret = SearchPathW(NULL, nameW, NULL, dstlen, dst, NULL);
1424 DeactivateActCtx(0, cookie);
1425 return !*dst;
1429 struct host_object_params
1431 struct class_reg_data regdata;
1432 CLSID clsid; /* clsid of object to marshal */
1433 IID iid; /* interface to marshal */
1434 HANDLE event; /* event signalling when ready for multi-threaded case */
1435 HRESULT hr; /* result for multi-threaded case */
1436 IStream *stream; /* stream that the object will be marshaled into */
1437 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1440 static HRESULT apartment_hostobject(struct apartment *apt,
1441 const struct host_object_params *params)
1443 IUnknown *object;
1444 HRESULT hr;
1445 static const LARGE_INTEGER llZero;
1446 WCHAR dllpath[MAX_PATH+1];
1448 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1450 if (COM_RegReadPath(&params->regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1452 /* failure: CLSID is not found in registry */
1453 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1454 return REGDB_E_CLASSNOTREG;
1457 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1458 &params->clsid, &params->iid, (void **)&object);
1459 if (FAILED(hr))
1460 return hr;
1462 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1463 if (FAILED(hr))
1464 IUnknown_Release(object);
1465 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1467 return hr;
1470 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1472 switch (msg)
1474 case DM_EXECUTERPC:
1475 RPC_ExecuteCall((struct dispatch_params *)lParam);
1476 return 0;
1477 case DM_HOSTOBJECT:
1478 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1479 default:
1480 return DefWindowProcW(hWnd, msg, wParam, lParam);
1484 struct host_thread_params
1486 COINIT threading_model;
1487 HANDLE ready_event;
1488 HWND apartment_hwnd;
1491 /* thread for hosting an object to allow an object to appear to be created in
1492 * an apartment with an incompatible threading model */
1493 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1495 struct host_thread_params *params = p;
1496 MSG msg;
1497 HRESULT hr;
1498 struct apartment *apt;
1500 TRACE("\n");
1502 hr = CoInitializeEx(NULL, params->threading_model);
1503 if (FAILED(hr)) return hr;
1505 apt = COM_CurrentApt();
1506 if (params->threading_model == COINIT_APARTMENTTHREADED)
1508 apartment_createwindowifneeded(apt);
1509 params->apartment_hwnd = apartment_getwindow(apt);
1511 else
1512 params->apartment_hwnd = NULL;
1514 /* force the message queue to be created before signaling parent thread */
1515 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1517 SetEvent(params->ready_event);
1518 params = NULL; /* can't touch params after here as it may be invalid */
1520 while (GetMessageW(&msg, NULL, 0, 0))
1522 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1524 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1525 obj_params->hr = apartment_hostobject(apt, obj_params);
1526 SetEvent(obj_params->event);
1528 else
1530 TranslateMessage(&msg);
1531 DispatchMessageW(&msg);
1535 TRACE("exiting\n");
1537 CoUninitialize();
1539 return S_OK;
1542 /* finds or creates a host apartment, creates the object inside it and returns
1543 * a proxy to it so that the object can be used in the apartment of the
1544 * caller of this function */
1545 static HRESULT apartment_hostobject_in_hostapt(
1546 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1547 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1549 struct host_object_params params;
1550 HWND apartment_hwnd = NULL;
1551 DWORD apartment_tid = 0;
1552 HRESULT hr;
1554 if (!multi_threaded && main_apartment)
1556 APARTMENT *host_apt = apartment_findmain();
1557 if (host_apt)
1559 apartment_hwnd = apartment_getwindow(host_apt);
1560 apartment_release(host_apt);
1564 if (!apartment_hwnd)
1566 EnterCriticalSection(&apt->cs);
1568 if (!apt->host_apt_tid)
1570 struct host_thread_params thread_params;
1571 HANDLE handles[2];
1572 DWORD wait_value;
1574 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1575 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1576 thread_params.apartment_hwnd = NULL;
1577 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1578 if (!handles[1])
1580 CloseHandle(handles[0]);
1581 LeaveCriticalSection(&apt->cs);
1582 return E_OUTOFMEMORY;
1584 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1585 CloseHandle(handles[0]);
1586 CloseHandle(handles[1]);
1587 if (wait_value == WAIT_OBJECT_0)
1588 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1589 else
1591 LeaveCriticalSection(&apt->cs);
1592 return E_OUTOFMEMORY;
1596 if (multi_threaded || !main_apartment)
1598 apartment_hwnd = apt->host_apt_hwnd;
1599 apartment_tid = apt->host_apt_tid;
1602 LeaveCriticalSection(&apt->cs);
1605 /* another thread may have become the main apartment in the time it took
1606 * us to create the thread for the host apartment */
1607 if (!apartment_hwnd && !multi_threaded && main_apartment)
1609 APARTMENT *host_apt = apartment_findmain();
1610 if (host_apt)
1612 apartment_hwnd = apartment_getwindow(host_apt);
1613 apartment_release(host_apt);
1617 params.regdata = *regdata;
1618 params.clsid = *rclsid;
1619 params.iid = *riid;
1620 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1621 if (FAILED(hr))
1622 return hr;
1623 params.apartment_threaded = !multi_threaded;
1624 if (multi_threaded)
1626 params.hr = S_OK;
1627 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1628 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1629 hr = E_OUTOFMEMORY;
1630 else
1632 WaitForSingleObject(params.event, INFINITE);
1633 hr = params.hr;
1635 CloseHandle(params.event);
1637 else
1639 if (!apartment_hwnd)
1641 ERR("host apartment didn't create window\n");
1642 hr = E_OUTOFMEMORY;
1644 else
1645 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1647 if (SUCCEEDED(hr))
1648 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1649 IStream_Release(params.stream);
1650 return hr;
1653 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1655 WNDCLASSW wclass;
1657 /* Dispatching to the correct thread in an apartment is done through
1658 * window messages rather than RPC transports. When an interface is
1659 * marshalled into another apartment in the same process, a window of the
1660 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1661 * application) is responsible for pumping the message loop in that thread.
1662 * The WM_USER messages which point to the RPCs are then dispatched to
1663 * apartment_wndproc by the user's code from the apartment in which the
1664 * interface was unmarshalled.
1666 memset(&wclass, 0, sizeof(wclass));
1667 wclass.lpfnWndProc = apartment_wndproc;
1668 wclass.hInstance = hProxyDll;
1669 wclass.lpszClassName = wszAptWinClass;
1670 RegisterClassW(&wclass);
1671 return TRUE;
1674 /* create a window for the apartment or return the current one if one has
1675 * already been created */
1676 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1678 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1680 if (apt->multi_threaded)
1681 return S_OK;
1683 if (!apt->win)
1685 HWND hwnd;
1687 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1689 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1690 HWND_MESSAGE, 0, hProxyDll, NULL);
1691 if (!hwnd)
1693 ERR("CreateWindow failed with error %d\n", GetLastError());
1694 return HRESULT_FROM_WIN32(GetLastError());
1696 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1697 /* someone beat us to it */
1698 DestroyWindow(hwnd);
1701 return S_OK;
1704 /* retrieves the window for the main- or apartment-threaded apartment */
1705 HWND apartment_getwindow(const struct apartment *apt)
1707 assert(!apt->multi_threaded);
1708 return apt->win;
1711 void apartment_joinmta(void)
1713 apartment_addref(MTA);
1714 COM_CurrentInfo()->apt = MTA;
1717 static void COM_TlsDestroy(void)
1719 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1720 if (info)
1722 if (info->apt) apartment_release(info->apt);
1723 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1724 if (info->state) IUnknown_Release(info->state);
1725 if (info->spy) IInitializeSpy_Release(info->spy);
1726 if (info->context_token) IObjContext_Release(info->context_token);
1727 HeapFree(GetProcessHeap(), 0, info);
1728 NtCurrentTeb()->ReservedForOle = NULL;
1732 /******************************************************************************
1733 * CoBuildVersion [OLE32.@]
1735 * Gets the build version of the DLL.
1737 * PARAMS
1739 * RETURNS
1740 * Current build version, hiword is majornumber, loword is minornumber
1742 DWORD WINAPI CoBuildVersion(void)
1744 TRACE("Returning version %d, build %d.\n", rmm, rup);
1745 return (rmm<<16)+rup;
1748 /******************************************************************************
1749 * CoRegisterInitializeSpy [OLE32.@]
1751 * Add a Spy that watches CoInitializeEx calls
1753 * PARAMS
1754 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1755 * cookie [II] cookie receiver
1757 * RETURNS
1758 * Success: S_OK if not already initialized, S_FALSE otherwise.
1759 * Failure: HRESULT code.
1761 * SEE ALSO
1762 * CoInitializeEx
1764 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1766 struct oletls *info = COM_CurrentInfo();
1767 HRESULT hr;
1769 TRACE("(%p, %p)\n", spy, cookie);
1771 if (!spy || !cookie || !info)
1773 if (!info)
1774 WARN("Could not allocate tls\n");
1775 return E_INVALIDARG;
1778 if (info->spy)
1780 FIXME("Already registered?\n");
1781 return E_UNEXPECTED;
1784 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1785 if (SUCCEEDED(hr))
1787 cookie->QuadPart = (DWORD_PTR)spy;
1788 return S_OK;
1790 return hr;
1793 /******************************************************************************
1794 * CoRevokeInitializeSpy [OLE32.@]
1796 * Remove a spy that previously watched CoInitializeEx calls
1798 * PARAMS
1799 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1801 * RETURNS
1802 * Success: S_OK if a spy is removed
1803 * Failure: E_INVALIDARG
1805 * SEE ALSO
1806 * CoInitializeEx
1808 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1810 struct oletls *info = COM_CurrentInfo();
1811 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1813 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1814 return E_INVALIDARG;
1816 IInitializeSpy_Release(info->spy);
1817 info->spy = NULL;
1818 return S_OK;
1822 /******************************************************************************
1823 * CoInitialize [OLE32.@]
1825 * Initializes the COM libraries by calling CoInitializeEx with
1826 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1828 * PARAMS
1829 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1831 * RETURNS
1832 * Success: S_OK if not already initialized, S_FALSE otherwise.
1833 * Failure: HRESULT code.
1835 * SEE ALSO
1836 * CoInitializeEx
1838 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1841 * Just delegate to the newer method.
1843 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1846 /******************************************************************************
1847 * CoInitializeEx [OLE32.@]
1849 * Initializes the COM libraries.
1851 * PARAMS
1852 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1853 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1855 * RETURNS
1856 * S_OK if successful,
1857 * S_FALSE if this function was called already.
1858 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1859 * threading model.
1861 * NOTES
1863 * The behavior used to set the IMalloc used for memory management is
1864 * obsolete.
1865 * The dwCoInit parameter must specify one of the following apartment
1866 * threading models:
1867 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1868 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1869 * The parameter may also specify zero or more of the following flags:
1870 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1871 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1873 * SEE ALSO
1874 * CoUninitialize
1876 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1878 struct oletls *info = COM_CurrentInfo();
1879 HRESULT hr = S_OK;
1880 APARTMENT *apt;
1882 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1884 if (lpReserved!=NULL)
1886 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1890 * Check the lock count. If this is the first time going through the initialize
1891 * process, we have to initialize the libraries.
1893 * And crank-up that lock count.
1895 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1898 * Initialize the various COM libraries and data structures.
1900 TRACE("() - Initializing the COM libraries\n");
1902 /* we may need to defer this until after apartment initialisation */
1903 RunningObjectTableImpl_Initialize();
1906 if (info->spy)
1907 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1909 if (!(apt = info->apt))
1911 apt = apartment_get_or_create(dwCoInit);
1912 if (!apt) return E_OUTOFMEMORY;
1914 else if (!apartment_is_model(apt, dwCoInit))
1916 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1917 code then we are probably using the wrong threading model to implement that API. */
1918 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1919 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1920 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1921 return RPC_E_CHANGED_MODE;
1923 else
1924 hr = S_FALSE;
1926 info->inits++;
1928 if (info->spy)
1929 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1931 return hr;
1934 /***********************************************************************
1935 * CoUninitialize [OLE32.@]
1937 * This method will decrement the refcount on the current apartment, freeing
1938 * the resources associated with it if it is the last thread in the apartment.
1939 * If the last apartment is freed, the function will additionally release
1940 * any COM resources associated with the process.
1942 * PARAMS
1944 * RETURNS
1945 * Nothing.
1947 * SEE ALSO
1948 * CoInitializeEx
1950 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
1952 struct oletls * info = COM_CurrentInfo();
1953 LONG lCOMRefCnt;
1955 TRACE("()\n");
1957 /* will only happen on OOM */
1958 if (!info) return;
1960 if (info->spy)
1961 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1963 /* sanity check */
1964 if (!info->inits)
1966 ERR("Mismatched CoUninitialize\n");
1968 if (info->spy)
1969 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1970 return;
1973 if (!--info->inits)
1975 apartment_release(info->apt);
1976 info->apt = NULL;
1980 * Decrease the reference count.
1981 * If we are back to 0 locks on the COM library, make sure we free
1982 * all the associated data structures.
1984 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1985 if (lCOMRefCnt==1)
1987 TRACE("() - Releasing the COM libraries\n");
1989 RunningObjectTableImpl_UnInitialize();
1991 else if (lCOMRefCnt<1) {
1992 ERR( "CoUninitialize() - not CoInitialized.\n" );
1993 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1995 if (info->spy)
1996 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1999 /******************************************************************************
2000 * CoDisconnectObject [OLE32.@]
2002 * Disconnects all connections to this object from remote processes. Dispatches
2003 * pending RPCs while blocking new RPCs from occurring, and then calls
2004 * IMarshal::DisconnectObject on the given object.
2006 * Typically called when the object server is forced to shut down, for instance by
2007 * the user.
2009 * PARAMS
2010 * lpUnk [I] The object whose stub should be disconnected.
2011 * reserved [I] Reserved. Should be set to 0.
2013 * RETURNS
2014 * Success: S_OK.
2015 * Failure: HRESULT code.
2017 * SEE ALSO
2018 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2020 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2022 HRESULT hr;
2023 IMarshal *marshal;
2024 APARTMENT *apt;
2026 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2028 if (!lpUnk) return E_INVALIDARG;
2030 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2031 if (hr == S_OK)
2033 hr = IMarshal_DisconnectObject(marshal, reserved);
2034 IMarshal_Release(marshal);
2035 return hr;
2038 apt = COM_CurrentApt();
2039 if (!apt)
2040 return CO_E_NOTINITIALIZED;
2042 apartment_disconnectobject(apt, lpUnk);
2044 /* Note: native is pretty broken here because it just silently
2045 * fails, without returning an appropriate error code if the object was
2046 * not found, making apps think that the object was disconnected, when
2047 * it actually wasn't */
2049 return S_OK;
2052 /******************************************************************************
2053 * CoCreateGuid [OLE32.@]
2055 * Simply forwards to UuidCreate in RPCRT4.
2057 * PARAMS
2058 * pguid [O] Points to the GUID to initialize.
2060 * RETURNS
2061 * Success: S_OK.
2062 * Failure: HRESULT code.
2064 * SEE ALSO
2065 * UuidCreate
2067 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2069 DWORD status;
2071 if(!pguid) return E_INVALIDARG;
2073 status = UuidCreate(pguid);
2074 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2075 return HRESULT_FROM_WIN32( status );
2078 static inline BOOL is_valid_hex(WCHAR c)
2080 if (!(((c >= '0') && (c <= '9')) ||
2081 ((c >= 'a') && (c <= 'f')) ||
2082 ((c >= 'A') && (c <= 'F'))))
2083 return FALSE;
2084 return TRUE;
2087 static const BYTE guid_conv_table[256] =
2089 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2090 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2091 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2092 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2093 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2094 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2095 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2098 /* conversion helper for CLSIDFromString/IIDFromString */
2099 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2101 int i;
2103 if (!s || s[0]!='{') {
2104 memset( id, 0, sizeof (CLSID) );
2105 if(!s) return TRUE;
2106 return FALSE;
2109 TRACE("%s -> %p\n", debugstr_w(s), id);
2111 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2113 id->Data1 = 0;
2114 for (i = 1; i < 9; i++) {
2115 if (!is_valid_hex(s[i])) return FALSE;
2116 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2118 if (s[9]!='-') return FALSE;
2120 id->Data2 = 0;
2121 for (i = 10; i < 14; i++) {
2122 if (!is_valid_hex(s[i])) return FALSE;
2123 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2125 if (s[14]!='-') return FALSE;
2127 id->Data3 = 0;
2128 for (i = 15; i < 19; i++) {
2129 if (!is_valid_hex(s[i])) return FALSE;
2130 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2132 if (s[19]!='-') return FALSE;
2134 for (i = 20; i < 37; i+=2) {
2135 if (i == 24) {
2136 if (s[i]!='-') return FALSE;
2137 i++;
2139 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2140 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2143 if (s[37] == '}' && s[38] == '\0')
2144 return TRUE;
2146 return FALSE;
2149 /*****************************************************************************/
2151 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2153 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2154 WCHAR buf2[CHARS_IN_GUID];
2155 LONG buf2len = sizeof(buf2);
2156 HKEY xhkey;
2157 WCHAR *buf;
2159 memset(clsid, 0, sizeof(*clsid));
2160 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2161 if (!buf) return E_OUTOFMEMORY;
2162 strcpyW( buf, progid );
2163 strcatW( buf, clsidW );
2164 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2166 HeapFree(GetProcessHeap(),0,buf);
2167 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2168 return CO_E_CLASSSTRING;
2170 HeapFree(GetProcessHeap(),0,buf);
2172 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2174 RegCloseKey(xhkey);
2175 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2176 return CO_E_CLASSSTRING;
2178 RegCloseKey(xhkey);
2179 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2182 /******************************************************************************
2183 * CLSIDFromString [OLE32.@]
2185 * Converts a unique identifier from its string representation into
2186 * the GUID struct.
2188 * PARAMS
2189 * idstr [I] The string representation of the GUID.
2190 * id [O] GUID converted from the string.
2192 * RETURNS
2193 * S_OK on success
2194 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2196 * SEE ALSO
2197 * StringFromCLSID
2199 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2201 HRESULT ret = CO_E_CLASSSTRING;
2202 CLSID tmp_id;
2204 if (!id)
2205 return E_INVALIDARG;
2207 if (guid_from_string(idstr, id))
2208 return S_OK;
2210 /* It appears a ProgID is also valid */
2211 ret = clsid_from_string_reg(idstr, &tmp_id);
2212 if(SUCCEEDED(ret))
2213 *id = tmp_id;
2215 return ret;
2218 /******************************************************************************
2219 * IIDFromString [OLE32.@]
2221 * Converts a interface identifier from its string representation into
2222 * the IID struct.
2224 * PARAMS
2225 * idstr [I] The string representation of the GUID.
2226 * id [O] IID converted from the string.
2228 * RETURNS
2229 * S_OK on success
2230 * CO_E_IIDSTRING if idstr is not a valid IID
2232 * SEE ALSO
2233 * StringFromIID
2235 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2237 TRACE("%s -> %p\n", debugstr_w(s), iid);
2239 if (!s)
2241 memset(iid, 0, sizeof(*iid));
2242 return S_OK;
2245 /* length mismatch is a special case */
2246 if (strlenW(s) + 1 != CHARS_IN_GUID)
2247 return E_INVALIDARG;
2249 if (s[0] != '{')
2250 return CO_E_IIDSTRING;
2252 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2255 /******************************************************************************
2256 * StringFromCLSID [OLE32.@]
2257 * StringFromIID [OLE32.@]
2259 * Converts a GUID into the respective string representation.
2260 * The target string is allocated using the OLE IMalloc.
2262 * PARAMS
2263 * id [I] the GUID to be converted.
2264 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2266 * RETURNS
2267 * S_OK
2268 * E_FAIL
2270 * SEE ALSO
2271 * StringFromGUID2, CLSIDFromString
2273 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2275 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2276 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2277 return S_OK;
2280 /******************************************************************************
2281 * StringFromGUID2 [OLE32.@]
2283 * Modified version of StringFromCLSID that allows you to specify max
2284 * buffer size.
2286 * PARAMS
2287 * id [I] GUID to convert to string.
2288 * str [O] Buffer where the result will be stored.
2289 * cmax [I] Size of the buffer in characters.
2291 * RETURNS
2292 * Success: The length of the resulting string in characters.
2293 * Failure: 0.
2295 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2297 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2298 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2299 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2300 '%','0','2','X','%','0','2','X','}',0 };
2301 if (!id || cmax < CHARS_IN_GUID) return 0;
2302 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2303 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2304 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2305 return CHARS_IN_GUID;
2308 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2309 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2311 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2312 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2313 LONG res;
2314 HKEY key;
2316 strcpyW(path, wszCLSIDSlash);
2317 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2318 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2319 if (res == ERROR_FILE_NOT_FOUND)
2320 return REGDB_E_CLASSNOTREG;
2321 else if (res != ERROR_SUCCESS)
2322 return REGDB_E_READREGDB;
2324 if (!keyname)
2326 *subkey = key;
2327 return S_OK;
2330 res = open_classes_key(key, keyname, access, subkey);
2331 RegCloseKey(key);
2332 if (res == ERROR_FILE_NOT_FOUND)
2333 return REGDB_E_KEYMISSING;
2334 else if (res != ERROR_SUCCESS)
2335 return REGDB_E_READREGDB;
2337 return S_OK;
2340 /* open HKCR\\AppId\\{string form of appid clsid} key */
2341 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2343 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2344 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2345 DWORD res;
2346 WCHAR buf[CHARS_IN_GUID];
2347 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2348 DWORD size;
2349 HKEY hkey;
2350 DWORD type;
2351 HRESULT hr;
2353 /* read the AppID value under the class's key */
2354 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2355 if (FAILED(hr))
2356 return hr;
2358 size = sizeof(buf);
2359 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2360 RegCloseKey(hkey);
2361 if (res == ERROR_FILE_NOT_FOUND)
2362 return REGDB_E_KEYMISSING;
2363 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2364 return REGDB_E_READREGDB;
2366 strcpyW(keyname, szAppIdKey);
2367 strcatW(keyname, buf);
2368 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2369 if (res == ERROR_FILE_NOT_FOUND)
2370 return REGDB_E_KEYMISSING;
2371 else if (res != ERROR_SUCCESS)
2372 return REGDB_E_READREGDB;
2374 return S_OK;
2377 /******************************************************************************
2378 * ProgIDFromCLSID [OLE32.@]
2380 * Converts a class id into the respective program ID.
2382 * PARAMS
2383 * clsid [I] Class ID, as found in registry.
2384 * ppszProgID [O] Associated ProgID.
2386 * RETURNS
2387 * S_OK
2388 * E_OUTOFMEMORY
2389 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2391 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2393 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2394 ACTCTX_SECTION_KEYED_DATA data;
2395 HKEY hkey;
2396 HRESULT ret;
2397 LONG progidlen = 0;
2399 if (!ppszProgID)
2400 return E_INVALIDARG;
2402 *ppszProgID = NULL;
2404 data.cbSize = sizeof(data);
2405 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2406 clsid, &data))
2408 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2409 if (comclass->progid_len)
2411 WCHAR *ptrW;
2413 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2414 if (!*ppszProgID) return E_OUTOFMEMORY;
2416 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2417 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2418 return S_OK;
2420 else
2421 return REGDB_E_CLASSNOTREG;
2424 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2425 if (FAILED(ret))
2426 return ret;
2428 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2429 ret = REGDB_E_CLASSNOTREG;
2431 if (ret == S_OK)
2433 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2434 if (*ppszProgID)
2436 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2437 ret = REGDB_E_CLASSNOTREG;
2438 CoTaskMemFree(*ppszProgID);
2439 *ppszProgID = NULL;
2442 else
2443 ret = E_OUTOFMEMORY;
2446 RegCloseKey(hkey);
2447 return ret;
2450 /******************************************************************************
2451 * CLSIDFromProgID [OLE32.@]
2453 * Converts a program id into the respective GUID.
2455 * PARAMS
2456 * progid [I] Unicode program ID, as found in registry.
2457 * clsid [O] Associated CLSID.
2459 * RETURNS
2460 * Success: S_OK
2461 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2463 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2465 ACTCTX_SECTION_KEYED_DATA data;
2467 if (!progid || !clsid)
2468 return E_INVALIDARG;
2470 data.cbSize = sizeof(data);
2471 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2472 progid, &data))
2474 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2475 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2476 *clsid = *alias;
2477 return S_OK;
2480 return clsid_from_string_reg(progid, clsid);
2483 /******************************************************************************
2484 * CLSIDFromProgIDEx [OLE32.@]
2486 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2488 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2490 return CLSIDFromProgID(progid, clsid);
2493 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2495 HKEY hkey;
2496 WCHAR value[CHARS_IN_GUID];
2497 DWORD len;
2499 access |= KEY_READ;
2501 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2502 return REGDB_E_IIDNOTREG;
2504 len = sizeof(value);
2505 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2506 return REGDB_E_IIDNOTREG;
2507 RegCloseKey(hkey);
2509 if (CLSIDFromString(value, pclsid) != NOERROR)
2510 return REGDB_E_IIDNOTREG;
2512 return S_OK;
2515 /*****************************************************************************
2516 * CoGetPSClsid [OLE32.@]
2518 * Retrieves the CLSID of the proxy/stub factory that implements
2519 * IPSFactoryBuffer for the specified interface.
2521 * PARAMS
2522 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2523 * pclsid [O] Where to store returned proxy/stub CLSID.
2525 * RETURNS
2526 * S_OK
2527 * E_OUTOFMEMORY
2528 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2530 * NOTES
2532 * The standard marshaller activates the object with the CLSID
2533 * returned and uses the CreateProxy and CreateStub methods on its
2534 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2535 * given object.
2537 * CoGetPSClsid determines this CLSID by searching the
2538 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2539 * in the registry and any interface id registered by
2540 * CoRegisterPSClsid within the current process.
2542 * BUGS
2544 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2545 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2546 * considered a bug in native unless an application depends on this (unlikely).
2548 * SEE ALSO
2549 * CoRegisterPSClsid.
2551 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2553 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2554 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2555 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2556 APARTMENT *apt = COM_CurrentApt();
2557 struct registered_psclsid *registered_psclsid;
2558 ACTCTX_SECTION_KEYED_DATA data;
2559 HRESULT hr;
2560 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2561 BOOL is_wow64;
2563 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2565 if (!apt)
2567 ERR("apartment not initialised\n");
2568 return CO_E_NOTINITIALIZED;
2571 if (!pclsid)
2572 return E_INVALIDARG;
2574 EnterCriticalSection(&apt->cs);
2576 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2577 if (IsEqualIID(&registered_psclsid->iid, riid))
2579 *pclsid = registered_psclsid->clsid;
2580 LeaveCriticalSection(&apt->cs);
2581 return S_OK;
2584 LeaveCriticalSection(&apt->cs);
2586 data.cbSize = sizeof(data);
2587 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2588 riid, &data))
2590 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2591 *pclsid = ifaceps->iid;
2592 return S_OK;
2595 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2596 strcpyW(path, wszInterface);
2597 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2598 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2600 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2601 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2602 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2603 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2605 if (hr == S_OK)
2606 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2607 else
2608 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2610 return hr;
2613 /*****************************************************************************
2614 * CoRegisterPSClsid [OLE32.@]
2616 * Register a proxy/stub CLSID for the given interface in the current process
2617 * only.
2619 * PARAMS
2620 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2621 * rclsid [I] CLSID of the proxy/stub.
2623 * RETURNS
2624 * Success: S_OK
2625 * Failure: E_OUTOFMEMORY
2627 * NOTES
2629 * This function does not add anything to the registry and the effects are
2630 * limited to the lifetime of the current process.
2632 * SEE ALSO
2633 * CoGetPSClsid.
2635 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2637 APARTMENT *apt = COM_CurrentApt();
2638 struct registered_psclsid *registered_psclsid;
2640 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2642 if (!apt)
2644 ERR("apartment not initialised\n");
2645 return CO_E_NOTINITIALIZED;
2648 EnterCriticalSection(&apt->cs);
2650 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2651 if (IsEqualIID(&registered_psclsid->iid, riid))
2653 registered_psclsid->clsid = *rclsid;
2654 LeaveCriticalSection(&apt->cs);
2655 return S_OK;
2658 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2659 if (!registered_psclsid)
2661 LeaveCriticalSection(&apt->cs);
2662 return E_OUTOFMEMORY;
2665 registered_psclsid->iid = *riid;
2666 registered_psclsid->clsid = *rclsid;
2667 list_add_head(&apt->psclsids, &registered_psclsid->entry);
2669 LeaveCriticalSection(&apt->cs);
2671 return S_OK;
2675 /***
2676 * COM_GetRegisteredClassObject
2678 * This internal method is used to scan the registered class list to
2679 * find a class object.
2681 * Params:
2682 * rclsid Class ID of the class to find.
2683 * dwClsContext Class context to match.
2684 * ppv [out] returns a pointer to the class object. Complying
2685 * to normal COM usage, this method will increase the
2686 * reference count on this object.
2688 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2689 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2691 HRESULT hr = S_FALSE;
2692 RegisteredClass *curClass;
2694 EnterCriticalSection( &csRegisteredClassList );
2696 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2699 * Check if we have a match on the class ID and context.
2701 if ((apt->oxid == curClass->apartment_id) &&
2702 (dwClsContext & curClass->runContext) &&
2703 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2706 * We have a match, return the pointer to the class object.
2708 *ppUnk = curClass->classObject;
2710 IUnknown_AddRef(curClass->classObject);
2712 hr = S_OK;
2713 break;
2717 LeaveCriticalSection( &csRegisteredClassList );
2719 return hr;
2722 /******************************************************************************
2723 * CoRegisterClassObject [OLE32.@]
2725 * Registers the class object for a given class ID. Servers housed in EXE
2726 * files use this method instead of exporting DllGetClassObject to allow
2727 * other code to connect to their objects.
2729 * PARAMS
2730 * rclsid [I] CLSID of the object to register.
2731 * pUnk [I] IUnknown of the object.
2732 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2733 * flags [I] REGCLS flags indicating how connections are made.
2734 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2736 * RETURNS
2737 * S_OK on success,
2738 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2739 * CO_E_OBJISREG if the object is already registered. We should not return this.
2741 * SEE ALSO
2742 * CoRevokeClassObject, CoGetClassObject
2744 * NOTES
2745 * In-process objects are only registered for the current apartment.
2746 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2747 * in other apartments.
2749 * BUGS
2750 * MSDN claims that multiple interface registrations are legal, but we
2751 * can't do that with our current implementation.
2753 HRESULT WINAPI CoRegisterClassObject(
2754 REFCLSID rclsid,
2755 LPUNKNOWN pUnk,
2756 DWORD dwClsContext,
2757 DWORD flags,
2758 LPDWORD lpdwRegister)
2760 static LONG next_cookie;
2761 RegisteredClass* newClass;
2762 LPUNKNOWN foundObject;
2763 HRESULT hr;
2764 APARTMENT *apt;
2766 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2767 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2769 if ( (lpdwRegister==0) || (pUnk==0) )
2770 return E_INVALIDARG;
2772 apt = COM_CurrentApt();
2773 if (!apt)
2775 ERR("COM was not initialized\n");
2776 return CO_E_NOTINITIALIZED;
2779 *lpdwRegister = 0;
2781 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2782 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2783 if (flags & REGCLS_MULTIPLEUSE)
2784 dwClsContext |= CLSCTX_INPROC_SERVER;
2787 * First, check if the class is already registered.
2788 * If it is, this should cause an error.
2790 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2791 if (hr == S_OK) {
2792 if (flags & REGCLS_MULTIPLEUSE) {
2793 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2794 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2795 IUnknown_Release(foundObject);
2796 return hr;
2798 IUnknown_Release(foundObject);
2799 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2800 return CO_E_OBJISREG;
2803 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2804 if ( newClass == NULL )
2805 return E_OUTOFMEMORY;
2807 newClass->classIdentifier = *rclsid;
2808 newClass->apartment_id = apt->oxid;
2809 newClass->runContext = dwClsContext;
2810 newClass->connectFlags = flags;
2811 newClass->RpcRegistration = NULL;
2813 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2814 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2817 * Since we're making a copy of the object pointer, we have to increase its
2818 * reference count.
2820 newClass->classObject = pUnk;
2821 IUnknown_AddRef(newClass->classObject);
2823 EnterCriticalSection( &csRegisteredClassList );
2824 list_add_tail(&RegisteredClassList, &newClass->entry);
2825 LeaveCriticalSection( &csRegisteredClassList );
2827 *lpdwRegister = newClass->dwCookie;
2829 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2830 IStream *marshal_stream;
2832 hr = get_local_server_stream(apt, &marshal_stream);
2833 if(FAILED(hr))
2834 return hr;
2836 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2837 marshal_stream,
2838 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2839 &newClass->RpcRegistration);
2840 IStream_Release(marshal_stream);
2842 return S_OK;
2845 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2847 if (data->hkey)
2849 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2850 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2851 static const WCHAR wszFree[] = {'F','r','e','e',0};
2852 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2853 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2854 DWORD dwLength = sizeof(threading_model);
2855 DWORD keytype;
2856 DWORD ret;
2858 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2859 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2860 threading_model[0] = '\0';
2862 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2863 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2864 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2866 /* there's not specific handling for this case */
2867 if (threading_model[0]) return ThreadingModel_Neutral;
2868 return ThreadingModel_No;
2870 else
2871 return data->u.actctx.data->model;
2874 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2875 REFCLSID rclsid, REFIID riid,
2876 BOOL hostifnecessary, void **ppv)
2878 WCHAR dllpath[MAX_PATH+1];
2879 BOOL apartment_threaded;
2881 if (hostifnecessary)
2883 enum comclass_threadingmodel model = get_threading_model(regdata);
2885 if (model == ThreadingModel_Apartment)
2887 apartment_threaded = TRUE;
2888 if (apt->multi_threaded)
2889 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2891 else if (model == ThreadingModel_Free)
2893 apartment_threaded = FALSE;
2894 if (!apt->multi_threaded)
2895 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2897 /* everything except "Apartment", "Free" and "Both" */
2898 else if (model != ThreadingModel_Both)
2900 apartment_threaded = TRUE;
2901 /* everything else is main-threaded */
2902 if (model != ThreadingModel_No)
2903 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2905 if (apt->multi_threaded || !apt->main)
2906 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2908 else
2909 apartment_threaded = FALSE;
2911 else
2912 apartment_threaded = !apt->multi_threaded;
2914 if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2916 /* failure: CLSID is not found in registry */
2917 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2918 return REGDB_E_CLASSNOTREG;
2921 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2922 rclsid, riid, ppv);
2925 /***********************************************************************
2926 * CoGetClassObject [OLE32.@]
2928 * Creates an object of the specified class.
2930 * PARAMS
2931 * rclsid [I] Class ID to create an instance of.
2932 * dwClsContext [I] Flags to restrict the location of the created instance.
2933 * pServerInfo [I] Optional. Details for connecting to a remote server.
2934 * iid [I] The ID of the interface of the instance to return.
2935 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2937 * RETURNS
2938 * Success: S_OK
2939 * Failure: HRESULT code.
2941 * NOTES
2942 * The dwClsContext parameter can be one or more of the following:
2943 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2944 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2945 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2946 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2948 * SEE ALSO
2949 * CoCreateInstance()
2951 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2952 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2953 REFIID iid, LPVOID *ppv)
2955 struct class_reg_data clsreg;
2956 IUnknown *regClassObject;
2957 HRESULT hres = E_UNEXPECTED;
2958 APARTMENT *apt;
2959 BOOL release_apt = FALSE;
2961 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2963 if (!ppv)
2964 return E_INVALIDARG;
2966 *ppv = NULL;
2968 if (!(apt = COM_CurrentApt()))
2970 if (!(apt = apartment_find_multi_threaded()))
2972 ERR("apartment not initialised\n");
2973 return CO_E_NOTINITIALIZED;
2975 release_apt = TRUE;
2978 if (pServerInfo) {
2979 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2980 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2983 if (CLSCTX_INPROC_SERVER & dwClsContext)
2985 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2987 if (release_apt) apartment_release(apt);
2988 return FTMarshalCF_Create(iid, ppv);
2992 if (CLSCTX_INPROC & dwClsContext)
2994 ACTCTX_SECTION_KEYED_DATA data;
2996 data.cbSize = sizeof(data);
2997 /* search activation context first */
2998 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2999 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3000 rclsid, &data))
3002 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3004 clsreg.u.actctx.hactctx = data.hActCtx;
3005 clsreg.u.actctx.data = data.lpData;
3006 clsreg.u.actctx.section = data.lpSectionBase;
3007 clsreg.hkey = FALSE;
3009 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3010 ReleaseActCtx(data.hActCtx);
3011 if (release_apt) apartment_release(apt);
3012 return hres;
3017 * First, try and see if we can't match the class ID with one of the
3018 * registered classes.
3020 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3021 &regClassObject))
3023 /* Get the required interface from the retrieved pointer. */
3024 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3027 * Since QI got another reference on the pointer, we want to release the
3028 * one we already have. If QI was unsuccessful, this will release the object. This
3029 * is good since we are not returning it in the "out" parameter.
3031 IUnknown_Release(regClassObject);
3032 if (release_apt) apartment_release(apt);
3033 return hres;
3036 /* First try in-process server */
3037 if (CLSCTX_INPROC_SERVER & dwClsContext)
3039 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3040 HKEY hkey;
3042 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3043 if (FAILED(hres))
3045 if (hres == REGDB_E_CLASSNOTREG)
3046 ERR("class %s not registered\n", debugstr_guid(rclsid));
3047 else if (hres == REGDB_E_KEYMISSING)
3049 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3050 hres = REGDB_E_CLASSNOTREG;
3054 if (SUCCEEDED(hres))
3056 clsreg.u.hkey = hkey;
3057 clsreg.hkey = TRUE;
3059 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3060 RegCloseKey(hkey);
3063 /* return if we got a class, otherwise fall through to one of the
3064 * other types */
3065 if (SUCCEEDED(hres))
3067 if (release_apt) apartment_release(apt);
3068 return hres;
3072 /* Next try in-process handler */
3073 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3075 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3076 HKEY hkey;
3078 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3079 if (FAILED(hres))
3081 if (hres == REGDB_E_CLASSNOTREG)
3082 ERR("class %s not registered\n", debugstr_guid(rclsid));
3083 else if (hres == REGDB_E_KEYMISSING)
3085 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3086 hres = REGDB_E_CLASSNOTREG;
3090 if (SUCCEEDED(hres))
3092 clsreg.u.hkey = hkey;
3093 clsreg.hkey = TRUE;
3095 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3096 RegCloseKey(hkey);
3099 /* return if we got a class, otherwise fall through to one of the
3100 * other types */
3101 if (SUCCEEDED(hres))
3103 if (release_apt) apartment_release(apt);
3104 return hres;
3107 if (release_apt) apartment_release(apt);
3109 /* Next try out of process */
3110 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3112 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3113 if (SUCCEEDED(hres))
3114 return hres;
3117 /* Finally try remote: this requires networked DCOM (a lot of work) */
3118 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3120 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3121 hres = REGDB_E_CLASSNOTREG;
3124 if (FAILED(hres))
3125 ERR("no class object %s could be created for context 0x%x\n",
3126 debugstr_guid(rclsid), dwClsContext);
3127 return hres;
3130 /***********************************************************************
3131 * CoResumeClassObjects (OLE32.@)
3133 * Resumes all class objects registered with REGCLS_SUSPENDED.
3135 * RETURNS
3136 * Success: S_OK.
3137 * Failure: HRESULT code.
3139 HRESULT WINAPI CoResumeClassObjects(void)
3141 FIXME("stub\n");
3142 return S_OK;
3145 /***********************************************************************
3146 * CoCreateInstance [OLE32.@]
3148 * Creates an instance of the specified class.
3150 * PARAMS
3151 * rclsid [I] Class ID to create an instance of.
3152 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3153 * dwClsContext [I] Flags to restrict the location of the created instance.
3154 * iid [I] The ID of the interface of the instance to return.
3155 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3157 * RETURNS
3158 * Success: S_OK
3159 * Failure: HRESULT code.
3161 * NOTES
3162 * The dwClsContext parameter can be one or more of the following:
3163 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3164 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3165 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3166 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3168 * Aggregation is the concept of deferring the IUnknown of an object to another
3169 * object. This allows a separate object to behave as though it was part of
3170 * the object and to allow this the pUnkOuter parameter can be set. Note that
3171 * not all objects support having an outer of unknown.
3173 * SEE ALSO
3174 * CoGetClassObject()
3176 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3177 REFCLSID rclsid,
3178 LPUNKNOWN pUnkOuter,
3179 DWORD dwClsContext,
3180 REFIID iid,
3181 LPVOID *ppv)
3183 HRESULT hres;
3184 LPCLASSFACTORY lpclf = 0;
3185 APARTMENT *apt;
3186 CLSID clsid;
3188 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3189 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3191 if (ppv==0)
3192 return E_POINTER;
3194 hres = CoGetTreatAsClass(rclsid, &clsid);
3195 if(FAILED(hres))
3196 clsid = *rclsid;
3198 *ppv = 0;
3200 if (!(apt = COM_CurrentApt()))
3202 if (!(apt = apartment_find_multi_threaded()))
3204 ERR("apartment not initialised\n");
3205 return CO_E_NOTINITIALIZED;
3207 apartment_release(apt);
3211 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3213 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3215 IGlobalInterfaceTable *git = get_std_git();
3216 hres = IGlobalInterfaceTable_QueryInterface(git, iid, ppv);
3217 if (hres != S_OK) return hres;
3219 TRACE("Retrieved GIT (%p)\n", *ppv);
3220 return S_OK;
3223 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent))
3224 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
3227 * Get a class factory to construct the object we want.
3229 hres = CoGetClassObject(&clsid,
3230 dwClsContext,
3231 NULL,
3232 &IID_IClassFactory,
3233 (LPVOID)&lpclf);
3235 if (FAILED(hres))
3236 return hres;
3239 * Create the object and don't forget to release the factory
3241 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
3242 IClassFactory_Release(lpclf);
3243 if (FAILED(hres))
3245 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3246 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3247 else
3248 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3249 debugstr_guid(iid),
3250 debugstr_guid(&clsid),hres);
3253 return hres;
3256 static void init_multi_qi(DWORD count, MULTI_QI *mqi)
3258 ULONG i;
3260 for (i = 0; i < count; i++)
3262 mqi[i].pItf = NULL;
3263 mqi[i].hr = E_NOINTERFACE;
3267 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi)
3269 ULONG index, fetched = 0;
3271 for (index = 0; index < count; index++)
3273 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3274 if (mqi[index].hr == S_OK)
3275 fetched++;
3278 IUnknown_Release(unk);
3280 if (fetched == 0)
3281 return E_NOINTERFACE;
3283 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3286 /***********************************************************************
3287 * CoCreateInstanceEx [OLE32.@]
3289 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3290 REFCLSID rclsid,
3291 LPUNKNOWN pUnkOuter,
3292 DWORD dwClsContext,
3293 COSERVERINFO* pServerInfo,
3294 ULONG cmq,
3295 MULTI_QI* pResults)
3297 IUnknown* pUnk = NULL;
3298 HRESULT hr;
3301 * Sanity check
3303 if ( (cmq==0) || (pResults==NULL))
3304 return E_INVALIDARG;
3306 if (pServerInfo!=NULL)
3307 FIXME("() non-NULL pServerInfo not supported!\n");
3309 init_multi_qi(cmq, pResults);
3312 * Get the object and get its IUnknown pointer.
3314 hr = CoCreateInstance(rclsid,
3315 pUnkOuter,
3316 dwClsContext,
3317 &IID_IUnknown,
3318 (VOID**)&pUnk);
3320 if (hr != S_OK)
3321 return hr;
3323 return return_multi_qi(pUnk, cmq, pResults);
3326 /***********************************************************************
3327 * CoGetInstanceFromFile [OLE32.@]
3329 HRESULT WINAPI CoGetInstanceFromFile(
3330 COSERVERINFO *server_info,
3331 CLSID *rclsid,
3332 IUnknown *outer,
3333 DWORD cls_context,
3334 DWORD grfmode,
3335 OLECHAR *filename,
3336 DWORD count,
3337 MULTI_QI *results
3340 IPersistFile *pf = NULL;
3341 IUnknown* unk = NULL;
3342 CLSID clsid;
3343 HRESULT hr;
3345 if (count == 0 || !results)
3346 return E_INVALIDARG;
3348 if (server_info)
3349 FIXME("() non-NULL server_info not supported\n");
3351 init_multi_qi(count, results);
3353 /* optionally get CLSID from a file */
3354 if (!rclsid)
3356 hr = GetClassFile(filename, &clsid);
3357 if (FAILED(hr))
3359 ERR("failed to get CLSID from a file\n");
3360 return hr;
3363 rclsid = &clsid;
3366 hr = CoCreateInstance(rclsid,
3367 outer,
3368 cls_context,
3369 &IID_IUnknown,
3370 (void**)&unk);
3372 if (hr != S_OK)
3373 return hr;
3375 /* init from file */
3376 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3377 if (FAILED(hr))
3378 ERR("failed to get IPersistFile\n");
3380 if (pf)
3382 IPersistFile_Load(pf, filename, grfmode);
3383 IPersistFile_Release(pf);
3386 return return_multi_qi(unk, count, results);
3389 /***********************************************************************
3390 * CoGetInstanceFromIStorage [OLE32.@]
3392 HRESULT WINAPI CoGetInstanceFromIStorage(
3393 COSERVERINFO *server_info,
3394 CLSID *rclsid,
3395 IUnknown *outer,
3396 DWORD cls_context,
3397 IStorage *storage,
3398 DWORD count,
3399 MULTI_QI *results
3402 IPersistStorage *ps = NULL;
3403 IUnknown* unk = NULL;
3404 STATSTG stat;
3405 HRESULT hr;
3407 if (count == 0 || !results || !storage)
3408 return E_INVALIDARG;
3410 if (server_info)
3411 FIXME("() non-NULL server_info not supported\n");
3413 init_multi_qi(count, results);
3415 /* optionally get CLSID from a file */
3416 if (!rclsid)
3418 memset(&stat.clsid, 0, sizeof(stat.clsid));
3419 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3420 if (FAILED(hr))
3422 ERR("failed to get CLSID from a file\n");
3423 return hr;
3426 rclsid = &stat.clsid;
3429 hr = CoCreateInstance(rclsid,
3430 outer,
3431 cls_context,
3432 &IID_IUnknown,
3433 (void**)&unk);
3435 if (hr != S_OK)
3436 return hr;
3438 /* init from IStorage */
3439 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3440 if (FAILED(hr))
3441 ERR("failed to get IPersistStorage\n");
3443 if (ps)
3445 IPersistStorage_Load(ps, storage);
3446 IPersistStorage_Release(ps);
3449 return return_multi_qi(unk, count, results);
3452 /***********************************************************************
3453 * CoLoadLibrary (OLE32.@)
3455 * Loads a library.
3457 * PARAMS
3458 * lpszLibName [I] Path to library.
3459 * bAutoFree [I] Whether the library should automatically be freed.
3461 * RETURNS
3462 * Success: Handle to loaded library.
3463 * Failure: NULL.
3465 * SEE ALSO
3466 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3468 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3470 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3472 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3475 /***********************************************************************
3476 * CoFreeLibrary [OLE32.@]
3478 * Unloads a library from memory.
3480 * PARAMS
3481 * hLibrary [I] Handle to library to unload.
3483 * RETURNS
3484 * Nothing
3486 * SEE ALSO
3487 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3489 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3491 FreeLibrary(hLibrary);
3495 /***********************************************************************
3496 * CoFreeAllLibraries [OLE32.@]
3498 * Function for backwards compatibility only. Does nothing.
3500 * RETURNS
3501 * Nothing.
3503 * SEE ALSO
3504 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3506 void WINAPI CoFreeAllLibraries(void)
3508 /* NOP */
3511 /***********************************************************************
3512 * CoFreeUnusedLibrariesEx [OLE32.@]
3514 * Frees any previously unused libraries whose delay has expired and marks
3515 * currently unused libraries for unloading. Unused are identified as those that
3516 * return S_OK from their DllCanUnloadNow function.
3518 * PARAMS
3519 * dwUnloadDelay [I] Unload delay in milliseconds.
3520 * dwReserved [I] Reserved. Set to 0.
3522 * RETURNS
3523 * Nothing.
3525 * SEE ALSO
3526 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3528 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3530 struct apartment *apt = COM_CurrentApt();
3531 if (!apt)
3533 ERR("apartment not initialised\n");
3534 return;
3537 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3540 /***********************************************************************
3541 * CoFreeUnusedLibraries [OLE32.@]
3543 * Frees any unused libraries. Unused are identified as those that return
3544 * S_OK from their DllCanUnloadNow function.
3546 * RETURNS
3547 * Nothing.
3549 * SEE ALSO
3550 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3552 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3554 CoFreeUnusedLibrariesEx(INFINITE, 0);
3557 /***********************************************************************
3558 * CoFileTimeNow [OLE32.@]
3560 * Retrieves the current time in FILETIME format.
3562 * PARAMS
3563 * lpFileTime [O] The current time.
3565 * RETURNS
3566 * S_OK.
3568 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3570 GetSystemTimeAsFileTime( lpFileTime );
3571 return S_OK;
3574 /******************************************************************************
3575 * CoLockObjectExternal [OLE32.@]
3577 * Increments or decrements the external reference count of a stub object.
3579 * PARAMS
3580 * pUnk [I] Stub object.
3581 * fLock [I] If TRUE then increments the external ref-count,
3582 * otherwise decrements.
3583 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3584 * calling CoDisconnectObject.
3586 * RETURNS
3587 * Success: S_OK.
3588 * Failure: HRESULT code.
3590 * NOTES
3591 * If fLock is TRUE and an object is passed in that doesn't have a stub
3592 * manager then a new stub manager is created for the object.
3594 HRESULT WINAPI CoLockObjectExternal(
3595 LPUNKNOWN pUnk,
3596 BOOL fLock,
3597 BOOL fLastUnlockReleases)
3599 struct stub_manager *stubmgr;
3600 struct apartment *apt;
3602 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3603 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3605 apt = COM_CurrentApt();
3606 if (!apt) return CO_E_NOTINITIALIZED;
3608 stubmgr = get_stub_manager_from_object(apt, pUnk);
3610 if (stubmgr)
3612 if (fLock)
3613 stub_manager_ext_addref(stubmgr, 1, FALSE);
3614 else
3615 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3617 stub_manager_int_release(stubmgr);
3619 return S_OK;
3621 else if (fLock)
3623 stubmgr = new_stub_manager(apt, pUnk);
3625 if (stubmgr)
3627 stub_manager_ext_addref(stubmgr, 1, FALSE);
3628 stub_manager_int_release(stubmgr);
3631 return S_OK;
3633 else
3635 WARN("stub object not found %p\n", pUnk);
3636 /* Note: native is pretty broken here because it just silently
3637 * fails, without returning an appropriate error code, making apps
3638 * think that the object was disconnected, when it actually wasn't */
3639 return S_OK;
3643 /***********************************************************************
3644 * CoInitializeWOW (OLE32.@)
3646 * WOW equivalent of CoInitialize?
3648 * PARAMS
3649 * x [I] Unknown.
3650 * y [I] Unknown.
3652 * RETURNS
3653 * Unknown.
3655 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3657 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3658 return 0;
3661 /***********************************************************************
3662 * CoGetState [OLE32.@]
3664 * Retrieves the thread state object previously stored by CoSetState().
3666 * PARAMS
3667 * ppv [I] Address where pointer to object will be stored.
3669 * RETURNS
3670 * Success: S_OK.
3671 * Failure: E_OUTOFMEMORY.
3673 * NOTES
3674 * Crashes on all invalid ppv addresses, including NULL.
3675 * If the function returns a non-NULL object then the caller must release its
3676 * reference on the object when the object is no longer required.
3678 * SEE ALSO
3679 * CoSetState().
3681 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3683 struct oletls *info = COM_CurrentInfo();
3684 if (!info) return E_OUTOFMEMORY;
3686 *ppv = NULL;
3688 if (info->state)
3690 IUnknown_AddRef(info->state);
3691 *ppv = info->state;
3692 TRACE("apt->state=%p\n", info->state);
3695 return S_OK;
3698 /***********************************************************************
3699 * CoSetState [OLE32.@]
3701 * Sets the thread state object.
3703 * PARAMS
3704 * pv [I] Pointer to state object to be stored.
3706 * NOTES
3707 * The system keeps a reference on the object while the object stored.
3709 * RETURNS
3710 * Success: S_OK.
3711 * Failure: E_OUTOFMEMORY.
3713 HRESULT WINAPI CoSetState(IUnknown * pv)
3715 struct oletls *info = COM_CurrentInfo();
3716 if (!info) return E_OUTOFMEMORY;
3718 if (pv) IUnknown_AddRef(pv);
3720 if (info->state)
3722 TRACE("-- release %p now\n", info->state);
3723 IUnknown_Release(info->state);
3726 info->state = pv;
3728 return S_OK;
3732 /******************************************************************************
3733 * CoTreatAsClass [OLE32.@]
3735 * Sets the TreatAs value of a class.
3737 * PARAMS
3738 * clsidOld [I] Class to set TreatAs value on.
3739 * clsidNew [I] The class the clsidOld should be treated as.
3741 * RETURNS
3742 * Success: S_OK.
3743 * Failure: HRESULT code.
3745 * SEE ALSO
3746 * CoGetTreatAsClass
3748 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3750 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3751 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3752 HKEY hkey = NULL;
3753 WCHAR szClsidNew[CHARS_IN_GUID];
3754 HRESULT res = S_OK;
3755 WCHAR auto_treat_as[CHARS_IN_GUID];
3756 LONG auto_treat_as_size = sizeof(auto_treat_as);
3757 CLSID id;
3759 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3760 if (FAILED(res))
3761 goto done;
3763 if (IsEqualGUID( clsidOld, clsidNew ))
3765 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3766 CLSIDFromString(auto_treat_as, &id) == S_OK)
3768 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3770 res = REGDB_E_WRITEREGDB;
3771 goto done;
3774 else
3776 if(RegDeleteKeyW(hkey, wszTreatAs))
3777 res = REGDB_E_WRITEREGDB;
3778 goto done;
3781 else
3783 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3784 RegDeleteKeyW(hkey, wszTreatAs);
3785 }else{
3786 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
3787 WARN("StringFromGUID2 failed\n");
3788 res = E_FAIL;
3789 goto done;
3792 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3793 WARN("RegSetValue failed\n");
3794 res = REGDB_E_WRITEREGDB;
3795 goto done;
3800 done:
3801 if (hkey) RegCloseKey(hkey);
3802 return res;
3805 /******************************************************************************
3806 * CoGetTreatAsClass [OLE32.@]
3808 * Gets the TreatAs value of a class.
3810 * PARAMS
3811 * clsidOld [I] Class to get the TreatAs value of.
3812 * clsidNew [I] The class the clsidOld should be treated as.
3814 * RETURNS
3815 * Success: S_OK.
3816 * Failure: HRESULT code.
3818 * SEE ALSO
3819 * CoSetTreatAsClass
3821 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3823 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3824 HKEY hkey = NULL;
3825 WCHAR szClsidNew[CHARS_IN_GUID];
3826 HRESULT res = S_OK;
3827 LONG len = sizeof(szClsidNew);
3829 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3830 *clsidNew = *clsidOld; /* copy over old value */
3832 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3833 if (FAILED(res))
3835 res = S_FALSE;
3836 goto done;
3838 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3840 res = S_FALSE;
3841 goto done;
3843 res = CLSIDFromString(szClsidNew,clsidNew);
3844 if (FAILED(res))
3845 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3846 done:
3847 if (hkey) RegCloseKey(hkey);
3848 return res;
3851 /******************************************************************************
3852 * CoGetCurrentProcess [OLE32.@]
3854 * Gets the current process ID.
3856 * RETURNS
3857 * The current process ID.
3859 * NOTES
3860 * Is DWORD really the correct return type for this function?
3862 DWORD WINAPI CoGetCurrentProcess(void)
3864 return GetCurrentProcessId();
3867 /******************************************************************************
3868 * CoRegisterMessageFilter [OLE32.@]
3870 * Registers a message filter.
3872 * PARAMS
3873 * lpMessageFilter [I] Pointer to interface.
3874 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3876 * RETURNS
3877 * Success: S_OK.
3878 * Failure: HRESULT code.
3880 * NOTES
3881 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3882 * lpMessageFilter removes the message filter.
3884 * If lplpMessageFilter is not NULL the previous message filter will be
3885 * returned in the memory pointer to this parameter and the caller is
3886 * responsible for releasing the object.
3888 * The current thread be in an apartment otherwise the function will crash.
3890 HRESULT WINAPI CoRegisterMessageFilter(
3891 LPMESSAGEFILTER lpMessageFilter,
3892 LPMESSAGEFILTER *lplpMessageFilter)
3894 struct apartment *apt;
3895 IMessageFilter *lpOldMessageFilter;
3897 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3899 apt = COM_CurrentApt();
3901 /* can't set a message filter in a multi-threaded apartment */
3902 if (!apt || apt->multi_threaded)
3904 WARN("can't set message filter in MTA or uninitialized apt\n");
3905 return CO_E_NOT_SUPPORTED;
3908 if (lpMessageFilter)
3909 IMessageFilter_AddRef(lpMessageFilter);
3911 EnterCriticalSection(&apt->cs);
3913 lpOldMessageFilter = apt->filter;
3914 apt->filter = lpMessageFilter;
3916 LeaveCriticalSection(&apt->cs);
3918 if (lplpMessageFilter)
3919 *lplpMessageFilter = lpOldMessageFilter;
3920 else if (lpOldMessageFilter)
3921 IMessageFilter_Release(lpOldMessageFilter);
3923 return S_OK;
3926 /***********************************************************************
3927 * CoIsOle1Class [OLE32.@]
3929 * Determines whether the specified class an OLE v1 class.
3931 * PARAMS
3932 * clsid [I] Class to test.
3934 * RETURNS
3935 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3937 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3939 FIXME("%s\n", debugstr_guid(clsid));
3940 return FALSE;
3943 /***********************************************************************
3944 * IsEqualGUID [OLE32.@]
3946 * Compares two Unique Identifiers.
3948 * PARAMS
3949 * rguid1 [I] The first GUID to compare.
3950 * rguid2 [I] The other GUID to compare.
3952 * RETURNS
3953 * TRUE if equal
3955 #undef IsEqualGUID
3956 BOOL WINAPI IsEqualGUID(
3957 REFGUID rguid1,
3958 REFGUID rguid2)
3960 return !memcmp(rguid1,rguid2,sizeof(GUID));
3963 /***********************************************************************
3964 * CoInitializeSecurity [OLE32.@]
3966 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3967 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3968 void* pReserved1, DWORD dwAuthnLevel,
3969 DWORD dwImpLevel, void* pReserved2,
3970 DWORD dwCapabilities, void* pReserved3)
3972 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3973 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3974 dwCapabilities, pReserved3);
3975 return S_OK;
3978 /***********************************************************************
3979 * CoSuspendClassObjects [OLE32.@]
3981 * Suspends all registered class objects to prevent further requests coming in
3982 * for those objects.
3984 * RETURNS
3985 * Success: S_OK.
3986 * Failure: HRESULT code.
3988 HRESULT WINAPI CoSuspendClassObjects(void)
3990 FIXME("\n");
3991 return S_OK;
3994 /***********************************************************************
3995 * CoAddRefServerProcess [OLE32.@]
3997 * Helper function for incrementing the reference count of a local-server
3998 * process.
4000 * RETURNS
4001 * New reference count.
4003 * SEE ALSO
4004 * CoReleaseServerProcess().
4006 ULONG WINAPI CoAddRefServerProcess(void)
4008 ULONG refs;
4010 TRACE("\n");
4012 EnterCriticalSection(&csRegisteredClassList);
4013 refs = ++s_COMServerProcessReferences;
4014 LeaveCriticalSection(&csRegisteredClassList);
4016 TRACE("refs before: %d\n", refs - 1);
4018 return refs;
4021 /***********************************************************************
4022 * CoReleaseServerProcess [OLE32.@]
4024 * Helper function for decrementing the reference count of a local-server
4025 * process.
4027 * RETURNS
4028 * New reference count.
4030 * NOTES
4031 * When reference count reaches 0, this function suspends all registered
4032 * classes so no new connections are accepted.
4034 * SEE ALSO
4035 * CoAddRefServerProcess(), CoSuspendClassObjects().
4037 ULONG WINAPI CoReleaseServerProcess(void)
4039 ULONG refs;
4041 TRACE("\n");
4043 EnterCriticalSection(&csRegisteredClassList);
4045 refs = --s_COMServerProcessReferences;
4046 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4048 LeaveCriticalSection(&csRegisteredClassList);
4050 TRACE("refs after: %d\n", refs);
4052 return refs;
4055 /***********************************************************************
4056 * CoIsHandlerConnected [OLE32.@]
4058 * Determines whether a proxy is connected to a remote stub.
4060 * PARAMS
4061 * pUnk [I] Pointer to object that may or may not be connected.
4063 * RETURNS
4064 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4065 * FALSE otherwise.
4067 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4069 FIXME("%p\n", pUnk);
4071 return TRUE;
4074 /***********************************************************************
4075 * CoAllowSetForegroundWindow [OLE32.@]
4078 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4080 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4081 return S_OK;
4084 /***********************************************************************
4085 * CoQueryProxyBlanket [OLE32.@]
4087 * Retrieves the security settings being used by a proxy.
4089 * PARAMS
4090 * pProxy [I] Pointer to the proxy object.
4091 * pAuthnSvc [O] The type of authentication service.
4092 * pAuthzSvc [O] The type of authorization service.
4093 * ppServerPrincName [O] Optional. The server prinicple name.
4094 * pAuthnLevel [O] The authentication level.
4095 * pImpLevel [O] The impersonation level.
4096 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4097 * pCapabilities [O] Flags affecting the security behaviour.
4099 * RETURNS
4100 * Success: S_OK.
4101 * Failure: HRESULT code.
4103 * SEE ALSO
4104 * CoCopyProxy, CoSetProxyBlanket.
4106 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4107 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4108 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4110 IClientSecurity *pCliSec;
4111 HRESULT hr;
4113 TRACE("%p\n", pProxy);
4115 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4116 if (SUCCEEDED(hr))
4118 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4119 pAuthzSvc, ppServerPrincName,
4120 pAuthnLevel, pImpLevel, ppAuthInfo,
4121 pCapabilities);
4122 IClientSecurity_Release(pCliSec);
4125 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4126 return hr;
4129 /***********************************************************************
4130 * CoSetProxyBlanket [OLE32.@]
4132 * Sets the security settings for a proxy.
4134 * PARAMS
4135 * pProxy [I] Pointer to the proxy object.
4136 * AuthnSvc [I] The type of authentication service.
4137 * AuthzSvc [I] The type of authorization service.
4138 * pServerPrincName [I] The server prinicple name.
4139 * AuthnLevel [I] The authentication level.
4140 * ImpLevel [I] The impersonation level.
4141 * pAuthInfo [I] Information specific to the authorization/authentication service.
4142 * Capabilities [I] Flags affecting the security behaviour.
4144 * RETURNS
4145 * Success: S_OK.
4146 * Failure: HRESULT code.
4148 * SEE ALSO
4149 * CoQueryProxyBlanket, CoCopyProxy.
4151 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4152 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4153 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4155 IClientSecurity *pCliSec;
4156 HRESULT hr;
4158 TRACE("%p\n", pProxy);
4160 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4161 if (SUCCEEDED(hr))
4163 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4164 AuthzSvc, pServerPrincName,
4165 AuthnLevel, ImpLevel, pAuthInfo,
4166 Capabilities);
4167 IClientSecurity_Release(pCliSec);
4170 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4171 return hr;
4174 /***********************************************************************
4175 * CoCopyProxy [OLE32.@]
4177 * Copies a proxy.
4179 * PARAMS
4180 * pProxy [I] Pointer to the proxy object.
4181 * ppCopy [O] Copy of the proxy.
4183 * RETURNS
4184 * Success: S_OK.
4185 * Failure: HRESULT code.
4187 * SEE ALSO
4188 * CoQueryProxyBlanket, CoSetProxyBlanket.
4190 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4192 IClientSecurity *pCliSec;
4193 HRESULT hr;
4195 TRACE("%p\n", pProxy);
4197 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4198 if (SUCCEEDED(hr))
4200 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4201 IClientSecurity_Release(pCliSec);
4204 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4205 return hr;
4209 /***********************************************************************
4210 * CoGetCallContext [OLE32.@]
4212 * Gets the context of the currently executing server call in the current
4213 * thread.
4215 * PARAMS
4216 * riid [I] Context interface to return.
4217 * ppv [O] Pointer to memory that will receive the context on return.
4219 * RETURNS
4220 * Success: S_OK.
4221 * Failure: HRESULT code.
4223 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4225 struct oletls *info = COM_CurrentInfo();
4227 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4229 if (!info)
4230 return E_OUTOFMEMORY;
4232 if (!info->call_state)
4233 return RPC_E_CALL_COMPLETE;
4235 return IUnknown_QueryInterface(info->call_state, riid, ppv);
4238 /***********************************************************************
4239 * CoSwitchCallContext [OLE32.@]
4241 * Switches the context of the currently executing server call in the current
4242 * thread.
4244 * PARAMS
4245 * pObject [I] Pointer to new context object
4246 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4248 * RETURNS
4249 * Success: S_OK.
4250 * Failure: HRESULT code.
4252 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4254 struct oletls *info = COM_CurrentInfo();
4256 TRACE("(%p, %p)\n", pObject, ppOldObject);
4258 if (!info)
4259 return E_OUTOFMEMORY;
4261 *ppOldObject = info->call_state;
4262 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4264 return S_OK;
4267 /***********************************************************************
4268 * CoQueryClientBlanket [OLE32.@]
4270 * Retrieves the authentication information about the client of the currently
4271 * executing server call in the current thread.
4273 * PARAMS
4274 * pAuthnSvc [O] Optional. The type of authentication service.
4275 * pAuthzSvc [O] Optional. The type of authorization service.
4276 * pServerPrincName [O] Optional. The server prinicple name.
4277 * pAuthnLevel [O] Optional. The authentication level.
4278 * pImpLevel [O] Optional. The impersonation level.
4279 * pPrivs [O] Optional. Information about the privileges of the client.
4280 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4282 * RETURNS
4283 * Success: S_OK.
4284 * Failure: HRESULT code.
4286 * SEE ALSO
4287 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4289 HRESULT WINAPI CoQueryClientBlanket(
4290 DWORD *pAuthnSvc,
4291 DWORD *pAuthzSvc,
4292 OLECHAR **pServerPrincName,
4293 DWORD *pAuthnLevel,
4294 DWORD *pImpLevel,
4295 RPC_AUTHZ_HANDLE *pPrivs,
4296 DWORD *pCapabilities)
4298 IServerSecurity *pSrvSec;
4299 HRESULT hr;
4301 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4302 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4303 pPrivs, pCapabilities);
4305 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4306 if (SUCCEEDED(hr))
4308 hr = IServerSecurity_QueryBlanket(
4309 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4310 pImpLevel, pPrivs, pCapabilities);
4311 IServerSecurity_Release(pSrvSec);
4314 return hr;
4317 /***********************************************************************
4318 * CoImpersonateClient [OLE32.@]
4320 * Impersonates the client of the currently executing server call in the
4321 * current thread.
4323 * PARAMS
4324 * None.
4326 * RETURNS
4327 * Success: S_OK.
4328 * Failure: HRESULT code.
4330 * NOTES
4331 * If this function fails then the current thread will not be impersonating
4332 * the client and all actions will take place on behalf of the server.
4333 * Therefore, it is important to check the return value from this function.
4335 * SEE ALSO
4336 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4338 HRESULT WINAPI CoImpersonateClient(void)
4340 IServerSecurity *pSrvSec;
4341 HRESULT hr;
4343 TRACE("\n");
4345 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4346 if (SUCCEEDED(hr))
4348 hr = IServerSecurity_ImpersonateClient(pSrvSec);
4349 IServerSecurity_Release(pSrvSec);
4352 return hr;
4355 /***********************************************************************
4356 * CoRevertToSelf [OLE32.@]
4358 * Ends the impersonation of the client of the currently executing server
4359 * call in the current thread.
4361 * PARAMS
4362 * None.
4364 * RETURNS
4365 * Success: S_OK.
4366 * Failure: HRESULT code.
4368 * SEE ALSO
4369 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4371 HRESULT WINAPI CoRevertToSelf(void)
4373 IServerSecurity *pSrvSec;
4374 HRESULT hr;
4376 TRACE("\n");
4378 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4379 if (SUCCEEDED(hr))
4381 hr = IServerSecurity_RevertToSelf(pSrvSec);
4382 IServerSecurity_Release(pSrvSec);
4385 return hr;
4388 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4390 /* first try to retrieve messages for incoming COM calls to the apartment window */
4391 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
4392 /* next retrieve other messages necessary for the app to remain responsive */
4393 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4394 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4397 /***********************************************************************
4398 * CoWaitForMultipleHandles [OLE32.@]
4400 * Waits for one or more handles to become signaled.
4402 * PARAMS
4403 * dwFlags [I] Flags. See notes.
4404 * dwTimeout [I] Timeout in milliseconds.
4405 * cHandles [I] Number of handles pointed to by pHandles.
4406 * pHandles [I] Handles to wait for.
4407 * lpdwindex [O] Index of handle that was signaled.
4409 * RETURNS
4410 * Success: S_OK.
4411 * Failure: RPC_S_CALLPENDING on timeout.
4413 * NOTES
4415 * The dwFlags parameter can be zero or more of the following:
4416 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4417 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4419 * SEE ALSO
4420 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4422 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4423 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4425 HRESULT hr = S_OK;
4426 DWORD start_time = GetTickCount();
4427 APARTMENT *apt = COM_CurrentApt();
4428 BOOL message_loop = apt && !apt->multi_threaded;
4429 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4431 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4432 pHandles, lpdwindex);
4434 if (!lpdwindex)
4435 return E_INVALIDARG;
4437 *lpdwindex = 0;
4439 if (!pHandles)
4440 return E_INVALIDARG;
4442 if (!cHandles)
4443 return RPC_E_NO_SYNC;
4445 while (TRUE)
4447 DWORD now = GetTickCount();
4448 DWORD res;
4450 if (now - start_time > dwTimeout)
4452 hr = RPC_S_CALLPENDING;
4453 break;
4456 if (message_loop)
4458 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4459 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4461 TRACE("waiting for rpc completion or window message\n");
4463 res = WAIT_TIMEOUT;
4465 if (check_apc)
4467 res = WaitForMultipleObjectsEx(cHandles, pHandles,
4468 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4469 check_apc = FALSE;
4472 if (res == WAIT_TIMEOUT)
4473 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4474 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4475 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4477 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4479 MSG msg;
4480 int count = 0;
4482 /* call message filter */
4484 if (COM_CurrentApt()->filter)
4486 PENDINGTYPE pendingtype =
4487 COM_CurrentInfo()->pending_call_count_server ?
4488 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4489 DWORD be_handled = IMessageFilter_MessagePending(
4490 COM_CurrentApt()->filter, 0 /* FIXME */,
4491 now - start_time, pendingtype);
4492 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4493 switch (be_handled)
4495 case PENDINGMSG_CANCELCALL:
4496 WARN("call canceled\n");
4497 hr = RPC_E_CALL_CANCELED;
4498 break;
4499 case PENDINGMSG_WAITNOPROCESS:
4500 case PENDINGMSG_WAITDEFPROCESS:
4501 default:
4502 /* FIXME: MSDN is very vague about the difference
4503 * between WAITNOPROCESS and WAITDEFPROCESS - there
4504 * appears to be none, so it is possibly a left-over
4505 * from the 16-bit world. */
4506 break;
4510 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4511 * so after processing 100 messages we go back to checking the wait handles */
4512 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4514 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4515 TranslateMessage(&msg);
4516 DispatchMessageW(&msg);
4517 if (msg.message == WM_QUIT)
4519 TRACE("resending WM_QUIT to outer message loop\n");
4520 PostQuitMessage(msg.wParam);
4521 /* no longer need to process messages */
4522 message_loop = FALSE;
4523 break;
4526 continue;
4529 else
4531 TRACE("waiting for rpc completion\n");
4533 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4534 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4535 (dwFlags & COWAIT_ALERTABLE) != 0);
4538 switch (res)
4540 case WAIT_TIMEOUT:
4541 hr = RPC_S_CALLPENDING;
4542 break;
4543 case WAIT_FAILED:
4544 hr = HRESULT_FROM_WIN32( GetLastError() );
4545 break;
4546 default:
4547 *lpdwindex = res;
4548 break;
4550 break;
4552 TRACE("-- 0x%08x\n", hr);
4553 return hr;
4557 /***********************************************************************
4558 * CoGetObject [OLE32.@]
4560 * Gets the object named by converting the name to a moniker and binding to it.
4562 * PARAMS
4563 * pszName [I] String representing the object.
4564 * pBindOptions [I] Parameters affecting the binding to the named object.
4565 * riid [I] Interface to bind to on the objecct.
4566 * ppv [O] On output, the interface riid of the object represented
4567 * by pszName.
4569 * RETURNS
4570 * Success: S_OK.
4571 * Failure: HRESULT code.
4573 * SEE ALSO
4574 * MkParseDisplayName.
4576 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4577 REFIID riid, void **ppv)
4579 IBindCtx *pbc;
4580 HRESULT hr;
4582 *ppv = NULL;
4584 hr = CreateBindCtx(0, &pbc);
4585 if (SUCCEEDED(hr))
4587 if (pBindOptions)
4588 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4590 if (SUCCEEDED(hr))
4592 ULONG chEaten;
4593 IMoniker *pmk;
4595 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4596 if (SUCCEEDED(hr))
4598 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4599 IMoniker_Release(pmk);
4603 IBindCtx_Release(pbc);
4605 return hr;
4608 /***********************************************************************
4609 * CoRegisterChannelHook [OLE32.@]
4611 * Registers a process-wide hook that is called during ORPC calls.
4613 * PARAMS
4614 * guidExtension [I] GUID of the channel hook to register.
4615 * pChannelHook [I] Channel hook object to register.
4617 * RETURNS
4618 * Success: S_OK.
4619 * Failure: HRESULT code.
4621 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4623 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4625 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4628 typedef struct Context
4630 IComThreadingInfo IComThreadingInfo_iface;
4631 IContextCallback IContextCallback_iface;
4632 IObjContext IObjContext_iface;
4633 LONG refs;
4634 APTTYPE apttype;
4635 } Context;
4637 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4639 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4642 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4644 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4647 static inline Context *impl_from_IObjContext( IObjContext *iface )
4649 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4652 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4654 *ppv = NULL;
4656 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4657 IsEqualIID(riid, &IID_IUnknown))
4659 *ppv = &iface->IComThreadingInfo_iface;
4661 else if (IsEqualIID(riid, &IID_IContextCallback))
4663 *ppv = &iface->IContextCallback_iface;
4665 else if (IsEqualIID(riid, &IID_IObjContext))
4667 *ppv = &iface->IObjContext_iface;
4670 if (*ppv)
4672 IUnknown_AddRef((IUnknown*)*ppv);
4673 return S_OK;
4676 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4677 return E_NOINTERFACE;
4680 static ULONG Context_AddRef(Context *This)
4682 return InterlockedIncrement(&This->refs);
4685 static ULONG Context_Release(Context *This)
4687 ULONG refs = InterlockedDecrement(&This->refs);
4688 if (!refs)
4689 HeapFree(GetProcessHeap(), 0, This);
4690 return refs;
4693 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4695 Context *This = impl_from_IComThreadingInfo(iface);
4696 return Context_QueryInterface(This, riid, ppv);
4699 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4701 Context *This = impl_from_IComThreadingInfo(iface);
4702 return Context_AddRef(This);
4705 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4707 Context *This = impl_from_IComThreadingInfo(iface);
4708 return Context_Release(This);
4711 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4713 Context *This = impl_from_IComThreadingInfo(iface);
4715 TRACE("(%p)\n", apttype);
4717 *apttype = This->apttype;
4718 return S_OK;
4721 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4723 Context *This = impl_from_IComThreadingInfo(iface);
4725 TRACE("(%p)\n", thdtype);
4727 switch (This->apttype)
4729 case APTTYPE_STA:
4730 case APTTYPE_MAINSTA:
4731 *thdtype = THDTYPE_PROCESSMESSAGES;
4732 break;
4733 default:
4734 *thdtype = THDTYPE_BLOCKMESSAGES;
4735 break;
4737 return S_OK;
4740 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4742 FIXME("(%p): stub\n", logical_thread_id);
4743 return E_NOTIMPL;
4746 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4748 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4749 return E_NOTIMPL;
4752 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4754 Context_CTI_QueryInterface,
4755 Context_CTI_AddRef,
4756 Context_CTI_Release,
4757 Context_CTI_GetCurrentApartmentType,
4758 Context_CTI_GetCurrentThreadType,
4759 Context_CTI_GetCurrentLogicalThreadId,
4760 Context_CTI_SetCurrentLogicalThreadId
4763 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4765 Context *This = impl_from_IContextCallback(iface);
4766 return Context_QueryInterface(This, riid, ppv);
4769 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4771 Context *This = impl_from_IContextCallback(iface);
4772 return Context_AddRef(This);
4775 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4777 Context *This = impl_from_IContextCallback(iface);
4778 return Context_Release(This);
4781 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4782 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4784 Context *This = impl_from_IContextCallback(iface);
4786 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4787 return E_NOTIMPL;
4790 static const IContextCallbackVtbl Context_Callback_Vtbl =
4792 Context_CC_QueryInterface,
4793 Context_CC_AddRef,
4794 Context_CC_Release,
4795 Context_CC_ContextCallback
4798 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4800 Context *This = impl_from_IObjContext(iface);
4801 return Context_QueryInterface(This, riid, ppv);
4804 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4806 Context *This = impl_from_IObjContext(iface);
4807 return Context_AddRef(This);
4810 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4812 Context *This = impl_from_IObjContext(iface);
4813 return Context_Release(This);
4816 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4818 Context *This = impl_from_IObjContext(iface);
4820 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4821 return E_NOTIMPL;
4824 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4826 Context *This = impl_from_IObjContext(iface);
4828 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4829 return E_NOTIMPL;
4832 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4834 Context *This = impl_from_IObjContext(iface);
4836 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4837 return E_NOTIMPL;
4840 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4842 Context *This = impl_from_IObjContext(iface);
4844 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4845 return E_NOTIMPL;
4848 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4850 Context *This = impl_from_IObjContext(iface);
4851 FIXME("(%p/%p)\n", This, iface);
4854 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4856 Context *This = impl_from_IObjContext(iface);
4857 FIXME("(%p/%p)\n", This, iface);
4860 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4862 Context *This = impl_from_IObjContext(iface);
4863 FIXME("(%p/%p)\n", This, iface);
4866 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4868 Context *This = impl_from_IObjContext(iface);
4869 FIXME("(%p/%p)\n", This, iface);
4872 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4874 Context *This = impl_from_IObjContext(iface);
4875 FIXME("(%p/%p)\n", This, iface);
4878 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4880 Context *This = impl_from_IObjContext(iface);
4881 FIXME("(%p/%p)\n", This, iface);
4884 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4886 Context *This = impl_from_IObjContext(iface);
4887 FIXME("(%p/%p)\n", This, iface);
4890 static const IObjContextVtbl Context_Object_Vtbl =
4892 Context_OC_QueryInterface,
4893 Context_OC_AddRef,
4894 Context_OC_Release,
4895 Context_OC_SetProperty,
4896 Context_OC_RemoveProperty,
4897 Context_OC_GetProperty,
4898 Context_OC_EnumContextProps,
4899 Context_OC_Reserved1,
4900 Context_OC_Reserved2,
4901 Context_OC_Reserved3,
4902 Context_OC_Reserved4,
4903 Context_OC_Reserved5,
4904 Context_OC_Reserved6,
4905 Context_OC_Reserved7
4908 /***********************************************************************
4909 * CoGetObjectContext [OLE32.@]
4911 * Retrieves an object associated with the current context (i.e. apartment).
4913 * PARAMS
4914 * riid [I] ID of the interface of the object to retrieve.
4915 * ppv [O] Address where object will be stored on return.
4917 * RETURNS
4918 * Success: S_OK.
4919 * Failure: HRESULT code.
4921 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4923 APARTMENT *apt = COM_CurrentApt();
4924 Context *context;
4925 HRESULT hr;
4927 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4929 *ppv = NULL;
4930 if (!apt)
4932 if (!(apt = apartment_find_multi_threaded()))
4934 ERR("apartment not initialised\n");
4935 return CO_E_NOTINITIALIZED;
4937 apartment_release(apt);
4940 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4941 if (!context)
4942 return E_OUTOFMEMORY;
4944 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4945 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4946 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4947 context->refs = 1;
4948 if (apt->multi_threaded)
4949 context->apttype = APTTYPE_MTA;
4950 else if (apt->main)
4951 context->apttype = APTTYPE_MAINSTA;
4952 else
4953 context->apttype = APTTYPE_STA;
4955 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4956 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4958 return hr;
4962 /***********************************************************************
4963 * CoGetContextToken [OLE32.@]
4965 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4967 struct oletls *info = COM_CurrentInfo();
4969 TRACE("(%p)\n", token);
4971 if (!info)
4972 return E_OUTOFMEMORY;
4974 if (!info->apt)
4976 APARTMENT *apt;
4977 if (!(apt = apartment_find_multi_threaded()))
4979 ERR("apartment not initialised\n");
4980 return CO_E_NOTINITIALIZED;
4982 apartment_release(apt);
4985 if (!token)
4986 return E_POINTER;
4988 if (!info->context_token)
4990 HRESULT hr;
4991 IObjContext *ctx;
4993 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4994 if (FAILED(hr)) return hr;
4995 info->context_token = ctx;
4998 *token = (ULONG_PTR)info->context_token;
4999 TRACE("apt->context_token=%p\n", info->context_token);
5001 return S_OK;
5004 /***********************************************************************
5005 * CoGetDefaultContext [OLE32.@]
5007 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
5009 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
5010 return E_NOINTERFACE;
5013 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
5015 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5016 HKEY hkey;
5017 HRESULT hres;
5019 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5020 if (SUCCEEDED(hres))
5022 struct class_reg_data regdata;
5023 WCHAR dllpath[MAX_PATH+1];
5025 regdata.u.hkey = hkey;
5026 regdata.hkey = TRUE;
5028 if (COM_RegReadPath(&regdata, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
5030 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5031 if (!strcmpiW(dllpath, wszOle32))
5033 RegCloseKey(hkey);
5034 return HandlerCF_Create(rclsid, riid, ppv);
5037 else
5038 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5039 RegCloseKey(hkey);
5042 return CLASS_E_CLASSNOTAVAILABLE;
5045 /***********************************************************************
5046 * DllMain (OLE32.@)
5048 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5050 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5052 switch(fdwReason) {
5053 case DLL_PROCESS_ATTACH:
5054 hProxyDll = hinstDLL;
5055 break;
5057 case DLL_PROCESS_DETACH:
5058 if (reserved) break;
5059 release_std_git();
5060 UnregisterClassW( wszAptWinClass, hProxyDll );
5061 RPC_UnregisterAllChannelHooks();
5062 COMPOBJ_DllList_Free();
5063 DeleteCriticalSection(&csRegisteredClassList);
5064 DeleteCriticalSection(&csApartment);
5065 break;
5067 case DLL_THREAD_DETACH:
5068 COM_TlsDestroy();
5069 break;
5071 return TRUE;
5074 /***********************************************************************
5075 * DllRegisterServer (OLE32.@)
5077 HRESULT WINAPI DllRegisterServer(void)
5079 return OLE32_DllRegisterServer();
5082 /***********************************************************************
5083 * DllUnregisterServer (OLE32.@)
5085 HRESULT WINAPI DllUnregisterServer(void)
5087 return OLE32_DllUnregisterServer();