ole32: New high resolution cursors generated from SVG.
[wine.git] / dlls / ole32 / compobj.c
blob60244485249b216d0a0d69d8e73aa1884708e113
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 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
335 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
337 static HKEY classes_root_hkey;
339 /* create the special HKEY_CLASSES_ROOT key */
340 static HKEY create_classes_root_hkey(DWORD access)
342 HKEY hkey, ret = 0;
343 OBJECT_ATTRIBUTES attr;
344 UNICODE_STRING name;
346 attr.Length = sizeof(attr);
347 attr.RootDirectory = 0;
348 attr.ObjectName = &name;
349 attr.Attributes = 0;
350 attr.SecurityDescriptor = NULL;
351 attr.SecurityQualityOfService = NULL;
352 RtlInitUnicodeString( &name, classes_rootW );
353 if (create_key( &hkey, access, &attr )) return 0;
354 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
356 if (!(access & KEY_WOW64_64KEY))
358 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
359 ret = hkey;
360 else
361 NtClose( hkey ); /* somebody beat us to it */
363 else
364 ret = hkey;
365 return ret;
368 /* map the hkey from special root to normal key if necessary */
369 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
371 HKEY ret = hkey;
372 const BOOL is_win64 = sizeof(void*) > sizeof(int);
373 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
375 if (hkey == HKEY_CLASSES_ROOT &&
376 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
377 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
378 if (force_wow32 && ret && ret == classes_root_hkey)
380 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
381 access &= ~KEY_WOW64_32KEY;
382 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
383 return 0;
384 ret = hkey;
387 return ret;
390 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
392 OBJECT_ATTRIBUTES attr;
393 UNICODE_STRING nameW;
395 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
397 attr.Length = sizeof(attr);
398 attr.RootDirectory = hkey;
399 attr.ObjectName = &nameW;
400 attr.Attributes = 0;
401 attr.SecurityDescriptor = NULL;
402 attr.SecurityQualityOfService = NULL;
403 RtlInitUnicodeString( &nameW, name );
405 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
408 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
410 OBJECT_ATTRIBUTES attr;
411 UNICODE_STRING nameW;
413 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
415 attr.Length = sizeof(attr);
416 attr.RootDirectory = hkey;
417 attr.ObjectName = &nameW;
418 attr.Attributes = 0;
419 attr.SecurityDescriptor = NULL;
420 attr.SecurityQualityOfService = NULL;
421 RtlInitUnicodeString( &nameW, name );
423 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
426 /*****************************************************************************
427 * This section contains OpenDllList definitions
429 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
430 * other functions that do LoadLibrary _without_ giving back a HMODULE.
431 * Without this list these handles would never be freed.
433 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
434 * next unload-call but not before 600 sec.
437 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
438 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
440 typedef struct tagOpenDll
442 LONG refs;
443 LPWSTR library_name;
444 HANDLE library;
445 DllGetClassObjectFunc DllGetClassObject;
446 DllCanUnloadNowFunc DllCanUnloadNow;
447 struct list entry;
448 } OpenDll;
450 static struct list openDllList = LIST_INIT(openDllList);
452 static CRITICAL_SECTION csOpenDllList;
453 static CRITICAL_SECTION_DEBUG dll_cs_debug =
455 0, 0, &csOpenDllList,
456 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
457 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
459 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
461 struct apartment_loaded_dll
463 struct list entry;
464 OpenDll *dll;
465 DWORD unload_time;
466 BOOL multi_threaded;
469 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',0};
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 DECLSPEC_HOTPATCH 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 DECLSPEC_HOTPATCH 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 if (info->ole_inits)
1976 WARN("uninitializing apartment while Ole is still initialized\n");
1977 apartment_release(info->apt);
1978 info->apt = NULL;
1982 * Decrease the reference count.
1983 * If we are back to 0 locks on the COM library, make sure we free
1984 * all the associated data structures.
1986 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1987 if (lCOMRefCnt==1)
1989 TRACE("() - Releasing the COM libraries\n");
1991 RunningObjectTableImpl_UnInitialize();
1993 else if (lCOMRefCnt<1) {
1994 ERR( "CoUninitialize() - not CoInitialized.\n" );
1995 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1997 if (info->spy)
1998 IInitializeSpy_PostUninitialize(info->spy, info->inits);
2001 /******************************************************************************
2002 * CoDisconnectObject [OLE32.@]
2004 * Disconnects all connections to this object from remote processes. Dispatches
2005 * pending RPCs while blocking new RPCs from occurring, and then calls
2006 * IMarshal::DisconnectObject on the given object.
2008 * Typically called when the object server is forced to shut down, for instance by
2009 * the user.
2011 * PARAMS
2012 * lpUnk [I] The object whose stub should be disconnected.
2013 * reserved [I] Reserved. Should be set to 0.
2015 * RETURNS
2016 * Success: S_OK.
2017 * Failure: HRESULT code.
2019 * SEE ALSO
2020 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2022 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2024 struct stub_manager *manager;
2025 HRESULT hr;
2026 IMarshal *marshal;
2027 APARTMENT *apt;
2029 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2031 if (!lpUnk) return E_INVALIDARG;
2033 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2034 if (hr == S_OK)
2036 hr = IMarshal_DisconnectObject(marshal, reserved);
2037 IMarshal_Release(marshal);
2038 return hr;
2041 apt = COM_CurrentApt();
2042 if (!apt)
2043 return CO_E_NOTINITIALIZED;
2045 manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2046 if (manager) {
2047 stub_manager_disconnect(manager);
2048 /* Release stub manager twice, to remove the apartment reference. */
2049 stub_manager_int_release(manager);
2050 stub_manager_int_release(manager);
2053 /* Note: native is pretty broken here because it just silently
2054 * fails, without returning an appropriate error code if the object was
2055 * not found, making apps think that the object was disconnected, when
2056 * it actually wasn't */
2058 return S_OK;
2061 /******************************************************************************
2062 * CoCreateGuid [OLE32.@]
2064 * Simply forwards to UuidCreate in RPCRT4.
2066 * PARAMS
2067 * pguid [O] Points to the GUID to initialize.
2069 * RETURNS
2070 * Success: S_OK.
2071 * Failure: HRESULT code.
2073 * SEE ALSO
2074 * UuidCreate
2076 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2078 DWORD status;
2080 if(!pguid) return E_INVALIDARG;
2082 status = UuidCreate(pguid);
2083 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2084 return HRESULT_FROM_WIN32( status );
2087 static inline BOOL is_valid_hex(WCHAR c)
2089 if (!(((c >= '0') && (c <= '9')) ||
2090 ((c >= 'a') && (c <= 'f')) ||
2091 ((c >= 'A') && (c <= 'F'))))
2092 return FALSE;
2093 return TRUE;
2096 static const BYTE guid_conv_table[256] =
2098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2099 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2101 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2102 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2104 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2107 /* conversion helper for CLSIDFromString/IIDFromString */
2108 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2110 int i;
2112 if (!s || s[0]!='{') {
2113 memset( id, 0, sizeof (CLSID) );
2114 if(!s) return TRUE;
2115 return FALSE;
2118 TRACE("%s -> %p\n", debugstr_w(s), id);
2120 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2122 id->Data1 = 0;
2123 for (i = 1; i < 9; i++) {
2124 if (!is_valid_hex(s[i])) return FALSE;
2125 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2127 if (s[9]!='-') return FALSE;
2129 id->Data2 = 0;
2130 for (i = 10; i < 14; i++) {
2131 if (!is_valid_hex(s[i])) return FALSE;
2132 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2134 if (s[14]!='-') return FALSE;
2136 id->Data3 = 0;
2137 for (i = 15; i < 19; i++) {
2138 if (!is_valid_hex(s[i])) return FALSE;
2139 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2141 if (s[19]!='-') return FALSE;
2143 for (i = 20; i < 37; i+=2) {
2144 if (i == 24) {
2145 if (s[i]!='-') return FALSE;
2146 i++;
2148 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2149 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2152 if (s[37] == '}' && s[38] == '\0')
2153 return TRUE;
2155 return FALSE;
2158 /*****************************************************************************/
2160 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2162 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2163 WCHAR buf2[CHARS_IN_GUID];
2164 LONG buf2len = sizeof(buf2);
2165 HKEY xhkey;
2166 WCHAR *buf;
2168 memset(clsid, 0, sizeof(*clsid));
2169 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2170 if (!buf) return E_OUTOFMEMORY;
2171 strcpyW( buf, progid );
2172 strcatW( buf, clsidW );
2173 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2175 HeapFree(GetProcessHeap(),0,buf);
2176 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2177 return CO_E_CLASSSTRING;
2179 HeapFree(GetProcessHeap(),0,buf);
2181 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2183 RegCloseKey(xhkey);
2184 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2185 return CO_E_CLASSSTRING;
2187 RegCloseKey(xhkey);
2188 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2191 /******************************************************************************
2192 * CLSIDFromString [OLE32.@]
2194 * Converts a unique identifier from its string representation into
2195 * the GUID struct.
2197 * PARAMS
2198 * idstr [I] The string representation of the GUID.
2199 * id [O] GUID converted from the string.
2201 * RETURNS
2202 * S_OK on success
2203 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2205 * SEE ALSO
2206 * StringFromCLSID
2208 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2210 HRESULT ret = CO_E_CLASSSTRING;
2211 CLSID tmp_id;
2213 if (!id)
2214 return E_INVALIDARG;
2216 if (guid_from_string(idstr, id))
2217 return S_OK;
2219 /* It appears a ProgID is also valid */
2220 ret = clsid_from_string_reg(idstr, &tmp_id);
2221 if(SUCCEEDED(ret))
2222 *id = tmp_id;
2224 return ret;
2227 /******************************************************************************
2228 * IIDFromString [OLE32.@]
2230 * Converts an interface identifier from its string representation to
2231 * the IID struct.
2233 * PARAMS
2234 * idstr [I] The string representation of the GUID.
2235 * id [O] IID converted from the string.
2237 * RETURNS
2238 * S_OK on success
2239 * CO_E_IIDSTRING if idstr is not a valid IID
2241 * SEE ALSO
2242 * StringFromIID
2244 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2246 TRACE("%s -> %p\n", debugstr_w(s), iid);
2248 if (!s)
2250 memset(iid, 0, sizeof(*iid));
2251 return S_OK;
2254 /* length mismatch is a special case */
2255 if (strlenW(s) + 1 != CHARS_IN_GUID)
2256 return E_INVALIDARG;
2258 if (s[0] != '{')
2259 return CO_E_IIDSTRING;
2261 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2264 /******************************************************************************
2265 * StringFromCLSID [OLE32.@]
2266 * StringFromIID [OLE32.@]
2268 * Converts a GUID into the respective string representation.
2269 * The target string is allocated using the OLE IMalloc.
2271 * PARAMS
2272 * id [I] the GUID to be converted.
2273 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2275 * RETURNS
2276 * S_OK
2277 * E_FAIL
2279 * SEE ALSO
2280 * StringFromGUID2, CLSIDFromString
2282 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2284 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2285 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2286 return S_OK;
2289 /******************************************************************************
2290 * StringFromGUID2 [OLE32.@]
2292 * Modified version of StringFromCLSID that allows you to specify max
2293 * buffer size.
2295 * PARAMS
2296 * id [I] GUID to convert to string.
2297 * str [O] Buffer where the result will be stored.
2298 * cmax [I] Size of the buffer in characters.
2300 * RETURNS
2301 * Success: The length of the resulting string in characters.
2302 * Failure: 0.
2304 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2306 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2307 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2308 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2309 '%','0','2','X','%','0','2','X','}',0 };
2310 if (!id || cmax < CHARS_IN_GUID) return 0;
2311 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2312 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2313 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2314 return CHARS_IN_GUID;
2317 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2318 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2320 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2321 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2322 LONG res;
2323 HKEY key;
2325 strcpyW(path, wszCLSIDSlash);
2326 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2327 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2328 if (res == ERROR_FILE_NOT_FOUND)
2329 return REGDB_E_CLASSNOTREG;
2330 else if (res != ERROR_SUCCESS)
2331 return REGDB_E_READREGDB;
2333 if (!keyname)
2335 *subkey = key;
2336 return S_OK;
2339 res = open_classes_key(key, keyname, access, subkey);
2340 RegCloseKey(key);
2341 if (res == ERROR_FILE_NOT_FOUND)
2342 return REGDB_E_KEYMISSING;
2343 else if (res != ERROR_SUCCESS)
2344 return REGDB_E_READREGDB;
2346 return S_OK;
2349 /* open HKCR\\AppId\\{string form of appid clsid} key */
2350 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2352 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2353 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2354 DWORD res;
2355 WCHAR buf[CHARS_IN_GUID];
2356 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2357 DWORD size;
2358 HKEY hkey;
2359 DWORD type;
2360 HRESULT hr;
2362 /* read the AppID value under the class's key */
2363 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2364 if (FAILED(hr))
2365 return hr;
2367 size = sizeof(buf);
2368 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2369 RegCloseKey(hkey);
2370 if (res == ERROR_FILE_NOT_FOUND)
2371 return REGDB_E_KEYMISSING;
2372 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2373 return REGDB_E_READREGDB;
2375 strcpyW(keyname, szAppIdKey);
2376 strcatW(keyname, buf);
2377 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2378 if (res == ERROR_FILE_NOT_FOUND)
2379 return REGDB_E_KEYMISSING;
2380 else if (res != ERROR_SUCCESS)
2381 return REGDB_E_READREGDB;
2383 return S_OK;
2386 /******************************************************************************
2387 * ProgIDFromCLSID [OLE32.@]
2389 * Converts a class id into the respective program ID.
2391 * PARAMS
2392 * clsid [I] Class ID, as found in registry.
2393 * ppszProgID [O] Associated ProgID.
2395 * RETURNS
2396 * S_OK
2397 * E_OUTOFMEMORY
2398 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2400 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2402 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2403 ACTCTX_SECTION_KEYED_DATA data;
2404 HKEY hkey;
2405 HRESULT ret;
2406 LONG progidlen = 0;
2408 if (!ppszProgID)
2409 return E_INVALIDARG;
2411 *ppszProgID = NULL;
2413 data.cbSize = sizeof(data);
2414 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2415 clsid, &data))
2417 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2418 if (comclass->progid_len)
2420 WCHAR *ptrW;
2422 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2423 if (!*ppszProgID) return E_OUTOFMEMORY;
2425 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2426 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2427 return S_OK;
2429 else
2430 return REGDB_E_CLASSNOTREG;
2433 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2434 if (FAILED(ret))
2435 return ret;
2437 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2438 ret = REGDB_E_CLASSNOTREG;
2440 if (ret == S_OK)
2442 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2443 if (*ppszProgID)
2445 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2446 ret = REGDB_E_CLASSNOTREG;
2447 CoTaskMemFree(*ppszProgID);
2448 *ppszProgID = NULL;
2451 else
2452 ret = E_OUTOFMEMORY;
2455 RegCloseKey(hkey);
2456 return ret;
2459 /******************************************************************************
2460 * CLSIDFromProgID [OLE32.@]
2462 * Converts a program id into the respective GUID.
2464 * PARAMS
2465 * progid [I] Unicode program ID, as found in registry.
2466 * clsid [O] Associated CLSID.
2468 * RETURNS
2469 * Success: S_OK
2470 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2472 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2474 ACTCTX_SECTION_KEYED_DATA data;
2476 if (!progid || !clsid)
2477 return E_INVALIDARG;
2479 data.cbSize = sizeof(data);
2480 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2481 progid, &data))
2483 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2484 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2485 *clsid = *alias;
2486 return S_OK;
2489 return clsid_from_string_reg(progid, clsid);
2492 /******************************************************************************
2493 * CLSIDFromProgIDEx [OLE32.@]
2495 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2497 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2499 return CLSIDFromProgID(progid, clsid);
2502 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2504 HKEY hkey;
2505 WCHAR value[CHARS_IN_GUID];
2506 DWORD len;
2508 access |= KEY_READ;
2510 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2511 return REGDB_E_IIDNOTREG;
2513 len = sizeof(value);
2514 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2515 return REGDB_E_IIDNOTREG;
2516 RegCloseKey(hkey);
2518 if (CLSIDFromString(value, pclsid) != NOERROR)
2519 return REGDB_E_IIDNOTREG;
2521 return S_OK;
2524 /*****************************************************************************
2525 * CoGetPSClsid [OLE32.@]
2527 * Retrieves the CLSID of the proxy/stub factory that implements
2528 * IPSFactoryBuffer for the specified interface.
2530 * PARAMS
2531 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2532 * pclsid [O] Where to store returned proxy/stub CLSID.
2534 * RETURNS
2535 * S_OK
2536 * E_OUTOFMEMORY
2537 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2539 * NOTES
2541 * The standard marshaller activates the object with the CLSID
2542 * returned and uses the CreateProxy and CreateStub methods on its
2543 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2544 * given object.
2546 * CoGetPSClsid determines this CLSID by searching the
2547 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2548 * in the registry and any interface id registered by
2549 * CoRegisterPSClsid within the current process.
2551 * BUGS
2553 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2554 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2555 * considered a bug in native unless an application depends on this (unlikely).
2557 * SEE ALSO
2558 * CoRegisterPSClsid.
2560 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2562 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2563 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2564 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2565 APARTMENT *apt = COM_CurrentApt();
2566 struct registered_psclsid *registered_psclsid;
2567 ACTCTX_SECTION_KEYED_DATA data;
2568 HRESULT hr;
2569 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2570 BOOL is_wow64;
2572 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2574 if (!apt)
2576 ERR("apartment not initialised\n");
2577 return CO_E_NOTINITIALIZED;
2580 if (!pclsid)
2581 return E_INVALIDARG;
2583 EnterCriticalSection(&apt->cs);
2585 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2586 if (IsEqualIID(&registered_psclsid->iid, riid))
2588 *pclsid = registered_psclsid->clsid;
2589 LeaveCriticalSection(&apt->cs);
2590 return S_OK;
2593 LeaveCriticalSection(&apt->cs);
2595 data.cbSize = sizeof(data);
2596 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2597 riid, &data))
2599 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2600 *pclsid = ifaceps->iid;
2601 return S_OK;
2604 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2605 strcpyW(path, wszInterface);
2606 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2607 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2609 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2610 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2611 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2612 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2614 if (hr == S_OK)
2615 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2616 else
2617 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2619 return hr;
2622 /*****************************************************************************
2623 * CoRegisterPSClsid [OLE32.@]
2625 * Register a proxy/stub CLSID for the given interface in the current process
2626 * only.
2628 * PARAMS
2629 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2630 * rclsid [I] CLSID of the proxy/stub.
2632 * RETURNS
2633 * Success: S_OK
2634 * Failure: E_OUTOFMEMORY
2636 * NOTES
2638 * This function does not add anything to the registry and the effects are
2639 * limited to the lifetime of the current process.
2641 * SEE ALSO
2642 * CoGetPSClsid.
2644 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2646 APARTMENT *apt = COM_CurrentApt();
2647 struct registered_psclsid *registered_psclsid;
2649 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2651 if (!apt)
2653 ERR("apartment not initialised\n");
2654 return CO_E_NOTINITIALIZED;
2657 EnterCriticalSection(&apt->cs);
2659 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2660 if (IsEqualIID(&registered_psclsid->iid, riid))
2662 registered_psclsid->clsid = *rclsid;
2663 LeaveCriticalSection(&apt->cs);
2664 return S_OK;
2667 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2668 if (!registered_psclsid)
2670 LeaveCriticalSection(&apt->cs);
2671 return E_OUTOFMEMORY;
2674 registered_psclsid->iid = *riid;
2675 registered_psclsid->clsid = *rclsid;
2676 list_add_head(&apt->psclsids, &registered_psclsid->entry);
2678 LeaveCriticalSection(&apt->cs);
2680 return S_OK;
2684 /***
2685 * COM_GetRegisteredClassObject
2687 * This internal method is used to scan the registered class list to
2688 * find a class object.
2690 * Params:
2691 * rclsid Class ID of the class to find.
2692 * dwClsContext Class context to match.
2693 * ppv [out] returns a pointer to the class object. Complying
2694 * to normal COM usage, this method will increase the
2695 * reference count on this object.
2697 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2698 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2700 HRESULT hr = S_FALSE;
2701 RegisteredClass *curClass;
2703 EnterCriticalSection( &csRegisteredClassList );
2705 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2708 * Check if we have a match on the class ID and context.
2710 if ((apt->oxid == curClass->apartment_id) &&
2711 (dwClsContext & curClass->runContext) &&
2712 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2715 * We have a match, return the pointer to the class object.
2717 *ppUnk = curClass->classObject;
2719 IUnknown_AddRef(curClass->classObject);
2721 hr = S_OK;
2722 break;
2726 LeaveCriticalSection( &csRegisteredClassList );
2728 return hr;
2731 /******************************************************************************
2732 * CoRegisterClassObject [OLE32.@]
2734 * Registers the class object for a given class ID. Servers housed in EXE
2735 * files use this method instead of exporting DllGetClassObject to allow
2736 * other code to connect to their objects.
2738 * PARAMS
2739 * rclsid [I] CLSID of the object to register.
2740 * pUnk [I] IUnknown of the object.
2741 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2742 * flags [I] REGCLS flags indicating how connections are made.
2743 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2745 * RETURNS
2746 * S_OK on success,
2747 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2748 * CO_E_OBJISREG if the object is already registered. We should not return this.
2750 * SEE ALSO
2751 * CoRevokeClassObject, CoGetClassObject
2753 * NOTES
2754 * In-process objects are only registered for the current apartment.
2755 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2756 * in other apartments.
2758 * BUGS
2759 * MSDN claims that multiple interface registrations are legal, but we
2760 * can't do that with our current implementation.
2762 HRESULT WINAPI CoRegisterClassObject(
2763 REFCLSID rclsid,
2764 LPUNKNOWN pUnk,
2765 DWORD dwClsContext,
2766 DWORD flags,
2767 LPDWORD lpdwRegister)
2769 static LONG next_cookie;
2770 RegisteredClass* newClass;
2771 LPUNKNOWN foundObject;
2772 HRESULT hr;
2773 APARTMENT *apt;
2775 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2776 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2778 if ( (lpdwRegister==0) || (pUnk==0) )
2779 return E_INVALIDARG;
2781 apt = COM_CurrentApt();
2782 if (!apt)
2784 ERR("COM was not initialized\n");
2785 return CO_E_NOTINITIALIZED;
2788 *lpdwRegister = 0;
2790 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2791 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2792 if (flags & REGCLS_MULTIPLEUSE)
2793 dwClsContext |= CLSCTX_INPROC_SERVER;
2796 * First, check if the class is already registered.
2797 * If it is, this should cause an error.
2799 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2800 if (hr == S_OK) {
2801 if (flags & REGCLS_MULTIPLEUSE) {
2802 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2803 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2804 IUnknown_Release(foundObject);
2805 return hr;
2807 IUnknown_Release(foundObject);
2808 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2809 return CO_E_OBJISREG;
2812 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2813 if ( newClass == NULL )
2814 return E_OUTOFMEMORY;
2816 newClass->classIdentifier = *rclsid;
2817 newClass->apartment_id = apt->oxid;
2818 newClass->runContext = dwClsContext;
2819 newClass->connectFlags = flags;
2820 newClass->RpcRegistration = NULL;
2822 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2823 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2826 * Since we're making a copy of the object pointer, we have to increase its
2827 * reference count.
2829 newClass->classObject = pUnk;
2830 IUnknown_AddRef(newClass->classObject);
2832 EnterCriticalSection( &csRegisteredClassList );
2833 list_add_tail(&RegisteredClassList, &newClass->entry);
2834 LeaveCriticalSection( &csRegisteredClassList );
2836 *lpdwRegister = newClass->dwCookie;
2838 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2839 IStream *marshal_stream;
2841 hr = get_local_server_stream(apt, &marshal_stream);
2842 if(FAILED(hr))
2843 return hr;
2845 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2846 marshal_stream,
2847 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2848 &newClass->RpcRegistration);
2849 IStream_Release(marshal_stream);
2851 return S_OK;
2854 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2856 if (data->hkey)
2858 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2859 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2860 static const WCHAR wszFree[] = {'F','r','e','e',0};
2861 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2862 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2863 DWORD dwLength = sizeof(threading_model);
2864 DWORD keytype;
2865 DWORD ret;
2867 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2868 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2869 threading_model[0] = '\0';
2871 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2872 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2873 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2875 /* there's not specific handling for this case */
2876 if (threading_model[0]) return ThreadingModel_Neutral;
2877 return ThreadingModel_No;
2879 else
2880 return data->u.actctx.data->model;
2883 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2884 REFCLSID rclsid, REFIID riid,
2885 BOOL hostifnecessary, void **ppv)
2887 WCHAR dllpath[MAX_PATH+1];
2888 BOOL apartment_threaded;
2890 if (hostifnecessary)
2892 enum comclass_threadingmodel model = get_threading_model(regdata);
2894 if (model == ThreadingModel_Apartment)
2896 apartment_threaded = TRUE;
2897 if (apt->multi_threaded)
2898 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2900 else if (model == ThreadingModel_Free)
2902 apartment_threaded = FALSE;
2903 if (!apt->multi_threaded)
2904 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2906 /* everything except "Apartment", "Free" and "Both" */
2907 else if (model != ThreadingModel_Both)
2909 apartment_threaded = TRUE;
2910 /* everything else is main-threaded */
2911 if (model != ThreadingModel_No)
2912 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2914 if (apt->multi_threaded || !apt->main)
2915 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2917 else
2918 apartment_threaded = FALSE;
2920 else
2921 apartment_threaded = !apt->multi_threaded;
2923 if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2925 /* failure: CLSID is not found in registry */
2926 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2927 return REGDB_E_CLASSNOTREG;
2930 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2931 rclsid, riid, ppv);
2934 /***********************************************************************
2935 * CoGetClassObject [OLE32.@]
2937 * Creates an object of the specified class.
2939 * PARAMS
2940 * rclsid [I] Class ID to create an instance of.
2941 * dwClsContext [I] Flags to restrict the location of the created instance.
2942 * pServerInfo [I] Optional. Details for connecting to a remote server.
2943 * iid [I] The ID of the interface of the instance to return.
2944 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2946 * RETURNS
2947 * Success: S_OK
2948 * Failure: HRESULT code.
2950 * NOTES
2951 * The dwClsContext parameter can be one or more of the following:
2952 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2953 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2954 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2955 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2957 * SEE ALSO
2958 * CoCreateInstance()
2960 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2961 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2962 REFIID iid, LPVOID *ppv)
2964 struct class_reg_data clsreg;
2965 IUnknown *regClassObject;
2966 HRESULT hres = E_UNEXPECTED;
2967 APARTMENT *apt;
2968 BOOL release_apt = FALSE;
2970 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2972 if (!ppv)
2973 return E_INVALIDARG;
2975 *ppv = NULL;
2977 if (!(apt = COM_CurrentApt()))
2979 if (!(apt = apartment_find_multi_threaded()))
2981 ERR("apartment not initialised\n");
2982 return CO_E_NOTINITIALIZED;
2984 release_apt = TRUE;
2987 if (pServerInfo) {
2988 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2989 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2992 if (CLSCTX_INPROC_SERVER & dwClsContext)
2994 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2996 if (release_apt) apartment_release(apt);
2997 return FTMarshalCF_Create(iid, ppv);
2999 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3000 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
3003 if (CLSCTX_INPROC & dwClsContext)
3005 ACTCTX_SECTION_KEYED_DATA data;
3007 data.cbSize = sizeof(data);
3008 /* search activation context first */
3009 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3010 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3011 rclsid, &data))
3013 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3015 clsreg.u.actctx.hactctx = data.hActCtx;
3016 clsreg.u.actctx.data = data.lpData;
3017 clsreg.u.actctx.section = data.lpSectionBase;
3018 clsreg.hkey = FALSE;
3020 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3021 ReleaseActCtx(data.hActCtx);
3022 if (release_apt) apartment_release(apt);
3023 return hres;
3028 * First, try and see if we can't match the class ID with one of the
3029 * registered classes.
3031 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3032 &regClassObject))
3034 /* Get the required interface from the retrieved pointer. */
3035 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3038 * Since QI got another reference on the pointer, we want to release the
3039 * one we already have. If QI was unsuccessful, this will release the object. This
3040 * is good since we are not returning it in the "out" parameter.
3042 IUnknown_Release(regClassObject);
3043 if (release_apt) apartment_release(apt);
3044 return hres;
3047 /* First try in-process server */
3048 if (CLSCTX_INPROC_SERVER & dwClsContext)
3050 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3051 HKEY hkey;
3053 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3054 if (FAILED(hres))
3056 if (hres == REGDB_E_CLASSNOTREG)
3057 ERR("class %s not registered\n", debugstr_guid(rclsid));
3058 else if (hres == REGDB_E_KEYMISSING)
3060 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3061 hres = REGDB_E_CLASSNOTREG;
3065 if (SUCCEEDED(hres))
3067 clsreg.u.hkey = hkey;
3068 clsreg.hkey = TRUE;
3070 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3071 RegCloseKey(hkey);
3074 /* return if we got a class, otherwise fall through to one of the
3075 * other types */
3076 if (SUCCEEDED(hres))
3078 if (release_apt) apartment_release(apt);
3079 return hres;
3083 /* Next try in-process handler */
3084 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3086 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3087 HKEY hkey;
3089 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3090 if (FAILED(hres))
3092 if (hres == REGDB_E_CLASSNOTREG)
3093 ERR("class %s not registered\n", debugstr_guid(rclsid));
3094 else if (hres == REGDB_E_KEYMISSING)
3096 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3097 hres = REGDB_E_CLASSNOTREG;
3101 if (SUCCEEDED(hres))
3103 clsreg.u.hkey = hkey;
3104 clsreg.hkey = TRUE;
3106 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3107 RegCloseKey(hkey);
3110 /* return if we got a class, otherwise fall through to one of the
3111 * other types */
3112 if (SUCCEEDED(hres))
3114 if (release_apt) apartment_release(apt);
3115 return hres;
3118 if (release_apt) apartment_release(apt);
3120 /* Next try out of process */
3121 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3123 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3124 if (SUCCEEDED(hres))
3125 return hres;
3128 /* Finally try remote: this requires networked DCOM (a lot of work) */
3129 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3131 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3132 hres = REGDB_E_CLASSNOTREG;
3135 if (FAILED(hres))
3136 ERR("no class object %s could be created for context 0x%x\n",
3137 debugstr_guid(rclsid), dwClsContext);
3138 return hres;
3141 /***********************************************************************
3142 * CoResumeClassObjects (OLE32.@)
3144 * Resumes all class objects registered with REGCLS_SUSPENDED.
3146 * RETURNS
3147 * Success: S_OK.
3148 * Failure: HRESULT code.
3150 HRESULT WINAPI CoResumeClassObjects(void)
3152 FIXME("stub\n");
3153 return S_OK;
3156 /***********************************************************************
3157 * CoCreateInstance [OLE32.@]
3159 * Creates an instance of the specified class.
3161 * PARAMS
3162 * rclsid [I] Class ID to create an instance of.
3163 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3164 * dwClsContext [I] Flags to restrict the location of the created instance.
3165 * iid [I] The ID of the interface of the instance to return.
3166 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3168 * RETURNS
3169 * Success: S_OK
3170 * Failure: HRESULT code.
3172 * NOTES
3173 * The dwClsContext parameter can be one or more of the following:
3174 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3175 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3176 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3177 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3179 * Aggregation is the concept of deferring the IUnknown of an object to another
3180 * object. This allows a separate object to behave as though it was part of
3181 * the object and to allow this the pUnkOuter parameter can be set. Note that
3182 * not all objects support having an outer of unknown.
3184 * SEE ALSO
3185 * CoGetClassObject()
3187 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3188 REFCLSID rclsid,
3189 LPUNKNOWN pUnkOuter,
3190 DWORD dwClsContext,
3191 REFIID iid,
3192 LPVOID *ppv)
3194 MULTI_QI multi_qi = { iid };
3195 HRESULT hres;
3197 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3198 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3200 if (ppv==0)
3201 return E_POINTER;
3203 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3204 *ppv = multi_qi.pItf;
3205 return hres;
3208 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3210 ULONG i;
3212 for (i = 0; i < count; i++)
3214 mqi[i].pItf = NULL;
3215 mqi[i].hr = hr;
3219 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3221 ULONG index = 0, fetched = 0;
3223 if (include_unk)
3225 mqi[0].hr = S_OK;
3226 mqi[0].pItf = unk;
3227 index = fetched = 1;
3230 for (; index < count; index++)
3232 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3233 if (mqi[index].hr == S_OK)
3234 fetched++;
3237 if (!include_unk)
3238 IUnknown_Release(unk);
3240 if (fetched == 0)
3241 return E_NOINTERFACE;
3243 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3246 /***********************************************************************
3247 * CoCreateInstanceEx [OLE32.@]
3249 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3250 REFCLSID rclsid,
3251 LPUNKNOWN pUnkOuter,
3252 DWORD dwClsContext,
3253 COSERVERINFO* pServerInfo,
3254 ULONG cmq,
3255 MULTI_QI* pResults)
3257 IUnknown *unk = NULL;
3258 IClassFactory *cf;
3259 APARTMENT *apt;
3260 CLSID clsid;
3261 HRESULT hres;
3263 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3265 if (!cmq || !pResults)
3266 return E_INVALIDARG;
3268 if (pServerInfo)
3269 FIXME("() non-NULL pServerInfo not supported!\n");
3271 init_multi_qi(cmq, pResults, E_NOINTERFACE);
3273 hres = CoGetTreatAsClass(rclsid, &clsid);
3274 if(FAILED(hres))
3275 clsid = *rclsid;
3277 if (!(apt = COM_CurrentApt()))
3279 if (!(apt = apartment_find_multi_threaded()))
3281 ERR("apartment not initialised\n");
3282 return CO_E_NOTINITIALIZED;
3284 apartment_release(apt);
3288 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3290 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3292 IGlobalInterfaceTable *git = get_std_git();
3293 TRACE("Retrieving GIT\n");
3294 return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3297 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) {
3298 hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3299 if (FAILED(hres))
3300 return hres;
3301 return return_multi_qi(unk, cmq, pResults, TRUE);
3305 * Get a class factory to construct the object we want.
3307 hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3308 if (FAILED(hres))
3309 return hres;
3312 * Create the object and don't forget to release the factory
3314 hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3315 IClassFactory_Release(cf);
3316 if (FAILED(hres))
3318 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3319 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3320 else
3321 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3322 debugstr_guid(pResults[0].pIID),
3323 debugstr_guid(&clsid),hres);
3324 return hres;
3327 return return_multi_qi(unk, cmq, pResults, TRUE);
3330 /***********************************************************************
3331 * CoGetInstanceFromFile [OLE32.@]
3333 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(
3334 COSERVERINFO *server_info,
3335 CLSID *rclsid,
3336 IUnknown *outer,
3337 DWORD cls_context,
3338 DWORD grfmode,
3339 OLECHAR *filename,
3340 DWORD count,
3341 MULTI_QI *results
3344 IPersistFile *pf = NULL;
3345 IUnknown* unk = NULL;
3346 CLSID clsid;
3347 HRESULT hr;
3349 if (count == 0 || !results)
3350 return E_INVALIDARG;
3352 if (server_info)
3353 FIXME("() non-NULL server_info not supported\n");
3355 init_multi_qi(count, results, E_NOINTERFACE);
3357 /* optionally get CLSID from a file */
3358 if (!rclsid)
3360 hr = GetClassFile(filename, &clsid);
3361 if (FAILED(hr))
3363 ERR("failed to get CLSID from a file\n");
3364 return hr;
3367 rclsid = &clsid;
3370 hr = CoCreateInstance(rclsid,
3371 outer,
3372 cls_context,
3373 &IID_IUnknown,
3374 (void**)&unk);
3376 if (hr != S_OK)
3378 init_multi_qi(count, results, hr);
3379 return hr;
3382 /* init from file */
3383 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3384 if (FAILED(hr))
3386 init_multi_qi(count, results, hr);
3387 IUnknown_Release(unk);
3388 return hr;
3391 hr = IPersistFile_Load(pf, filename, grfmode);
3392 IPersistFile_Release(pf);
3393 if (SUCCEEDED(hr))
3394 return return_multi_qi(unk, count, results, FALSE);
3395 else
3397 init_multi_qi(count, results, hr);
3398 IUnknown_Release(unk);
3399 return hr;
3403 /***********************************************************************
3404 * CoGetInstanceFromIStorage [OLE32.@]
3406 HRESULT WINAPI CoGetInstanceFromIStorage(
3407 COSERVERINFO *server_info,
3408 CLSID *rclsid,
3409 IUnknown *outer,
3410 DWORD cls_context,
3411 IStorage *storage,
3412 DWORD count,
3413 MULTI_QI *results
3416 IPersistStorage *ps = NULL;
3417 IUnknown* unk = NULL;
3418 STATSTG stat;
3419 HRESULT hr;
3421 if (count == 0 || !results || !storage)
3422 return E_INVALIDARG;
3424 if (server_info)
3425 FIXME("() non-NULL server_info not supported\n");
3427 init_multi_qi(count, results, E_NOINTERFACE);
3429 /* optionally get CLSID from a file */
3430 if (!rclsid)
3432 memset(&stat.clsid, 0, sizeof(stat.clsid));
3433 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3434 if (FAILED(hr))
3436 ERR("failed to get CLSID from a file\n");
3437 return hr;
3440 rclsid = &stat.clsid;
3443 hr = CoCreateInstance(rclsid,
3444 outer,
3445 cls_context,
3446 &IID_IUnknown,
3447 (void**)&unk);
3449 if (hr != S_OK)
3450 return hr;
3452 /* init from IStorage */
3453 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3454 if (FAILED(hr))
3455 ERR("failed to get IPersistStorage\n");
3457 if (ps)
3459 IPersistStorage_Load(ps, storage);
3460 IPersistStorage_Release(ps);
3463 return return_multi_qi(unk, count, results, FALSE);
3466 /***********************************************************************
3467 * CoLoadLibrary (OLE32.@)
3469 * Loads a library.
3471 * PARAMS
3472 * lpszLibName [I] Path to library.
3473 * bAutoFree [I] Whether the library should automatically be freed.
3475 * RETURNS
3476 * Success: Handle to loaded library.
3477 * Failure: NULL.
3479 * SEE ALSO
3480 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3482 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3484 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3486 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3489 /***********************************************************************
3490 * CoFreeLibrary [OLE32.@]
3492 * Unloads a library from memory.
3494 * PARAMS
3495 * hLibrary [I] Handle to library to unload.
3497 * RETURNS
3498 * Nothing
3500 * SEE ALSO
3501 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3503 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3505 FreeLibrary(hLibrary);
3509 /***********************************************************************
3510 * CoFreeAllLibraries [OLE32.@]
3512 * Function for backwards compatibility only. Does nothing.
3514 * RETURNS
3515 * Nothing.
3517 * SEE ALSO
3518 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3520 void WINAPI CoFreeAllLibraries(void)
3522 /* NOP */
3525 /***********************************************************************
3526 * CoFreeUnusedLibrariesEx [OLE32.@]
3528 * Frees any previously unused libraries whose delay has expired and marks
3529 * currently unused libraries for unloading. Unused are identified as those that
3530 * return S_OK from their DllCanUnloadNow function.
3532 * PARAMS
3533 * dwUnloadDelay [I] Unload delay in milliseconds.
3534 * dwReserved [I] Reserved. Set to 0.
3536 * RETURNS
3537 * Nothing.
3539 * SEE ALSO
3540 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3542 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3544 struct apartment *apt = COM_CurrentApt();
3545 if (!apt)
3547 ERR("apartment not initialised\n");
3548 return;
3551 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3554 /***********************************************************************
3555 * CoFreeUnusedLibraries [OLE32.@]
3557 * Frees any unused libraries. Unused are identified as those that return
3558 * S_OK from their DllCanUnloadNow function.
3560 * RETURNS
3561 * Nothing.
3563 * SEE ALSO
3564 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3566 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3568 CoFreeUnusedLibrariesEx(INFINITE, 0);
3571 /***********************************************************************
3572 * CoFileTimeNow [OLE32.@]
3574 * Retrieves the current time in FILETIME format.
3576 * PARAMS
3577 * lpFileTime [O] The current time.
3579 * RETURNS
3580 * S_OK.
3582 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3584 GetSystemTimeAsFileTime( lpFileTime );
3585 return S_OK;
3588 /******************************************************************************
3589 * CoLockObjectExternal [OLE32.@]
3591 * Increments or decrements the external reference count of a stub object.
3593 * PARAMS
3594 * pUnk [I] Stub object.
3595 * fLock [I] If TRUE then increments the external ref-count,
3596 * otherwise decrements.
3597 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3598 * calling CoDisconnectObject.
3600 * RETURNS
3601 * Success: S_OK.
3602 * Failure: HRESULT code.
3604 * NOTES
3605 * If fLock is TRUE and an object is passed in that doesn't have a stub
3606 * manager then a new stub manager is created for the object.
3608 HRESULT WINAPI CoLockObjectExternal(
3609 LPUNKNOWN pUnk,
3610 BOOL fLock,
3611 BOOL fLastUnlockReleases)
3613 struct stub_manager *stubmgr;
3614 struct apartment *apt;
3616 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3617 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3619 apt = COM_CurrentApt();
3620 if (!apt) return CO_E_NOTINITIALIZED;
3622 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3623 if (!stubmgr)
3625 WARN("stub object not found %p\n", pUnk);
3626 /* Note: native is pretty broken here because it just silently
3627 * fails, without returning an appropriate error code, making apps
3628 * think that the object was disconnected, when it actually wasn't */
3629 return S_OK;
3632 if (fLock)
3633 stub_manager_ext_addref(stubmgr, 1, FALSE);
3634 else
3635 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3637 stub_manager_int_release(stubmgr);
3638 return S_OK;
3641 /***********************************************************************
3642 * CoInitializeWOW (OLE32.@)
3644 * WOW equivalent of CoInitialize?
3646 * PARAMS
3647 * x [I] Unknown.
3648 * y [I] Unknown.
3650 * RETURNS
3651 * Unknown.
3653 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3655 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3656 return 0;
3659 /***********************************************************************
3660 * CoGetState [OLE32.@]
3662 * Retrieves the thread state object previously stored by CoSetState().
3664 * PARAMS
3665 * ppv [I] Address where pointer to object will be stored.
3667 * RETURNS
3668 * Success: S_OK.
3669 * Failure: E_OUTOFMEMORY.
3671 * NOTES
3672 * Crashes on all invalid ppv addresses, including NULL.
3673 * If the function returns a non-NULL object then the caller must release its
3674 * reference on the object when the object is no longer required.
3676 * SEE ALSO
3677 * CoSetState().
3679 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3681 struct oletls *info = COM_CurrentInfo();
3682 if (!info) return E_OUTOFMEMORY;
3684 *ppv = NULL;
3686 if (info->state)
3688 IUnknown_AddRef(info->state);
3689 *ppv = info->state;
3690 TRACE("apt->state=%p\n", info->state);
3693 return S_OK;
3696 /***********************************************************************
3697 * CoSetState [OLE32.@]
3699 * Sets the thread state object.
3701 * PARAMS
3702 * pv [I] Pointer to state object to be stored.
3704 * NOTES
3705 * The system keeps a reference on the object while the object stored.
3707 * RETURNS
3708 * Success: S_OK.
3709 * Failure: E_OUTOFMEMORY.
3711 HRESULT WINAPI CoSetState(IUnknown * pv)
3713 struct oletls *info = COM_CurrentInfo();
3714 if (!info) return E_OUTOFMEMORY;
3716 if (pv) IUnknown_AddRef(pv);
3718 if (info->state)
3720 TRACE("-- release %p now\n", info->state);
3721 IUnknown_Release(info->state);
3724 info->state = pv;
3726 return S_OK;
3730 /******************************************************************************
3731 * CoTreatAsClass [OLE32.@]
3733 * Sets the TreatAs value of a class.
3735 * PARAMS
3736 * clsidOld [I] Class to set TreatAs value on.
3737 * clsidNew [I] The class the clsidOld should be treated as.
3739 * RETURNS
3740 * Success: S_OK.
3741 * Failure: HRESULT code.
3743 * SEE ALSO
3744 * CoGetTreatAsClass
3746 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3748 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3749 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3750 HKEY hkey = NULL;
3751 WCHAR szClsidNew[CHARS_IN_GUID];
3752 HRESULT res = S_OK;
3753 WCHAR auto_treat_as[CHARS_IN_GUID];
3754 LONG auto_treat_as_size = sizeof(auto_treat_as);
3755 CLSID id;
3757 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3758 if (FAILED(res))
3759 goto done;
3761 if (IsEqualGUID( clsidOld, clsidNew ))
3763 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3764 CLSIDFromString(auto_treat_as, &id) == S_OK)
3766 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3768 res = REGDB_E_WRITEREGDB;
3769 goto done;
3772 else
3774 if(RegDeleteKeyW(hkey, wszTreatAs))
3775 res = REGDB_E_WRITEREGDB;
3776 goto done;
3779 else
3781 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3782 RegDeleteKeyW(hkey, wszTreatAs);
3783 }else{
3784 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
3785 WARN("StringFromGUID2 failed\n");
3786 res = E_FAIL;
3787 goto done;
3790 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3791 WARN("RegSetValue failed\n");
3792 res = REGDB_E_WRITEREGDB;
3793 goto done;
3798 done:
3799 if (hkey) RegCloseKey(hkey);
3800 return res;
3803 /******************************************************************************
3804 * CoGetTreatAsClass [OLE32.@]
3806 * Gets the TreatAs value of a class.
3808 * PARAMS
3809 * clsidOld [I] Class to get the TreatAs value of.
3810 * clsidNew [I] The class the clsidOld should be treated as.
3812 * RETURNS
3813 * Success: S_OK.
3814 * Failure: HRESULT code.
3816 * SEE ALSO
3817 * CoSetTreatAsClass
3819 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3821 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3822 HKEY hkey = NULL;
3823 WCHAR szClsidNew[CHARS_IN_GUID];
3824 HRESULT res = S_OK;
3825 LONG len = sizeof(szClsidNew);
3827 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3829 if (!clsidOld || !clsidNew)
3830 return E_INVALIDARG;
3832 *clsidNew = *clsidOld; /* copy over old value */
3834 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3835 if (FAILED(res))
3837 res = S_FALSE;
3838 goto done;
3840 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3842 res = S_FALSE;
3843 goto done;
3845 res = CLSIDFromString(szClsidNew,clsidNew);
3846 if (FAILED(res))
3847 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3848 done:
3849 if (hkey) RegCloseKey(hkey);
3850 return res;
3853 /******************************************************************************
3854 * CoGetCurrentProcess [OLE32.@]
3856 * Gets the current process ID.
3858 * RETURNS
3859 * The current process ID.
3861 * NOTES
3862 * Is DWORD really the correct return type for this function?
3864 DWORD WINAPI CoGetCurrentProcess(void)
3866 return GetCurrentProcessId();
3869 /***********************************************************************
3870 * CoGetCurrentLogicalThreadId [OLE32.@]
3872 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
3874 TRACE("(%p)\n", id);
3876 if (!id)
3877 return E_INVALIDARG;
3879 *id = COM_CurrentCausalityId();
3880 return S_OK;
3883 /******************************************************************************
3884 * CoRegisterMessageFilter [OLE32.@]
3886 * Registers a message filter.
3888 * PARAMS
3889 * lpMessageFilter [I] Pointer to interface.
3890 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3892 * RETURNS
3893 * Success: S_OK.
3894 * Failure: HRESULT code.
3896 * NOTES
3897 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3898 * lpMessageFilter removes the message filter.
3900 * If lplpMessageFilter is not NULL the previous message filter will be
3901 * returned in the memory pointer to this parameter and the caller is
3902 * responsible for releasing the object.
3904 * The current thread be in an apartment otherwise the function will crash.
3906 HRESULT WINAPI CoRegisterMessageFilter(
3907 LPMESSAGEFILTER lpMessageFilter,
3908 LPMESSAGEFILTER *lplpMessageFilter)
3910 struct apartment *apt;
3911 IMessageFilter *lpOldMessageFilter;
3913 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3915 apt = COM_CurrentApt();
3917 /* can't set a message filter in a multi-threaded apartment */
3918 if (!apt || apt->multi_threaded)
3920 WARN("can't set message filter in MTA or uninitialized apt\n");
3921 return CO_E_NOT_SUPPORTED;
3924 if (lpMessageFilter)
3925 IMessageFilter_AddRef(lpMessageFilter);
3927 EnterCriticalSection(&apt->cs);
3929 lpOldMessageFilter = apt->filter;
3930 apt->filter = lpMessageFilter;
3932 LeaveCriticalSection(&apt->cs);
3934 if (lplpMessageFilter)
3935 *lplpMessageFilter = lpOldMessageFilter;
3936 else if (lpOldMessageFilter)
3937 IMessageFilter_Release(lpOldMessageFilter);
3939 return S_OK;
3942 /***********************************************************************
3943 * CoIsOle1Class [OLE32.@]
3945 * Determines whether the specified class an OLE v1 class.
3947 * PARAMS
3948 * clsid [I] Class to test.
3950 * RETURNS
3951 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3953 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3955 FIXME("%s\n", debugstr_guid(clsid));
3956 return FALSE;
3959 /***********************************************************************
3960 * IsEqualGUID [OLE32.@]
3962 * Compares two Unique Identifiers.
3964 * PARAMS
3965 * rguid1 [I] The first GUID to compare.
3966 * rguid2 [I] The other GUID to compare.
3968 * RETURNS
3969 * TRUE if equal
3971 #undef IsEqualGUID
3972 BOOL WINAPI IsEqualGUID(
3973 REFGUID rguid1,
3974 REFGUID rguid2)
3976 return !memcmp(rguid1,rguid2,sizeof(GUID));
3979 /***********************************************************************
3980 * CoInitializeSecurity [OLE32.@]
3982 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3983 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3984 void* pReserved1, DWORD dwAuthnLevel,
3985 DWORD dwImpLevel, void* pReserved2,
3986 DWORD dwCapabilities, void* pReserved3)
3988 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3989 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3990 dwCapabilities, pReserved3);
3991 return S_OK;
3994 /***********************************************************************
3995 * CoSuspendClassObjects [OLE32.@]
3997 * Suspends all registered class objects to prevent further requests coming in
3998 * for those objects.
4000 * RETURNS
4001 * Success: S_OK.
4002 * Failure: HRESULT code.
4004 HRESULT WINAPI CoSuspendClassObjects(void)
4006 FIXME("\n");
4007 return S_OK;
4010 /***********************************************************************
4011 * CoAddRefServerProcess [OLE32.@]
4013 * Helper function for incrementing the reference count of a local-server
4014 * process.
4016 * RETURNS
4017 * New reference count.
4019 * SEE ALSO
4020 * CoReleaseServerProcess().
4022 ULONG WINAPI CoAddRefServerProcess(void)
4024 ULONG refs;
4026 TRACE("\n");
4028 EnterCriticalSection(&csRegisteredClassList);
4029 refs = ++s_COMServerProcessReferences;
4030 LeaveCriticalSection(&csRegisteredClassList);
4032 TRACE("refs before: %d\n", refs - 1);
4034 return refs;
4037 /***********************************************************************
4038 * CoReleaseServerProcess [OLE32.@]
4040 * Helper function for decrementing the reference count of a local-server
4041 * process.
4043 * RETURNS
4044 * New reference count.
4046 * NOTES
4047 * When reference count reaches 0, this function suspends all registered
4048 * classes so no new connections are accepted.
4050 * SEE ALSO
4051 * CoAddRefServerProcess(), CoSuspendClassObjects().
4053 ULONG WINAPI CoReleaseServerProcess(void)
4055 ULONG refs;
4057 TRACE("\n");
4059 EnterCriticalSection(&csRegisteredClassList);
4061 refs = --s_COMServerProcessReferences;
4062 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4064 LeaveCriticalSection(&csRegisteredClassList);
4066 TRACE("refs after: %d\n", refs);
4068 return refs;
4071 /***********************************************************************
4072 * CoIsHandlerConnected [OLE32.@]
4074 * Determines whether a proxy is connected to a remote stub.
4076 * PARAMS
4077 * pUnk [I] Pointer to object that may or may not be connected.
4079 * RETURNS
4080 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4081 * FALSE otherwise.
4083 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4085 FIXME("%p\n", pUnk);
4087 return TRUE;
4090 /***********************************************************************
4091 * CoAllowSetForegroundWindow [OLE32.@]
4094 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4096 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4097 return S_OK;
4100 /***********************************************************************
4101 * CoQueryProxyBlanket [OLE32.@]
4103 * Retrieves the security settings being used by a proxy.
4105 * PARAMS
4106 * pProxy [I] Pointer to the proxy object.
4107 * pAuthnSvc [O] The type of authentication service.
4108 * pAuthzSvc [O] The type of authorization service.
4109 * ppServerPrincName [O] Optional. The server prinicple name.
4110 * pAuthnLevel [O] The authentication level.
4111 * pImpLevel [O] The impersonation level.
4112 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4113 * pCapabilities [O] Flags affecting the security behaviour.
4115 * RETURNS
4116 * Success: S_OK.
4117 * Failure: HRESULT code.
4119 * SEE ALSO
4120 * CoCopyProxy, CoSetProxyBlanket.
4122 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4123 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4124 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4126 IClientSecurity *pCliSec;
4127 HRESULT hr;
4129 TRACE("%p\n", pProxy);
4131 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4132 if (SUCCEEDED(hr))
4134 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4135 pAuthzSvc, ppServerPrincName,
4136 pAuthnLevel, pImpLevel, ppAuthInfo,
4137 pCapabilities);
4138 IClientSecurity_Release(pCliSec);
4141 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4142 return hr;
4145 /***********************************************************************
4146 * CoSetProxyBlanket [OLE32.@]
4148 * Sets the security settings for a proxy.
4150 * PARAMS
4151 * pProxy [I] Pointer to the proxy object.
4152 * AuthnSvc [I] The type of authentication service.
4153 * AuthzSvc [I] The type of authorization service.
4154 * pServerPrincName [I] The server prinicple name.
4155 * AuthnLevel [I] The authentication level.
4156 * ImpLevel [I] The impersonation level.
4157 * pAuthInfo [I] Information specific to the authorization/authentication service.
4158 * Capabilities [I] Flags affecting the security behaviour.
4160 * RETURNS
4161 * Success: S_OK.
4162 * Failure: HRESULT code.
4164 * SEE ALSO
4165 * CoQueryProxyBlanket, CoCopyProxy.
4167 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4168 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4169 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4171 IClientSecurity *pCliSec;
4172 HRESULT hr;
4174 TRACE("%p\n", pProxy);
4176 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4177 if (SUCCEEDED(hr))
4179 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4180 AuthzSvc, pServerPrincName,
4181 AuthnLevel, ImpLevel, pAuthInfo,
4182 Capabilities);
4183 IClientSecurity_Release(pCliSec);
4186 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4187 return hr;
4190 /***********************************************************************
4191 * CoCopyProxy [OLE32.@]
4193 * Copies a proxy.
4195 * PARAMS
4196 * pProxy [I] Pointer to the proxy object.
4197 * ppCopy [O] Copy of the proxy.
4199 * RETURNS
4200 * Success: S_OK.
4201 * Failure: HRESULT code.
4203 * SEE ALSO
4204 * CoQueryProxyBlanket, CoSetProxyBlanket.
4206 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4208 IClientSecurity *pCliSec;
4209 HRESULT hr;
4211 TRACE("%p\n", pProxy);
4213 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4214 if (SUCCEEDED(hr))
4216 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4217 IClientSecurity_Release(pCliSec);
4220 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4221 return hr;
4225 /***********************************************************************
4226 * CoGetCallContext [OLE32.@]
4228 * Gets the context of the currently executing server call in the current
4229 * thread.
4231 * PARAMS
4232 * riid [I] Context interface to return.
4233 * ppv [O] Pointer to memory that will receive the context on return.
4235 * RETURNS
4236 * Success: S_OK.
4237 * Failure: HRESULT code.
4239 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4241 struct oletls *info = COM_CurrentInfo();
4243 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4245 if (!info)
4246 return E_OUTOFMEMORY;
4248 if (!info->call_state)
4249 return RPC_E_CALL_COMPLETE;
4251 return IUnknown_QueryInterface(info->call_state, riid, ppv);
4254 /***********************************************************************
4255 * CoSwitchCallContext [OLE32.@]
4257 * Switches the context of the currently executing server call in the current
4258 * thread.
4260 * PARAMS
4261 * pObject [I] Pointer to new context object
4262 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4264 * RETURNS
4265 * Success: S_OK.
4266 * Failure: HRESULT code.
4268 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4270 struct oletls *info = COM_CurrentInfo();
4272 TRACE("(%p, %p)\n", pObject, ppOldObject);
4274 if (!info)
4275 return E_OUTOFMEMORY;
4277 *ppOldObject = info->call_state;
4278 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4280 return S_OK;
4283 /***********************************************************************
4284 * CoQueryClientBlanket [OLE32.@]
4286 * Retrieves the authentication information about the client of the currently
4287 * executing server call in the current thread.
4289 * PARAMS
4290 * pAuthnSvc [O] Optional. The type of authentication service.
4291 * pAuthzSvc [O] Optional. The type of authorization service.
4292 * pServerPrincName [O] Optional. The server prinicple name.
4293 * pAuthnLevel [O] Optional. The authentication level.
4294 * pImpLevel [O] Optional. The impersonation level.
4295 * pPrivs [O] Optional. Information about the privileges of the client.
4296 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4298 * RETURNS
4299 * Success: S_OK.
4300 * Failure: HRESULT code.
4302 * SEE ALSO
4303 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4305 HRESULT WINAPI CoQueryClientBlanket(
4306 DWORD *pAuthnSvc,
4307 DWORD *pAuthzSvc,
4308 OLECHAR **pServerPrincName,
4309 DWORD *pAuthnLevel,
4310 DWORD *pImpLevel,
4311 RPC_AUTHZ_HANDLE *pPrivs,
4312 DWORD *pCapabilities)
4314 IServerSecurity *pSrvSec;
4315 HRESULT hr;
4317 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4318 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4319 pPrivs, pCapabilities);
4321 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4322 if (SUCCEEDED(hr))
4324 hr = IServerSecurity_QueryBlanket(
4325 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4326 pImpLevel, pPrivs, pCapabilities);
4327 IServerSecurity_Release(pSrvSec);
4330 return hr;
4333 /***********************************************************************
4334 * CoImpersonateClient [OLE32.@]
4336 * Impersonates the client of the currently executing server call in the
4337 * current thread.
4339 * PARAMS
4340 * None.
4342 * RETURNS
4343 * Success: S_OK.
4344 * Failure: HRESULT code.
4346 * NOTES
4347 * If this function fails then the current thread will not be impersonating
4348 * the client and all actions will take place on behalf of the server.
4349 * Therefore, it is important to check the return value from this function.
4351 * SEE ALSO
4352 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4354 HRESULT WINAPI CoImpersonateClient(void)
4356 IServerSecurity *pSrvSec;
4357 HRESULT hr;
4359 TRACE("\n");
4361 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4362 if (SUCCEEDED(hr))
4364 hr = IServerSecurity_ImpersonateClient(pSrvSec);
4365 IServerSecurity_Release(pSrvSec);
4368 return hr;
4371 /***********************************************************************
4372 * CoRevertToSelf [OLE32.@]
4374 * Ends the impersonation of the client of the currently executing server
4375 * call in the current thread.
4377 * PARAMS
4378 * None.
4380 * RETURNS
4381 * Success: S_OK.
4382 * Failure: HRESULT code.
4384 * SEE ALSO
4385 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4387 HRESULT WINAPI CoRevertToSelf(void)
4389 IServerSecurity *pSrvSec;
4390 HRESULT hr;
4392 TRACE("\n");
4394 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4395 if (SUCCEEDED(hr))
4397 hr = IServerSecurity_RevertToSelf(pSrvSec);
4398 IServerSecurity_Release(pSrvSec);
4401 return hr;
4404 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4406 /* first try to retrieve messages for incoming COM calls to the apartment window */
4407 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4408 /* next retrieve other messages necessary for the app to remain responsive */
4409 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4410 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4413 /***********************************************************************
4414 * CoWaitForMultipleHandles [OLE32.@]
4416 * Waits for one or more handles to become signaled.
4418 * PARAMS
4419 * dwFlags [I] Flags. See notes.
4420 * dwTimeout [I] Timeout in milliseconds.
4421 * cHandles [I] Number of handles pointed to by pHandles.
4422 * pHandles [I] Handles to wait for.
4423 * lpdwindex [O] Index of handle that was signaled.
4425 * RETURNS
4426 * Success: S_OK.
4427 * Failure: RPC_S_CALLPENDING on timeout.
4429 * NOTES
4431 * The dwFlags parameter can be zero or more of the following:
4432 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4433 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4435 * SEE ALSO
4436 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4438 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4439 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4441 HRESULT hr = S_OK;
4442 DWORD start_time = GetTickCount();
4443 APARTMENT *apt = COM_CurrentApt();
4444 BOOL message_loop = apt && !apt->multi_threaded;
4445 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4447 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4448 pHandles, lpdwindex);
4450 if (!lpdwindex)
4451 return E_INVALIDARG;
4453 *lpdwindex = 0;
4455 if (!pHandles)
4456 return E_INVALIDARG;
4458 if (!cHandles)
4459 return RPC_E_NO_SYNC;
4461 while (TRUE)
4463 DWORD now = GetTickCount();
4464 DWORD res;
4466 if (now - start_time > dwTimeout)
4468 hr = RPC_S_CALLPENDING;
4469 break;
4472 if (message_loop)
4474 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4475 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4477 TRACE("waiting for rpc completion or window message\n");
4479 res = WAIT_TIMEOUT;
4481 if (check_apc)
4483 res = WaitForMultipleObjectsEx(cHandles, pHandles,
4484 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4485 check_apc = FALSE;
4488 if (res == WAIT_TIMEOUT)
4489 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4490 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4491 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4493 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4495 MSG msg;
4496 int count = 0;
4498 /* call message filter */
4500 if (COM_CurrentApt()->filter)
4502 PENDINGTYPE pendingtype =
4503 COM_CurrentInfo()->pending_call_count_server ?
4504 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4505 DWORD be_handled = IMessageFilter_MessagePending(
4506 COM_CurrentApt()->filter, 0 /* FIXME */,
4507 now - start_time, pendingtype);
4508 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4509 switch (be_handled)
4511 case PENDINGMSG_CANCELCALL:
4512 WARN("call canceled\n");
4513 hr = RPC_E_CALL_CANCELED;
4514 break;
4515 case PENDINGMSG_WAITNOPROCESS:
4516 case PENDINGMSG_WAITDEFPROCESS:
4517 default:
4518 /* FIXME: MSDN is very vague about the difference
4519 * between WAITNOPROCESS and WAITDEFPROCESS - there
4520 * appears to be none, so it is possibly a left-over
4521 * from the 16-bit world. */
4522 break;
4526 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4527 * so after processing 100 messages we go back to checking the wait handles */
4528 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4530 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4531 TranslateMessage(&msg);
4532 DispatchMessageW(&msg);
4533 if (msg.message == WM_QUIT)
4535 TRACE("resending WM_QUIT to outer message loop\n");
4536 PostQuitMessage(msg.wParam);
4537 /* no longer need to process messages */
4538 message_loop = FALSE;
4539 break;
4542 continue;
4545 else
4547 TRACE("waiting for rpc completion\n");
4549 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4550 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4551 (dwFlags & COWAIT_ALERTABLE) != 0);
4554 switch (res)
4556 case WAIT_TIMEOUT:
4557 hr = RPC_S_CALLPENDING;
4558 break;
4559 case WAIT_FAILED:
4560 hr = HRESULT_FROM_WIN32( GetLastError() );
4561 break;
4562 default:
4563 *lpdwindex = res;
4564 break;
4566 break;
4568 TRACE("-- 0x%08x\n", hr);
4569 return hr;
4573 /***********************************************************************
4574 * CoGetObject [OLE32.@]
4576 * Gets the object named by converting the name to a moniker and binding to it.
4578 * PARAMS
4579 * pszName [I] String representing the object.
4580 * pBindOptions [I] Parameters affecting the binding to the named object.
4581 * riid [I] Interface to bind to on the objecct.
4582 * ppv [O] On output, the interface riid of the object represented
4583 * by pszName.
4585 * RETURNS
4586 * Success: S_OK.
4587 * Failure: HRESULT code.
4589 * SEE ALSO
4590 * MkParseDisplayName.
4592 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4593 REFIID riid, void **ppv)
4595 IBindCtx *pbc;
4596 HRESULT hr;
4598 *ppv = NULL;
4600 hr = CreateBindCtx(0, &pbc);
4601 if (SUCCEEDED(hr))
4603 if (pBindOptions)
4604 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4606 if (SUCCEEDED(hr))
4608 ULONG chEaten;
4609 IMoniker *pmk;
4611 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4612 if (SUCCEEDED(hr))
4614 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4615 IMoniker_Release(pmk);
4619 IBindCtx_Release(pbc);
4621 return hr;
4624 /***********************************************************************
4625 * CoRegisterChannelHook [OLE32.@]
4627 * Registers a process-wide hook that is called during ORPC calls.
4629 * PARAMS
4630 * guidExtension [I] GUID of the channel hook to register.
4631 * pChannelHook [I] Channel hook object to register.
4633 * RETURNS
4634 * Success: S_OK.
4635 * Failure: HRESULT code.
4637 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4639 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4641 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4644 typedef struct Context
4646 IComThreadingInfo IComThreadingInfo_iface;
4647 IContextCallback IContextCallback_iface;
4648 IObjContext IObjContext_iface;
4649 LONG refs;
4650 } Context;
4652 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4654 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4657 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4659 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4662 static inline Context *impl_from_IObjContext( IObjContext *iface )
4664 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4667 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4669 *ppv = NULL;
4671 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4672 IsEqualIID(riid, &IID_IUnknown))
4674 *ppv = &iface->IComThreadingInfo_iface;
4676 else if (IsEqualIID(riid, &IID_IContextCallback))
4678 *ppv = &iface->IContextCallback_iface;
4680 else if (IsEqualIID(riid, &IID_IObjContext))
4682 *ppv = &iface->IObjContext_iface;
4685 if (*ppv)
4687 IUnknown_AddRef((IUnknown*)*ppv);
4688 return S_OK;
4691 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4692 return E_NOINTERFACE;
4695 static ULONG Context_AddRef(Context *This)
4697 return InterlockedIncrement(&This->refs);
4700 static ULONG Context_Release(Context *This)
4702 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4703 releasing context while refcount is at 0 destroys it. */
4704 if (!This->refs)
4706 HeapFree(GetProcessHeap(), 0, This);
4707 return 0;
4710 return InterlockedDecrement(&This->refs);
4713 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4715 Context *This = impl_from_IComThreadingInfo(iface);
4716 return Context_QueryInterface(This, riid, ppv);
4719 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4721 Context *This = impl_from_IComThreadingInfo(iface);
4722 return Context_AddRef(This);
4725 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4727 Context *This = impl_from_IComThreadingInfo(iface);
4728 return Context_Release(This);
4731 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4733 APTTYPEQUALIFIER qualifier;
4735 TRACE("(%p)\n", apttype);
4737 return CoGetApartmentType(apttype, &qualifier);
4740 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4742 APTTYPEQUALIFIER qualifier;
4743 APTTYPE apttype;
4744 HRESULT hr;
4746 hr = CoGetApartmentType(&apttype, &qualifier);
4747 if (FAILED(hr))
4748 return hr;
4750 TRACE("(%p)\n", thdtype);
4752 switch (apttype)
4754 case APTTYPE_STA:
4755 case APTTYPE_MAINSTA:
4756 *thdtype = THDTYPE_PROCESSMESSAGES;
4757 break;
4758 default:
4759 *thdtype = THDTYPE_BLOCKMESSAGES;
4760 break;
4762 return S_OK;
4765 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4767 TRACE("(%p)\n", logical_thread_id);
4768 return CoGetCurrentLogicalThreadId(logical_thread_id);
4771 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4773 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4774 return E_NOTIMPL;
4777 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4779 Context_CTI_QueryInterface,
4780 Context_CTI_AddRef,
4781 Context_CTI_Release,
4782 Context_CTI_GetCurrentApartmentType,
4783 Context_CTI_GetCurrentThreadType,
4784 Context_CTI_GetCurrentLogicalThreadId,
4785 Context_CTI_SetCurrentLogicalThreadId
4788 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4790 Context *This = impl_from_IContextCallback(iface);
4791 return Context_QueryInterface(This, riid, ppv);
4794 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4796 Context *This = impl_from_IContextCallback(iface);
4797 return Context_AddRef(This);
4800 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4802 Context *This = impl_from_IContextCallback(iface);
4803 return Context_Release(This);
4806 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4807 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4809 Context *This = impl_from_IContextCallback(iface);
4811 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4812 return E_NOTIMPL;
4815 static const IContextCallbackVtbl Context_Callback_Vtbl =
4817 Context_CC_QueryInterface,
4818 Context_CC_AddRef,
4819 Context_CC_Release,
4820 Context_CC_ContextCallback
4823 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4825 Context *This = impl_from_IObjContext(iface);
4826 return Context_QueryInterface(This, riid, ppv);
4829 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4831 Context *This = impl_from_IObjContext(iface);
4832 return Context_AddRef(This);
4835 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4837 Context *This = impl_from_IObjContext(iface);
4838 return Context_Release(This);
4841 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4843 Context *This = impl_from_IObjContext(iface);
4845 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4846 return E_NOTIMPL;
4849 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4851 Context *This = impl_from_IObjContext(iface);
4853 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4854 return E_NOTIMPL;
4857 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4859 Context *This = impl_from_IObjContext(iface);
4861 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4862 return E_NOTIMPL;
4865 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4867 Context *This = impl_from_IObjContext(iface);
4869 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4870 return E_NOTIMPL;
4873 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4875 Context *This = impl_from_IObjContext(iface);
4876 FIXME("(%p/%p)\n", This, iface);
4879 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4881 Context *This = impl_from_IObjContext(iface);
4882 FIXME("(%p/%p)\n", This, iface);
4885 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4887 Context *This = impl_from_IObjContext(iface);
4888 FIXME("(%p/%p)\n", This, iface);
4891 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4893 Context *This = impl_from_IObjContext(iface);
4894 FIXME("(%p/%p)\n", This, iface);
4897 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4899 Context *This = impl_from_IObjContext(iface);
4900 FIXME("(%p/%p)\n", This, iface);
4903 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4905 Context *This = impl_from_IObjContext(iface);
4906 FIXME("(%p/%p)\n", This, iface);
4909 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4911 Context *This = impl_from_IObjContext(iface);
4912 FIXME("(%p/%p)\n", This, iface);
4915 static const IObjContextVtbl Context_Object_Vtbl =
4917 Context_OC_QueryInterface,
4918 Context_OC_AddRef,
4919 Context_OC_Release,
4920 Context_OC_SetProperty,
4921 Context_OC_RemoveProperty,
4922 Context_OC_GetProperty,
4923 Context_OC_EnumContextProps,
4924 Context_OC_Reserved1,
4925 Context_OC_Reserved2,
4926 Context_OC_Reserved3,
4927 Context_OC_Reserved4,
4928 Context_OC_Reserved5,
4929 Context_OC_Reserved6,
4930 Context_OC_Reserved7
4933 /***********************************************************************
4934 * CoGetObjectContext [OLE32.@]
4936 * Retrieves an object associated with the current context (i.e. apartment).
4938 * PARAMS
4939 * riid [I] ID of the interface of the object to retrieve.
4940 * ppv [O] Address where object will be stored on return.
4942 * RETURNS
4943 * Success: S_OK.
4944 * Failure: HRESULT code.
4946 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4948 IObjContext *context;
4949 HRESULT hr;
4951 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4953 *ppv = NULL;
4954 hr = CoGetContextToken((ULONG_PTR*)&context);
4955 if (FAILED(hr))
4956 return hr;
4958 return IObjContext_QueryInterface(context, riid, ppv);
4961 /***********************************************************************
4962 * CoGetContextToken [OLE32.@]
4964 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4966 struct oletls *info = COM_CurrentInfo();
4968 TRACE("(%p)\n", token);
4970 if (!info)
4971 return E_OUTOFMEMORY;
4973 if (!info->apt)
4975 APARTMENT *apt;
4976 if (!(apt = apartment_find_multi_threaded()))
4978 ERR("apartment not initialised\n");
4979 return CO_E_NOTINITIALIZED;
4981 apartment_release(apt);
4984 if (!token)
4985 return E_POINTER;
4987 if (!info->context_token)
4989 Context *context;
4991 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4992 if (!context)
4993 return E_OUTOFMEMORY;
4995 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4996 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4997 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4998 /* Context token does not take a reference, it's always zero until the
4999 interface is explicitly requested with CoGetObjectContext(). */
5000 context->refs = 0;
5002 info->context_token = &context->IObjContext_iface;
5005 *token = (ULONG_PTR)info->context_token;
5006 TRACE("context_token=%p\n", info->context_token);
5008 return S_OK;
5011 /***********************************************************************
5012 * CoGetDefaultContext [OLE32.@]
5014 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
5016 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
5017 return E_NOINTERFACE;
5020 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
5022 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5023 HKEY hkey;
5024 HRESULT hres;
5026 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5027 if (SUCCEEDED(hres))
5029 struct class_reg_data regdata;
5030 WCHAR dllpath[MAX_PATH+1];
5032 regdata.u.hkey = hkey;
5033 regdata.hkey = TRUE;
5035 if (COM_RegReadPath(&regdata, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
5037 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5038 if (!strcmpiW(dllpath, wszOle32))
5040 RegCloseKey(hkey);
5041 return HandlerCF_Create(rclsid, riid, ppv);
5044 else
5045 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5046 RegCloseKey(hkey);
5049 return CLASS_E_CLASSNOTAVAILABLE;
5052 /***********************************************************************
5053 * CoGetApartmentType [OLE32.@]
5055 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
5057 struct oletls *info = COM_CurrentInfo();
5059 FIXME("(%p, %p): semi-stub\n", type, qualifier);
5061 if (!type || !qualifier)
5062 return E_INVALIDARG;
5064 if (!info)
5065 return E_OUTOFMEMORY;
5067 if (!info->apt)
5068 *type = APTTYPE_CURRENT;
5069 else if (info->apt->multi_threaded)
5070 *type = APTTYPE_MTA;
5071 else if (info->apt->main)
5072 *type = APTTYPE_MAINSTA;
5073 else
5074 *type = APTTYPE_STA;
5076 *qualifier = APTTYPEQUALIFIER_NONE;
5078 return info->apt ? S_OK : CO_E_NOTINITIALIZED;
5081 /***********************************************************************
5082 * CoRegisterSurrogate [OLE32.@]
5084 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
5086 FIXME("(%p): stub\n", surrogate);
5088 return E_NOTIMPL;
5091 /***********************************************************************
5092 * CoRegisterSurrogateEx [OLE32.@]
5094 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
5096 FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved);
5098 return E_NOTIMPL;
5101 typedef struct {
5102 IGlobalOptions IGlobalOptions_iface;
5103 LONG ref;
5104 } GlobalOptions;
5106 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface)
5108 return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface);
5111 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
5113 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5115 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5117 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
5119 *ppv = iface;
5121 else
5123 *ppv = NULL;
5124 return E_NOINTERFACE;
5127 IUnknown_AddRef((IUnknown*)*ppv);
5128 return S_OK;
5131 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface)
5133 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5134 LONG ref = InterlockedIncrement(&This->ref);
5136 TRACE("(%p) ref=%d\n", This, ref);
5138 return ref;
5141 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface)
5143 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5144 LONG ref = InterlockedDecrement(&This->ref);
5146 TRACE("(%p) ref=%d\n", This, ref);
5148 if (!ref)
5149 heap_free(This);
5151 return ref;
5154 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
5156 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5157 FIXME("(%p)->(%u %lx)\n", This, property, value);
5158 return S_OK;
5161 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
5163 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5164 FIXME("(%p)->(%u %p)\n", This, property, value);
5165 return E_NOTIMPL;
5168 static const IGlobalOptionsVtbl GlobalOptionsVtbl = {
5169 GlobalOptions_QueryInterface,
5170 GlobalOptions_AddRef,
5171 GlobalOptions_Release,
5172 GlobalOptions_Set,
5173 GlobalOptions_Query
5176 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
5178 GlobalOptions *global_options;
5179 HRESULT hres;
5181 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
5183 if (outer)
5184 return E_INVALIDARG;
5186 global_options = heap_alloc(sizeof(*global_options));
5187 if (!global_options)
5188 return E_OUTOFMEMORY;
5189 global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl;
5190 global_options->ref = 1;
5192 hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv);
5193 IGlobalOptions_Release(&global_options->IGlobalOptions_iface);
5194 return hres;
5197 /***********************************************************************
5198 * DllMain (OLE32.@)
5200 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5202 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5204 switch(fdwReason) {
5205 case DLL_PROCESS_ATTACH:
5206 hProxyDll = hinstDLL;
5207 break;
5209 case DLL_PROCESS_DETACH:
5210 if (reserved) break;
5211 release_std_git();
5212 UnregisterClassW( wszAptWinClass, hProxyDll );
5213 RPC_UnregisterAllChannelHooks();
5214 COMPOBJ_DllList_Free();
5215 DeleteCriticalSection(&csRegisteredClassList);
5216 DeleteCriticalSection(&csApartment);
5217 break;
5219 case DLL_THREAD_DETACH:
5220 COM_TlsDestroy();
5221 break;
5223 return TRUE;
5226 /***********************************************************************
5227 * DllRegisterServer (OLE32.@)
5229 HRESULT WINAPI DllRegisterServer(void)
5231 return OLE32_DllRegisterServer();
5234 /***********************************************************************
5235 * DllUnregisterServer (OLE32.@)
5237 HRESULT WINAPI DllUnregisterServer(void)
5239 return OLE32_DllUnregisterServer();