[OLE32] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / dll / win32 / ole32 / compobj.c
1 /*
2 * COMPOBJ library
3 *
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)
11 *
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.
16 *
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.
21 *
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
25 *
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
29 *
30 * TODO list: (items bunched together depend on each other)
31 *
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
36 *
37 */
38
39 #include "config.h"
40
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
45
46 #define COBJMACROS
47 #define NONAMELESSUNION
48
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"
63
64 #ifndef __REACTOS__
65 #include "initguid.h"
66 #endif
67 #include "compobj_private.h"
68 #include "moniker.h"
69
70 #include "wine/unicode.h"
71 #include "wine/debug.h"
72
73 WINE_DEFAULT_DEBUG_CHANNEL(ole);
74
75 /****************************************************************************
76 * This section defines variables internal to the COM module.
77 */
78
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 */
82
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
85 {
86 0, 0, &csApartment,
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
89 };
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
91
92 enum comclass_threadingmodel
93 {
94 ThreadingModel_Apartment = 1,
95 ThreadingModel_Free = 2,
96 ThreadingModel_No = 3,
97 ThreadingModel_Both = 4,
98 ThreadingModel_Neutral = 5
99 };
100
101 enum comclass_miscfields
102 {
103 MiscStatus = 1,
104 MiscStatusIcon = 2,
105 MiscStatusContent = 4,
106 MiscStatusThumbnail = 8,
107 MiscStatusDocPrint = 16
108 };
109
110 struct comclassredirect_data
111 {
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;
132 };
133
134 struct ifacepsredirect_data
135 {
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;
144 };
145
146 struct progidredirect_data
147 {
148 ULONG size;
149 DWORD reserved;
150 ULONG clsid_offset;
151 };
152
153 struct class_reg_data
154 {
155 union
156 {
157 struct
158 {
159 struct comclassredirect_data *data;
160 void *section;
161 HANDLE hactctx;
162 } actctx;
163 HKEY hkey;
164 } u;
165 BOOL hkey;
166 };
167
168 struct registered_psclsid
169 {
170 struct list entry;
171 IID iid;
172 CLSID clsid;
173 };
174
175 static struct list registered_psclsid_list = LIST_INIT(registered_psclsid_list);
176
177 static CRITICAL_SECTION cs_registered_psclsid_list;
178 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
179 {
180 0, 0, &cs_registered_psclsid_list,
181 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
182 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
183 };
184 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
185
186 /*
187 * This is a marshallable object exposing registered local servers.
188 * IServiceProvider is used only because it happens meet requirements
189 * and already has proxy/stub code. If more functionality is needed,
190 * a custom interface may be used instead.
191 */
192 struct LocalServer
193 {
194 IServiceProvider IServiceProvider_iface;
195 LONG ref;
196 APARTMENT *apt;
197 IStream *marshal_stream;
198 };
199
200 /*
201 * This lock count counts the number of times CoInitialize is called. It is
202 * decreased every time CoUninitialize is called. When it hits 0, the COM
203 * libraries are freed
204 */
205 static LONG s_COMLockCount = 0;
206 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
207 static LONG s_COMServerProcessReferences = 0;
208
209 /*
210 * This linked list contains the list of registered class objects. These
211 * are mostly used to register the factories for out-of-proc servers of OLE
212 * objects.
213 *
214 * TODO: Make this data structure aware of inter-process communication. This
215 * means that parts of this will be exported to rpcss.
216 */
217 typedef struct tagRegisteredClass
218 {
219 struct list entry;
220 CLSID classIdentifier;
221 OXID apartment_id;
222 LPUNKNOWN classObject;
223 DWORD runContext;
224 DWORD connectFlags;
225 DWORD dwCookie;
226 void *RpcRegistration;
227 } RegisteredClass;
228
229 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
230
231 static CRITICAL_SECTION csRegisteredClassList;
232 static CRITICAL_SECTION_DEBUG class_cs_debug =
233 {
234 0, 0, &csRegisteredClassList,
235 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
236 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
237 };
238 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
239
240 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
241 {
242 switch (aspect)
243 {
244 case DVASPECT_CONTENT:
245 return MiscStatusContent;
246 case DVASPECT_THUMBNAIL:
247 return MiscStatusThumbnail;
248 case DVASPECT_ICON:
249 return MiscStatusIcon;
250 case DVASPECT_DOCPRINT:
251 return MiscStatusDocPrint;
252 default:
253 return MiscStatus;
254 };
255 }
256
257 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
258 {
259 ACTCTX_SECTION_KEYED_DATA data;
260
261 data.cbSize = sizeof(data);
262 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
263 clsid, &data))
264 {
265 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
266 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
267
268 if (!(comclass->miscmask & misc))
269 {
270 if (!(comclass->miscmask & MiscStatus))
271 {
272 *status = 0;
273 return TRUE;
274 }
275 misc = MiscStatus;
276 }
277
278 switch (misc)
279 {
280 case MiscStatus:
281 *status = comclass->miscstatus;
282 break;
283 case MiscStatusIcon:
284 *status = comclass->miscstatusicon;
285 break;
286 case MiscStatusContent:
287 *status = comclass->miscstatuscontent;
288 break;
289 case MiscStatusThumbnail:
290 *status = comclass->miscstatusthumbnail;
291 break;
292 case MiscStatusDocPrint:
293 *status = comclass->miscstatusdocprint;
294 break;
295 default:
296 ;
297 };
298
299 return TRUE;
300 }
301 else
302 return FALSE;
303 }
304
305 /* wrapper for NtCreateKey that creates the key recursively if necessary */
306 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
307 {
308 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
309
310 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
311 {
312 HANDLE subkey, root = attr->RootDirectory;
313 WCHAR *buffer = attr->ObjectName->Buffer;
314 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
315 UNICODE_STRING str;
316
317 while (i < len && buffer[i] != '\\') i++;
318 if (i == len) return status;
319
320 attrs = attr->Attributes;
321 attr->ObjectName = &str;
322
323 while (i < len)
324 {
325 str.Buffer = buffer + pos;
326 str.Length = (i - pos) * sizeof(WCHAR);
327 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
328 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
329 if (status) return status;
330 attr->RootDirectory = subkey;
331 while (i < len && buffer[i] == '\\') i++;
332 pos = i;
333 while (i < len && buffer[i] != '\\') i++;
334 }
335 str.Buffer = buffer + pos;
336 str.Length = (i - pos) * sizeof(WCHAR);
337 attr->Attributes = attrs;
338 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
339 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
340 }
341 return status;
342 }
343
344 #ifdef __REACTOS__
345 static const WCHAR classes_rootW[] = L"\\REGISTRY\\Machine\\Software\\Classes";
346 #else
347 static const WCHAR classes_rootW[] =
348 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
349 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
350 #endif
351
352 static HKEY classes_root_hkey;
353
354 /* create the special HKEY_CLASSES_ROOT key */
355 static HKEY create_classes_root_hkey(DWORD access)
356 {
357 HKEY hkey, ret = 0;
358 OBJECT_ATTRIBUTES attr;
359 UNICODE_STRING name;
360
361 attr.Length = sizeof(attr);
362 attr.RootDirectory = 0;
363 attr.ObjectName = &name;
364 attr.Attributes = 0;
365 attr.SecurityDescriptor = NULL;
366 attr.SecurityQualityOfService = NULL;
367 RtlInitUnicodeString( &name, classes_rootW );
368 if (create_key( &hkey, access, &attr )) return 0;
369 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
370
371 if (!(access & KEY_WOW64_64KEY))
372 {
373 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
374 ret = hkey;
375 else
376 NtClose( hkey ); /* somebody beat us to it */
377 }
378 else
379 ret = hkey;
380 return ret;
381 }
382
383 /* map the hkey from special root to normal key if necessary */
384 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
385 {
386 HKEY ret = hkey;
387 const BOOL is_win64 = sizeof(void*) > sizeof(int);
388 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
389
390 if (hkey == HKEY_CLASSES_ROOT &&
391 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
392 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
393 if (force_wow32 && ret && ret == classes_root_hkey)
394 {
395 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
396 access &= ~KEY_WOW64_32KEY;
397 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
398 return 0;
399 ret = hkey;
400 }
401
402 return ret;
403 }
404
405 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
406 {
407 OBJECT_ATTRIBUTES attr;
408 UNICODE_STRING nameW;
409
410 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
411
412 attr.Length = sizeof(attr);
413 attr.RootDirectory = hkey;
414 attr.ObjectName = &nameW;
415 attr.Attributes = 0;
416 attr.SecurityDescriptor = NULL;
417 attr.SecurityQualityOfService = NULL;
418 RtlInitUnicodeString( &nameW, name );
419
420 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
421 }
422
423 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
424 {
425 OBJECT_ATTRIBUTES attr;
426 UNICODE_STRING nameW;
427
428 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
429
430 attr.Length = sizeof(attr);
431 attr.RootDirectory = hkey;
432 attr.ObjectName = &nameW;
433 attr.Attributes = 0;
434 attr.SecurityDescriptor = NULL;
435 attr.SecurityQualityOfService = NULL;
436 RtlInitUnicodeString( &nameW, name );
437
438 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
439 }
440
441 /*****************************************************************************
442 * This section contains OpenDllList definitions
443 *
444 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
445 * other functions that do LoadLibrary _without_ giving back a HMODULE.
446 * Without this list these handles would never be freed.
447 *
448 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
449 * next unload-call but not before 600 sec.
450 */
451
452 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
453 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
454
455 typedef struct tagOpenDll
456 {
457 LONG refs;
458 LPWSTR library_name;
459 HANDLE library;
460 DllGetClassObjectFunc DllGetClassObject;
461 DllCanUnloadNowFunc DllCanUnloadNow;
462 struct list entry;
463 } OpenDll;
464
465 static struct list openDllList = LIST_INIT(openDllList);
466
467 static CRITICAL_SECTION csOpenDllList;
468 static CRITICAL_SECTION_DEBUG dll_cs_debug =
469 {
470 0, 0, &csOpenDllList,
471 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
472 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
473 };
474 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
475
476 struct apartment_loaded_dll
477 {
478 struct list entry;
479 OpenDll *dll;
480 DWORD unload_time;
481 BOOL multi_threaded;
482 };
483
484 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};
485
486 static ATOM apt_win_class;
487
488 /*****************************************************************************
489 * This section contains OpenDllList implementation
490 */
491
492 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
493 {
494 OpenDll *ptr;
495 OpenDll *ret = NULL;
496 EnterCriticalSection(&csOpenDllList);
497 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
498 {
499 if (!strcmpiW(library_name, ptr->library_name) &&
500 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
501 {
502 ret = ptr;
503 break;
504 }
505 }
506 LeaveCriticalSection(&csOpenDllList);
507 return ret;
508 }
509
510 /* caller must ensure that library_name is not already in the open dll list */
511 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
512 {
513 OpenDll *entry;
514 int len;
515 HRESULT hr = S_OK;
516 HANDLE hLibrary;
517 DllCanUnloadNowFunc DllCanUnloadNow;
518 DllGetClassObjectFunc DllGetClassObject;
519
520 TRACE("%s\n", debugstr_w(library_name));
521
522 *ret = COMPOBJ_DllList_Get(library_name);
523 if (*ret) return S_OK;
524
525 /* do this outside the csOpenDllList to avoid creating a lock dependency on
526 * the loader lock */
527 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
528 if (!hLibrary)
529 {
530 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
531 /* failure: DLL could not be loaded */
532 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
533 }
534
535 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
536 /* Note: failing to find DllCanUnloadNow is not a failure */
537 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
538 if (!DllGetClassObject)
539 {
540 /* failure: the dll did not export DllGetClassObject */
541 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
542 FreeLibrary(hLibrary);
543 return CO_E_DLLNOTFOUND;
544 }
545
546 EnterCriticalSection( &csOpenDllList );
547
548 *ret = COMPOBJ_DllList_Get(library_name);
549 if (*ret)
550 {
551 /* another caller to this function already added the dll while we
552 * weren't in the critical section */
553 FreeLibrary(hLibrary);
554 }
555 else
556 {
557 len = strlenW(library_name);
558 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
559 if (entry)
560 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
561 if (entry && entry->library_name)
562 {
563 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
564 entry->library = hLibrary;
565 entry->refs = 1;
566 entry->DllCanUnloadNow = DllCanUnloadNow;
567 entry->DllGetClassObject = DllGetClassObject;
568 list_add_tail(&openDllList, &entry->entry);
569 *ret = entry;
570 }
571 else
572 {
573 HeapFree(GetProcessHeap(), 0, entry);
574 hr = E_OUTOFMEMORY;
575 FreeLibrary(hLibrary);
576 }
577 }
578
579 LeaveCriticalSection( &csOpenDllList );
580
581 return hr;
582 }
583
584 /* pass FALSE for free_entry to release a reference without destroying the
585 * entry if it reaches zero or TRUE otherwise */
586 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
587 {
588 if (!InterlockedDecrement(&entry->refs) && free_entry)
589 {
590 EnterCriticalSection(&csOpenDllList);
591 list_remove(&entry->entry);
592 LeaveCriticalSection(&csOpenDllList);
593
594 TRACE("freeing %p\n", entry->library);
595 FreeLibrary(entry->library);
596
597 HeapFree(GetProcessHeap(), 0, entry->library_name);
598 HeapFree(GetProcessHeap(), 0, entry);
599 }
600 }
601
602 /* frees memory associated with active dll list */
603 static void COMPOBJ_DllList_Free(void)
604 {
605 OpenDll *entry, *cursor2;
606 EnterCriticalSection(&csOpenDllList);
607 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
608 {
609 list_remove(&entry->entry);
610
611 HeapFree(GetProcessHeap(), 0, entry->library_name);
612 HeapFree(GetProcessHeap(), 0, entry);
613 }
614 LeaveCriticalSection(&csOpenDllList);
615 DeleteCriticalSection(&csOpenDllList);
616 }
617
618 /******************************************************************************
619 * Manage apartments.
620 */
621
622 static DWORD apartment_addref(struct apartment *apt)
623 {
624 DWORD refs = InterlockedIncrement(&apt->refs);
625 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
626 return refs;
627 }
628
629 /* allocates memory and fills in the necessary fields for a new apartment
630 * object. must be called inside apartment cs */
631 static APARTMENT *apartment_construct(DWORD model)
632 {
633 APARTMENT *apt;
634
635 TRACE("creating new apartment, model=%d\n", model);
636
637 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
638 apt->tid = GetCurrentThreadId();
639
640 list_init(&apt->proxies);
641 list_init(&apt->stubmgrs);
642 list_init(&apt->loaded_dlls);
643 apt->ipidc = 0;
644 apt->refs = 1;
645 apt->remunk_exported = FALSE;
646 apt->oidc = 1;
647 InitializeCriticalSection(&apt->cs);
648 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
649
650 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
651
652 if (apt->multi_threaded)
653 {
654 /* FIXME: should be randomly generated by in an RPC call to rpcss */
655 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
656 }
657 else
658 {
659 /* FIXME: should be randomly generated by in an RPC call to rpcss */
660 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
661 }
662
663 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
664
665 list_add_head(&apts, &apt->entry);
666
667 return apt;
668 }
669
670 /* gets and existing apartment if one exists or otherwise creates an apartment
671 * structure which stores OLE apartment-local information and stores a pointer
672 * to it in the thread-local storage */
673 static APARTMENT *apartment_get_or_create(DWORD model)
674 {
675 APARTMENT *apt = COM_CurrentApt();
676
677 if (!apt)
678 {
679 if (model & COINIT_APARTMENTTHREADED)
680 {
681 EnterCriticalSection(&csApartment);
682
683 apt = apartment_construct(model);
684 if (!MainApartment)
685 {
686 MainApartment = apt;
687 apt->main = TRUE;
688 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
689 }
690
691 LeaveCriticalSection(&csApartment);
692
693 if (apt->main)
694 apartment_createwindowifneeded(apt);
695 }
696 else
697 {
698 EnterCriticalSection(&csApartment);
699
700 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
701 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
702 * in a process */
703 if (MTA)
704 {
705 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
706 apartment_addref(MTA);
707 }
708 else
709 MTA = apartment_construct(model);
710
711 apt = MTA;
712
713 LeaveCriticalSection(&csApartment);
714 }
715 COM_CurrentInfo()->apt = apt;
716 }
717
718 return apt;
719 }
720
721 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
722 {
723 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
724 }
725
726 /* gets the multi-threaded apartment if it exists. The caller must
727 * release the reference from the apartment as soon as the apartment pointer
728 * is no longer required. */
729 static APARTMENT *apartment_find_mta(void)
730 {
731 APARTMENT *apt;
732
733 EnterCriticalSection(&csApartment);
734
735 if ((apt = MTA))
736 apartment_addref(apt);
737
738 LeaveCriticalSection(&csApartment);
739
740 return apt;
741 }
742
743 /* Return the current apartment if it exists, or, failing that, the MTA. Caller
744 * must free the returned apartment in either case. */
745 APARTMENT *apartment_get_current_or_mta(void)
746 {
747 APARTMENT *apt = COM_CurrentApt();
748 if (apt)
749 {
750 apartment_addref(apt);
751 return apt;
752 }
753 return apartment_find_mta();
754 }
755
756 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
757 {
758 list_remove(&curClass->entry);
759
760 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
761 RPC_StopLocalServer(curClass->RpcRegistration);
762
763 IUnknown_Release(curClass->classObject);
764 HeapFree(GetProcessHeap(), 0, curClass);
765 }
766
767 static void COM_RevokeAllClasses(const struct apartment *apt)
768 {
769 RegisteredClass *curClass, *cursor;
770
771 EnterCriticalSection( &csRegisteredClassList );
772
773 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
774 {
775 if (curClass->apartment_id == apt->oxid)
776 COM_RevokeRegisteredClassObject(curClass);
777 }
778
779 LeaveCriticalSection( &csRegisteredClassList );
780 }
781
782 static void revoke_registered_psclsids(void)
783 {
784 struct registered_psclsid *psclsid, *psclsid2;
785
786 EnterCriticalSection( &cs_registered_psclsid_list );
787
788 LIST_FOR_EACH_ENTRY_SAFE(psclsid, psclsid2, &registered_psclsid_list, struct registered_psclsid, entry)
789 {
790 list_remove(&psclsid->entry);
791 HeapFree(GetProcessHeap(), 0, psclsid);
792 }
793
794 LeaveCriticalSection( &cs_registered_psclsid_list );
795 }
796
797 /******************************************************************************
798 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
799 */
800
801 typedef struct ManualResetEvent {
802 ISynchronize ISynchronize_iface;
803 ISynchronizeHandle ISynchronizeHandle_iface;
804 LONG ref;
805 HANDLE event;
806 } MREImpl;
807
808 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
809 {
810 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
811 }
812
813 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
814 {
815 MREImpl *This = impl_from_ISynchronize(iface);
816
817 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
818
819 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
820 *ppv = &This->ISynchronize_iface;
821 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
822 *ppv = &This->ISynchronizeHandle_iface;
823 }else {
824 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
825 *ppv = NULL;
826 return E_NOINTERFACE;
827 }
828
829 IUnknown_AddRef((IUnknown*)*ppv);
830 return S_OK;
831 }
832
833 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
834 {
835 MREImpl *This = impl_from_ISynchronize(iface);
836 LONG ref = InterlockedIncrement(&This->ref);
837 TRACE("%p - ref %d\n", This, ref);
838
839 return ref;
840 }
841
842 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
843 {
844 MREImpl *This = impl_from_ISynchronize(iface);
845 LONG ref = InterlockedDecrement(&This->ref);
846 TRACE("%p - ref %d\n", This, ref);
847
848 if(!ref)
849 {
850 CloseHandle(This->event);
851 HeapFree(GetProcessHeap(), 0, This);
852 }
853
854 return ref;
855 }
856
857 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
858 {
859 MREImpl *This = impl_from_ISynchronize(iface);
860 UINT index;
861 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
862 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
863 }
864
865 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
866 {
867 MREImpl *This = impl_from_ISynchronize(iface);
868 TRACE("%p\n", This);
869 SetEvent(This->event);
870 return S_OK;
871 }
872
873 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
874 {
875 MREImpl *This = impl_from_ISynchronize(iface);
876 TRACE("%p\n", This);
877 ResetEvent(This->event);
878 return S_OK;
879 }
880
881 static ISynchronizeVtbl vt_ISynchronize = {
882 ISynchronize_fnQueryInterface,
883 ISynchronize_fnAddRef,
884 ISynchronize_fnRelease,
885 ISynchronize_fnWait,
886 ISynchronize_fnSignal,
887 ISynchronize_fnReset
888 };
889
890 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
891 {
892 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
893 }
894
895 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
896 {
897 MREImpl *This = impl_from_ISynchronizeHandle(iface);
898 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
899 }
900
901 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
902 {
903 MREImpl *This = impl_from_ISynchronizeHandle(iface);
904 return ISynchronize_AddRef(&This->ISynchronize_iface);
905 }
906
907 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
908 {
909 MREImpl *This = impl_from_ISynchronizeHandle(iface);
910 return ISynchronize_Release(&This->ISynchronize_iface);
911 }
912
913 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
914 {
915 MREImpl *This = impl_from_ISynchronizeHandle(iface);
916
917 *ph = This->event;
918 return S_OK;
919 }
920
921 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
922 SynchronizeHandle_QueryInterface,
923 SynchronizeHandle_AddRef,
924 SynchronizeHandle_Release,
925 SynchronizeHandle_GetHandle
926 };
927
928 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
929 {
930 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
931 HRESULT hr;
932
933 if(punkouter)
934 FIXME("Aggregation not implemented.\n");
935
936 This->ref = 1;
937 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
938 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
939 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
940
941 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
942 ISynchronize_Release(&This->ISynchronize_iface);
943 return hr;
944 }
945
946 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
947 {
948 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
949 }
950
951 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
952 {
953 LocalServer *This = impl_from_IServiceProvider(iface);
954
955 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
956
957 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
958 *ppv = &This->IServiceProvider_iface;
959 }else {
960 *ppv = NULL;
961 return E_NOINTERFACE;
962 }
963
964 IUnknown_AddRef((IUnknown*)*ppv);
965 return S_OK;
966 }
967
968 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
969 {
970 LocalServer *This = impl_from_IServiceProvider(iface);
971 LONG ref = InterlockedIncrement(&This->ref);
972
973 TRACE("(%p) ref=%d\n", This, ref);
974
975 return ref;
976 }
977
978 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
979 {
980 LocalServer *This = impl_from_IServiceProvider(iface);
981 LONG ref = InterlockedDecrement(&This->ref);
982
983 TRACE("(%p) ref=%d\n", This, ref);
984
985 if(!ref) {
986 assert(!This->apt);
987 HeapFree(GetProcessHeap(), 0, This);
988 }
989
990 return ref;
991 }
992
993 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
994 {
995 LocalServer *This = impl_from_IServiceProvider(iface);
996 APARTMENT *apt = COM_CurrentApt();
997 RegisteredClass *iter;
998 HRESULT hres = E_FAIL;
999
1000 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
1001
1002 if(!This->apt)
1003 return E_UNEXPECTED;
1004
1005 EnterCriticalSection(&csRegisteredClassList);
1006
1007 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
1008 if(iter->apartment_id == apt->oxid
1009 && (iter->runContext & CLSCTX_LOCAL_SERVER)
1010 && IsEqualGUID(&iter->classIdentifier, guid)) {
1011 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
1012 break;
1013 }
1014 }
1015
1016 LeaveCriticalSection( &csRegisteredClassList );
1017
1018 return hres;
1019 }
1020
1021 static const IServiceProviderVtbl LocalServerVtbl = {
1022 LocalServer_QueryInterface,
1023 LocalServer_AddRef,
1024 LocalServer_Release,
1025 LocalServer_QueryService
1026 };
1027
1028 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
1029 {
1030 HRESULT hres = S_OK;
1031
1032 EnterCriticalSection(&apt->cs);
1033
1034 if(!apt->local_server) {
1035 LocalServer *obj;
1036
1037 obj = heap_alloc(sizeof(*obj));
1038 if(obj) {
1039 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
1040 obj->ref = 1;
1041 obj->apt = apt;
1042
1043 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
1044 if(SUCCEEDED(hres)) {
1045 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
1046 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1047 if(FAILED(hres))
1048 IStream_Release(obj->marshal_stream);
1049 }
1050
1051 if(SUCCEEDED(hres))
1052 apt->local_server = obj;
1053 else
1054 heap_free(obj);
1055 }else {
1056 hres = E_OUTOFMEMORY;
1057 }
1058 }
1059
1060 if(SUCCEEDED(hres))
1061 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1062
1063 LeaveCriticalSection(&apt->cs);
1064
1065 if(FAILED(hres))
1066 ERR("Failed: %08x\n", hres);
1067 return hres;
1068 }
1069
1070 /***********************************************************************
1071 * CoRevokeClassObject [OLE32.@]
1072 *
1073 * Removes a class object from the class registry.
1074 *
1075 * PARAMS
1076 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1077 *
1078 * RETURNS
1079 * Success: S_OK.
1080 * Failure: HRESULT code.
1081 *
1082 * NOTES
1083 * Must be called from the same apartment that called CoRegisterClassObject(),
1084 * otherwise it will fail with RPC_E_WRONG_THREAD.
1085 *
1086 * SEE ALSO
1087 * CoRegisterClassObject
1088 */
1089 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(
1090 DWORD dwRegister)
1091 {
1092 HRESULT hr = E_INVALIDARG;
1093 RegisteredClass *curClass;
1094 APARTMENT *apt;
1095
1096 TRACE("(%08x)\n",dwRegister);
1097
1098 if (!(apt = apartment_get_current_or_mta()))
1099 {
1100 ERR("COM was not initialized\n");
1101 return CO_E_NOTINITIALIZED;
1102 }
1103
1104 EnterCriticalSection( &csRegisteredClassList );
1105
1106 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1107 {
1108 /*
1109 * Check if we have a match on the cookie.
1110 */
1111 if (curClass->dwCookie == dwRegister)
1112 {
1113 if (curClass->apartment_id == apt->oxid)
1114 {
1115 COM_RevokeRegisteredClassObject(curClass);
1116 hr = S_OK;
1117 }
1118 else
1119 {
1120 ERR("called from wrong apartment, should be called from %s\n",
1121 wine_dbgstr_longlong(curClass->apartment_id));
1122 hr = RPC_E_WRONG_THREAD;
1123 }
1124 break;
1125 }
1126 }
1127
1128 LeaveCriticalSection( &csRegisteredClassList );
1129 apartment_release(apt);
1130 return hr;
1131 }
1132
1133 /* frees unused libraries loaded by apartment_getclassobject by calling the
1134 * DLL's DllCanUnloadNow entry point */
1135 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1136 {
1137 struct apartment_loaded_dll *entry, *next;
1138 EnterCriticalSection(&apt->cs);
1139 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1140 {
1141 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1142 {
1143 DWORD real_delay = delay;
1144
1145 if (real_delay == INFINITE)
1146 {
1147 /* DLLs that return multi-threaded objects aren't unloaded
1148 * straight away to cope for programs that have races between
1149 * last object destruction and threads in the DLLs that haven't
1150 * finished, despite DllCanUnloadNow returning S_OK */
1151 if (entry->multi_threaded)
1152 real_delay = 10 * 60 * 1000; /* 10 minutes */
1153 else
1154 real_delay = 0;
1155 }
1156
1157 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1158 {
1159 list_remove(&entry->entry);
1160 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1161 HeapFree(GetProcessHeap(), 0, entry);
1162 }
1163 else
1164 {
1165 entry->unload_time = GetTickCount() + real_delay;
1166 if (!entry->unload_time) entry->unload_time = 1;
1167 }
1168 }
1169 else if (entry->unload_time)
1170 entry->unload_time = 0;
1171 }
1172 LeaveCriticalSection(&apt->cs);
1173 }
1174
1175 DWORD apartment_release(struct apartment *apt)
1176 {
1177 DWORD ret;
1178
1179 EnterCriticalSection(&csApartment);
1180
1181 ret = InterlockedDecrement(&apt->refs);
1182 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1183
1184 if (apt->being_destroyed)
1185 {
1186 LeaveCriticalSection(&csApartment);
1187 return ret;
1188 }
1189
1190 /* destruction stuff that needs to happen under csApartment CS */
1191 if (ret == 0)
1192 {
1193 apt->being_destroyed = TRUE;
1194 if (apt == MTA) MTA = NULL;
1195 else if (apt == MainApartment) MainApartment = NULL;
1196 list_remove(&apt->entry);
1197 }
1198
1199 LeaveCriticalSection(&csApartment);
1200
1201 if (ret == 0)
1202 {
1203 struct list *cursor, *cursor2;
1204
1205 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1206
1207 if(apt->local_server) {
1208 LocalServer *local_server = apt->local_server;
1209 LARGE_INTEGER zero;
1210
1211 memset(&zero, 0, sizeof(zero));
1212 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1213 CoReleaseMarshalData(local_server->marshal_stream);
1214 IStream_Release(local_server->marshal_stream);
1215 local_server->marshal_stream = NULL;
1216
1217 apt->local_server = NULL;
1218 local_server->apt = NULL;
1219 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1220 }
1221
1222 /* Release the references to the registered class objects */
1223 COM_RevokeAllClasses(apt);
1224
1225 /* no locking is needed for this apartment, because no other thread
1226 * can access it at this point */
1227
1228 apartment_disconnectproxies(apt);
1229
1230 if (apt->win) DestroyWindow(apt->win);
1231 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1232
1233 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1234 {
1235 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1236 /* release the implicit reference given by the fact that the
1237 * stub has external references (it must do since it is in the
1238 * stub manager list in the apartment and all non-apartment users
1239 * must have a ref on the apartment and so it cannot be destroyed).
1240 */
1241 stub_manager_int_release(stubmgr);
1242 }
1243
1244 /* if this assert fires, then another thread took a reference to a
1245 * stub manager without taking a reference to the containing
1246 * apartment, which it must do. */
1247 assert(list_empty(&apt->stubmgrs));
1248
1249 if (apt->filter) IMessageFilter_Release(apt->filter);
1250
1251 /* free as many unused libraries as possible... */
1252 apartment_freeunusedlibraries(apt, 0);
1253
1254 /* ... and free the memory for the apartment loaded dll entry and
1255 * release the dll list reference without freeing the library for the
1256 * rest */
1257 while ((cursor = list_head(&apt->loaded_dlls)))
1258 {
1259 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1260 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1261 list_remove(cursor);
1262 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1263 }
1264
1265 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1266 DeleteCriticalSection(&apt->cs);
1267
1268 HeapFree(GetProcessHeap(), 0, apt);
1269 }
1270
1271 return ret;
1272 }
1273
1274 /* The given OXID must be local to this process:
1275 *
1276 * The ref parameter is here mostly to ensure people remember that
1277 * they get one, you should normally take a ref for thread safety.
1278 */
1279 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1280 {
1281 APARTMENT *result = NULL;
1282 struct list *cursor;
1283
1284 EnterCriticalSection(&csApartment);
1285 LIST_FOR_EACH( cursor, &apts )
1286 {
1287 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1288 if (apt->oxid == oxid)
1289 {
1290 result = apt;
1291 if (ref) apartment_addref(result);
1292 break;
1293 }
1294 }
1295 LeaveCriticalSection(&csApartment);
1296
1297 return result;
1298 }
1299
1300 /* gets the apartment which has a given creator thread ID. The caller must
1301 * release the reference from the apartment as soon as the apartment pointer
1302 * is no longer required. */
1303 APARTMENT *apartment_findfromtid(DWORD tid)
1304 {
1305 APARTMENT *result = NULL;
1306 struct list *cursor;
1307
1308 EnterCriticalSection(&csApartment);
1309 LIST_FOR_EACH( cursor, &apts )
1310 {
1311 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1312 if (apt->tid == tid)
1313 {
1314 result = apt;
1315 apartment_addref(result);
1316 break;
1317 }
1318 }
1319 LeaveCriticalSection(&csApartment);
1320
1321 return result;
1322 }
1323
1324 /* gets the main apartment if it exists. The caller must
1325 * release the reference from the apartment as soon as the apartment pointer
1326 * is no longer required. */
1327 static APARTMENT *apartment_findmain(void)
1328 {
1329 APARTMENT *result;
1330
1331 EnterCriticalSection(&csApartment);
1332
1333 result = MainApartment;
1334 if (result) apartment_addref(result);
1335
1336 LeaveCriticalSection(&csApartment);
1337
1338 return result;
1339 }
1340
1341 /* gets the specified class object by loading the appropriate DLL, if
1342 * necessary and calls the DllGetClassObject function for the DLL */
1343 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1344 BOOL apartment_threaded,
1345 REFCLSID rclsid, REFIID riid, void **ppv)
1346 {
1347 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1348 HRESULT hr = S_OK;
1349 BOOL found = FALSE;
1350 struct apartment_loaded_dll *apartment_loaded_dll;
1351
1352 if (!strcmpiW(dllpath, wszOle32))
1353 {
1354 /* we don't need to control the lifetime of this dll, so use the local
1355 * implementation of DllGetClassObject directly */
1356 TRACE("calling ole32!DllGetClassObject\n");
1357 hr = DllGetClassObject(rclsid, riid, ppv);
1358
1359 if (hr != S_OK)
1360 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1361
1362 return hr;
1363 }
1364
1365 EnterCriticalSection(&apt->cs);
1366
1367 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1368 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1369 {
1370 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1371 found = TRUE;
1372 break;
1373 }
1374
1375 if (!found)
1376 {
1377 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1378 if (!apartment_loaded_dll)
1379 hr = E_OUTOFMEMORY;
1380 if (SUCCEEDED(hr))
1381 {
1382 apartment_loaded_dll->unload_time = 0;
1383 apartment_loaded_dll->multi_threaded = FALSE;
1384 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1385 if (FAILED(hr))
1386 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1387 }
1388 if (SUCCEEDED(hr))
1389 {
1390 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1391 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1392 }
1393 }
1394
1395 LeaveCriticalSection(&apt->cs);
1396
1397 if (SUCCEEDED(hr))
1398 {
1399 /* one component being multi-threaded overrides any number of
1400 * apartment-threaded components */
1401 if (!apartment_threaded)
1402 apartment_loaded_dll->multi_threaded = TRUE;
1403
1404 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1405 /* OK: get the ClassObject */
1406 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1407
1408 if (hr != S_OK)
1409 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1410 }
1411
1412 return hr;
1413 }
1414
1415 /* Returns expanded dll path from the registry or activation context. */
1416 static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1417 {
1418 DWORD ret;
1419
1420 if (regdata->hkey)
1421 {
1422 DWORD keytype;
1423 WCHAR src[MAX_PATH];
1424 DWORD dwLength = dstlen * sizeof(WCHAR);
1425
1426 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1427 if (keytype == REG_EXPAND_SZ) {
1428 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1429 } else {
1430 const WCHAR *quote_start;
1431 quote_start = strchrW(src, '\"');
1432 if (quote_start) {
1433 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1434 if (quote_end) {
1435 memmove(src, quote_start + 1,
1436 (quote_end - quote_start - 1) * sizeof(WCHAR));
1437 src[quote_end - quote_start - 1] = '\0';
1438 }
1439 }
1440 lstrcpynW(dst, src, dstlen);
1441 }
1442 }
1443 return !ret;
1444 }
1445 else
1446 {
1447 static const WCHAR dllW[] = {'.','d','l','l',0};
1448 ULONG_PTR cookie;
1449 WCHAR *nameW;
1450
1451 *dst = 0;
1452 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1453 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1454 ret = SearchPathW(NULL, nameW, dllW, dstlen, dst, NULL);
1455 DeactivateActCtx(0, cookie);
1456 return *dst != 0;
1457 }
1458 }
1459
1460 struct host_object_params
1461 {
1462 struct class_reg_data regdata;
1463 CLSID clsid; /* clsid of object to marshal */
1464 IID iid; /* interface to marshal */
1465 HANDLE event; /* event signalling when ready for multi-threaded case */
1466 HRESULT hr; /* result for multi-threaded case */
1467 IStream *stream; /* stream that the object will be marshaled into */
1468 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1469 };
1470
1471 static HRESULT apartment_hostobject(struct apartment *apt,
1472 const struct host_object_params *params)
1473 {
1474 IUnknown *object;
1475 HRESULT hr;
1476 static const LARGE_INTEGER llZero;
1477 WCHAR dllpath[MAX_PATH+1];
1478
1479 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1480
1481 if (!get_object_dll_path(&params->regdata, dllpath, ARRAY_SIZE(dllpath)))
1482 {
1483 /* failure: CLSID is not found in registry */
1484 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1485 return REGDB_E_CLASSNOTREG;
1486 }
1487
1488 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1489 &params->clsid, &params->iid, (void **)&object);
1490 if (FAILED(hr))
1491 return hr;
1492
1493 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1494 if (FAILED(hr))
1495 IUnknown_Release(object);
1496 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1497
1498 return hr;
1499 }
1500
1501 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1502 {
1503 switch (msg)
1504 {
1505 case DM_EXECUTERPC:
1506 RPC_ExecuteCall((struct dispatch_params *)lParam);
1507 return 0;
1508 case DM_HOSTOBJECT:
1509 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1510 default:
1511 return DefWindowProcW(hWnd, msg, wParam, lParam);
1512 }
1513 }
1514
1515 struct host_thread_params
1516 {
1517 COINIT threading_model;
1518 HANDLE ready_event;
1519 HWND apartment_hwnd;
1520 };
1521
1522 /* thread for hosting an object to allow an object to appear to be created in
1523 * an apartment with an incompatible threading model */
1524 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1525 {
1526 struct host_thread_params *params = p;
1527 MSG msg;
1528 HRESULT hr;
1529 struct apartment *apt;
1530
1531 TRACE("\n");
1532
1533 hr = CoInitializeEx(NULL, params->threading_model);
1534 if (FAILED(hr)) return hr;
1535
1536 apt = COM_CurrentApt();
1537 if (params->threading_model == COINIT_APARTMENTTHREADED)
1538 {
1539 apartment_createwindowifneeded(apt);
1540 params->apartment_hwnd = apartment_getwindow(apt);
1541 }
1542 else
1543 params->apartment_hwnd = NULL;
1544
1545 /* force the message queue to be created before signaling parent thread */
1546 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1547
1548 SetEvent(params->ready_event);
1549 params = NULL; /* can't touch params after here as it may be invalid */
1550
1551 while (GetMessageW(&msg, NULL, 0, 0))
1552 {
1553 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1554 {
1555 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1556 obj_params->hr = apartment_hostobject(apt, obj_params);
1557 SetEvent(obj_params->event);
1558 }
1559 else
1560 {
1561 TranslateMessage(&msg);
1562 DispatchMessageW(&msg);
1563 }
1564 }
1565
1566 TRACE("exiting\n");
1567
1568 CoUninitialize();
1569
1570 return S_OK;
1571 }
1572
1573 /* finds or creates a host apartment, creates the object inside it and returns
1574 * a proxy to it so that the object can be used in the apartment of the
1575 * caller of this function */
1576 static HRESULT apartment_hostobject_in_hostapt(
1577 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1578 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1579 {
1580 struct host_object_params params;
1581 HWND apartment_hwnd = NULL;
1582 DWORD apartment_tid = 0;
1583 HRESULT hr;
1584
1585 if (!multi_threaded && main_apartment)
1586 {
1587 APARTMENT *host_apt = apartment_findmain();
1588 if (host_apt)
1589 {
1590 apartment_hwnd = apartment_getwindow(host_apt);
1591 apartment_release(host_apt);
1592 }
1593 }
1594
1595 if (!apartment_hwnd)
1596 {
1597 EnterCriticalSection(&apt->cs);
1598
1599 if (!apt->host_apt_tid)
1600 {
1601 struct host_thread_params thread_params;
1602 HANDLE handles[2];
1603 DWORD wait_value;
1604
1605 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1606 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1607 thread_params.apartment_hwnd = NULL;
1608 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1609 if (!handles[1])
1610 {
1611 CloseHandle(handles[0]);
1612 LeaveCriticalSection(&apt->cs);
1613 return E_OUTOFMEMORY;
1614 }
1615 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1616 CloseHandle(handles[0]);
1617 CloseHandle(handles[1]);
1618 if (wait_value == WAIT_OBJECT_0)
1619 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1620 else
1621 {
1622 LeaveCriticalSection(&apt->cs);
1623 return E_OUTOFMEMORY;
1624 }
1625 }
1626
1627 if (multi_threaded || !main_apartment)
1628 {
1629 apartment_hwnd = apt->host_apt_hwnd;
1630 apartment_tid = apt->host_apt_tid;
1631 }
1632
1633 LeaveCriticalSection(&apt->cs);
1634 }
1635
1636 /* another thread may have become the main apartment in the time it took
1637 * us to create the thread for the host apartment */
1638 if (!apartment_hwnd && !multi_threaded && main_apartment)
1639 {
1640 APARTMENT *host_apt = apartment_findmain();
1641 if (host_apt)
1642 {
1643 apartment_hwnd = apartment_getwindow(host_apt);
1644 apartment_release(host_apt);
1645 }
1646 }
1647
1648 params.regdata = *regdata;
1649 params.clsid = *rclsid;
1650 params.iid = *riid;
1651 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1652 if (FAILED(hr))
1653 return hr;
1654 params.apartment_threaded = !multi_threaded;
1655 if (multi_threaded)
1656 {
1657 params.hr = S_OK;
1658 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1659 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1660 hr = E_OUTOFMEMORY;
1661 else
1662 {
1663 WaitForSingleObject(params.event, INFINITE);
1664 hr = params.hr;
1665 }
1666 CloseHandle(params.event);
1667 }
1668 else
1669 {
1670 if (!apartment_hwnd)
1671 {
1672 ERR("host apartment didn't create window\n");
1673 hr = E_OUTOFMEMORY;
1674 }
1675 else
1676 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1677 }
1678 if (SUCCEEDED(hr))
1679 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1680 IStream_Release(params.stream);
1681 return hr;
1682 }
1683
1684 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1685 {
1686 WNDCLASSW wclass;
1687
1688 /* Dispatching to the correct thread in an apartment is done through
1689 * window messages rather than RPC transports. When an interface is
1690 * marshalled into another apartment in the same process, a window of the
1691 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1692 * application) is responsible for pumping the message loop in that thread.
1693 * The WM_USER messages which point to the RPCs are then dispatched to
1694 * apartment_wndproc by the user's code from the apartment in which the
1695 * interface was unmarshalled.
1696 */
1697 memset(&wclass, 0, sizeof(wclass));
1698 wclass.lpfnWndProc = apartment_wndproc;
1699 wclass.hInstance = hProxyDll;
1700 wclass.lpszClassName = wszAptWinClass;
1701 apt_win_class = RegisterClassW(&wclass);
1702 return TRUE;
1703 }
1704
1705 /* create a window for the apartment or return the current one if one has
1706 * already been created */
1707 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1708 {
1709 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1710
1711 if (apt->multi_threaded)
1712 return S_OK;
1713
1714 if (!apt->win)
1715 {
1716 HWND hwnd;
1717
1718 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1719
1720 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1721 HWND_MESSAGE, 0, hProxyDll, NULL);
1722 if (!hwnd)
1723 {
1724 ERR("CreateWindow failed with error %d\n", GetLastError());
1725 return HRESULT_FROM_WIN32(GetLastError());
1726 }
1727 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1728 /* someone beat us to it */
1729 DestroyWindow(hwnd);
1730 }
1731
1732 return S_OK;
1733 }
1734
1735 /* retrieves the window for the main- or apartment-threaded apartment */
1736 HWND apartment_getwindow(const struct apartment *apt)
1737 {
1738 assert(!apt->multi_threaded);
1739 return apt->win;
1740 }
1741
1742 static void COM_TlsDestroy(void)
1743 {
1744 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1745 if (info)
1746 {
1747 if (info->apt) apartment_release(info->apt);
1748 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1749 if (info->state) IUnknown_Release(info->state);
1750 if (info->spy) IInitializeSpy_Release(info->spy);
1751 if (info->context_token) IObjContext_Release(info->context_token);
1752 HeapFree(GetProcessHeap(), 0, info);
1753 NtCurrentTeb()->ReservedForOle = NULL;
1754 }
1755 }
1756
1757 /******************************************************************************
1758 * CoBuildVersion [OLE32.@]
1759 *
1760 * Gets the build version of the DLL.
1761 *
1762 * PARAMS
1763 *
1764 * RETURNS
1765 * Current build version, hiword is majornumber, loword is minornumber
1766 */
1767 DWORD WINAPI CoBuildVersion(void)
1768 {
1769 TRACE("Returning version %d, build %d.\n", rmm, rup);
1770 return (rmm<<16)+rup;
1771 }
1772
1773 /******************************************************************************
1774 * CoRegisterInitializeSpy [OLE32.@]
1775 *
1776 * Add a Spy that watches CoInitializeEx calls
1777 *
1778 * PARAMS
1779 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1780 * cookie [II] cookie receiver
1781 *
1782 * RETURNS
1783 * Success: S_OK if not already initialized, S_FALSE otherwise.
1784 * Failure: HRESULT code.
1785 *
1786 * SEE ALSO
1787 * CoInitializeEx
1788 */
1789 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1790 {
1791 struct oletls *info = COM_CurrentInfo();
1792 HRESULT hr;
1793
1794 TRACE("(%p, %p)\n", spy, cookie);
1795
1796 if (!spy || !cookie || !info)
1797 {
1798 if (!info)
1799 WARN("Could not allocate tls\n");
1800 return E_INVALIDARG;
1801 }
1802
1803 if (info->spy)
1804 {
1805 FIXME("Already registered?\n");
1806 return E_UNEXPECTED;
1807 }
1808
1809 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1810 if (SUCCEEDED(hr))
1811 {
1812 cookie->QuadPart = (DWORD_PTR)spy;
1813 return S_OK;
1814 }
1815 return hr;
1816 }
1817
1818 /******************************************************************************
1819 * CoRevokeInitializeSpy [OLE32.@]
1820 *
1821 * Remove a spy that previously watched CoInitializeEx calls
1822 *
1823 * PARAMS
1824 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1825 *
1826 * RETURNS
1827 * Success: S_OK if a spy is removed
1828 * Failure: E_INVALIDARG
1829 *
1830 * SEE ALSO
1831 * CoInitializeEx
1832 */
1833 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1834 {
1835 struct oletls *info = COM_CurrentInfo();
1836 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1837
1838 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1839 return E_INVALIDARG;
1840
1841 IInitializeSpy_Release(info->spy);
1842 info->spy = NULL;
1843 return S_OK;
1844 }
1845
1846 HRESULT enter_apartment( struct oletls *info, DWORD model )
1847 {
1848 HRESULT hr = S_OK;
1849
1850 if (!info->apt)
1851 {
1852 if (!apartment_get_or_create( model ))
1853 return E_OUTOFMEMORY;
1854 }
1855 else if (!apartment_is_model( info->apt, model ))
1856 {
1857 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1858 info->apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1859 model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" );
1860 return RPC_E_CHANGED_MODE;
1861 }
1862 else
1863 hr = S_FALSE;
1864
1865 info->inits++;
1866
1867 return hr;
1868 }
1869
1870 void leave_apartment( struct oletls *info )
1871 {
1872 if (!--info->inits)
1873 {
1874 if (info->ole_inits)
1875 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1876 apartment_release( info->apt );
1877 info->apt = NULL;
1878 }
1879 }
1880
1881 /******************************************************************************
1882 * CoInitialize [OLE32.@]
1883 *
1884 * Initializes the COM libraries by calling CoInitializeEx with
1885 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1886 *
1887 * PARAMS
1888 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1889 *
1890 * RETURNS
1891 * Success: S_OK if not already initialized, S_FALSE otherwise.
1892 * Failure: HRESULT code.
1893 *
1894 * SEE ALSO
1895 * CoInitializeEx
1896 */
1897 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1898 {
1899 /*
1900 * Just delegate to the newer method.
1901 */
1902 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1903 }
1904
1905 /******************************************************************************
1906 * CoInitializeEx [OLE32.@]
1907 *
1908 * Initializes the COM libraries.
1909 *
1910 * PARAMS
1911 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1912 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1913 *
1914 * RETURNS
1915 * S_OK if successful,
1916 * S_FALSE if this function was called already.
1917 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1918 * threading model.
1919 *
1920 * NOTES
1921 *
1922 * The behavior used to set the IMalloc used for memory management is
1923 * obsolete.
1924 * The dwCoInit parameter must specify one of the following apartment
1925 * threading models:
1926 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1927 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1928 * The parameter may also specify zero or more of the following flags:
1929 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1930 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1931 *
1932 * SEE ALSO
1933 * CoUninitialize
1934 */
1935 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1936 {
1937 struct oletls *info = COM_CurrentInfo();
1938 HRESULT hr;
1939
1940 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1941
1942 if (lpReserved!=NULL)
1943 {
1944 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1945 }
1946
1947 /*
1948 * Check the lock count. If this is the first time going through the initialize
1949 * process, we have to initialize the libraries.
1950 *
1951 * And crank-up that lock count.
1952 */
1953 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1954 {
1955 /*
1956 * Initialize the various COM libraries and data structures.
1957 */
1958 TRACE("() - Initializing the COM libraries\n");
1959
1960 /* we may need to defer this until after apartment initialisation */
1961 RunningObjectTableImpl_Initialize();
1962 }
1963
1964 if (info->spy)
1965 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1966
1967 hr = enter_apartment( info, dwCoInit );
1968
1969 if (info->spy)
1970 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1971
1972 return hr;
1973 }
1974
1975 /***********************************************************************
1976 * CoUninitialize [OLE32.@]
1977 *
1978 * This method will decrement the refcount on the current apartment, freeing
1979 * the resources associated with it if it is the last thread in the apartment.
1980 * If the last apartment is freed, the function will additionally release
1981 * any COM resources associated with the process.
1982 *
1983 * PARAMS
1984 *
1985 * RETURNS
1986 * Nothing.
1987 *
1988 * SEE ALSO
1989 * CoInitializeEx
1990 */
1991 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
1992 {
1993 struct oletls * info = COM_CurrentInfo();
1994 LONG lCOMRefCnt;
1995
1996 TRACE("()\n");
1997
1998 /* will only happen on OOM */
1999 if (!info) return;
2000
2001 if (info->spy)
2002 IInitializeSpy_PreUninitialize(info->spy, info->inits);
2003
2004 /* sanity check */
2005 if (!info->inits)
2006 {
2007 ERR("Mismatched CoUninitialize\n");
2008
2009 if (info->spy)
2010 IInitializeSpy_PostUninitialize(info->spy, info->inits);
2011 return;
2012 }
2013
2014 leave_apartment( info );
2015
2016 /*
2017 * Decrease the reference count.
2018 * If we are back to 0 locks on the COM library, make sure we free
2019 * all the associated data structures.
2020 */
2021 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
2022 if (lCOMRefCnt==1)
2023 {
2024 TRACE("() - Releasing the COM libraries\n");
2025
2026 revoke_registered_psclsids();
2027 RunningObjectTableImpl_UnInitialize();
2028 }
2029 else if (lCOMRefCnt<1) {
2030 ERR( "CoUninitialize() - not CoInitialized.\n" );
2031 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
2032 }
2033 if (info->spy)
2034 IInitializeSpy_PostUninitialize(info->spy, info->inits);
2035 }
2036
2037 /******************************************************************************
2038 * CoDisconnectObject [OLE32.@]
2039 *
2040 * Disconnects all connections to this object from remote processes. Dispatches
2041 * pending RPCs while blocking new RPCs from occurring, and then calls
2042 * IMarshal::DisconnectObject on the given object.
2043 *
2044 * Typically called when the object server is forced to shut down, for instance by
2045 * the user.
2046 *
2047 * PARAMS
2048 * lpUnk [I] The object whose stub should be disconnected.
2049 * reserved [I] Reserved. Should be set to 0.
2050 *
2051 * RETURNS
2052 * Success: S_OK.
2053 * Failure: HRESULT code.
2054 *
2055 * SEE ALSO
2056 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2057 */
2058 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2059 {
2060 struct stub_manager *manager;
2061 HRESULT hr;
2062 IMarshal *marshal;
2063 APARTMENT *apt;
2064
2065 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2066
2067 if (!lpUnk) return E_INVALIDARG;
2068
2069 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2070 if (hr == S_OK)
2071 {
2072 hr = IMarshal_DisconnectObject(marshal, reserved);
2073 IMarshal_Release(marshal);
2074 return hr;
2075 }
2076
2077 if (!(apt = apartment_get_current_or_mta()))
2078 {
2079 ERR("apartment not initialised\n");
2080 return CO_E_NOTINITIALIZED;
2081 }
2082
2083 manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2084 if (manager) {
2085 stub_manager_disconnect(manager);
2086 /* Release stub manager twice, to remove the apartment reference. */
2087 stub_manager_int_release(manager);
2088 stub_manager_int_release(manager);
2089 }
2090
2091 /* Note: native is pretty broken here because it just silently
2092 * fails, without returning an appropriate error code if the object was
2093 * not found, making apps think that the object was disconnected, when
2094 * it actually wasn't */
2095
2096 apartment_release(apt);
2097 return S_OK;
2098 }
2099
2100 /******************************************************************************
2101 * CoCreateGuid [OLE32.@]
2102 *
2103 * Simply forwards to UuidCreate in RPCRT4.
2104 *
2105 * PARAMS
2106 * pguid [O] Points to the GUID to initialize.
2107 *
2108 * RETURNS
2109 * Success: S_OK.
2110 * Failure: HRESULT code.
2111 *
2112 * SEE ALSO
2113 * UuidCreate
2114 */
2115 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2116 {
2117 DWORD status;
2118
2119 if(!pguid) return E_INVALIDARG;
2120
2121 status = UuidCreate(pguid);
2122 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2123 return HRESULT_FROM_WIN32( status );
2124 }
2125
2126 static inline BOOL is_valid_hex(WCHAR c)
2127 {
2128 if (!(((c >= '0') && (c <= '9')) ||
2129 ((c >= 'a') && (c <= 'f')) ||
2130 ((c >= 'A') && (c <= 'F'))))
2131 return FALSE;
2132 return TRUE;
2133 }
2134
2135 static const BYTE guid_conv_table[256] =
2136 {
2137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2140 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2141 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2142 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2143 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2144 };
2145
2146 /* conversion helper for CLSIDFromString/IIDFromString */
2147 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2148 {
2149 int i;
2150
2151 if (!s || s[0]!='{') {
2152 memset( id, 0, sizeof (CLSID) );
2153 if(!s) return TRUE;
2154 return FALSE;
2155 }
2156
2157 TRACE("%s -> %p\n", debugstr_w(s), id);
2158
2159 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2160
2161 id->Data1 = 0;
2162 for (i = 1; i < 9; i++) {
2163 if (!is_valid_hex(s[i])) return FALSE;
2164 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2165 }
2166 if (s[9]!='-') return FALSE;
2167
2168 id->Data2 = 0;
2169 for (i = 10; i < 14; i++) {
2170 if (!is_valid_hex(s[i])) return FALSE;
2171 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2172 }
2173 if (s[14]!='-') return FALSE;
2174
2175 id->Data3 = 0;
2176 for (i = 15; i < 19; i++) {
2177 if (!is_valid_hex(s[i])) return FALSE;
2178 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2179 }
2180 if (s[19]!='-') return FALSE;
2181
2182 for (i = 20; i < 37; i+=2) {
2183 if (i == 24) {
2184 if (s[i]!='-') return FALSE;
2185 i++;
2186 }
2187 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2188 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2189 }
2190
2191 if (s[37] == '}' && s[38] == '\0')
2192 return TRUE;
2193
2194 return FALSE;
2195 }
2196
2197 /*****************************************************************************/
2198
2199 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2200 {
2201 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2202 WCHAR buf2[CHARS_IN_GUID];
2203 LONG buf2len = sizeof(buf2);
2204 HKEY xhkey;
2205 WCHAR *buf;
2206
2207 memset(clsid, 0, sizeof(*clsid));
2208 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2209 if (!buf) return E_OUTOFMEMORY;
2210 strcpyW( buf, progid );
2211 strcatW( buf, clsidW );
2212 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2213 {
2214 HeapFree(GetProcessHeap(),0,buf);
2215 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2216 return CO_E_CLASSSTRING;
2217 }
2218 HeapFree(GetProcessHeap(),0,buf);
2219
2220 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2221 {
2222 RegCloseKey(xhkey);
2223 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2224 return CO_E_CLASSSTRING;
2225 }
2226 RegCloseKey(xhkey);
2227 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2228 }
2229
2230 /******************************************************************************
2231 * CLSIDFromString [OLE32.@]
2232 *
2233 * Converts a unique identifier from its string representation into
2234 * the GUID struct.
2235 *
2236 * PARAMS
2237 * idstr [I] The string representation of the GUID.
2238 * id [O] GUID converted from the string.
2239 *
2240 * RETURNS
2241 * S_OK on success
2242 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2243 *
2244 * SEE ALSO
2245 * StringFromCLSID
2246 */
2247 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2248 {
2249 HRESULT ret = CO_E_CLASSSTRING;
2250 CLSID tmp_id;
2251
2252 if (!id)
2253 return E_INVALIDARG;
2254
2255 if (guid_from_string(idstr, id))
2256 return S_OK;
2257
2258 /* It appears a ProgID is also valid */
2259 ret = clsid_from_string_reg(idstr, &tmp_id);
2260 if(SUCCEEDED(ret))
2261 *id = tmp_id;
2262
2263 return ret;
2264 }
2265
2266 /******************************************************************************
2267 * IIDFromString [OLE32.@]
2268 *
2269 * Converts an interface identifier from its string representation to
2270 * the IID struct.
2271 *
2272 * PARAMS
2273 * idstr [I] The string representation of the GUID.
2274 * id [O] IID converted from the string.
2275 *
2276 * RETURNS
2277 * S_OK on success
2278 * CO_E_IIDSTRING if idstr is not a valid IID
2279 *
2280 * SEE ALSO
2281 * StringFromIID
2282 */
2283 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2284 {
2285 TRACE("%s -> %p\n", debugstr_w(s), iid);
2286
2287 if (!s)
2288 {
2289 memset(iid, 0, sizeof(*iid));
2290 return S_OK;
2291 }
2292
2293 /* length mismatch is a special case */
2294 if (strlenW(s) + 1 != CHARS_IN_GUID)
2295 return E_INVALIDARG;
2296
2297 if (s[0] != '{')
2298 return CO_E_IIDSTRING;
2299
2300 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2301 }
2302
2303 /******************************************************************************
2304 * StringFromCLSID [OLE32.@]
2305 * StringFromIID [OLE32.@]
2306 *
2307 * Converts a GUID into the respective string representation.
2308 * The target string is allocated using the OLE IMalloc.
2309 *
2310 * PARAMS
2311 * id [I] the GUID to be converted.
2312 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2313 *
2314 * RETURNS
2315 * S_OK
2316 * E_FAIL
2317 *
2318 * SEE ALSO
2319 * StringFromGUID2, CLSIDFromString
2320 */
2321 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2322 {
2323 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2324 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2325 return S_OK;
2326 }
2327
2328 /******************************************************************************
2329 * StringFromGUID2 [OLE32.@]
2330 *
2331 * Modified version of StringFromCLSID that allows you to specify max
2332 * buffer size.
2333 *
2334 * PARAMS
2335 * id [I] GUID to convert to string.
2336 * str [O] Buffer where the result will be stored.
2337 * cmax [I] Size of the buffer in characters.
2338 *
2339 * RETURNS
2340 * Success: The length of the resulting string in characters.
2341 * Failure: 0.
2342 */
2343 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2344 {
2345 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2346 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2347 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2348 '%','0','2','X','%','0','2','X','}',0 };
2349 if (!id || cmax < CHARS_IN_GUID) return 0;
2350 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2351 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2352 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2353 return CHARS_IN_GUID;
2354 }
2355
2356 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2357 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2358 {
2359 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2360 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(wszCLSIDSlash) - 1];
2361 LONG res;
2362 HKEY key;
2363
2364 strcpyW(path, wszCLSIDSlash);
2365 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2366 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2367 if (res == ERROR_FILE_NOT_FOUND)
2368 return REGDB_E_CLASSNOTREG;
2369 else if (res != ERROR_SUCCESS)
2370 return REGDB_E_READREGDB;
2371
2372 if (!keyname)
2373 {
2374 *subkey = key;
2375 return S_OK;
2376 }
2377
2378 res = open_classes_key(key, keyname, access, subkey);
2379 RegCloseKey(key);
2380 if (res == ERROR_FILE_NOT_FOUND)
2381 return REGDB_E_KEYMISSING;
2382 else if (res != ERROR_SUCCESS)
2383 return REGDB_E_READREGDB;
2384
2385 return S_OK;
2386 }
2387
2388 /* open HKCR\\AppId\\{string form of appid clsid} key */
2389 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2390 {
2391 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2392 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2393 DWORD res;
2394 WCHAR buf[CHARS_IN_GUID];
2395 WCHAR keyname[ARRAY_SIZE(szAppIdKey) + CHARS_IN_GUID];
2396 DWORD size;
2397 HKEY hkey;
2398 DWORD type;
2399 HRESULT hr;
2400
2401 /* read the AppID value under the class's key */
2402 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2403 if (FAILED(hr))
2404 return hr;
2405
2406 size = sizeof(buf);
2407 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2408 RegCloseKey(hkey);
2409 if (res == ERROR_FILE_NOT_FOUND)
2410 return REGDB_E_KEYMISSING;
2411 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2412 return REGDB_E_READREGDB;
2413
2414 strcpyW(keyname, szAppIdKey);
2415 strcatW(keyname, buf);
2416 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2417 if (res == ERROR_FILE_NOT_FOUND)
2418 return REGDB_E_KEYMISSING;
2419 else if (res != ERROR_SUCCESS)
2420 return REGDB_E_READREGDB;
2421
2422 return S_OK;
2423 }
2424
2425 /******************************************************************************
2426 * ProgIDFromCLSID [OLE32.@]
2427 *
2428 * Converts a class id into the respective program ID.
2429 *
2430 * PARAMS
2431 * clsid [I] Class ID, as found in registry.
2432 * ppszProgID [O] Associated ProgID.
2433 *
2434 * RETURNS
2435 * S_OK
2436 * E_OUTOFMEMORY
2437 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2438 */
2439 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2440 {
2441 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2442 ACTCTX_SECTION_KEYED_DATA data;
2443 HKEY hkey;
2444 HRESULT ret;
2445 LONG progidlen = 0;
2446
2447 if (!ppszProgID)
2448 return E_INVALIDARG;
2449
2450 *ppszProgID = NULL;
2451
2452 data.cbSize = sizeof(data);
2453 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2454 clsid, &data))
2455 {
2456 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2457 if (comclass->progid_len)
2458 {
2459 WCHAR *ptrW;
2460
2461 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2462 if (!*ppszProgID) return E_OUTOFMEMORY;
2463
2464 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2465 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2466 return S_OK;
2467 }
2468 else
2469 return REGDB_E_CLASSNOTREG;
2470 }
2471
2472 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2473 if (FAILED(ret))
2474 return ret;
2475
2476 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2477 ret = REGDB_E_CLASSNOTREG;
2478
2479 if (ret == S_OK)
2480 {
2481 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2482 if (*ppszProgID)
2483 {
2484 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2485 ret = REGDB_E_CLASSNOTREG;
2486 CoTaskMemFree(*ppszProgID);
2487 *ppszProgID = NULL;
2488 }
2489 }
2490 else
2491 ret = E_OUTOFMEMORY;
2492 }
2493
2494 RegCloseKey(hkey);
2495 return ret;
2496 }
2497
2498 /******************************************************************************
2499 * CLSIDFromProgID [OLE32.@]
2500 *
2501 * Converts a program id into the respective GUID.
2502 *
2503 * PARAMS
2504 * progid [I] Unicode program ID, as found in registry.
2505 * clsid [O] Associated CLSID.
2506 *
2507 * RETURNS
2508 * Success: S_OK
2509 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2510 */
2511 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2512 {
2513 ACTCTX_SECTION_KEYED_DATA data;
2514
2515 if (!progid || !clsid)
2516 return E_INVALIDARG;
2517
2518 data.cbSize = sizeof(data);
2519 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2520 progid, &data))
2521 {
2522 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2523 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2524 *clsid = *alias;
2525 return S_OK;
2526 }
2527
2528 return clsid_from_string_reg(progid, clsid);
2529 }
2530
2531 /******************************************************************************
2532 * CLSIDFromProgIDEx [OLE32.@]
2533 */
2534 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2535 {
2536 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2537
2538 return CLSIDFromProgID(progid, clsid);
2539 }
2540
2541 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2542 {
2543 HKEY hkey;
2544 WCHAR value[CHARS_IN_GUID];
2545 DWORD len;
2546
2547 access |= KEY_READ;
2548
2549 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2550 return REGDB_E_IIDNOTREG;
2551
2552 len = sizeof(value);
2553 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2554 return REGDB_E_IIDNOTREG;
2555 RegCloseKey(hkey);
2556
2557 if (CLSIDFromString(value, pclsid) != NOERROR)
2558 return REGDB_E_IIDNOTREG;
2559
2560 return S_OK;
2561 }
2562
2563 /*****************************************************************************
2564 * CoGetPSClsid [OLE32.@]
2565 *
2566 * Retrieves the CLSID of the proxy/stub factory that implements
2567 * IPSFactoryBuffer for the specified interface.
2568 *
2569 * PARAMS
2570 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2571 * pclsid [O] Where to store returned proxy/stub CLSID.
2572 *
2573 * RETURNS
2574 * S_OK
2575 * E_OUTOFMEMORY
2576 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2577 *
2578 * NOTES
2579 *
2580 * The standard marshaller activates the object with the CLSID
2581 * returned and uses the CreateProxy and CreateStub methods on its
2582 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2583 * given object.
2584 *
2585 * CoGetPSClsid determines this CLSID by searching the
2586 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2587 * in the registry and any interface id registered by
2588 * CoRegisterPSClsid within the current process.
2589 *
2590 * BUGS
2591 *
2592 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2593 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2594 * considered a bug in native unless an application depends on this (unlikely).
2595 *
2596 * SEE ALSO
2597 * CoRegisterPSClsid.
2598 */
2599 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2600 {
2601 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2602 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2603 WCHAR path[ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(wszPSC)];
2604 APARTMENT *apt;
2605 struct registered_psclsid *registered_psclsid;
2606 ACTCTX_SECTION_KEYED_DATA data;
2607 HRESULT hr;
2608 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2609 BOOL is_wow64;
2610
2611 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2612
2613 if (!(apt = apartment_get_current_or_mta()))
2614 {
2615 ERR("apartment not initialised\n");
2616 return CO_E_NOTINITIALIZED;
2617 }
2618 apartment_release(apt);
2619
2620 if (!pclsid)
2621 return E_INVALIDARG;
2622
2623 EnterCriticalSection(&cs_registered_psclsid_list);
2624
2625 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2626 if (IsEqualIID(&registered_psclsid->iid, riid))
2627 {
2628 *pclsid = registered_psclsid->clsid;
2629 LeaveCriticalSection(&cs_registered_psclsid_list);
2630 return S_OK;
2631 }
2632
2633 LeaveCriticalSection(&cs_registered_psclsid_list);
2634
2635 data.cbSize = sizeof(data);
2636 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2637 riid, &data))
2638 {
2639 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2640 *pclsid = ifaceps->iid;
2641 return S_OK;
2642 }
2643
2644 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2645 strcpyW(path, wszInterface);
2646 StringFromGUID2(riid, path + ARRAY_SIZE(wszInterface) - 1, CHARS_IN_GUID);
2647 strcpyW(path + ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2648
2649 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2650 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2651 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2652 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2653
2654 if (hr == S_OK)
2655 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2656 else
2657 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2658
2659 return hr;
2660 }
2661
2662 /*****************************************************************************
2663 * CoRegisterPSClsid [OLE32.@]
2664 *
2665 * Register a proxy/stub CLSID for the given interface in the current process
2666 * only.
2667 *
2668 * PARAMS
2669 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2670 * rclsid [I] CLSID of the proxy/stub.
2671 *
2672 * RETURNS
2673 * Success: S_OK
2674 * Failure: E_OUTOFMEMORY
2675 *
2676 * NOTES
2677 *
2678 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2679 * will be returned from other apartments in the same process.
2680 *
2681 * This function does not add anything to the registry and the effects are
2682 * limited to the lifetime of the current process.
2683 *
2684 * SEE ALSO
2685 * CoGetPSClsid.
2686 */
2687 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2688 {
2689 APARTMENT *apt;
2690 struct registered_psclsid *registered_psclsid;
2691
2692 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2693
2694 if (!(apt = apartment_get_current_or_mta()))
2695 {
2696 ERR("apartment not initialised\n");
2697 return CO_E_NOTINITIALIZED;
2698 }
2699 apartment_release(apt);
2700
2701 EnterCriticalSection(&cs_registered_psclsid_list);
2702
2703 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2704 if (IsEqualIID(&registered_psclsid->iid, riid))
2705 {
2706 registered_psclsid->clsid = *rclsid;
2707 LeaveCriticalSection(&cs_registered_psclsid_list);
2708 return S_OK;
2709 }
2710
2711 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2712 if (!registered_psclsid)
2713 {
2714 LeaveCriticalSection(&cs_registered_psclsid_list);
2715 return E_OUTOFMEMORY;
2716 }
2717
2718 registered_psclsid->iid = *riid;
2719 registered_psclsid->clsid = *rclsid;
2720 list_add_head(&registered_psclsid_list, &registered_psclsid->entry);
2721
2722 LeaveCriticalSection(&cs_registered_psclsid_list);
2723
2724 return S_OK;
2725 }
2726
2727
2728 /***
2729 * COM_GetRegisteredClassObject
2730 *
2731 * This internal method is used to scan the registered class list to
2732 * find a class object.
2733 *
2734 * Params:
2735 * rclsid Class ID of the class to find.
2736 * dwClsContext Class context to match.
2737 * ppv [out] returns a pointer to the class object. Complying
2738 * to normal COM usage, this method will increase the
2739 * reference count on this object.
2740 */
2741 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2742 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2743 {
2744 HRESULT hr = S_FALSE;
2745 RegisteredClass *curClass;
2746
2747 EnterCriticalSection( &csRegisteredClassList );
2748
2749 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2750 {
2751 /*
2752 * Check if we have a match on the class ID and context.
2753 */
2754 if ((apt->oxid == curClass->apartment_id) &&
2755 (dwClsContext & curClass->runContext) &&
2756 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2757 {
2758 /*
2759 * We have a match, return the pointer to the class object.
2760 */
2761 *ppUnk = curClass->classObject;
2762
2763 IUnknown_AddRef(curClass->classObject);
2764
2765 hr = S_OK;
2766 break;
2767 }
2768 }
2769
2770 LeaveCriticalSection( &csRegisteredClassList );
2771
2772 return hr;
2773 }
2774
2775 /******************************************************************************
2776 * CoRegisterClassObject [OLE32.@]
2777 *
2778 * Registers the class object for a given class ID. Servers housed in EXE
2779 * files use this method instead of exporting DllGetClassObject to allow
2780 * other code to connect to their objects.
2781 *
2782 * PARAMS
2783 * rclsid [I] CLSID of the object to register.
2784 * pUnk [I] IUnknown of the object.
2785 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2786 * flags [I] REGCLS flags indicating how connections are made.
2787 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2788 *
2789 * RETURNS
2790 * S_OK on success,
2791 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2792 * CO_E_OBJISREG if the object is already registered. We should not return this.
2793 *
2794 * SEE ALSO
2795 * CoRevokeClassObject, CoGetClassObject
2796 *
2797 * NOTES
2798 * In-process objects are only registered for the current apartment.
2799 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2800 * in other apartments.
2801 *
2802 * BUGS
2803 * MSDN claims that multiple interface registrations are legal, but we
2804 * can't do that with our current implementation.
2805 */
2806 HRESULT WINAPI CoRegisterClassObject(
2807 REFCLSID rclsid,
2808 LPUNKNOWN pUnk,
2809 DWORD dwClsContext,
2810 DWORD flags,
2811 LPDWORD lpdwRegister)
2812 {
2813 static LONG next_cookie;
2814 RegisteredClass* newClass;
2815 LPUNKNOWN foundObject;
2816 HRESULT hr;
2817 APARTMENT *apt;
2818
2819 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2820 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2821
2822 if ( (lpdwRegister==0) || (pUnk==0) )
2823 return E_INVALIDARG;
2824
2825 if (!(apt = apartment_get_current_or_mta()))
2826 {
2827 ERR("COM was not initialized\n");
2828 return CO_E_NOTINITIALIZED;
2829 }
2830
2831 *lpdwRegister = 0;
2832
2833 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2834 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2835 if (flags & REGCLS_MULTIPLEUSE)
2836 dwClsContext |= CLSCTX_INPROC_SERVER;
2837
2838 /*
2839 * First, check if the class is already registered.
2840 * If it is, this should cause an error.
2841 */
2842 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2843 if (hr == S_OK) {
2844 if (flags & REGCLS_MULTIPLEUSE) {
2845 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2846 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2847 IUnknown_Release(foundObject);
2848 apartment_release(apt);
2849 return hr;
2850 }
2851 IUnknown_Release(foundObject);
2852 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2853 apartment_release(apt);
2854 return CO_E_OBJISREG;
2855 }
2856
2857 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2858 if ( newClass == NULL )
2859 {
2860 apartment_release(apt);
2861 return E_OUTOFMEMORY;
2862 }
2863
2864 newClass->classIdentifier = *rclsid;
2865 newClass->apartment_id = apt->oxid;
2866 newClass->runContext = dwClsContext;
2867 newClass->connectFlags = flags;
2868 newClass->RpcRegistration = NULL;
2869
2870 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2871 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2872
2873 /*
2874 * Since we're making a copy of the object pointer, we have to increase its
2875 * reference count.
2876 */
2877 newClass->classObject = pUnk;
2878 IUnknown_AddRef(newClass->classObject);
2879
2880 EnterCriticalSection( &csRegisteredClassList );
2881 list_add_tail(&RegisteredClassList, &newClass->entry);
2882 LeaveCriticalSection( &csRegisteredClassList );
2883
2884 *lpdwRegister = newClass->dwCookie;
2885
2886 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2887 IStream *marshal_stream;
2888
2889 hr = get_local_server_stream(apt, &marshal_stream);
2890 if(FAILED(hr))
2891 {
2892 apartment_release(apt);
2893 return hr;
2894 }
2895
2896 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2897 marshal_stream,
2898 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2899 &newClass->RpcRegistration);
2900 IStream_Release(marshal_stream);
2901 }
2902 apartment_release(apt);
2903 return S_OK;
2904 }
2905
2906 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2907 {
2908 if (data->hkey)
2909 {
2910 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2911 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2912 static const WCHAR wszFree[] = {'F','r','e','e',0};
2913 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2914 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2915 DWORD dwLength = sizeof(threading_model);
2916 DWORD keytype;
2917 DWORD ret;
2918
2919 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2920 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2921 threading_model[0] = '\0';
2922
2923 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2924 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2925 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2926
2927 /* there's not specific handling for this case */
2928 if (threading_model[0]) return ThreadingModel_Neutral;
2929 return ThreadingModel_No;
2930 }
2931 else
2932 return data->u.actctx.data->model;
2933 }
2934
2935 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2936 REFCLSID rclsid, REFIID riid,
2937 BOOL hostifnecessary, void **ppv)
2938 {
2939 WCHAR dllpath[MAX_PATH+1];
2940 BOOL apartment_threaded;
2941
2942 if (hostifnecessary)
2943 {
2944 enum comclass_threadingmodel model = get_threading_model(regdata);
2945
2946 if (model == ThreadingModel_Apartment)
2947 {
2948 apartment_threaded = TRUE;
2949 if (apt->multi_threaded)
2950 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2951 }
2952 else if (model == ThreadingModel_Free)
2953 {
2954 apartment_threaded = FALSE;
2955 if (!apt->multi_threaded)
2956 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2957 }
2958 /* everything except "Apartment", "Free" and "Both" */
2959 else if (model != ThreadingModel_Both)
2960 {
2961 apartment_threaded = TRUE;
2962 /* everything else is main-threaded */
2963 if (model != ThreadingModel_No)
2964 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2965
2966 if (apt->multi_threaded || !apt->main)
2967 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2968 }
2969 else
2970 apartment_threaded = FALSE;
2971 }
2972 else
2973 apartment_threaded = !apt->multi_threaded;
2974
2975 if (!get_object_dll_path(regdata, dllpath, ARRAY_SIZE(dllpath)))
2976 {
2977 /* failure: CLSID is not found in registry */
2978 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2979 return REGDB_E_CLASSNOTREG;
2980 }
2981
2982 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2983 rclsid, riid, ppv);
2984 }
2985
2986 /***********************************************************************
2987 * CoGetClassObject [OLE32.@]
2988 *
2989 * Creates an object of the specified class.
2990 *
2991 * PARAMS
2992 * rclsid [I] Class ID to create an instance of.
2993 * dwClsContext [I] Flags to restrict the location of the created instance.
2994 * pServerInfo [I] Optional. Details for connecting to a remote server.
2995 * iid [I] The ID of the interface of the instance to return.
2996 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2997 *
2998 * RETURNS
2999 * Success: S_OK
3000 * Failure: HRESULT code.
3001 *
3002 * NOTES
3003 * The dwClsContext parameter can be one or more of the following:
3004 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3005 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3006 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3007 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3008 *
3009 * SEE ALSO
3010 * CoCreateInstance()
3011 */
3012 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
3013 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
3014 REFIID iid, LPVOID *ppv)
3015 {
3016 struct class_reg_data clsreg;
3017 IUnknown *regClassObject;
3018 HRESULT hres = E_UNEXPECTED;
3019 APARTMENT *apt;
3020
3021 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
3022
3023 if (!ppv)
3024 return E_INVALIDARG;
3025
3026 *ppv = NULL;
3027
3028 if (!(apt = apartment_get_current_or_mta()))
3029 {
3030 ERR("apartment not initialised\n");
3031 return CO_E_NOTINITIALIZED;
3032 }
3033
3034 if (pServerInfo) {
3035 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3036 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
3037 }
3038
3039 if (CLSCTX_INPROC_SERVER & dwClsContext)
3040 {
3041 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
3042 {
3043 apartment_release(apt);
3044 return FTMarshalCF_Create(iid, ppv);
3045 }
3046 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3047 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
3048 }
3049
3050 if (CLSCTX_INPROC & dwClsContext)
3051 {
3052 ACTCTX_SECTION_KEYED_DATA data;
3053
3054 data.cbSize = sizeof(data);
3055 /* search activation context first */
3056 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3057 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3058 rclsid, &data))
3059 {
3060 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3061
3062 clsreg.u.actctx.hactctx = data.hActCtx;
3063 clsreg.u.actctx.data = data.lpData;
3064 clsreg.u.actctx.section = data.lpSectionBase;
3065 clsreg.hkey = FALSE;
3066
3067 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3068 ReleaseActCtx(data.hActCtx);
3069 apartment_release(apt);
3070 return hres;
3071 }
3072 }
3073
3074 /*
3075 * First, try and see if we can't match the class ID with one of the
3076 * registered classes.
3077 */
3078 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3079 &regClassObject))
3080 {
3081 /* Get the required interface from the retrieved pointer. */
3082 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3083
3084 /*
3085 * Since QI got another reference on the pointer, we want to release the
3086 * one we already have. If QI was unsuccessful, this will release the object. This
3087 * is good since we are not returning it in the "out" parameter.
3088 */
3089 IUnknown_Release(regClassObject);
3090 apartment_release(apt);
3091 return hres;
3092 }
3093
3094 /* First try in-process server */
3095 if (CLSCTX_INPROC_SERVER & dwClsContext)
3096 {
3097 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3098 HKEY hkey;
3099
3100 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3101 if (FAILED(hres))
3102 {
3103 if (hres == REGDB_E_CLASSNOTREG)
3104 ERR("class %s not registered\n", debugstr_guid(rclsid));
3105 else if (hres == REGDB_E_KEYMISSING)
3106 {
3107 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3108 hres = REGDB_E_CLASSNOTREG;
3109 }
3110 }
3111
3112 if (SUCCEEDED(hres))
3113 {
3114 clsreg.u.hkey = hkey;
3115 clsreg.hkey = TRUE;
3116
3117 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3118 RegCloseKey(hkey);
3119 }
3120
3121 /* return if we got a class, otherwise fall through to one of the
3122 * other types */
3123 if (SUCCEEDED(hres))
3124 {
3125 apartment_release(apt);
3126 return hres;
3127 }
3128 }
3129
3130 /* Next try in-process handler */
3131 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3132 {
3133 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3134 HKEY hkey;
3135
3136 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3137 if (FAILED(hres))
3138 {
3139 if (hres == REGDB_E_CLASSNOTREG)
3140 ERR("class %s not registered\n", debugstr_guid(rclsid));
3141 else if (hres == REGDB_E_KEYMISSING)
3142 {
3143 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3144 hres = REGDB_E_CLASSNOTREG;
3145 }
3146 }
3147
3148 if (SUCCEEDED(hres))
3149 {
3150 clsreg.u.hkey = hkey;
3151 clsreg.hkey = TRUE;
3152
3153 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3154 RegCloseKey(hkey);
3155 }
3156
3157 /* return if we got a class, otherwise fall through to one of the
3158 * other types */
3159 if (SUCCEEDED(hres))
3160 {
3161 apartment_release(apt);
3162 return hres;
3163 }
3164 }
3165 apartment_release(apt);
3166
3167 /* Next try out of process */
3168 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3169 {
3170 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3171 if (SUCCEEDED(hres))
3172 return hres;
3173 }
3174
3175 /* Finally try remote: this requires networked DCOM (a lot of work) */
3176 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3177 {
3178 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3179 hres = REGDB_E_CLASSNOTREG;
3180 }
3181
3182 if (FAILED(hres))
3183 ERR("no class object %s could be created for context 0x%x\n",
3184 debugstr_guid(rclsid), dwClsContext);
3185 return hres;
3186 }
3187
3188 /***********************************************************************
3189 * CoResumeClassObjects (OLE32.@)
3190 *
3191 * Resumes all class objects registered with REGCLS_SUSPENDED.
3192 *
3193 * RETURNS
3194 * Success: S_OK.
3195 * Failure: HRESULT code.
3196 */
3197 HRESULT WINAPI CoResumeClassObjects(void)
3198 {
3199 FIXME("stub\n");
3200 return S_OK;
3201 }
3202
3203 /***********************************************************************
3204 * CoCreateInstance [OLE32.@]
3205 *
3206 * Creates an instance of the specified class.
3207 *
3208 * PARAMS
3209 * rclsid [I] Class ID to create an instance of.
3210 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3211 * dwClsContext [I] Flags to restrict the location of the created instance.
3212 * iid [I] The ID of the interface of the instance to return.
3213 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3214 *
3215 * RETURNS
3216 * Success: S_OK
3217 * Failure: HRESULT code.
3218 *
3219 * NOTES
3220 * The dwClsContext parameter can be one or more of the following:
3221 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3222 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3223 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3224 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3225 *
3226 * Aggregation is the concept of deferring the IUnknown of an object to another
3227 * object. This allows a separate object to behave as though it was part of
3228 * the object and to allow this the pUnkOuter parameter can be set. Note that
3229 * not all objects support having an outer of unknown.
3230 *
3231 * SEE ALSO
3232 * CoGetClassObject()
3233 */
3234 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3235 REFCLSID rclsid,
3236 LPUNKNOWN pUnkOuter,
3237 DWORD dwClsContext,
3238 REFIID iid,
3239 LPVOID *ppv)
3240 {
3241 MULTI_QI multi_qi = { iid };
3242 HRESULT hres;
3243
3244 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3245 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3246
3247 if (ppv==0)
3248 return E_POINTER;
3249
3250 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3251 *ppv = multi_qi.pItf;
3252 return hres;
3253 }
3254
3255 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3256 {
3257 ULONG i;
3258
3259 for (i = 0; i < count; i++)
3260 {
3261 mqi[i].pItf = NULL;
3262 mqi[i].hr = hr;
3263 }
3264 }
3265
3266 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3267 {
3268 ULONG index = 0, fetched = 0;
3269
3270 if (include_unk)
3271