[OLE32]
[reactos.git] / reactos / 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 "precomp.h"
40
41 #include <ctxtcall.h>
42 #include <dde.h>
43
44 WINE_DEFAULT_DEBUG_CHANNEL(ole);
45
46 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
47
48 /****************************************************************************
49 * This section defines variables internal to the COM module.
50 */
51
52 static APARTMENT *MTA; /* protected by csApartment */
53 static APARTMENT *MainApartment; /* the first STA apartment */
54 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
55
56 static CRITICAL_SECTION csApartment;
57 static CRITICAL_SECTION_DEBUG critsect_debug =
58 {
59 0, 0, &csApartment,
60 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
61 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
62 };
63 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
64
65 enum comclass_threadingmodel
66 {
67 ThreadingModel_Apartment = 1,
68 ThreadingModel_Free = 2,
69 ThreadingModel_No = 3,
70 ThreadingModel_Both = 4,
71 ThreadingModel_Neutral = 5
72 };
73
74 enum comclass_miscfields
75 {
76 MiscStatus = 1,
77 MiscStatusIcon = 2,
78 MiscStatusContent = 4,
79 MiscStatusThumbnail = 8,
80 MiscStatusDocPrint = 16
81 };
82
83 struct comclassredirect_data
84 {
85 ULONG size;
86 BYTE res;
87 BYTE miscmask;
88 BYTE res1[2];
89 DWORD model;
90 GUID clsid;
91 GUID alias;
92 GUID clsid2;
93 GUID tlbid;
94 ULONG name_len;
95 ULONG name_offset;
96 ULONG progid_len;
97 ULONG progid_offset;
98 ULONG clrdata_len;
99 ULONG clrdata_offset;
100 DWORD miscstatus;
101 DWORD miscstatuscontent;
102 DWORD miscstatusthumbnail;
103 DWORD miscstatusicon;
104 DWORD miscstatusdocprint;
105 };
106
107 struct ifacepsredirect_data
108 {
109 ULONG size;
110 DWORD mask;
111 GUID iid;
112 ULONG nummethods;
113 GUID tlbid;
114 GUID base;
115 ULONG name_len;
116 ULONG name_offset;
117 };
118
119 struct progidredirect_data
120 {
121 ULONG size;
122 DWORD reserved;
123 ULONG clsid_offset;
124 };
125
126 struct class_reg_data
127 {
128 union
129 {
130 struct
131 {
132 struct comclassredirect_data *data;
133 void *section;
134 HANDLE hactctx;
135 } actctx;
136 HKEY hkey;
137 } u;
138 BOOL hkey;
139 };
140
141 struct registered_psclsid
142 {
143 struct list entry;
144 IID iid;
145 CLSID clsid;
146 };
147
148 /*
149 * This is a marshallable object exposing registered local servers.
150 * IServiceProvider is used only because it happens meet requirements
151 * and already has proxy/stub code. If more functionality is needed,
152 * a custom interface may be used instead.
153 */
154 struct LocalServer
155 {
156 IServiceProvider IServiceProvider_iface;
157 LONG ref;
158 APARTMENT *apt;
159 IStream *marshal_stream;
160 };
161
162 /*
163 * This lock count counts the number of times CoInitialize is called. It is
164 * decreased every time CoUninitialize is called. When it hits 0, the COM
165 * libraries are freed
166 */
167 static LONG s_COMLockCount = 0;
168 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
169 static LONG s_COMServerProcessReferences = 0;
170
171 /*
172 * This linked list contains the list of registered class objects. These
173 * are mostly used to register the factories for out-of-proc servers of OLE
174 * objects.
175 *
176 * TODO: Make this data structure aware of inter-process communication. This
177 * means that parts of this will be exported to rpcss.
178 */
179 typedef struct tagRegisteredClass
180 {
181 struct list entry;
182 CLSID classIdentifier;
183 OXID apartment_id;
184 LPUNKNOWN classObject;
185 DWORD runContext;
186 DWORD connectFlags;
187 DWORD dwCookie;
188 void *RpcRegistration;
189 } RegisteredClass;
190
191 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
192
193 static CRITICAL_SECTION csRegisteredClassList;
194 static CRITICAL_SECTION_DEBUG class_cs_debug =
195 {
196 0, 0, &csRegisteredClassList,
197 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
198 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
199 };
200 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
201
202 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
203 {
204 switch (aspect)
205 {
206 case DVASPECT_CONTENT:
207 return MiscStatusContent;
208 case DVASPECT_THUMBNAIL:
209 return MiscStatusThumbnail;
210 case DVASPECT_ICON:
211 return MiscStatusIcon;
212 case DVASPECT_DOCPRINT:
213 return MiscStatusDocPrint;
214 default:
215 return MiscStatus;
216 };
217 }
218
219 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
220 {
221 ACTCTX_SECTION_KEYED_DATA data;
222
223 data.cbSize = sizeof(data);
224 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
225 clsid, &data))
226 {
227 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
228 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
229
230 if (!(comclass->miscmask & misc))
231 {
232 if (!(comclass->miscmask & MiscStatus))
233 {
234 *status = 0;
235 return TRUE;
236 }
237 misc = MiscStatus;
238 }
239
240 switch (misc)
241 {
242 case MiscStatus:
243 *status = comclass->miscstatus;
244 break;
245 case MiscStatusIcon:
246 *status = comclass->miscstatusicon;
247 break;
248 case MiscStatusContent:
249 *status = comclass->miscstatuscontent;
250 break;
251 case MiscStatusThumbnail:
252 *status = comclass->miscstatusthumbnail;
253 break;
254 case MiscStatusDocPrint:
255 *status = comclass->miscstatusdocprint;
256 break;
257 default:
258 ;
259 };
260
261 return TRUE;
262 }
263 else
264 return FALSE;
265 }
266
267 /* wrapper for NtCreateKey that creates the key recursively if necessary */
268 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
269 {
270 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
271
272 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
273 {
274 HANDLE subkey, root = attr->RootDirectory;
275 WCHAR *buffer = attr->ObjectName->Buffer;
276 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
277 UNICODE_STRING str;
278
279 while (i < len && buffer[i] != '\\') i++;
280 if (i == len) return status;
281
282 attrs = attr->Attributes;
283 attr->ObjectName = &str;
284
285 while (i < len)
286 {
287 str.Buffer = buffer + pos;
288 str.Length = (i - pos) * sizeof(WCHAR);
289 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
290 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
291 if (status) return status;
292 attr->RootDirectory = subkey;
293 while (i < len && buffer[i] == '\\') i++;
294 pos = i;
295 while (i < len && buffer[i] != '\\') i++;
296 }
297 str.Buffer = buffer + pos;
298 str.Length = (i - pos) * sizeof(WCHAR);
299 attr->Attributes = attrs;
300 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
301 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
302 }
303 return status;
304 }
305
306 #ifdef __REACTOS__
307 static const WCHAR classes_rootW[] = L"\\REGISTRY\\Machine\\Software\\Classes";
308 #else
309 static const WCHAR classes_rootW[] =
310 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
311 #endif
312
313 static HKEY classes_root_hkey;
314
315 /* create the special HKEY_CLASSES_ROOT key */
316 static HKEY create_classes_root_hkey(void)
317 {
318 HKEY hkey, ret = 0;
319 OBJECT_ATTRIBUTES attr;
320 UNICODE_STRING name;
321
322 attr.Length = sizeof(attr);
323 attr.RootDirectory = 0;
324 attr.ObjectName = &name;
325 attr.Attributes = 0;
326 attr.SecurityDescriptor = NULL;
327 attr.SecurityQualityOfService = NULL;
328 RtlInitUnicodeString( &name, classes_rootW );
329 if (create_key( &hkey, MAXIMUM_ALLOWED, &attr )) return 0;
330 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
331
332 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
333 ret = hkey;
334 else
335 NtClose( hkey ); /* somebody beat us to it */
336 return ret;
337 }
338
339 /* map the hkey from special root to normal key if necessary */
340 static inline HKEY get_classes_root_hkey( HKEY hkey )
341 {
342 HKEY ret = hkey;
343
344 if (hkey == HKEY_CLASSES_ROOT && !(ret = classes_root_hkey))
345 ret = create_classes_root_hkey();
346
347 return ret;
348 }
349
350 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
351 {
352 OBJECT_ATTRIBUTES attr;
353 UNICODE_STRING nameW;
354
355 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
356
357 attr.Length = sizeof(attr);
358 attr.RootDirectory = hkey;
359 attr.ObjectName = &nameW;
360 attr.Attributes = 0;
361 attr.SecurityDescriptor = NULL;
362 attr.SecurityQualityOfService = NULL;
363 RtlInitUnicodeString( &nameW, name );
364
365 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
366 }
367
368 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
369 {
370 OBJECT_ATTRIBUTES attr;
371 UNICODE_STRING nameW;
372
373 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
374
375 attr.Length = sizeof(attr);
376 attr.RootDirectory = hkey;
377 attr.ObjectName = &nameW;
378 attr.Attributes = 0;
379 attr.SecurityDescriptor = NULL;
380 attr.SecurityQualityOfService = NULL;
381 RtlInitUnicodeString( &nameW, name );
382
383 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
384 }
385
386 /*****************************************************************************
387 * This section contains OpenDllList definitions
388 *
389 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
390 * other functions that do LoadLibrary _without_ giving back a HMODULE.
391 * Without this list these handles would never be freed.
392 *
393 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
394 * next unload-call but not before 600 sec.
395 */
396
397 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
398 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
399
400 typedef struct tagOpenDll
401 {
402 LONG refs;
403 LPWSTR library_name;
404 HANDLE library;
405 DllGetClassObjectFunc DllGetClassObject;
406 DllCanUnloadNowFunc DllCanUnloadNow;
407 struct list entry;
408 } OpenDll;
409
410 static struct list openDllList = LIST_INIT(openDllList);
411
412 static CRITICAL_SECTION csOpenDllList;
413 static CRITICAL_SECTION_DEBUG dll_cs_debug =
414 {
415 0, 0, &csOpenDllList,
416 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
417 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
418 };
419 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
420
421 struct apartment_loaded_dll
422 {
423 struct list entry;
424 OpenDll *dll;
425 DWORD unload_time;
426 BOOL multi_threaded;
427 };
428
429 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',' ',
430 '0','x','#','#','#','#','#','#','#','#',' ',0};
431
432 /*****************************************************************************
433 * This section contains OpenDllList implementation
434 */
435
436 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
437 {
438 OpenDll *ptr;
439 OpenDll *ret = NULL;
440 EnterCriticalSection(&csOpenDllList);
441 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
442 {
443 if (!strcmpiW(library_name, ptr->library_name) &&
444 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
445 {
446 ret = ptr;
447 break;
448 }
449 }
450 LeaveCriticalSection(&csOpenDllList);
451 return ret;
452 }
453
454 /* caller must ensure that library_name is not already in the open dll list */
455 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
456 {
457 OpenDll *entry;
458 int len;
459 HRESULT hr = S_OK;
460 HANDLE hLibrary;
461 DllCanUnloadNowFunc DllCanUnloadNow;
462 DllGetClassObjectFunc DllGetClassObject;
463
464 TRACE("%s\n", debugstr_w(library_name));
465
466 *ret = COMPOBJ_DllList_Get(library_name);
467 if (*ret) return S_OK;
468
469 /* do this outside the csOpenDllList to avoid creating a lock dependency on
470 * the loader lock */
471 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
472 if (!hLibrary)
473 {
474 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
475 /* failure: DLL could not be loaded */
476 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
477 }
478
479 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
480 /* Note: failing to find DllCanUnloadNow is not a failure */
481 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
482 if (!DllGetClassObject)
483 {
484 /* failure: the dll did not export DllGetClassObject */
485 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
486 FreeLibrary(hLibrary);
487 return CO_E_DLLNOTFOUND;
488 }
489
490 EnterCriticalSection( &csOpenDllList );
491
492 *ret = COMPOBJ_DllList_Get(library_name);
493 if (*ret)
494 {
495 /* another caller to this function already added the dll while we
496 * weren't in the critical section */
497 FreeLibrary(hLibrary);
498 }
499 else
500 {
501 len = strlenW(library_name);
502 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
503 if (entry)
504 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
505 if (entry && entry->library_name)
506 {
507 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
508 entry->library = hLibrary;
509 entry->refs = 1;
510 entry->DllCanUnloadNow = DllCanUnloadNow;
511 entry->DllGetClassObject = DllGetClassObject;
512 list_add_tail(&openDllList, &entry->entry);
513 *ret = entry;
514 }
515 else
516 {
517 HeapFree(GetProcessHeap(), 0, entry);
518 hr = E_OUTOFMEMORY;
519 FreeLibrary(hLibrary);
520 }
521 }
522
523 LeaveCriticalSection( &csOpenDllList );
524
525 return hr;
526 }
527
528 /* pass FALSE for free_entry to release a reference without destroying the
529 * entry if it reaches zero or TRUE otherwise */
530 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
531 {
532 if (!InterlockedDecrement(&entry->refs) && free_entry)
533 {
534 EnterCriticalSection(&csOpenDllList);
535 list_remove(&entry->entry);
536 LeaveCriticalSection(&csOpenDllList);
537
538 TRACE("freeing %p\n", entry->library);
539 FreeLibrary(entry->library);
540
541 HeapFree(GetProcessHeap(), 0, entry->library_name);
542 HeapFree(GetProcessHeap(), 0, entry);
543 }
544 }
545
546 /* frees memory associated with active dll list */
547 static void COMPOBJ_DllList_Free(void)
548 {
549 OpenDll *entry, *cursor2;
550 EnterCriticalSection(&csOpenDllList);
551 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
552 {
553 list_remove(&entry->entry);
554
555 HeapFree(GetProcessHeap(), 0, entry->library_name);
556 HeapFree(GetProcessHeap(), 0, entry);
557 }
558 LeaveCriticalSection(&csOpenDllList);
559 DeleteCriticalSection(&csOpenDllList);
560 }
561
562 /******************************************************************************
563 * Manage apartments.
564 */
565
566 static DWORD apartment_addref(struct apartment *apt)
567 {
568 DWORD refs = InterlockedIncrement(&apt->refs);
569 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
570 return refs;
571 }
572
573 /* allocates memory and fills in the necessary fields for a new apartment
574 * object. must be called inside apartment cs */
575 static APARTMENT *apartment_construct(DWORD model)
576 {
577 APARTMENT *apt;
578
579 TRACE("creating new apartment, model=%d\n", model);
580
581 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
582 apt->tid = GetCurrentThreadId();
583
584 list_init(&apt->proxies);
585 list_init(&apt->stubmgrs);
586 list_init(&apt->psclsids);
587 list_init(&apt->loaded_dlls);
588 apt->ipidc = 0;
589 apt->refs = 1;
590 apt->remunk_exported = FALSE;
591 apt->oidc = 1;
592 InitializeCriticalSection(&apt->cs);
593 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
594
595 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
596
597 if (apt->multi_threaded)
598 {
599 /* FIXME: should be randomly generated by in an RPC call to rpcss */
600 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
601 }
602 else
603 {
604 /* FIXME: should be randomly generated by in an RPC call to rpcss */
605 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
606 }
607
608 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
609
610 list_add_head(&apts, &apt->entry);
611
612 return apt;
613 }
614
615 /* gets and existing apartment if one exists or otherwise creates an apartment
616 * structure which stores OLE apartment-local information and stores a pointer
617 * to it in the thread-local storage */
618 static APARTMENT *apartment_get_or_create(DWORD model)
619 {
620 APARTMENT *apt = COM_CurrentApt();
621
622 if (!apt)
623 {
624 if (model & COINIT_APARTMENTTHREADED)
625 {
626 EnterCriticalSection(&csApartment);
627
628 apt = apartment_construct(model);
629 if (!MainApartment)
630 {
631 MainApartment = apt;
632 apt->main = TRUE;
633 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
634 }
635
636 LeaveCriticalSection(&csApartment);
637
638 if (apt->main)
639 apartment_createwindowifneeded(apt);
640 }
641 else
642 {
643 EnterCriticalSection(&csApartment);
644
645 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
646 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
647 * in a process */
648 if (MTA)
649 {
650 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
651 apartment_addref(MTA);
652 }
653 else
654 MTA = apartment_construct(model);
655
656 apt = MTA;
657
658 LeaveCriticalSection(&csApartment);
659 }
660 COM_CurrentInfo()->apt = apt;
661 }
662
663 return apt;
664 }
665
666 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
667 {
668 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
669 }
670
671 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
672 {
673 list_remove(&curClass->entry);
674
675 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
676 RPC_StopLocalServer(curClass->RpcRegistration);
677
678 IUnknown_Release(curClass->classObject);
679 HeapFree(GetProcessHeap(), 0, curClass);
680 }
681
682 static void COM_RevokeAllClasses(const struct apartment *apt)
683 {
684 RegisteredClass *curClass, *cursor;
685
686 EnterCriticalSection( &csRegisteredClassList );
687
688 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
689 {
690 if (curClass->apartment_id == apt->oxid)
691 COM_RevokeRegisteredClassObject(curClass);
692 }
693
694 LeaveCriticalSection( &csRegisteredClassList );
695 }
696
697 /******************************************************************************
698 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
699 */
700
701 typedef struct ManualResetEvent {
702 ISynchronize ISynchronize_iface;
703 ISynchronizeHandle ISynchronizeHandle_iface;
704 LONG ref;
705 HANDLE event;
706 } MREImpl;
707
708 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
709 {
710 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
711 }
712
713 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
714 {
715 MREImpl *This = impl_from_ISynchronize(iface);
716
717 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
718
719 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
720 *ppv = &This->ISynchronize_iface;
721 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
722 *ppv = &This->ISynchronizeHandle_iface;
723 }else {
724 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
725 *ppv = NULL;
726 return E_NOINTERFACE;
727 }
728
729 IUnknown_AddRef((IUnknown*)*ppv);
730 return S_OK;
731 }
732
733 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
734 {
735 MREImpl *This = impl_from_ISynchronize(iface);
736 LONG ref = InterlockedIncrement(&This->ref);
737 TRACE("%p - ref %d\n", This, ref);
738
739 return ref;
740 }
741
742 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
743 {
744 MREImpl *This = impl_from_ISynchronize(iface);
745 LONG ref = InterlockedDecrement(&This->ref);
746 TRACE("%p - ref %d\n", This, ref);
747
748 if(!ref)
749 {
750 CloseHandle(This->event);
751 HeapFree(GetProcessHeap(), 0, This);
752 }
753
754 return ref;
755 }
756
757 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
758 {
759 MREImpl *This = impl_from_ISynchronize(iface);
760 UINT index;
761 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
762 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
763 }
764
765 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
766 {
767 MREImpl *This = impl_from_ISynchronize(iface);
768 TRACE("%p\n", This);
769 SetEvent(This->event);
770 return S_OK;
771 }
772
773 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
774 {
775 MREImpl *This = impl_from_ISynchronize(iface);
776 TRACE("%p\n", This);
777 ResetEvent(This->event);
778 return S_OK;
779 }
780
781 static ISynchronizeVtbl vt_ISynchronize = {
782 ISynchronize_fnQueryInterface,
783 ISynchronize_fnAddRef,
784 ISynchronize_fnRelease,
785 ISynchronize_fnWait,
786 ISynchronize_fnSignal,
787 ISynchronize_fnReset
788 };
789
790 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
791 {
792 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
793 }
794
795 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
796 {
797 MREImpl *This = impl_from_ISynchronizeHandle(iface);
798 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
799 }
800
801 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
802 {
803 MREImpl *This = impl_from_ISynchronizeHandle(iface);
804 return ISynchronize_AddRef(&This->ISynchronize_iface);
805 }
806
807 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
808 {
809 MREImpl *This = impl_from_ISynchronizeHandle(iface);
810 return ISynchronize_Release(&This->ISynchronize_iface);
811 }
812
813 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
814 {
815 MREImpl *This = impl_from_ISynchronizeHandle(iface);
816
817 *ph = This->event;
818 return S_OK;
819 }
820
821 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
822 SynchronizeHandle_QueryInterface,
823 SynchronizeHandle_AddRef,
824 SynchronizeHandle_Release,
825 SynchronizeHandle_GetHandle
826 };
827
828 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
829 {
830 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
831 HRESULT hr;
832
833 if(punkouter)
834 FIXME("Aggregation not implemented.\n");
835
836 This->ref = 1;
837 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
838 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
839 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
840
841 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
842 ISynchronize_Release(&This->ISynchronize_iface);
843 return hr;
844 }
845
846 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
847 {
848 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
849 }
850
851 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
852 {
853 LocalServer *This = impl_from_IServiceProvider(iface);
854
855 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
856
857 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
858 *ppv = &This->IServiceProvider_iface;
859 }else {
860 *ppv = NULL;
861 return E_NOINTERFACE;
862 }
863
864 IUnknown_AddRef((IUnknown*)*ppv);
865 return S_OK;
866 }
867
868 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
869 {
870 LocalServer *This = impl_from_IServiceProvider(iface);
871 LONG ref = InterlockedIncrement(&This->ref);
872
873 TRACE("(%p) ref=%d\n", This, ref);
874
875 return ref;
876 }
877
878 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
879 {
880 LocalServer *This = impl_from_IServiceProvider(iface);
881 LONG ref = InterlockedDecrement(&This->ref);
882
883 TRACE("(%p) ref=%d\n", This, ref);
884
885 if(!ref) {
886 assert(!This->apt);
887 HeapFree(GetProcessHeap(), 0, This);
888 }
889
890 return ref;
891 }
892
893 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
894 {
895 LocalServer *This = impl_from_IServiceProvider(iface);
896 APARTMENT *apt = COM_CurrentApt();
897 RegisteredClass *iter;
898 HRESULT hres = E_FAIL;
899
900 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
901
902 if(!This->apt)
903 return E_UNEXPECTED;
904
905 EnterCriticalSection(&csRegisteredClassList);
906
907 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
908 if(iter->apartment_id == apt->oxid
909 && (iter->runContext & CLSCTX_LOCAL_SERVER)
910 && IsEqualGUID(&iter->classIdentifier, guid)) {
911 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
912 break;
913 }
914 }
915
916 LeaveCriticalSection( &csRegisteredClassList );
917
918 return hres;
919 }
920
921 static const IServiceProviderVtbl LocalServerVtbl = {
922 LocalServer_QueryInterface,
923 LocalServer_AddRef,
924 LocalServer_Release,
925 LocalServer_QueryService
926 };
927
928 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
929 {
930 HRESULT hres = S_OK;
931
932 EnterCriticalSection(&apt->cs);
933
934 if(!apt->local_server) {
935 LocalServer *obj;
936
937 obj = heap_alloc(sizeof(*obj));
938 if(obj) {
939 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
940 obj->ref = 1;
941 obj->apt = apt;
942
943 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
944 if(SUCCEEDED(hres)) {
945 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
946 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
947 if(FAILED(hres))
948 IStream_Release(obj->marshal_stream);
949 }
950
951 if(SUCCEEDED(hres))
952 apt->local_server = obj;
953 else
954 heap_free(obj);
955 }else {
956 hres = E_OUTOFMEMORY;
957 }
958 }
959
960 if(SUCCEEDED(hres))
961 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
962
963 LeaveCriticalSection(&apt->cs);
964
965 if(FAILED(hres))
966 ERR("Failed: %08x\n", hres);
967 return hres;
968 }
969
970 /***********************************************************************
971 * CoRevokeClassObject [OLE32.@]
972 *
973 * Removes a class object from the class registry.
974 *
975 * PARAMS
976 * dwRegister [I] Cookie returned from CoRegisterClassObject().
977 *
978 * RETURNS
979 * Success: S_OK.
980 * Failure: HRESULT code.
981 *
982 * NOTES
983 * Must be called from the same apartment that called CoRegisterClassObject(),
984 * otherwise it will fail with RPC_E_WRONG_THREAD.
985 *
986 * SEE ALSO
987 * CoRegisterClassObject
988 */
989 HRESULT WINAPI CoRevokeClassObject(
990 DWORD dwRegister)
991 {
992 HRESULT hr = E_INVALIDARG;
993 RegisteredClass *curClass;
994 APARTMENT *apt;
995
996 TRACE("(%08x)\n",dwRegister);
997
998 apt = COM_CurrentApt();
999 if (!apt)
1000 {
1001 ERR("COM was not initialized\n");
1002 return CO_E_NOTINITIALIZED;
1003 }
1004
1005 EnterCriticalSection( &csRegisteredClassList );
1006
1007 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1008 {
1009 /*
1010 * Check if we have a match on the cookie.
1011 */
1012 if (curClass->dwCookie == dwRegister)
1013 {
1014 if (curClass->apartment_id == apt->oxid)
1015 {
1016 COM_RevokeRegisteredClassObject(curClass);
1017 hr = S_OK;
1018 }
1019 else
1020 {
1021 ERR("called from wrong apartment, should be called from %s\n",
1022 wine_dbgstr_longlong(curClass->apartment_id));
1023 hr = RPC_E_WRONG_THREAD;
1024 }
1025 break;
1026 }
1027 }
1028
1029 LeaveCriticalSection( &csRegisteredClassList );
1030
1031 return hr;
1032 }
1033
1034 /* frees unused libraries loaded by apartment_getclassobject by calling the
1035 * DLL's DllCanUnloadNow entry point */
1036 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1037 {
1038 struct apartment_loaded_dll *entry, *next;
1039 EnterCriticalSection(&apt->cs);
1040 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1041 {
1042 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1043 {
1044 DWORD real_delay = delay;
1045
1046 if (real_delay == INFINITE)
1047 {
1048 /* DLLs that return multi-threaded objects aren't unloaded
1049 * straight away to cope for programs that have races between
1050 * last object destruction and threads in the DLLs that haven't
1051 * finished, despite DllCanUnloadNow returning S_OK */
1052 if (entry->multi_threaded)
1053 real_delay = 10 * 60 * 1000; /* 10 minutes */
1054 else
1055 real_delay = 0;
1056 }
1057
1058 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1059 {
1060 list_remove(&entry->entry);
1061 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1062 HeapFree(GetProcessHeap(), 0, entry);
1063 }
1064 else
1065 {
1066 entry->unload_time = GetTickCount() + real_delay;
1067 if (!entry->unload_time) entry->unload_time = 1;
1068 }
1069 }
1070 else if (entry->unload_time)
1071 entry->unload_time = 0;
1072 }
1073 LeaveCriticalSection(&apt->cs);
1074 }
1075
1076 DWORD apartment_release(struct apartment *apt)
1077 {
1078 DWORD ret;
1079
1080 EnterCriticalSection(&csApartment);
1081
1082 ret = InterlockedDecrement(&apt->refs);
1083 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1084 /* destruction stuff that needs to happen under csApartment CS */
1085 if (ret == 0)
1086 {
1087 if (apt == MTA) MTA = NULL;
1088 else if (apt == MainApartment) MainApartment = NULL;
1089 list_remove(&apt->entry);
1090 }
1091
1092 LeaveCriticalSection(&csApartment);
1093
1094 if (ret == 0)
1095 {
1096 struct list *cursor, *cursor2;
1097
1098 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1099
1100 if(apt->local_server) {
1101 LocalServer *local_server = apt->local_server;
1102 LARGE_INTEGER zero;
1103
1104 memset(&zero, 0, sizeof(zero));
1105 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1106 CoReleaseMarshalData(local_server->marshal_stream);
1107 IStream_Release(local_server->marshal_stream);
1108 local_server->marshal_stream = NULL;
1109
1110 apt->local_server = NULL;
1111 local_server->apt = NULL;
1112 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1113 }
1114
1115 /* Release the references to the registered class objects */
1116 COM_RevokeAllClasses(apt);
1117
1118 /* no locking is needed for this apartment, because no other thread
1119 * can access it at this point */
1120
1121 apartment_disconnectproxies(apt);
1122
1123 if (apt->win) DestroyWindow(apt->win);
1124 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1125
1126 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1127 {
1128 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1129 /* release the implicit reference given by the fact that the
1130 * stub has external references (it must do since it is in the
1131 * stub manager list in the apartment and all non-apartment users
1132 * must have a ref on the apartment and so it cannot be destroyed).
1133 */
1134 stub_manager_int_release(stubmgr);
1135 }
1136
1137 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
1138 {
1139 struct registered_psclsid *registered_psclsid =
1140 LIST_ENTRY(cursor, struct registered_psclsid, entry);
1141
1142 list_remove(&registered_psclsid->entry);
1143 HeapFree(GetProcessHeap(), 0, registered_psclsid);
1144 }
1145
1146 /* if this assert fires, then another thread took a reference to a
1147 * stub manager without taking a reference to the containing
1148 * apartment, which it must do. */
1149 assert(list_empty(&apt->stubmgrs));
1150
1151 if (apt->filter) IMessageFilter_Release(apt->filter);
1152
1153 /* free as many unused libraries as possible... */
1154 apartment_freeunusedlibraries(apt, 0);
1155
1156 /* ... and free the memory for the apartment loaded dll entry and
1157 * release the dll list reference without freeing the library for the
1158 * rest */
1159 while ((cursor = list_head(&apt->loaded_dlls)))
1160 {
1161 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1162 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1163 list_remove(cursor);
1164 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1165 }
1166
1167 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1168 DeleteCriticalSection(&apt->cs);
1169
1170 HeapFree(GetProcessHeap(), 0, apt);
1171 }
1172
1173 return ret;
1174 }
1175
1176 /* The given OXID must be local to this process:
1177 *
1178 * The ref parameter is here mostly to ensure people remember that
1179 * they get one, you should normally take a ref for thread safety.
1180 */
1181 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1182 {
1183 APARTMENT *result = NULL;
1184 struct list *cursor;
1185
1186 EnterCriticalSection(&csApartment);
1187 LIST_FOR_EACH( cursor, &apts )
1188 {
1189 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1190 if (apt->oxid == oxid)
1191 {
1192 result = apt;
1193 if (ref) apartment_addref(result);
1194 break;
1195 }
1196 }
1197 LeaveCriticalSection(&csApartment);
1198
1199 return result;
1200 }
1201
1202 /* gets the apartment which has a given creator thread ID. The caller must
1203 * release the reference from the apartment as soon as the apartment pointer
1204 * is no longer required. */
1205 APARTMENT *apartment_findfromtid(DWORD tid)
1206 {
1207 APARTMENT *result = NULL;
1208 struct list *cursor;
1209
1210 EnterCriticalSection(&csApartment);
1211 LIST_FOR_EACH( cursor, &apts )
1212 {
1213 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1214 if (apt->tid == tid)
1215 {
1216 result = apt;
1217 apartment_addref(result);
1218 break;
1219 }
1220 }
1221 LeaveCriticalSection(&csApartment);
1222
1223 return result;
1224 }
1225
1226 /* gets the main apartment if it exists. The caller must
1227 * release the reference from the apartment as soon as the apartment pointer
1228 * is no longer required. */
1229 static APARTMENT *apartment_findmain(void)
1230 {
1231 APARTMENT *result;
1232
1233 EnterCriticalSection(&csApartment);
1234
1235 result = MainApartment;
1236 if (result) apartment_addref(result);
1237
1238 LeaveCriticalSection(&csApartment);
1239
1240 return result;
1241 }
1242
1243 /* gets the multi-threaded apartment if it exists. The caller must
1244 * release the reference from the apartment as soon as the apartment pointer
1245 * is no longer required. */
1246 static APARTMENT *apartment_find_multi_threaded(void)
1247 {
1248 APARTMENT *result = NULL;
1249 struct list *cursor;
1250
1251 EnterCriticalSection(&csApartment);
1252
1253 LIST_FOR_EACH( cursor, &apts )
1254 {
1255 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1256 if (apt->multi_threaded)
1257 {
1258 result = apt;
1259 apartment_addref(result);
1260 break;
1261 }
1262 }
1263
1264 LeaveCriticalSection(&csApartment);
1265 return result;
1266 }
1267
1268 /* gets the specified class object by loading the appropriate DLL, if
1269 * necessary and calls the DllGetClassObject function for the DLL */
1270 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1271 BOOL apartment_threaded,
1272 REFCLSID rclsid, REFIID riid, void **ppv)
1273 {
1274 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1275 HRESULT hr = S_OK;
1276 BOOL found = FALSE;
1277 struct apartment_loaded_dll *apartment_loaded_dll;
1278
1279 if (!strcmpiW(dllpath, wszOle32))
1280 {
1281 /* we don't need to control the lifetime of this dll, so use the local
1282 * implementation of DllGetClassObject directly */
1283 TRACE("calling ole32!DllGetClassObject\n");
1284 hr = DllGetClassObject(rclsid, riid, ppv);
1285
1286 if (hr != S_OK)
1287 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1288
1289 return hr;
1290 }
1291
1292 EnterCriticalSection(&apt->cs);
1293
1294 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1295 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1296 {
1297 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1298 found = TRUE;
1299 break;
1300 }
1301
1302 if (!found)
1303 {
1304 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1305 if (!apartment_loaded_dll)
1306 hr = E_OUTOFMEMORY;
1307 if (SUCCEEDED(hr))
1308 {
1309 apartment_loaded_dll->unload_time = 0;
1310 apartment_loaded_dll->multi_threaded = FALSE;
1311 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1312 if (FAILED(hr))
1313 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1314 }
1315 if (SUCCEEDED(hr))
1316 {
1317 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1318 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1319 }
1320 }
1321
1322 LeaveCriticalSection(&apt->cs);
1323
1324 if (SUCCEEDED(hr))
1325 {
1326 /* one component being multi-threaded overrides any number of
1327 * apartment-threaded components */
1328 if (!apartment_threaded)
1329 apartment_loaded_dll->multi_threaded = TRUE;
1330
1331 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1332 /* OK: get the ClassObject */
1333 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1334
1335 if (hr != S_OK)
1336 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1337 }
1338
1339 return hr;
1340 }
1341
1342 /***********************************************************************
1343 * COM_RegReadPath [internal]
1344 *
1345 * Reads a registry value and expands it when necessary
1346 */
1347 static DWORD COM_RegReadPath(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1348 {
1349 DWORD ret;
1350
1351 if (regdata->hkey)
1352 {
1353 DWORD keytype;
1354 WCHAR src[MAX_PATH];
1355 DWORD dwLength = dstlen * sizeof(WCHAR);
1356
1357 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1358 if (keytype == REG_EXPAND_SZ) {
1359 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1360 } else {
1361 const WCHAR *quote_start;
1362 quote_start = strchrW(src, '\"');
1363 if (quote_start) {
1364 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1365 if (quote_end) {
1366 memmove(src, quote_start + 1,
1367 (quote_end - quote_start - 1) * sizeof(WCHAR));
1368 src[quote_end - quote_start - 1] = '\0';
1369 }
1370 }
1371 lstrcpynW(dst, src, dstlen);
1372 }
1373 }
1374 return ret;
1375 }
1376 else
1377 {
1378 ULONG_PTR cookie;
1379 WCHAR *nameW;
1380
1381 *dst = 0;
1382 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1383 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1384 ret = SearchPathW(NULL, nameW, NULL, dstlen, dst, NULL);
1385 DeactivateActCtx(0, cookie);
1386 return !*dst;
1387 }
1388 }
1389
1390 struct host_object_params
1391 {
1392 struct class_reg_data regdata;
1393 CLSID clsid; /* clsid of object to marshal */
1394 IID iid; /* interface to marshal */
1395 HANDLE event; /* event signalling when ready for multi-threaded case */
1396 HRESULT hr; /* result for multi-threaded case */
1397 IStream *stream; /* stream that the object will be marshaled into */
1398 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1399 };
1400
1401 static HRESULT apartment_hostobject(struct apartment *apt,
1402 const struct host_object_params *params)
1403 {
1404 IUnknown *object;
1405 HRESULT hr;
1406 static const LARGE_INTEGER llZero;
1407 WCHAR dllpath[MAX_PATH+1];
1408
1409 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1410
1411 if (COM_RegReadPath(&params->regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1412 {
1413 /* failure: CLSID is not found in registry */
1414 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1415 return REGDB_E_CLASSNOTREG;
1416 }
1417
1418 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1419 &params->clsid, &params->iid, (void **)&object);
1420 if (FAILED(hr))
1421 return hr;
1422
1423 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1424 if (FAILED(hr))
1425 IUnknown_Release(object);
1426 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1427
1428 return hr;
1429 }
1430
1431 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1432 {
1433 switch (msg)
1434 {
1435 case DM_EXECUTERPC:
1436 RPC_ExecuteCall((struct dispatch_params *)lParam);
1437 return 0;
1438 case DM_HOSTOBJECT:
1439 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1440 default:
1441 return DefWindowProcW(hWnd, msg, wParam, lParam);
1442 }
1443 }
1444
1445 struct host_thread_params
1446 {
1447 COINIT threading_model;
1448 HANDLE ready_event;
1449 HWND apartment_hwnd;
1450 };
1451
1452 /* thread for hosting an object to allow an object to appear to be created in
1453 * an apartment with an incompatible threading model */
1454 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1455 {
1456 struct host_thread_params *params = p;
1457 MSG msg;
1458 HRESULT hr;
1459 struct apartment *apt;
1460
1461 TRACE("\n");
1462
1463 hr = CoInitializeEx(NULL, params->threading_model);
1464 if (FAILED(hr)) return hr;
1465
1466 apt = COM_CurrentApt();
1467 if (params->threading_model == COINIT_APARTMENTTHREADED)
1468 {
1469 apartment_createwindowifneeded(apt);
1470 params->apartment_hwnd = apartment_getwindow(apt);
1471 }
1472 else
1473 params->apartment_hwnd = NULL;
1474
1475 /* force the message queue to be created before signaling parent thread */
1476 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1477
1478 SetEvent(params->ready_event);
1479 params = NULL; /* can't touch params after here as it may be invalid */
1480
1481 while (GetMessageW(&msg, NULL, 0, 0))
1482 {
1483 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1484 {
1485 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1486 obj_params->hr = apartment_hostobject(apt, obj_params);
1487 SetEvent(obj_params->event);
1488 }
1489 else
1490 {
1491 TranslateMessage(&msg);
1492 DispatchMessageW(&msg);
1493 }
1494 }
1495
1496 TRACE("exiting\n");
1497
1498 CoUninitialize();
1499
1500 return S_OK;
1501 }
1502
1503 /* finds or creates a host apartment, creates the object inside it and returns
1504 * a proxy to it so that the object can be used in the apartment of the
1505 * caller of this function */
1506 static HRESULT apartment_hostobject_in_hostapt(
1507 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1508 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1509 {
1510 struct host_object_params params;
1511 HWND apartment_hwnd = NULL;
1512 DWORD apartment_tid = 0;
1513 HRESULT hr;
1514
1515 if (!multi_threaded && main_apartment)
1516 {
1517 APARTMENT *host_apt = apartment_findmain();
1518 if (host_apt)
1519 {
1520 apartment_hwnd = apartment_getwindow(host_apt);
1521 apartment_release(host_apt);
1522 }
1523 }
1524
1525 if (!apartment_hwnd)
1526 {
1527 EnterCriticalSection(&apt->cs);
1528
1529 if (!apt->host_apt_tid)
1530 {
1531 struct host_thread_params thread_params;
1532 HANDLE handles[2];
1533 DWORD wait_value;
1534
1535 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1536 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1537 thread_params.apartment_hwnd = NULL;
1538 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1539 if (!handles[1])
1540 {
1541 CloseHandle(handles[0]);
1542 LeaveCriticalSection(&apt->cs);
1543 return E_OUTOFMEMORY;
1544 }
1545 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1546 CloseHandle(handles[0]);
1547 CloseHandle(handles[1]);
1548 if (wait_value == WAIT_OBJECT_0)
1549 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1550 else
1551 {
1552 LeaveCriticalSection(&apt->cs);
1553 return E_OUTOFMEMORY;
1554 }
1555 }
1556
1557 if (multi_threaded || !main_apartment)
1558 {
1559 apartment_hwnd = apt->host_apt_hwnd;
1560 apartment_tid = apt->host_apt_tid;
1561 }
1562
1563 LeaveCriticalSection(&apt->cs);
1564 }
1565
1566 /* another thread may have become the main apartment in the time it took
1567 * us to create the thread for the host apartment */
1568 if (!apartment_hwnd && !multi_threaded && main_apartment)
1569 {
1570 APARTMENT *host_apt = apartment_findmain();
1571 if (host_apt)
1572 {
1573 apartment_hwnd = apartment_getwindow(host_apt);
1574 apartment_release(host_apt);
1575 }
1576 }
1577
1578 params.regdata = *regdata;
1579 params.clsid = *rclsid;
1580 params.iid = *riid;
1581 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1582 if (FAILED(hr))
1583 return hr;
1584 params.apartment_threaded = !multi_threaded;
1585 if (multi_threaded)
1586 {
1587 params.hr = S_OK;
1588 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1589 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1590 hr = E_OUTOFMEMORY;
1591 else
1592 {
1593 WaitForSingleObject(params.event, INFINITE);
1594 hr = params.hr;
1595 }
1596 CloseHandle(params.event);
1597 }
1598 else
1599 {
1600 if (!apartment_hwnd)
1601 {
1602 ERR("host apartment didn't create window\n");
1603 hr = E_OUTOFMEMORY;
1604 }
1605 else
1606 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1607 }
1608 if (SUCCEEDED(hr))
1609 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1610 IStream_Release(params.stream);
1611 return hr;
1612 }
1613
1614 #ifndef __REACTOS__
1615 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1616 {
1617 WNDCLASSW wclass;
1618
1619 /* Dispatching to the correct thread in an apartment is done through
1620 * window messages rather than RPC transports. When an interface is
1621 * marshalled into another apartment in the same process, a window of the
1622 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1623 * application) is responsible for pumping the message loop in that thread.
1624 * The WM_USER messages which point to the RPCs are then dispatched to
1625 * apartment_wndproc by the user's code from the apartment in which the
1626 * interface was unmarshalled.
1627 */
1628 memset(&wclass, 0, sizeof(wclass));
1629 wclass.lpfnWndProc = apartment_wndproc;
1630 wclass.hInstance = hProxyDll;
1631 wclass.lpszClassName = wszAptWinClass;
1632 RegisterClassW(&wclass);
1633 return TRUE;
1634 }
1635 #endif
1636
1637 /* create a window for the apartment or return the current one if one has
1638 * already been created */
1639 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1640 {
1641 if (apt->multi_threaded)
1642 return S_OK;
1643
1644 if (!apt->win)
1645 {
1646 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1647 0, 0, 0, 0,
1648 HWND_MESSAGE, 0, hProxyDll, NULL);
1649 if (!hwnd)
1650 {
1651 ERR("CreateWindow failed with error %d\n", GetLastError());
1652 return HRESULT_FROM_WIN32(GetLastError());
1653 }
1654 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1655 /* someone beat us to it */
1656 DestroyWindow(hwnd);
1657 }
1658
1659 return S_OK;
1660 }
1661
1662 /* retrieves the window for the main- or apartment-threaded apartment */
1663 HWND apartment_getwindow(const struct apartment *apt)
1664 {
1665 assert(!apt->multi_threaded);
1666 return apt->win;
1667 }
1668
1669 void apartment_joinmta(void)
1670 {
1671 apartment_addref(MTA);
1672 COM_CurrentInfo()->apt = MTA;
1673 }
1674
1675 #ifdef __REACTOS__
1676
1677 static void COMPOBJ_InitProcess( void )
1678 {
1679 WNDCLASSW wclass;
1680
1681 /* Dispatching to the correct thread in an apartment is done through
1682 * window messages rather than RPC transports. When an interface is
1683 * marshalled into another apartment in the same process, a window of the
1684 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1685 * application) is responsible for pumping the message loop in that thread.
1686 * The WM_USER messages which point to the RPCs are then dispatched to
1687 * apartment_wndproc by the user's code from the apartment in which the
1688 * interface was unmarshalled.
1689 */
1690 memset(&wclass, 0, sizeof(wclass));
1691 wclass.lpfnWndProc = apartment_wndproc;
1692 wclass.hInstance = hProxyDll;
1693 wclass.lpszClassName = wszAptWinClass;
1694 RegisterClassW(&wclass);
1695 }
1696
1697 static void COMPOBJ_UninitProcess( void )
1698 {
1699 UnregisterClassW(wszAptWinClass, hProxyDll);
1700 }
1701
1702 #endif
1703
1704 static void COM_TlsDestroy(void)
1705 {
1706 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1707 if (info)
1708 {
1709 if (info->apt) apartment_release(info->apt);
1710 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1711 if (info->state) IUnknown_Release(info->state);
1712 if (info->spy) IInitializeSpy_Release(info->spy);
1713 if (info->context_token) IObjContext_Release(info->context_token);
1714 HeapFree(GetProcessHeap(), 0, info);
1715 NtCurrentTeb()->ReservedForOle = NULL;
1716 }
1717 }
1718
1719 /******************************************************************************
1720 * CoBuildVersion [OLE32.@]
1721 *
1722 * Gets the build version of the DLL.
1723 *
1724 * PARAMS
1725 *
1726 * RETURNS
1727 * Current build version, hiword is majornumber, loword is minornumber
1728 */
1729 DWORD WINAPI CoBuildVersion(void)
1730 {
1731 TRACE("Returning version %d, build %d.\n", rmm, rup);
1732 return (rmm<<16)+rup;
1733 }
1734
1735 /******************************************************************************
1736 * CoRegisterInitializeSpy [OLE32.@]
1737 *
1738 * Add a Spy that watches CoInitializeEx calls
1739 *
1740 * PARAMS
1741 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1742 * cookie [II] cookie receiver
1743 *
1744 * RETURNS
1745 * Success: S_OK if not already initialized, S_FALSE otherwise.
1746 * Failure: HRESULT code.
1747 *
1748 * SEE ALSO
1749 * CoInitializeEx
1750 */
1751 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1752 {
1753 struct oletls *info = COM_CurrentInfo();
1754 HRESULT hr;
1755
1756 TRACE("(%p, %p)\n", spy, cookie);
1757
1758 if (!spy || !cookie || !info)
1759 {
1760 if (!info)
1761 WARN("Could not allocate tls\n");
1762 return E_INVALIDARG;
1763 }
1764
1765 if (info->spy)
1766 {
1767 FIXME("Already registered?\n");
1768 return E_UNEXPECTED;
1769 }
1770
1771 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1772 if (SUCCEEDED(hr))
1773 {
1774 cookie->QuadPart = (DWORD_PTR)spy;
1775 return S_OK;
1776 }
1777 return hr;
1778 }
1779
1780 /******************************************************************************
1781 * CoRevokeInitializeSpy [OLE32.@]
1782 *
1783 * Remove a spy that previously watched CoInitializeEx calls
1784 *
1785 * PARAMS
1786 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1787 *
1788 * RETURNS
1789 * Success: S_OK if a spy is removed
1790 * Failure: E_INVALIDARG
1791 *
1792 * SEE ALSO
1793 * CoInitializeEx
1794 */
1795 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1796 {
1797 struct oletls *info = COM_CurrentInfo();
1798 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1799
1800 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1801 return E_INVALIDARG;
1802
1803 IInitializeSpy_Release(info->spy);
1804 info->spy = NULL;
1805 return S_OK;
1806 }
1807
1808
1809 /******************************************************************************
1810 * CoInitialize [OLE32.@]
1811 *
1812 * Initializes the COM libraries by calling CoInitializeEx with
1813 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1814 *
1815 * PARAMS
1816 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1817 *
1818 * RETURNS
1819 * Success: S_OK if not already initialized, S_FALSE otherwise.
1820 * Failure: HRESULT code.
1821 *
1822 * SEE ALSO
1823 * CoInitializeEx
1824 */
1825 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1826 {
1827 /*
1828 * Just delegate to the newer method.
1829 */
1830 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1831 }
1832
1833 /******************************************************************************
1834 * CoInitializeEx [OLE32.@]
1835 *
1836 * Initializes the COM libraries.
1837 *
1838 * PARAMS
1839 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1840 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1841 *
1842 * RETURNS
1843 * S_OK if successful,
1844 * S_FALSE if this function was called already.
1845 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1846 * threading model.
1847 *
1848 * NOTES
1849 *
1850 * The behavior used to set the IMalloc used for memory management is
1851 * obsolete.
1852 * The dwCoInit parameter must specify one of the following apartment
1853 * threading models:
1854 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1855 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1856 * The parameter may also specify zero or more of the following flags:
1857 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1858 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1859 *
1860 * SEE ALSO
1861 * CoUninitialize
1862 */
1863 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1864 {
1865 struct oletls *info = COM_CurrentInfo();
1866 HRESULT hr = S_OK;
1867 APARTMENT *apt;
1868
1869 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1870
1871 if (lpReserved!=NULL)
1872 {
1873 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1874 }
1875
1876 /*
1877 * Check the lock count. If this is the first time going through the initialize
1878 * process, we have to initialize the libraries.
1879 *
1880 * And crank-up that lock count.
1881 */
1882 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1883 {
1884 /*
1885 * Initialize the various COM libraries and data structures.
1886 */
1887 TRACE("() - Initializing the COM libraries\n");
1888
1889 /* we may need to defer this until after apartment initialisation */
1890 RunningObjectTableImpl_Initialize();
1891 }
1892
1893 if (info->spy)
1894 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1895
1896 if (!(apt = info->apt))
1897 {
1898 apt = apartment_get_or_create(dwCoInit);
1899 if (!apt) return E_OUTOFMEMORY;
1900 }
1901 else if (!apartment_is_model(apt, dwCoInit))
1902 {
1903 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1904 code then we are probably using the wrong threading model to implement that API. */
1905 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1906 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1907 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1908 return RPC_E_CHANGED_MODE;
1909 }
1910 else
1911 hr = S_FALSE;
1912
1913 info->inits++;
1914
1915 if (info->spy)
1916 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1917
1918 return hr;
1919 }
1920
1921 /***********************************************************************
1922 * CoUninitialize [OLE32.@]
1923 *
1924 * This method will decrement the refcount on the current apartment, freeing
1925 * the resources associated with it if it is the last thread in the apartment.
1926 * If the last apartment is freed, the function will additionally release
1927 * any COM resources associated with the process.
1928 *
1929 * PARAMS
1930 *
1931 * RETURNS
1932 * Nothing.
1933 *
1934 * SEE ALSO
1935 * CoInitializeEx
1936 */
1937 void WINAPI CoUninitialize(void)
1938 {
1939 struct oletls * info = COM_CurrentInfo();
1940 LONG lCOMRefCnt;
1941
1942 TRACE("()\n");
1943
1944 /* will only happen on OOM */
1945 if (!info) return;
1946
1947 if (info->spy)
1948 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1949
1950 /* sanity check */
1951 if (!info->inits)
1952 {
1953 ERR("Mismatched CoUninitialize\n");
1954
1955 if (info->spy)
1956 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1957 return;
1958 }
1959
1960 if (!--info->inits)
1961 {
1962 apartment_release(info->apt);
1963 info->apt = NULL;
1964 }
1965
1966 /*
1967 * Decrease the reference count.
1968 * If we are back to 0 locks on the COM library, make sure we free
1969 * all the associated data structures.
1970 */
1971 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1972 if (lCOMRefCnt==1)
1973 {
1974 TRACE("() - Releasing the COM libraries\n");
1975
1976 RunningObjectTableImpl_UnInitialize();
1977 }
1978 else if (lCOMRefCnt<1) {
1979 ERR( "CoUninitialize() - not CoInitialized.\n" );
1980 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1981 }
1982 if (info->spy)
1983 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1984 }
1985
1986 /******************************************************************************
1987 * CoDisconnectObject [OLE32.@]
1988 *
1989 * Disconnects all connections to this object from remote processes. Dispatches
1990 * pending RPCs while blocking new RPCs from occurring, and then calls
1991 * IMarshal::DisconnectObject on the given object.
1992 *
1993 * Typically called when the object server is forced to shut down, for instance by
1994 * the user.
1995 *
1996 * PARAMS
1997 * lpUnk [I] The object whose stub should be disconnected.
1998 * reserved [I] Reserved. Should be set to 0.
1999 *
2000 * RETURNS
2001 * Success: S_OK.
2002 * Failure: HRESULT code.
2003 *
2004 * SEE ALSO
2005 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2006 */
2007 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2008 {
2009 HRESULT hr;
2010 IMarshal *marshal;
2011 APARTMENT *apt;
2012
2013 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2014
2015 if (!lpUnk) return E_INVALIDARG;
2016
2017 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2018 if (hr == S_OK)
2019 {
2020 hr = IMarshal_DisconnectObject(marshal, reserved);
2021 IMarshal_Release(marshal);
2022 return hr;
2023 }
2024
2025 apt = COM_CurrentApt();
2026 if (!apt)
2027 return CO_E_NOTINITIALIZED;
2028
2029 apartment_disconnectobject(apt, lpUnk);
2030
2031 /* Note: native is pretty broken here because it just silently
2032 * fails, without returning an appropriate error code if the object was
2033 * not found, making apps think that the object was disconnected, when
2034 * it actually wasn't */
2035
2036 return S_OK;
2037 }
2038
2039 /******************************************************************************
2040 * CoCreateGuid [OLE32.@]
2041 *
2042 * Simply forwards to UuidCreate in RPCRT4.
2043 *
2044 * PARAMS
2045 * pguid [O] Points to the GUID to initialize.
2046 *
2047 * RETURNS
2048 * Success: S_OK.
2049 * Failure: HRESULT code.
2050 *
2051 * SEE ALSO
2052 * UuidCreate
2053 */
2054 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2055 {
2056 DWORD status = UuidCreate(pguid);
2057 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2058 return HRESULT_FROM_WIN32( status );
2059 }
2060
2061 static inline BOOL is_valid_hex(WCHAR c)
2062 {
2063 if (!(((c >= '0') && (c <= '9')) ||
2064 ((c >= 'a') && (c <= 'f')) ||
2065 ((c >= 'A') && (c <= 'F'))))
2066 return FALSE;
2067 return TRUE;
2068 }
2069
2070 static const BYTE guid_conv_table[256] =
2071 {
2072 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2073 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2074 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2075 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2076 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2077 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2078 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2079 };
2080
2081 /* conversion helper for CLSIDFromString/IIDFromString */
2082 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2083 {
2084 int i;
2085
2086 if (!s || s[0]!='{') {
2087 memset( id, 0, sizeof (CLSID) );
2088 if(!s) return TRUE;
2089 return FALSE;
2090 }
2091
2092 TRACE("%s -> %p\n", debugstr_w(s), id);
2093
2094 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2095
2096 id->Data1 = 0;
2097 for (i = 1; i < 9; i++) {
2098 if (!is_valid_hex(s[i])) return FALSE;
2099 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2100 }
2101 if (s[9]!='-') return FALSE;
2102
2103 id->Data2 = 0;
2104 for (i = 10; i < 14; i++) {
2105 if (!is_valid_hex(s[i])) return FALSE;
2106 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2107 }
2108 if (s[14]!='-') return FALSE;
2109
2110 id->Data3 = 0;
2111 for (i = 15; i < 19; i++) {
2112 if (!is_valid_hex(s[i])) return FALSE;
2113 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2114 }
2115 if (s[19]!='-') return FALSE;
2116
2117 for (i = 20; i < 37; i+=2) {
2118 if (i == 24) {
2119 if (s[i]!='-') return FALSE;
2120 i++;
2121 }
2122 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2123 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2124 }
2125
2126 if (s[37] == '}' && s[38] == '\0')
2127 return TRUE;
2128
2129 return FALSE;
2130 }
2131
2132 /*****************************************************************************/
2133
2134 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2135 {
2136 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2137 WCHAR buf2[CHARS_IN_GUID];
2138 LONG buf2len = sizeof(buf2);
2139 HKEY xhkey;
2140 WCHAR *buf;
2141
2142 memset(clsid, 0, sizeof(*clsid));
2143 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2144 if (!buf) return E_OUTOFMEMORY;
2145 strcpyW( buf, progid );
2146 strcatW( buf, clsidW );
2147 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2148 {
2149 HeapFree(GetProcessHeap(),0,buf);
2150 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2151 return CO_E_CLASSSTRING;
2152 }
2153 HeapFree(GetProcessHeap(),0,buf);
2154
2155 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2156 {
2157 RegCloseKey(xhkey);
2158 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2159 return CO_E_CLASSSTRING;
2160 }
2161 RegCloseKey(xhkey);
2162 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2163 }
2164
2165 /******************************************************************************
2166 * CLSIDFromString [OLE32.@]
2167 *
2168 * Converts a unique identifier from its string representation into
2169 * the GUID struct.
2170 *
2171 * PARAMS
2172 * idstr [I] The string representation of the GUID.
2173 * id [O] GUID converted from the string.
2174 *
2175 * RETURNS
2176 * S_OK on success
2177 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2178 *
2179 * SEE ALSO
2180 * StringFromCLSID
2181 */
2182 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2183 {
2184 HRESULT ret = CO_E_CLASSSTRING;
2185 CLSID tmp_id;
2186
2187 if (!id)
2188 return E_INVALIDARG;
2189
2190 if (guid_from_string(idstr, id))
2191 return S_OK;
2192
2193 /* It appears a ProgID is also valid */
2194 ret = clsid_from_string_reg(idstr, &tmp_id);
2195 if(SUCCEEDED(ret))
2196 *id = tmp_id;
2197
2198 return ret;
2199 }
2200
2201 /******************************************************************************
2202 * IIDFromString [OLE32.@]
2203 *
2204 * Converts a interface identifier from its string representation into
2205 * the IID struct.
2206 *
2207 * PARAMS
2208 * idstr [I] The string representation of the GUID.
2209 * id [O] IID converted from the string.
2210 *
2211 * RETURNS
2212 * S_OK on success
2213 * CO_E_IIDSTRING if idstr is not a valid IID
2214 *
2215 * SEE ALSO
2216 * StringFromIID
2217 */
2218 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2219 {
2220 TRACE("%s -> %p\n", debugstr_w(s), iid);
2221
2222 if (!s)
2223 {
2224 memset(iid, 0, sizeof(*iid));
2225 return S_OK;
2226 }
2227
2228 /* length mismatch is a special case */
2229 if (strlenW(s) + 1 != CHARS_IN_GUID)
2230 return E_INVALIDARG;
2231
2232 if (s[0] != '{')
2233 return CO_E_IIDSTRING;
2234
2235 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2236 }
2237
2238 /******************************************************************************
2239 * StringFromCLSID [OLE32.@]
2240 * StringFromIID [OLE32.@]
2241 *
2242 * Converts a GUID into the respective string representation.
2243 * The target string is allocated using the OLE IMalloc.
2244 *
2245 * PARAMS
2246 * id [I] the GUID to be converted.
2247 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2248 *
2249 * RETURNS
2250 * S_OK
2251 * E_FAIL
2252 *
2253 * SEE ALSO
2254 * StringFromGUID2, CLSIDFromString
2255 */
2256 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2257 {
2258 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2259 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2260 return S_OK;
2261 }
2262
2263 /******************************************************************************
2264 * StringFromGUID2 [OLE32.@]
2265 *
2266 * Modified version of StringFromCLSID that allows you to specify max
2267 * buffer size.
2268 *
2269 * PARAMS
2270 * id [I] GUID to convert to string.
2271 * str [O] Buffer where the result will be stored.
2272 * cmax [I] Size of the buffer in characters.
2273 *
2274 * RETURNS
2275 * Success: The length of the resulting string in characters.
2276 * Failure: 0.
2277 */
2278 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2279 {
2280 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2281 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2282 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2283 '%','0','2','X','%','0','2','X','}',0 };
2284 if (!id || cmax < CHARS_IN_GUID) return 0;
2285 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2286 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2287 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2288 return CHARS_IN_GUID;
2289 }
2290
2291 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2292 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2293 {
2294 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2295 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2296 LONG res;
2297 HKEY key;
2298
2299 strcpyW(path, wszCLSIDSlash);
2300 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2301 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2302 if (res == ERROR_FILE_NOT_FOUND)
2303 return REGDB_E_CLASSNOTREG;
2304 else if (res != ERROR_SUCCESS)
2305 return REGDB_E_READREGDB;
2306
2307 if (!keyname)
2308 {
2309 *subkey = key;
2310 return S_OK;
2311 }
2312
2313 res = open_classes_key(key, keyname, access, subkey);
2314 RegCloseKey(key);
2315 if (res == ERROR_FILE_NOT_FOUND)
2316 return REGDB_E_KEYMISSING;
2317 else if (res != ERROR_SUCCESS)
2318 return REGDB_E_READREGDB;
2319
2320 return S_OK;
2321 }
2322
2323 /* open HKCR\\AppId\\{string form of appid clsid} key */
2324 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2325 {
2326 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2327 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2328 DWORD res;
2329 WCHAR buf[CHARS_IN_GUID];
2330 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2331 DWORD size;
2332 HKEY hkey;
2333 DWORD type;
2334 HRESULT hr;
2335
2336 /* read the AppID value under the class's key */
2337 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2338 if (FAILED(hr))
2339 return hr;
2340
2341 size = sizeof(buf);
2342 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2343 RegCloseKey(hkey);
2344 if (res == ERROR_FILE_NOT_FOUND)
2345 return REGDB_E_KEYMISSING;
2346 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2347 return REGDB_E_READREGDB;
2348
2349 strcpyW(keyname, szAppIdKey);
2350 strcatW(keyname, buf);
2351 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2352 if (res == ERROR_FILE_NOT_FOUND)
2353 return REGDB_E_KEYMISSING;
2354 else if (res != ERROR_SUCCESS)
2355 return REGDB_E_READREGDB;
2356
2357 return S_OK;
2358 }
2359
2360 /******************************************************************************
2361 * ProgIDFromCLSID [OLE32.@]
2362 *
2363 * Converts a class id into the respective program ID.
2364 *
2365 * PARAMS
2366 * clsid [I] Class ID, as found in registry.
2367 * ppszProgID [O] Associated ProgID.
2368 *
2369 * RETURNS
2370 * S_OK
2371 * E_OUTOFMEMORY
2372 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2373 */
2374 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2375 {
2376 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2377 ACTCTX_SECTION_KEYED_DATA data;
2378 HKEY hkey;
2379 HRESULT ret;
2380 LONG progidlen = 0;
2381
2382 if (!ppszProgID)
2383 return E_INVALIDARG;
2384
2385 *ppszProgID = NULL;
2386
2387 data.cbSize = sizeof(data);
2388 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2389 clsid, &data))
2390 {
2391 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2392 if (comclass->progid_len)
2393 {
2394 WCHAR *ptrW;
2395
2396 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2397 if (!*ppszProgID) return E_OUTOFMEMORY;
2398
2399 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2400 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2401 return S_OK;
2402 }
2403 else
2404 return REGDB_E_CLASSNOTREG;
2405 }
2406
2407 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2408 if (FAILED(ret))
2409 return ret;
2410
2411 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2412 ret = REGDB_E_CLASSNOTREG;
2413
2414 if (ret == S_OK)
2415 {
2416 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2417 if (*ppszProgID)
2418 {
2419 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2420 ret = REGDB_E_CLASSNOTREG;
2421 CoTaskMemFree(*ppszProgID);
2422 *ppszProgID = NULL;
2423 }
2424 }
2425 else
2426 ret = E_OUTOFMEMORY;
2427 }
2428
2429 RegCloseKey(hkey);
2430 return ret;
2431 }
2432
2433 /******************************************************************************
2434 * CLSIDFromProgID [OLE32.@]
2435 *
2436 * Converts a program id into the respective GUID.
2437 *
2438 * PARAMS
2439 * progid [I] Unicode program ID, as found in registry.
2440 * clsid [O] Associated CLSID.
2441 *
2442 * RETURNS
2443 * Success: S_OK
2444 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2445 */
2446 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2447 {
2448 ACTCTX_SECTION_KEYED_DATA data;
2449
2450 if (!progid || !clsid)
2451 return E_INVALIDARG;
2452
2453 data.cbSize = sizeof(data);
2454 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2455 progid, &data))
2456 {
2457 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2458 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2459 *clsid = *alias;
2460 return S_OK;
2461 }
2462
2463 return clsid_from_string_reg(progid, clsid);
2464 }
2465
2466 /******************************************************************************
2467 * CLSIDFromProgIDEx [OLE32.@]
2468 */
2469 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2470 {
2471 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2472
2473 return CLSIDFromProgID(progid, clsid);
2474 }
2475
2476 /*****************************************************************************
2477 * CoGetPSClsid [OLE32.@]
2478 *
2479 * Retrieves the CLSID of the proxy/stub factory that implements
2480 * IPSFactoryBuffer for the specified interface.
2481 *
2482 * PARAMS
2483 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2484 * pclsid [O] Where to store returned proxy/stub CLSID.
2485 *
2486 * RETURNS
2487 * S_OK
2488 * E_OUTOFMEMORY
2489 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2490 *
2491 * NOTES
2492 *
2493 * The standard marshaller activates the object with the CLSID
2494 * returned and uses the CreateProxy and CreateStub methods on its
2495 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2496 * given object.
2497 *
2498 * CoGetPSClsid determines this CLSID by searching the
2499 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2500 * in the registry and any interface id registered by
2501 * CoRegisterPSClsid within the current process.
2502 *
2503 * BUGS
2504 *
2505 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2506 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2507 * considered a bug in native unless an application depends on this (unlikely).
2508 *
2509 * SEE ALSO
2510 * CoRegisterPSClsid.
2511 */
2512 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2513 {
2514 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2515 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2516 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2517 WCHAR value[CHARS_IN_GUID];
2518 LONG len;
2519 HKEY hkey;
2520 APARTMENT *apt = COM_CurrentApt();
2521 struct registered_psclsid *registered_psclsid;
2522 ACTCTX_SECTION_KEYED_DATA data;
2523
2524 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2525
2526 if (!apt)
2527 {
2528 ERR("apartment not initialised\n");
2529 return CO_E_NOTINITIALIZED;
2530 }
2531
2532 if (!pclsid)
2533 return E_INVALIDARG;
2534
2535 EnterCriticalSection(&apt->cs);
2536
2537 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2538 if (IsEqualIID(&registered_psclsid->iid, riid))
2539 {
2540 *pclsid = registered_psclsid->clsid;
2541 LeaveCriticalSection(&apt->cs);
2542 return S_OK;
2543 }
2544
2545 LeaveCriticalSection(&apt->cs);
2546
2547 data.cbSize = sizeof(data);
2548 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2549 riid, &data))
2550 {
2551 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2552 *pclsid = ifaceps->iid;
2553 return S_OK;
2554 }
2555
2556 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2557 strcpyW(path, wszInterface);
2558 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2559 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2560
2561 /* Open the key.. */
2562 if (open_classes_key(HKEY_CLASSES_ROOT, path, KEY_READ, &hkey))
2563 {
2564 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2565 return REGDB_E_IIDNOTREG;
2566 }
2567
2568 /* ... Once we have the key, query the registry to get the
2569 value of CLSID as a string, and convert it into a
2570 proper CLSID structure to be passed back to the app */
2571 len = sizeof(value);
2572 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
2573 {
2574 RegCloseKey(hkey);
2575 return REGDB_E_IIDNOTREG;
2576 }
2577 RegCloseKey(hkey);
2578
2579 /* We have the CLSID we want back from the registry as a string, so
2580 let's convert it into a CLSID structure */
2581 if (CLSIDFromString(value, pclsid) != NOERROR)
2582 return REGDB_E_IIDNOTREG;
2583
2584 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2585 return S_OK;
2586 }
2587
2588 /*****************************************************************************
2589 * CoRegisterPSClsid [OLE32.@]
2590 *
2591 * Register a proxy/stub CLSID for the given interface in the current process
2592 * only.
2593 *
2594 * PARAMS
2595 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2596 * rclsid [I] CLSID of the proxy/stub.
2597 *
2598 * RETURNS
2599 * Success: S_OK
2600 * Failure: E_OUTOFMEMORY
2601 *
2602 * NOTES
2603 *
2604 * This function does not add anything to the registry and the effects are
2605 * limited to the lifetime of the current process.
2606 *
2607 * SEE ALSO
2608 * CoGetPSClsid.
2609 */
2610 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2611 {
2612 APARTMENT *apt = COM_CurrentApt();
2613 struct registered_psclsid *registered_psclsid;
2614
2615 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2616
2617 if (!apt)
2618 {
2619 ERR("apartment not initialised\n");
2620 return CO_E_NOTINITIALIZED;
2621 }
2622
2623 EnterCriticalSection(&apt->cs);
2624
2625 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2626 if (IsEqualIID(&registered_psclsid->iid, riid))
2627 {
2628 registered_psclsid->clsid = *rclsid;
2629 LeaveCriticalSection(&apt->cs);
2630 return S_OK;
2631 }
2632
2633 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2634 if (!registered_psclsid)
2635 {
2636 LeaveCriticalSection(&apt->cs);
2637 return E_OUTOFMEMORY;
2638 }
2639
2640 registered_psclsid->iid = *riid;
2641 registered_psclsid->clsid = *rclsid;
2642 list_add_head(&apt->psclsids, &registered_psclsid->entry);
2643
2644 LeaveCriticalSection(&apt->cs);
2645
2646 return S_OK;
2647 }
2648
2649
2650 /***
2651 * COM_GetRegisteredClassObject
2652 *
2653 * This internal method is used to scan the registered class list to
2654 * find a class object.
2655 *
2656 * Params:
2657 * rclsid Class ID of the class to find.
2658 * dwClsContext Class context to match.
2659 * ppv [out] returns a pointer to the class object. Complying
2660 * to normal COM usage, this method will increase the
2661 * reference count on this object.
2662 */
2663 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2664 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2665 {
2666 HRESULT hr = S_FALSE;
2667 RegisteredClass *curClass;
2668
2669 EnterCriticalSection( &csRegisteredClassList );
2670
2671 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2672 {
2673 /*
2674 * Check if we have a match on the class ID and context.
2675 */
2676 if ((apt->oxid == curClass->apartment_id) &&
2677 (dwClsContext & curClass->runContext) &&
2678 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2679 {
2680 /*
2681 * We have a match, return the pointer to the class object.
2682 */
2683 *ppUnk = curClass->classObject;
2684
2685 IUnknown_AddRef(curClass->classObject);
2686
2687 hr = S_OK;
2688 break;
2689 }
2690 }
2691
2692 LeaveCriticalSection( &csRegisteredClassList );
2693
2694 return hr;
2695 }
2696
2697 /******************************************************************************
2698 * CoRegisterClassObject [OLE32.@]
2699 *
2700 * Registers the class object for a given class ID. Servers housed in EXE
2701 * files use this method instead of exporting DllGetClassObject to allow
2702 * other code to connect to their objects.
2703 *
2704 * PARAMS
2705 * rclsid [I] CLSID of the object to register.
2706 * pUnk [I] IUnknown of the object.
2707 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2708 * flags [I] REGCLS flags indicating how connections are made.
2709 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2710 *
2711 * RETURNS
2712 * S_OK on success,
2713 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2714 * CO_E_OBJISREG if the object is already registered. We should not return this.
2715 *
2716 * SEE ALSO
2717 * CoRevokeClassObject, CoGetClassObject
2718 *
2719 * NOTES
2720 * In-process objects are only registered for the current apartment.
2721 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2722 * in other apartments.
2723 *
2724 * BUGS
2725 * MSDN claims that multiple interface registrations are legal, but we
2726 * can't do that with our current implementation.
2727 */
2728 HRESULT WINAPI CoRegisterClassObject(
2729 REFCLSID rclsid,
2730 LPUNKNOWN pUnk,
2731 DWORD dwClsContext,
2732 DWORD flags,
2733 LPDWORD lpdwRegister)
2734 {
2735 static LONG next_cookie;
2736 RegisteredClass* newClass;
2737 LPUNKNOWN foundObject;
2738 HRESULT hr;
2739 APARTMENT *apt;
2740
2741 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2742 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2743
2744 if ( (lpdwRegister==0) || (pUnk==0) )
2745 return E_INVALIDARG;
2746
2747 apt = COM_CurrentApt();
2748 if (!apt)
2749 {
2750 ERR("COM was not initialized\n");
2751 return CO_E_NOTINITIALIZED;
2752 }
2753
2754 *lpdwRegister = 0;
2755
2756 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2757 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2758 if (flags & REGCLS_MULTIPLEUSE)
2759 dwClsContext |= CLSCTX_INPROC_SERVER;
2760
2761 /*
2762 * First, check if the class is already registered.
2763 * If it is, this should cause an error.
2764 */
2765 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2766 if (hr == S_OK) {
2767 if (flags & REGCLS_MULTIPLEUSE) {
2768 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2769 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2770 IUnknown_Release(foundObject);
2771 return hr;
2772 }
2773 IUnknown_Release(foundObject);
2774 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2775 return CO_E_OBJISREG;
2776 }
2777
2778 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2779 if ( newClass == NULL )
2780 return E_OUTOFMEMORY;
2781
2782 newClass->classIdentifier = *rclsid;
2783 newClass->apartment_id = apt->oxid;
2784 newClass->runContext = dwClsContext;
2785 newClass->connectFlags = flags;
2786 newClass->RpcRegistration = NULL;
2787
2788 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2789 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2790
2791 /*
2792 * Since we're making a copy of the object pointer, we have to increase its
2793 * reference count.
2794 */
2795 newClass->classObject = pUnk;
2796 IUnknown_AddRef(newClass->classObject);
2797
2798 EnterCriticalSection( &csRegisteredClassList );
2799 list_add_tail(&RegisteredClassList, &newClass->entry);
2800 LeaveCriticalSection( &csRegisteredClassList );
2801
2802 *lpdwRegister = newClass->dwCookie;
2803
2804 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2805 IStream *marshal_stream;
2806
2807 hr = get_local_server_stream(apt, &marshal_stream);
2808 if(FAILED(hr))
2809 return hr;
2810
2811 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2812 marshal_stream,
2813 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2814 &newClass->RpcRegistration);
2815 IStream_Release(marshal_stream);
2816 }
2817 return S_OK;
2818 }
2819
2820 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2821 {
2822 if (data->hkey)
2823 {
2824 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2825 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2826 static const WCHAR wszFree[] = {'F','r','e','e',0};
2827 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2828 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2829 DWORD dwLength = sizeof(threading_model);
2830 DWORD keytype;
2831 DWORD ret;
2832
2833 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2834 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2835 threading_model[0] = '\0';
2836
2837 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2838 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2839 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2840
2841 /* there's not specific handling for this case */
2842 if (threading_model[0]) return ThreadingModel_Neutral;
2843 return ThreadingModel_No;
2844 }
2845 else
2846 return data->u.actctx.data->model;
2847 }
2848
2849 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2850 REFCLSID rclsid, REFIID riid,
2851 BOOL hostifnecessary, void **ppv)
2852 {
2853 WCHAR dllpath[MAX_PATH+1];
2854 BOOL apartment_threaded;
2855
2856 if (hostifnecessary)
2857 {
2858 enum comclass_threadingmodel model = get_threading_model(regdata);
2859
2860 if (model == ThreadingModel_Apartment)
2861 {
2862 apartment_threaded = TRUE;
2863 if (apt->multi_threaded)
2864 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2865 }
2866 else if (model == ThreadingModel_Free)
2867 {
2868 apartment_threaded = FALSE;
2869 if (!apt->multi_threaded)
2870 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2871 }
2872 /* everything except "Apartment", "Free" and "Both" */
2873 else if (model != ThreadingModel_Both)
2874 {
2875 apartment_threaded = TRUE;
2876 /* everything else is main-threaded */
2877 if (model != ThreadingModel_No)
2878 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2879
2880 if (apt->multi_threaded || !apt->main)
2881 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2882 }
2883 else
2884 apartment_threaded = FALSE;
2885 }
2886 else
2887 apartment_threaded = !apt->multi_threaded;
2888
2889 if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2890 {
2891 /* failure: CLSID is not found in registry */
2892 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2893 return REGDB_E_CLASSNOTREG;
2894 }
2895
2896 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2897 rclsid, riid, ppv);
2898 }
2899
2900 /***********************************************************************
2901 * CoGetClassObject [OLE32.@]
2902 *
2903 * Creates an object of the specified class.
2904 *
2905 * PARAMS
2906 * rclsid [I] Class ID to create an instance of.
2907 * dwClsContext [I] Flags to restrict the location of the created instance.
2908 * pServerInfo [I] Optional. Details for connecting to a remote server.
2909 * iid [I] The ID of the interface of the instance to return.
2910 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2911 *
2912 * RETURNS
2913 * Success: S_OK
2914 * Failure: HRESULT code.
2915 *
2916 * NOTES
2917 * The dwClsContext parameter can be one or more of the following:
2918 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2919 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2920 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2921 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2922 *
2923 * SEE ALSO
2924 * CoCreateInstance()
2925 */
2926 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2927 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2928 REFIID iid, LPVOID *ppv)
2929 {
2930 struct class_reg_data clsreg;
2931 IUnknown *regClassObject;
2932 HRESULT hres = E_UNEXPECTED;
2933 APARTMENT *apt;
2934 BOOL release_apt = FALSE;
2935
2936 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2937
2938 if (!ppv)
2939 return E_INVALIDARG;
2940
2941 *ppv = NULL;
2942
2943 if (!(apt = COM_CurrentApt()))
2944 {
2945 if (!(apt = apartment_find_multi_threaded()))
2946 {
2947 ERR("apartment not initialised\n");
2948 return CO_E_NOTINITIALIZED;
2949 }
2950 release_apt = TRUE;
2951 }
2952
2953 if (pServerInfo) {
2954 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2955 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2956 }
2957
2958 if (CLSCTX_INPROC_SERVER & dwClsContext)
2959 {
2960 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2961 {
2962 if (release_apt) apartment_release(apt);
2963 return FTMarshalCF_Create(iid, ppv);
2964 }
2965 }
2966
2967 if (CLSCTX_INPROC & dwClsContext)
2968 {
2969 ACTCTX_SECTION_KEYED_DATA data;
2970
2971 data.cbSize = sizeof(data);
2972 /* search activation context first */
2973 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2974 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2975 rclsid, &data))
2976 {
2977 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2978
2979 clsreg.u.actctx.hactctx = data.hActCtx;
2980 clsreg.u.actctx.data = data.lpData;
2981 clsreg.u.actctx.section = data.lpSectionBase;
2982 clsreg.hkey = FALSE;
2983
2984 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2985 ReleaseActCtx(data.hActCtx);
2986 if (release_apt) apartment_release(apt);
2987 return hres;
2988 }
2989 }
2990
2991 /*
2992 * First, try and see if we can't match the class ID with one of the
2993 * registered classes.
2994 */
2995 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2996 &regClassObject))
2997 {
2998 /* Get the required interface from the retrieved pointer. */
2999 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3000
3001 /*
3002 * Since QI got another reference on the pointer, we want to release the
3003 * one we already have. If QI was unsuccessful, this will release the object. This
3004 * is good since we are not returning it in the "out" parameter.
3005 */
3006 IUnknown_Release(regClassObject);
3007 if (release_apt) apartment_release(apt);
3008 return hres;
3009 }
3010
3011 /* First try in-process server */
3012 if (CLSCTX_INPROC_SERVER & dwClsContext)
3013 {
3014 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3015 HKEY hkey;
3016
3017 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3018 if (FAILED(hres))
3019 {
3020 if (hres == REGDB_E_CLASSNOTREG)
3021 ERR("class %s not registered\n", debugstr_guid(rclsid));
3022 else if (hres == REGDB_E_KEYMISSING)
3023 {
3024 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3025 hres = REGDB_E_CLASSNOTREG;
3026 }
3027 }
3028
3029 if (SUCCEEDED(hres))
3030 {
3031 clsreg.u.hkey = hkey;
3032 clsreg.hkey = TRUE;
3033
3034 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3035 RegCloseKey(hkey);
3036 }
3037
3038 /* return if we got a class, otherwise fall through to one of the
3039 * other types */
3040 if (SUCCEEDED(hres))
3041 {
3042 if (release_apt) apartment_release(apt);
3043 return hres;
3044 }
3045 }
3046
3047 /* Next try in-process handler */
3048 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3049 {
3050 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3051 HKEY hkey;
3052
3053 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3054 if (FAILED(hres))
3055 {
3056 if (hres == REGDB_E_CLASSNOTREG)
3057 ERR("class %s not registered\n", debugstr_guid(rclsid));
3058 else if (hres == REGDB_E_KEYMISSING)
3059 {
3060 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3061 hres = REGDB_E_CLASSNOTREG;
3062 }
3063 }
3064
3065 if (SUCCEEDED(hres))
3066 {
3067 clsreg.u.hkey = hkey;
3068 clsreg.hkey = TRUE;
3069
3070 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3071 RegCloseKey(hkey);
3072 }
3073
3074 /* return if we got a class, otherwise fall through to one of the
3075 * other types */
3076 if (SUCCEEDED(hres))
3077 {
3078 if (release_apt) apartment_release(apt);
3079 return hres;
3080 }
3081 }
3082 if (release_apt) apartment_release(apt);
3083
3084 /* Next try out of process */
3085 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3086 {
3087 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3088 if (SUCCEEDED(hres))
3089 return hres;
3090 }
3091
3092 /* Finally try remote: this requires networked DCOM (a lot of work) */
3093 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3094 {
3095 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3096 hres = REGDB_E_CLASSNOTREG;
3097 }
3098
3099 if (FAILED(hres))
3100 ERR("no class object %s could be created for context 0x%x\n",
3101 debugstr_guid(rclsid), dwClsContext);
3102 return hres;
3103 }
3104
3105 /***********************************************************************
3106 * CoResumeClassObjects (OLE32.@)
3107 *
3108 * Resumes all class objects registered with REGCLS_SUSPENDED.
3109 *
3110 * RETURNS
3111 * Success: S_OK.
3112 * Failure: HRESULT code.
3113 */
3114 HRESULT WINAPI CoResumeClassObjects(void)
3115 {
3116 FIXME("stub\n");
3117 return S_OK;
3118 }
3119
3120 /***********************************************************************
3121 * CoCreateInstance [OLE32.@]
3122 *
3123 * Creates an instance of the specified class.
3124 *
3125 * PARAMS
3126 * rclsid [I] Class ID to create an instance of.
3127 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3128 * dwClsContext [I] Flags to restrict the location of the created instance.
3129 * iid [I] The ID of the interface of the instance to return.
3130 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3131 *
3132 * RETURNS
3133 * Success: S_OK
3134 * Failure: HRESULT code.
3135 *
3136 * NOTES
3137 * The dwClsContext parameter can be one or more of the following:
3138 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3139 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3140 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3141 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3142 *
3143 * Aggregation is the concept of deferring the IUnknown of an object to another
3144 * object. This allows a separate object to behave as though it was part of
3145 * the object and to allow this the pUnkOuter parameter can be set. Note that
3146 * not all objects support having an outer of unknown.
3147 *
3148 * SEE ALSO
3149 * CoGetClassObject()
3150 */
3151 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3152 REFCLSID rclsid,
3153 LPUNKNOWN pUnkOuter,
3154 DWORD dwClsContext,
3155 REFIID iid,
3156 LPVOID *ppv)
3157 {
3158 HRESULT hres;
3159 LPCLASSFACTORY lpclf = 0;
3160 APARTMENT *apt;
3161
3162 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3163 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3164
3165 if (ppv==0)
3166 return E_POINTER;
3167
3168 *ppv = 0;
3169
3170 if (!(apt = COM_CurrentApt()))
3171 {
3172 if (!(apt = apartment_find_multi_threaded()))
3173 {
3174 ERR("apartment not initialised\n");
3175 return CO_E_NOTINITIALIZED;
3176 }
3177 apartment_release(apt);
3178 }
3179
3180 /*
3181 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3182 */
3183 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable))
3184 {
3185 IGlobalInterfaceTable *git = get_std_git();
3186 hres = IGlobalInterfaceTable_QueryInterface(git, iid, ppv);
3187 if (hres != S_OK) return hres;
3188
3189 TRACE("Retrieved GIT (%p)\n", *ppv);
3190 return S_OK;
3191 }
3192
3193 if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
3194 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
3195
3196 /*
3197 * Get a class factory to construct the object we want.
3198 */
3199 hres = CoGetClassObject(rclsid,
3200 dwClsContext,
3201 NULL,
3202 &IID_IClassFactory,
3203 (LPVOID)&lpclf);
3204
3205 if (FAILED(hres))
3206 return hres;
3207
3208 /*
3209 * Create the object and don't forget to release the factory
3210 */
3211 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
3212 IClassFactory_Release(lpclf);
3213 if (FAILED(hres))
3214 {
3215 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3216 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
3217 else
3218 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3219 debugstr_guid(iid),
3220 debugstr_guid(rclsid),hres);
3221 }
3222
3223 return hres;
3224 }
3225
3226 static void init_multi_qi(DWORD count, MULTI_QI *mqi)
3227 {
3228 ULONG i;
3229
3230 for (i = 0; i < count; i++)
3231 {
3232 mqi[i].pItf = NULL;
3233 mqi[i].hr = E_NOINTERFACE;
3234 }
3235 }
3236
3237 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi)
3238 {
3239 ULONG index, fetched = 0;
3240
3241 for (index = 0; index < count; index++)
3242 {
3243 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3244 if (mqi[index].hr == S_OK)
3245 fetched++;
3246 }
3247
3248 IUnknown_Release(unk);
3249
3250 if (fetched == 0)
3251 return E_NOINTERFACE;
3252
3253 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3254 }
3255
3256 /***********************************************************************
3257 * CoCreateInstanceEx [OLE32.@]
3258 */
3259 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3260 REFCLSID rclsid,
3261 LPUNKNOWN pUnkOuter,
3262 DWORD dwClsContext,
3263 COSERVERINFO* pServerInfo,
3264 ULONG cmq,
3265 MULTI_QI* pResults)
3266 {
3267 IUnknown* pUnk = NULL;
3268 HRESULT hr;
3269
3270 /*
3271 * Sanity check
3272 */
3273 if ( (cmq==0) || (pResults==NULL))
3274 return E_INVALIDARG;
3275
3276 if (pServerInfo!=NULL)
3277 FIXME("() non-NULL pServerInfo not supported!\n");
3278
3279 init_multi_qi(cmq, pResults);
3280
3281 /*
3282 * Get the object and get its IUnknown pointer.
3283 */
3284 hr = CoCreateInstance(rclsid,
3285 pUnkOuter,
3286 dwClsContext,
3287 &IID_IUnknown,
3288 (VOID**)&pUnk);
3289
3290 if (hr != S_OK)
3291 return hr;
3292
3293 return return_multi_qi(pUnk, cmq, pResults);
3294 }
3295
3296 /***********************************************************************
3297 * CoGetInstanceFromFile [OLE32.@]
3298 */
3299 HRESULT WINAPI CoGetInstanceFromFile(
3300 COSERVERINFO *server_info,
3301 CLSID *rclsid,
3302 IUnknown *outer,
3303 DWORD cls_context,
3304 DWORD grfmode,
3305 OLECHAR *filename,
3306 DWORD count,
3307 MULTI_QI *results
3308 )
3309 {
3310 IPersistFile *pf = NULL;
3311 IUnknown* unk = NULL;
3312 CLSID clsid;
3313 HRESULT hr;
3314
3315 if (count == 0 || !results)
3316 return E_INVALIDARG;
3317
3318 if (server_info)
3319 FIXME("() non-NULL server_info not supported\n");
3320
3321 init_multi_qi(count, results);
3322
3323 /* optionaly get CLSID from a file */
3324 if (!rclsid)
3325 {
3326 hr = GetClassFile(filename, &clsid);
3327 if (FAILED(hr))
3328 {
3329 ERR("failed to get CLSID from a file\n");
3330 return hr;
3331 }
3332
3333 rclsid = &clsid;
3334 }
3335
3336 hr = CoCreateInstance(rclsid,
3337 outer,
3338 cls_context,
3339 &IID_IUnknown,
3340 (void**)&unk);
3341
3342 if (hr != S_OK)
3343 return hr;
3344
3345 /* init from file */
3346 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3347 if (FAILED(hr))
3348 ERR("failed to get IPersistFile\n");
3349
3350 if (pf)
3351 {
3352 IPersistFile_Load(pf, filename, grfmode);
3353 IPersistFile_Release(pf);
3354 }
3355
3356 return return_multi_qi(unk, count, results);
3357 }
3358
3359 /***********************************************************************
3360 * CoGetInstanceFromIStorage [OLE32.@]
3361 */
3362 HRESULT WINAPI CoGetInstanceFromIStorage(
3363 COSERVERINFO *server_info,
3364 CLSID *rclsid,
3365 IUnknown *outer,
3366 DWORD cls_context,
3367 IStorage *storage,
3368 DWORD count,
3369 MULTI_QI *results
3370 )
3371 {
3372 IPersistStorage *ps = NULL;
3373 IUnknown* unk = NULL;
3374 STATSTG stat;
3375 HRESULT hr;
3376
3377 if (count == 0 || !results || !storage)
3378 return E_INVALIDARG;
3379
3380 if (server_info)
3381 FIXME("() non-NULL server_info not supported\n");
3382
3383 init_multi_qi(count, results);
3384
3385 /* optionaly get CLSID from a file */
3386 if (!rclsid)
3387 {
3388 memset(&stat.clsid, 0, sizeof(stat.clsid));
3389 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3390 if (FAILED(hr))
3391 {
3392 ERR("failed to get CLSID from a file\n");
3393 return hr;
3394 }
3395
3396 rclsid = &stat.clsid;
3397 }
3398
3399 hr = CoCreateInstance(rclsid,
3400 outer,
3401 cls_context,
3402 &IID_IUnknown,
3403 (void**)&unk);
3404
3405 if (hr != S_OK)
3406 return hr;
3407
3408 /* init from IStorage */
3409 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3410 if (FAILED(hr))
3411 ERR("failed to get IPersistStorage\n");
3412
3413 if (ps)
3414 {
3415 IPersistStorage_Load(ps, storage);
3416 IPersistStorage_Release(ps);
3417 }
3418
3419 return return_multi_qi(unk, count, results);
3420 }
3421
3422 /***********************************************************************
3423 * CoLoadLibrary (OLE32.@)
3424 *
3425 * Loads a library.
3426 *
3427 * PARAMS
3428 * lpszLibName [I] Path to library.
3429 * bAutoFree [I] Whether the library should automatically be freed.
3430 *
3431 * RETURNS
3432 * Success: Handle to loaded library.
3433 * Failure: NULL.
3434 *
3435 * SEE ALSO
3436 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3437 */
3438 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3439 {
3440 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3441
3442 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3443 }
3444
3445 /***********************************************************************
3446 * CoFreeLibrary [OLE32.@]
3447 *
3448 * Unloads a library from memory.
3449 *
3450 * PARAMS
3451 * hLibrary [I] Handle to library to unload.
3452 *
3453 * RETURNS
3454 * Nothing
3455 *
3456 * SEE ALSO
3457 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3458 */
3459 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3460 {
3461 FreeLibrary(hLibrary);
3462 }
3463
3464
3465 /***********************************************************************
3466 * CoFreeAllLibraries [OLE32.@]
3467 *
3468 * Function for backwards compatibility only. Does nothing.
3469 *
3470 * RETURNS
3471 * Nothing.
3472 *
3473 * SEE ALSO
3474 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3475 */
3476 void WINAPI CoFreeAllLibraries(void)
3477 {
3478 /* NOP */
3479 }
3480
3481 /***********************************************************************
3482 * CoFreeUnusedLibrariesEx [OLE32.@]
3483 *
3484 * Frees any previously unused libraries whose delay has expired and marks
3485 * currently unused libraries for unloading. Unused are identified as those that
3486 * return S_OK from their DllCanUnloadNow function.
3487 *
3488 * PARAMS
3489 * dwUnloadDelay [I] Unload delay in milliseconds.
3490 * dwReserved [I] Reserved. Set to 0.
3491 *
3492 * RETURNS
3493 * Nothing.
3494 *
3495 * SEE ALSO
3496 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3497 */
3498 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3499 {
3500 struct apartment *apt = COM_CurrentApt();
3501 if (!apt)
3502 {
3503 ERR("apartment not initialised\n");
3504 return;
3505 }
3506
3507 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3508 }
3509
3510 /***********************************************************************
3511 * CoFreeUnusedLibraries [OLE32.@]
3512 *
3513 * Frees any unused libraries. Unused are identified as those that return
3514 * S_OK from their DllCanUnloadNow function.
3515 *
3516 * RETURNS
3517 * Nothing.
3518 *
3519 * SEE ALSO
3520 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3521 */
3522 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3523 {
3524 CoFreeUnusedLibrariesEx(INFINITE, 0);
3525 }
3526
3527 /***********************************************************************
3528 * CoFileTimeNow [OLE32.@]
3529 *
3530 * Retrieves the current time in FILETIME format.
3531 *
3532 * PARAMS
3533 * lpFileTime [O] The current time.
3534 *
3535 * RETURNS
3536 * S_OK.
3537 */
3538 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3539 {
3540 GetSystemTimeAsFileTime( lpFileTime );
3541 return S_OK;
3542 }
3543
3544 /******************************************************************************
3545 * CoLockObjectExternal [OLE32.@]
3546 *
3547 * Increments or decrements the external reference count of a stub object.
3548 *
3549 * PARAMS
3550 * pUnk [I] Stub object.
3551 * fLock [I] If TRUE then increments the external ref-count,
3552 * otherwise decrements.
3553 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3554 * calling CoDisconnectObject.
3555 *
3556 * RETURNS
3557 * Success: S_OK.
3558 * Failure: HRESULT code.
3559 *
3560 * NOTES
3561 * If fLock is TRUE and an object is passed in that doesn't have a stub
3562 * manager then a new stub manager is created for the object.
3563 */
3564 HRESULT WINAPI CoLockObjectExternal(
3565 LPUNKNOWN pUnk,
3566 BOOL fLock,
3567 BOOL fLastUnlockReleases)
3568 {
3569 struct stub_manager *stubmgr;
3570 struct apartment *apt;
3571
3572 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3573 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3574
3575 apt = COM_CurrentApt();
3576 if (!apt) return CO_E_NOTINITIALIZED;
3577
3578 stubmgr = get_stub_manager_from_object(apt, pUnk);
3579
3580 if (stubmgr)
3581 {
3582 if (fLock)
3583 stub_manager_ext_addref(stubmgr, 1, FALSE);
3584 else
3585 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3586
3587 stub_manager_int_release(stubmgr);
3588
3589 return S_OK;
3590 }
3591 else if (fLock)
3592 {
3593 stubmgr = new_stub_manager(apt, pUnk);
3594
3595 if (stubmgr)
3596 {
3597 stub_manager_ext_addref(stubmgr, 1, FALSE);
3598 stub_manager_int_release(stubmgr);
3599 }
3600
3601 return S_OK;
3602 }
3603 else
3604 {
3605 WARN("stub object not found %p\n", pUnk);
3606 /* Note: native is pretty broken here because it just silently
3607 * fails, without returning an appropriate error code, making apps
3608 * think that the object was disconnected, when it actually wasn't */
3609 return S_OK;
3610 }
3611 }
3612
3613 /***********************************************************************
3614 * CoInitializeWOW (OLE32.@)
3615 *
3616 * WOW equivalent of CoInitialize?
3617 *
3618 * PARAMS
3619 * x [I] Unknown.
3620 * y [I] Unknown.
3621 *
3622 * RETURNS
3623 * Unknown.
3624 */
3625 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3626 {
3627 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3628 return 0;
3629 }
3630
3631 /***********************************************************************
3632 * CoGetState [OLE32.@]
3633 *
3634 * Retrieves the thread state object previously stored by CoSetState().
3635 *
3636 * PARAMS
3637 * ppv [I] Address where pointer to object will be stored.
3638 *
3639 * RETURNS
3640 * Success: S_OK.
3641 * Failure: E_OUTOFMEMORY.
3642 *
3643 * NOTES
3644 * Crashes on all invalid ppv addresses, including NULL.
3645 * If the function returns a non-NULL object then the caller must release its
3646 * reference on the object when the object is no longer required.
3647 *
3648 * SEE ALSO
3649 * CoSetState().
3650 */
3651 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3652 {
3653 struct oletls *info = COM_CurrentInfo();
3654 if (!info) return E_OUTOFMEMORY;
3655
3656 *ppv = NULL;
3657
3658 if (info->state)
3659 {
3660 IUnknown_AddRef(info->state);
3661 *ppv = info->state;
3662 TRACE("apt->state=%p\n", info->state);
3663 }
3664
3665 return S_OK;
3666 }
3667
3668 /***********************************************************************
3669 * CoSetState [OLE32.@]
3670 *
3671 * Sets the thread state object.
3672 *
3673 * PARAMS
3674 * pv [I] Pointer to state object to be stored.
3675 *
3676 * NOTES
3677 * The system keeps a reference on the object while the object stored.
3678 *
3679 * RETURNS
3680 * Success: S_OK.
3681 * Failure: E_OUTOFMEMORY.
3682 */
3683 HRESULT WINAPI CoSetState(IUnknown * pv)
3684 {
3685 struct oletls *info = COM_CurrentInfo();
3686 if (!info) return E_OUTOFMEMORY;
3687
3688 if (pv) IUnknown_AddRef(pv);
3689
3690 if (info->state)
3691 {
3692 TRACE("-- release %p now\n", info->state);
3693 IUnknown_Release(info->state);
3694 }
3695
3696 info->state = pv;
3697
3698 return S_OK;
3699 }
3700
3701
3702 /******************************************************************************
3703 * CoTreatAsClass [OLE32.@]
3704 *
3705 * Sets the TreatAs value of a class.
3706 *
3707 * PARAMS
3708 * clsidOld [I] Class to set TreatAs value on.
3709 * clsidNew [I] The class the clsidOld should be treated as.
3710 *
3711 * RETURNS
3712 * Success: S_OK.
3713 * Failure: HRESULT code.
3714 *
3715 * SEE ALSO
3716 * CoGetTreatAsClass
3717 */
3718 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3719 {
3720 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3721 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3722 HKEY hkey = NULL;
3723 WCHAR szClsidNew[CHARS_IN_GUID];
3724 HRESULT res = S_OK;
3725 WCHAR auto_treat_as[CHARS_IN_GUID];
3726 LONG auto_treat_as_size = sizeof(auto_treat_as);
3727 CLSID id;
3728
3729 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3730 if (FAILED(res))
3731 goto done;
3732 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
3733 {
3734 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3735 CLSIDFromString(auto_treat_as, &id) == S_OK)
3736 {
3737 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3738 {
3739 res = REGDB_E_WRITEREGDB;
3740 goto done;
3741 }
3742 }
3743 else
3744 {
3745 RegDeleteKeyW(hkey, wszTreatAs);
3746 goto done;
3747 }
3748 }
3749 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
3750 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
3751 {
3752 res = REGDB_E_WRITEREGDB;
3753 goto done;
3754 }
3755
3756 done:
3757 if (hkey) RegCloseKey(hkey);
3758 return res;
3759 }
3760
3761 /******************************************************************************
3762 * CoGetTreatAsClass [OLE32.@]
3763 *
3764 * Gets the TreatAs value of a class.
3765 *
3766 * PARAMS
3767 * clsidOld [I] Class to get the TreatAs value of.
3768 * clsidNew [I] The class the clsidOld should be treated as.
3769 *
3770 * RETURNS
3771 * Success: S_OK.
3772 * Failure: HRESULT code.
3773 *
3774 * SEE ALSO
3775 * CoSetTreatAsClass
3776 */
3777 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3778 {
3779 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3780 HKEY hkey = NULL;
3781 WCHAR szClsidNew[CHARS_IN_GUID];
3782 HRESULT res = S_OK;
3783 LONG len = sizeof(szClsidNew);
3784
3785 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3786 *clsidNew = *clsidOld; /* copy over old value */
3787
3788 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3789 if (FAILED(res))
3790 {
3791 res = S_FALSE;
3792 goto done;
3793 }
3794 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3795 {
3796 res = S_FALSE;
3797 goto done;
3798 }
3799 res = CLSIDFromString(szClsidNew,clsidNew);
3800 if (FAILED(res))
3801 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3802 done:
3803 if (hkey) RegCloseKey(hkey);
3804 return res;
3805 }
3806
3807 /******************************************************************************
3808 * CoGetCurrentProcess [OLE32.@]
3809 *
3810 * Gets the current process ID.
3811 *
3812 * RETURNS
3813 * The current process ID.
3814 *
3815 * NOTES
3816 * Is DWORD really the correct return type for this function?
3817 */
3818 DWORD WINAPI CoGetCurrentProcess(void)
3819 {
3820 return GetCurrentProcessId();
3821 }
3822
3823 /******************************************************************************
3824 * CoRegisterMessageFilter [OLE32.@]
3825 *
3826 * Registers a message filter.
3827 *
3828 * PARAMS
3829 * lpMessageFilter [I] Pointer to interface.
3830 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3831 *
3832 * RETURNS
3833 * Success: S_OK.
3834 * Failure: HRESULT code.
3835 *
3836 * NOTES
3837 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3838 * lpMessageFilter removes the message filter.
3839 *
3840 * If lplpMessageFilter is not NULL the previous message filter will be
3841 * returned in the memory pointer to this parameter and the caller is
3842 * responsible for releasing the object.
3843 *
3844 * The current thread be in an apartment otherwise the function will crash.
3845 */
3846 HRESULT WINAPI CoRegisterMessageFilter(
3847 LPMESSAGEFILTER lpMessageFilter,
3848 LPMESSAGEFILTER *lplpMessageFilter)
3849 {
3850 struct apartment *apt;
3851 IMessageFilter *lpOldMessageFilter;
3852
3853 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3854
3855 apt = COM_CurrentApt();
3856
3857 /* can't set a message filter in a multi-threaded apartment */
3858 if (!apt || apt->multi_threaded)
3859 {
3860 WARN("can't set message filter in MTA or uninitialized apt\n");
3861 return CO_E_NOT_SUPPORTED;
3862 }
3863
3864 if (lpMessageFilter)
3865 IMessageFilter_AddRef(lpMessageFilter);
3866
3867 EnterCriticalSection(&apt->cs);
3868
3869 lpOldMessageFilter = apt->filter;
3870 apt->filter = lpMessageFilter;
3871
3872 LeaveCriticalSection(&apt->cs);
3873
3874 if (lplpMessageFilter)
3875 *lplpMessageFilter = lpOldMessageFilter;
3876 else if (lpOldMessageFilter)
3877 IMessageFilter_Release(lpOldMessageFilter);
3878
3879 return S_OK;
3880 }
3881
3882 /***********************************************************************
3883 * CoIsOle1Class [OLE32.@]
3884 *
3885 * Determines whether the specified class an OLE v1 class.
3886 *
3887 * PARAMS
3888 * clsid [I] Class to test.
3889 *
3890 * RETURNS
3891 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3892 */
3893 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3894 {
3895 FIXME("%s\n", debugstr_guid(clsid));
3896 return FALSE;
3897 }
3898
3899 /***********************************************************************
3900 * IsEqualGUID [OLE32.@]
3901 *
3902 * Compares two Unique Identifiers.
3903 *
3904 * PARAMS
3905 * rguid1 [I] The first GUID to compare.
3906 * rguid2 [I] The other GUID to compare.
3907 *
3908 * RETURNS
3909 * TRUE if equal
3910 */
3911 #undef IsEqualGUID
3912 BOOL WINAPI IsEqualGUID(
3913 REFGUID rguid1,
3914 REFGUID rguid2)
3915 {
3916 return !memcmp(rguid1,rguid2,sizeof(GUID));
3917 }
3918
3919 /***********************************************************************
3920 * CoInitializeSecurity [OLE32.@]
3921 */
3922 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3923 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3924 void* pReserved1, DWORD dwAuthnLevel,
3925 DWORD dwImpLevel, void* pReserved2,
3926 DWORD dwCapabilities, void* pReserved3)
3927 {
3928 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3929 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3930 dwCapabilities, pReserved3);
3931 return S_OK;
3932 }
3933
3934 /***********************************************************************
3935 * CoSuspendClassObjects [OLE32.@]
3936 *
3937 * Suspends all registered class objects to prevent further requests coming in
3938 * for those objects.
3939 *
3940 * RETURNS
3941 * Success: S_OK.
3942 * Failure: HRESULT code.
3943 */
3944 HRESULT WINAPI CoSuspendClassObjects(void)
3945 {
3946 FIXME("\n");
3947 return S_OK;
3948 }
3949
3950 /***********************************************************************
3951 * CoAddRefServerProcess [OLE32.@]
3952 *
3953 * Helper function for incrementing the reference count of a local-server
3954 * process.
3955 *
3956 * RETURNS
3957 * New reference count.
3958 *
3959 * SEE ALSO
3960 * CoReleaseServerProcess().
3961 */
3962 ULONG WINAPI CoAddRefServerProcess(void)
3963 {
3964 ULONG refs;
3965
3966 TRACE("\n");
3967
3968 EnterCriticalSection(&csRegisteredClassList);
3969 refs = ++s_COMServerProcessReferences;
3970 LeaveCriticalSection(&csRegisteredClassList);
3971
3972 TRACE("refs before: %d\n", refs - 1);
3973
3974 return refs;
3975 }
3976
3977 /***********************************************************************
3978 * CoReleaseServerProcess [OLE32.@]
3979 *
3980 * Helper function for decrementing the reference count of a local-server
3981 * process.
3982 *
3983 * RETURNS
3984 * New reference count.
3985 *
3986 * NOTES
3987 * When reference count reaches 0, this function suspends all registered
3988 * classes so no new connections are accepted.
3989 *
3990 * SEE ALSO
3991 * CoAddRefServerProcess(), CoSuspendClassObjects().
3992 */
3993 ULONG WINAPI CoReleaseServerProcess(void)
3994 {
3995 ULONG refs;
3996
3997 TRACE("\n");
3998
3999 EnterCriticalSection(&csRegisteredClassList);
4000
4001 refs = --s_COMServerProcessReferences;
4002 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4003
4004 LeaveCriticalSection(&csRegisteredClassList);
4005
4006 TRACE("refs after: %d\n", refs);
4007
4008 return refs;
4009 }
4010
4011 /***********************************************************************
4012 * CoIsHandlerConnected [OLE32.@]
4013 *
4014 * Determines whether a proxy is connected to a remote stub.
4015 *
4016 * PARAMS
4017 * pUnk [I] Pointer to object that may or may not be connected.
4018 *
4019 * RETURNS
4020 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4021 * FALSE otherwise.
4022 */
4023 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4024 {
4025 FIXME("%p\n", pUnk);
4026
4027 return TRUE;
4028 }
4029
4030 /***********************************************************************
4031 * CoAllowSetForegroundWindow [OLE32.@]
4032 *
4033 */
4034 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4035 {
4036 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4037 return S_OK;
4038 }
4039
4040 /***********************************************************************
4041 * CoQueryProxyBlanket [OLE32.@]
4042 *
4043 * Retrieves the security settings being used by a proxy.
4044 *
4045 * PARAMS
4046 * pProxy [I] Pointer to the proxy object.
4047 * pAuthnSvc [O] The type of authentication service.
4048 * pAuthzSvc [O] The type of authorization service.
4049 * ppServerPrincName [O] Optional. The server prinicple name.
4050 * pAuthnLevel [O] The authentication level.
4051 * pImpLevel [O] The impersonation level.
4052 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4053 * pCapabilities [O] Flags affecting the security behaviour.
4054 *
4055 * RETURNS
4056 * Success: S_OK.
4057 * Failure: HRESULT code.
4058 *
4059 * SEE ALSO
4060 * CoCopyProxy, CoSetProxyBlanket.
4061 */
4062 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4063 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4064 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4065 {
4066 IClientSecurity *pCliSec;
4067 HRESULT hr;
4068
4069 TRACE("%p\n", pProxy);
4070
4071 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4072 if (SUCCEEDED(hr))
4073 {
4074 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4075 pAuthzSvc, ppServerPrincName,
4076 pAuthnLevel, pImpLevel, ppAuthInfo,
4077 pCapabilities);
4078 IClientSecurity_Release(pCliSec);
4079 }
4080
4081 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4082 return hr;
4083 }
4084
4085 /***********************************************************************
4086 * CoSetProxyBlanket [OLE32.@]
4087 *
4088 * Sets the security settings for a proxy.
4089 *
4090 * PARAMS
4091 * pProxy [I] Pointer to the proxy object.
4092 * AuthnSvc [I] The type of authentication service.
4093 * AuthzSvc [I] The type of authorization service.
4094 * pServerPrincName [I] The server prinicple name.
4095 * AuthnLevel [I] The authentication level.
4096 * ImpLevel [I] The impersonation level.
4097 * pAuthInfo [I] Information specific to the authorization/authentication service.
4098 * Capabilities [I] Flags affecting the security behaviour.
4099 *
4100 * RETURNS
4101 * Success: S_OK.
4102 * Failure: HRESULT code.
4103 *
4104 * SEE ALSO
4105 * CoQueryProxyBlanket, CoCopyProxy.
4106 */
4107 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4108 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4109 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4110 {
4111 IClientSecurity *pCliSec;
4112 HRESULT hr;
4113
4114 TRACE("%p\n", pProxy);
4115
4116 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4117 if (SUCCEEDED(hr))
4118 {
4119 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4120 AuthzSvc, pServerPrincName,
4121 AuthnLevel, ImpLevel, pAuthInfo,
4122 Capabilities);
4123 IClientSecurity_Release(pCliSec);
4124 }
4125
4126 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4127 return hr;
4128 }
4129
4130 /***********************************************************************
4131 * CoCopyProxy [OLE32.@]
4132 *
4133 * Copies a proxy.
4134 *
4135 * PARAMS
4136 * pProxy [I] Pointer to the proxy object.
4137 * ppCopy [O] Copy of the proxy.
4138 *
4139 * RETURNS
4140 * Success: S_OK.
4141 * Failure: HRESULT code.
4142 *
4143 * SEE ALSO
4144 * CoQueryProxyBlanket, CoSetProxyBlanket.
4145 */
4146 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4147 {
4148 IClientSecurity *pCliSec;
4149 HRESULT hr;
4150
4151 TRACE("%p\n", pProxy);
4152
4153 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4154 if (SUCCEEDED(hr))
4155 {
4156 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4157 IClientSecurity_Release(pCliSec);
4158 }
4159
4160 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4161 return hr;
4162 }
4163
4164
4165 /***********************************************************************
4166 * CoGetCallContext [OLE32.@]
4167 *
4168 * Gets the context of the currently executing server call in the current
4169 * thread.
4170 *
4171 * PARAMS
4172 * riid [I] Context interface to return.
4173 * ppv [O] Pointer to memory that will receive the context on return.
4174 *
4175 * RETURNS
4176 * Success: S_OK.
4177 * Failure: HRESULT code.
4178 */
4179 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4180 {
4181 struct oletls *info = COM_CurrentInfo();
4182
4183 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4184
4185 if (!info)
4186 return E_OUTOFMEMORY;
4187
4188 if (!info->call_state)
4189 return RPC_E_CALL_COMPLETE;
4190
4191 return IUnknown_QueryInterface(info->call_state, riid, ppv);
4192 }
4193
4194 /***********************************************************************
4195 * CoSwitchCallContext [OLE32.@]
4196 *
4197 * Switches the context of the currently executing server call in the current
4198 * thread.
4199 *
4200 * PARAMS
4201 * pObject [I] Pointer to new context object
4202 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4203 *
4204 * RETURNS
4205 * Success: S_OK.
4206 * Failure: HRESULT code.
4207 */
4208 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4209 {
4210 struct oletls *info = COM_CurrentInfo();
4211
4212 TRACE("(%p, %p)\n", pObject, ppOldObject);
4213
4214 if (!info)
4215 return E_OUTOFMEMORY;
4216
4217 *ppOldObject = info->call_state;
4218 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4219
4220 return S_OK;
4221 }
4222
4223 /***********************************************************************
4224 * CoQueryClientBlanket [OLE32.@]
4225 *
4226 * Retrieves the authentication information about the client of the currently
4227 * executing server call in the current thread.
4228 *
4229 * PARAMS
4230 * pAuthnSvc [O] Optional. The type of authentication service.
4231 * pAuthzSvc [O] Optional. The type of authorization service.
4232 * pServerPrincName [O] Optional. The server prinicple name.
4233 * pAuthnLevel [O] Optional. The authentication level.
4234 * pImpLevel [O] Optional. The impersonation level.
4235 * pPrivs [O] Optional. Information about the privileges of the client.
4236 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4237 *
4238 * RETURNS
4239 * Success: S_OK.
4240 * Failure: HRESULT code.
4241 *
4242 * SEE ALSO
4243 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4244 */
4245 HRESULT WINAPI CoQueryClientBlanket(
4246 DWORD *pAuthnSvc,
4247 DWORD *pAuthzSvc,
4248 OLECHAR **pServerPrincName,
4249 DWORD *pAuthnLevel,
4250 DWORD *pImpLevel,
4251 RPC_AUTHZ_HANDLE *pPrivs,
4252 DWORD *pCapabilities)
4253 {
4254 IServerSecurity *pSrvSec;
4255 HRESULT hr;
4256
4257 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4258 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4259 pPrivs, pCapabilities);
4260
4261 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4262 if (SUCCEEDED(hr))
4263 {
4264 hr = IServerSecurity_QueryBlanket(
4265 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4266 pImpLevel, pPrivs, pCapabilities);
4267 IServerSecurity_Release(pSrvSec);
4268 }
4269
4270 return hr;
4271 }
4272
4273 /***********************************************************************
4274 * CoImpersonateClient [OLE32.@]
4275 *
4276 * Impersonates the client of the currently executing server call in the
4277 * current thread.
4278 *
4279 * PARAMS
4280 * None.
4281 *
4282 * RETURNS
4283 * Success: S_OK.
4284 * Failure: HRESULT code.
4285 *
4286 * NOTES
4287 * If this function fails then the current thread will not be impersonating
4288 * the client and all actions will take place on behalf of the server.
4289 * Therefore, it is important to check the return value from this function.
4290 *
4291 * SEE ALSO
4292 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4293 */
4294 HRESULT WINAPI CoImpersonateClient(void)
4295 {
4296 IServerSecurity *pSrvSec;
4297 HRESULT hr;
4298
4299 TRACE("\n");
4300
4301 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4302 if (SUCCEEDED(hr))
4303 {
4304 hr = IServerSecurity_ImpersonateClient(pSrvSec);
4305 IServerSecurity_Release(pSrvSec);
4306 }
4307
4308 return hr;
4309 }
4310
4311 /***********************************************************************
4312 * CoRevertToSelf [OLE32.@]
4313 *
4314 * Ends the impersonation of the client of the currently executing server
4315 * call in the current thread.
4316 *
4317 * PARAMS
4318 * None.
4319 *
4320 * RETURNS
4321 * Success: S_OK.
4322 * Failure: HRESULT code.
4323 *
4324 * SEE ALSO
4325 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4326 */
4327 HRESULT WINAPI CoRevertToSelf(void)
4328 {
4329 IServerSecurity *pSrvSec;
4330 HRESULT hr;
4331
4332 TRACE("\n");
4333
4334 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4335 if (SUCCEEDED(hr))
4336 {
4337 hr = IServerSecurity_RevertToSelf(pSrvSec);
4338 IServerSecurity_Release(pSrvSec);
4339 }
4340
4341 return hr;
4342 }
4343
4344 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4345 {
4346 /* first try to retrieve messages for incoming COM calls to the apartment window */
4347 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
4348 /* next retrieve other messages necessary for the app to remain responsive */
4349 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4350 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4351 }
4352
4353 /***********************************************************************
4354 * CoWaitForMultipleHandles [OLE32.@]
4355 *
4356 * Waits for one or more handles to become signaled.
4357 *
4358 * PARAMS
4359 * dwFlags [I] Flags. See notes.
4360 * dwTimeout [I] Timeout in milliseconds.
4361 * cHandles [I] Number of handles pointed to by pHandles.
4362 * pHandles [I] Handles to wait for.
4363 * lpdwindex [O] Index of handle that was signaled.
4364 *
4365 * RETURNS
4366 * Success: S_OK.
4367 * Failure: RPC_S_CALLPENDING on timeout.
4368 *
4369 * NOTES
4370 *
4371 * The dwFlags parameter can be zero or more of the following:
4372 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4373 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4374 *
4375 * SEE ALSO
4376 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4377 */
4378 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4379 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4380 {
4381 HRESULT hr = S_OK;
4382 DWORD start_time = GetTickCount();
4383 APARTMENT *apt = COM_CurrentApt();
4384 BOOL message_loop = apt && !apt->multi_threaded;
4385
4386 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4387 pHandles, lpdwindex);
4388
4389 while (TRUE)
4390 {
4391 DWORD now = GetTickCount();
4392 DWORD res;
4393
4394 if (now - start_time > dwTimeout)
4395 {
4396 hr = RPC_S_CALLPENDING;
4397 break;
4398 }
4399
4400 if (message_loop)
4401 {
4402 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4403 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4404
4405 TRACE("waiting for rpc completion or window message\n");
4406
4407 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4408 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4409 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4410
4411 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4412 {
4413 MSG msg;
4414 int count = 0;
4415
4416 /* call message filter */
4417
4418 if (COM_CurrentApt()->filter)
4419 {
4420 PENDINGTYPE pendingtype =
4421 COM_CurrentInfo()->pending_call_count_server ?
4422 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4423 DWORD be_handled = IMessageFilter_MessagePending(
4424 COM_CurrentApt()->filter, 0 /* FIXME */,
4425 now - start_time, pendingtype);
4426 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4427 switch (be_handled)
4428 {
4429 case PENDINGMSG_CANCELCALL:
4430 WARN("call canceled\n");
4431 hr = RPC_E_CALL_CANCELED;
4432 break;
4433 case PENDINGMSG_WAITNOPROCESS:
4434 case PENDINGMSG_WAITDEFPROCESS:
4435 default:
4436 /* FIXME: MSDN is very vague about the difference
4437 * between WAITNOPROCESS and WAITDEFPROCESS - there
4438 * appears to be none, so it is possibly a left-over
4439 * from the 16-bit world. */
4440 break;
4441 }
4442 }
4443
4444 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4445 * so after processing 100 messages we go back to checking the wait handles */
4446 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4447 {
4448 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4449 TranslateMessage(&msg);
4450 DispatchMessageW(&msg);
4451 if (msg.message == WM_QUIT)
4452 {
4453 TRACE("resending WM_QUIT to outer message loop\n");
4454 PostQuitMessage(msg.wParam);
4455 /* no longer need to process messages */
4456 message_loop = FALSE;
4457 break;
4458 }
4459 }
4460 continue;
4461 }
4462 }
4463 else
4464 {
4465 TRACE("waiting for rpc completion\n");
4466
4467 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4468 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4469 (dwFlags & COWAIT_ALERTABLE) != 0);
4470 }
4471
4472 switch (res)
4473 {
4474 case WAIT_TIMEOUT:
4475 hr = RPC_S_CALLPENDING;
4476 break;
4477 case WAIT_FAILED:
4478 hr = HRESULT_FROM_WIN32( GetLastError() );
4479 break;
4480 default:
4481 *lpdwindex = res;
4482 break;
4483 }
4484 break;
4485 }
4486 TRACE("-- 0x%08x\n", hr);
4487 return hr;
4488 }
4489
4490
4491 /***********************************************************************
4492 * CoGetObject [OLE32.@]
4493 *
4494 * Gets the object named by converting the name to a moniker and binding to it.
4495 *
4496 * PARAMS
4497 * pszName [I] String representing the object.
4498 * pBindOptions [I] Parameters affecting the binding to the named object.
4499 * riid [I] Interface to bind to on the objecct.
4500 * ppv [O] On output, the interface riid of the object represented
4501 * by pszName.
4502 *
4503 * RETURNS
4504 * Success: S_OK.
4505 * Failure: HRESULT code.
4506 *
4507 * SEE ALSO
4508 * MkParseDisplayName.
4509 */
4510 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4511 REFIID riid, void **ppv)
4512 {
4513 IBindCtx *pbc;
4514 HRESULT hr;
4515
4516 *ppv = NULL;
4517
4518 hr = CreateBindCtx(0, &pbc);
4519 if (SUCCEEDED(hr))
4520 {
4521 if (pBindOptions)
4522 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4523
4524 if (SUCCEEDED(hr))
4525 {
4526 ULONG chEaten;
4527 IMoniker *pmk;
4528
4529 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4530 if (SUCCEEDED(hr))
4531 {
4532 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4533 IMoniker_Release(pmk);
4534 }
4535 }
4536
4537 IBindCtx_Release(pbc);
4538 }
4539 return hr;
4540 }
4541
4542 /***********************************************************************
4543 * CoRegisterChannelHook [OLE32.@]
4544 *
4545 * Registers a process-wide hook that is called during ORPC calls.
4546 *
4547 * PARAMS
4548 * guidExtension [I] GUID of the channel hook to register.
4549 * pChannelHook [I] Channel hook object to register.
4550 *
4551 * RETURNS
4552 * Success: S_OK.
4553 * Failure: HRESULT code.
4554 */
4555 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4556 {
4557 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4558
4559 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4560 }
4561
4562 typedef struct Context
4563 {
4564 IComThreadingInfo IComThreadingInfo_iface;
4565 IContextCallback IContextCallback_iface;
4566 IObjContext IObjContext_iface;
4567 LONG refs;
4568 APTTYPE apttype;
4569 } Context;
4570
4571 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4572 {
4573 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4574 }
4575
4576 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4577 {
4578 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4579 }
4580
4581 static inline Context *impl_from_IObjContext( IObjContext *iface )
4582 {
4583 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4584 }
4585
4586 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4587 {
4588 *ppv = NULL;
4589
4590 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4591 IsEqualIID(riid, &IID_IUnknown))
4592 {
4593 *ppv = &iface->IComThreadingInfo_iface;
4594 }
4595 else if (IsEqualIID(riid, &IID_IContextCallback))
4596 {
4597 *ppv = &iface->IContextCallback_iface;
4598 }
4599 else if (IsEqualIID(riid, &IID_IObjContext))
4600 {
4601 *ppv = &iface->IObjContext_iface;
4602 }
4603
4604 if (*ppv)
4605 {
4606 IUnknown_AddRef((IUnknown*)*ppv);
4607 return S_OK;
4608 }
4609
4610 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4611 return E_NOINTERFACE;
4612 }
4613
4614 static ULONG Context_AddRef(Context *This)
4615 {
4616 return InterlockedIncrement(&This->refs);
4617 }
4618
4619 static ULONG Context_Release(Context *This)
4620 {
4621 ULONG refs = InterlockedDecrement(&This->refs);
4622 if (!refs)
4623 HeapFree(GetProcessHeap(), 0, This);
4624 return refs;
4625 }
4626
4627 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4628 {
4629 Context *This = impl_from_IComThreadingInfo(iface);
4630 return Context_QueryInterface(This, riid, ppv);
4631 }
4632
4633 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4634 {
4635 Context *This = impl_from_IComThreadingInfo(iface);
4636 return Context_AddRef(This);
4637 }
4638
4639 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4640 {
4641 Context *This = impl_from_IComThreadingInfo(iface);
4642 return Context_Release(This);
4643 }
4644
4645 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4646 {
4647 Context *This = impl_from_IComThreadingInfo(iface);
4648
4649 TRACE("(%p)\n", apttype);
4650
4651 *apttype = This->apttype;
4652 return S_OK;
4653 }
4654
4655 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4656 {
4657 Context *This = impl_from_IComThreadingInfo(iface);
4658
4659 TRACE("(%p)\n", thdtype);
4660
4661 switch (This->apttype)
4662 {
4663 case APTTYPE_STA:
4664 case APTTYPE_MAINSTA:
4665 *thdtype = THDTYPE_PROCESSMESSAGES;
4666 break;
4667 default:
4668 *thdtype = THDTYPE_BLOCKMESSAGES;
4669 break;
4670 }
4671 return S_OK;
4672 }
4673
4674 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4675 {
4676 FIXME("(%p): stub\n", logical_thread_id);
4677 return E_NOTIMPL;
4678 }
4679
4680 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4681 {
4682 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4683 return E_NOTIMPL;
4684 }
4685
4686 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4687 {
4688 Context_CTI_QueryInterface,
4689 Context_CTI_AddRef,
4690 Context_CTI_Release,
4691 Context_CTI_GetCurrentApartmentType,
4692 Context_CTI_GetCurrentThreadType,
4693 Context_CTI_GetCurrentLogicalThreadId,
4694 Context_CTI_SetCurrentLogicalThreadId
4695 };
4696
4697 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4698 {
4699 Context *This = impl_from_IContextCallback(iface);
4700 return Context_QueryInterface(This, riid, ppv);
4701 }
4702
4703 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4704 {
4705 Context *This = impl_from_IContextCallback(iface);
4706 return Context_AddRef(This);
4707 }
4708
4709 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4710 {
4711 Context *This = impl_from_IContextCallback(iface);
4712 return Context_Release(This);
4713 }
4714
4715 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4716 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4717 {
4718 Context *This = impl_from_IContextCallback(iface);
4719
4720 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4721 return E_NOTIMPL;
4722 }
4723
4724 static const IContextCallbackVtbl Context_Callback_Vtbl =
4725 {
4726 Context_CC_QueryInterface,
4727 Context_CC_AddRef,
4728 Context_CC_Release,
4729 Context_CC_ContextCallback
4730 };
4731
4732 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4733 {
4734 Context *This = impl_from_IObjContext(iface);
4735 return Context_QueryInterface(This, riid, ppv);
4736 }
4737
4738 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4739 {
4740 Context *This = impl_from_IObjContext(iface);
4741 return Context_AddRef(This);
4742 }
4743
4744 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4745 {
4746 Context *This = impl_from_IObjContext(iface);
4747 return Context_Release(This);
4748 }
4749
4750 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4751 {
4752 Context *This = impl_from_IObjContext(iface);
4753
4754 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4755 return E_NOTIMPL;
4756 }
4757
4758 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4759 {
4760 Context *This = impl_from_IObjContext(iface);
4761
4762 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4763 return E_NOTIMPL;
4764 }
4765
4766 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4767 {
4768 Context *This = impl_from_IObjContext(iface);
4769
4770 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4771 return E_NOTIMPL;
4772 }
4773
4774 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4775 {
4776 Context *This = impl_from_IObjContext(iface);
4777
4778 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4779 return E_NOTIMPL;
4780 }
4781
4782 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4783 {
4784 Context *This = impl_from_IObjContext(iface);
4785 FIXME("(%p/%p)\n", This, iface);
4786 }
4787
4788 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4789 {
4790 Context *This = impl_from_IObjContext(iface);
4791 FIXME("(%p/%p)\n", This, iface);
4792 }
4793
4794 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4795 {
4796 Context *This = impl_from_IObjContext(iface);
4797 FIXME("(%p/%p)\n", This, iface);
4798 }
4799
4800 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4801 {
4802 Context *This = impl_from_IObjContext(iface);
4803 FIXME("(%p/%p)\n", This, iface);
4804 }
4805
4806 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4807 {
4808 Context *This = impl_from_IObjContext(iface);
4809 FIXME("(%p/%p)\n", This, iface);
4810 }
4811
4812 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4813 {
4814 Context *This = impl_from_IObjContext(iface);
4815 FIXME("(%p/%p)\n", This, iface);
4816 }
4817
4818 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4819 {
4820 Context *This = impl_from_IObjContext(iface);
4821 FIXME("(%p/%p)\n", This, iface);
4822 }
4823
4824 static const IObjContextVtbl Context_Object_Vtbl =
4825 {
4826 Context_OC_QueryInterface,
4827 Context_OC_AddRef,
4828 Context_OC_Release,
4829 Context_OC_SetProperty,
4830 Context_OC_RemoveProperty,
4831 Context_OC_GetProperty,
4832 Context_OC_EnumContextProps,
4833 Context_OC_Reserved1,
4834 Context_OC_Reserved2,
4835 Context_OC_Reserved3,
4836 Context_OC_Reserved4,
4837 Context_OC_Reserved5,
4838 Context_OC_Reserved6,
4839 Context_OC_Reserved7
4840 };
4841
4842 /***********************************************************************
4843 * CoGetObjectContext [OLE32.@]
4844 *
4845 * Retrieves an object associated with the current context (i.e. apartment).
4846 *
4847 * PARAMS
4848 * riid [I] ID of the interface of the object to retrieve.
4849 * ppv [O] Address where object will be stored on return.
4850 *
4851 * RETURNS
4852 * Success: S_OK.
4853 * Failure: HRESULT code.
4854 */
4855 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4856 {
4857 APARTMENT *apt = COM_CurrentApt();
4858 Context *context;
4859 HRESULT hr;
4860
4861 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4862
4863 *ppv = NULL;
4864 if (!apt)
4865 {
4866 if (!(apt = apartment_find_multi_threaded()))
4867 {
4868 ERR("apartment not initialised\n");
4869 return CO_E_NOTINITIALIZED;
4870 }
4871 apartment_release(apt);
4872 }
4873
4874 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4875 if (!context)
4876 return E_OUTOFMEMORY;
4877
4878 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4879 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4880 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4881 context->refs = 1;
4882 if (apt->multi_threaded)
4883 context->apttype = APTTYPE_MTA;
4884 else if (apt->main)
4885 context->apttype = APTTYPE_MAINSTA;
4886 else
4887 context->apttype = APTTYPE_STA;
4888
4889 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4890 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4891
4892 return hr;
4893 }
4894
4895
4896 /***********************************************************************
4897 * CoGetContextToken [OLE32.@]
4898 */
4899 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4900 {
4901 struct oletls *info = COM_CurrentInfo();
4902
4903 TRACE("(%p)\n", token);
4904
4905 if (!info)
4906 return E_OUTOFMEMORY;
4907
4908 if (!info->apt)
4909 {
4910 APARTMENT *apt;
4911 if (!(apt = apartment_find_multi_threaded()))
4912 {
4913 ERR("apartment not initialised\n");
4914 return CO_E_NOTINITIALIZED;
4915 }
4916 apartment_release(apt);
4917 }
4918
4919 if (!token)
4920 return E_POINTER;
4921
4922 if (!info->context_token)
4923 {
4924 HRESULT hr;
4925 IObjContext *ctx;
4926
4927 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4928 if (FAILED(hr)) return hr;
4929 info->context_token = ctx;
4930 }
4931
4932 *token = (ULONG_PTR)info->context_token;
4933 TRACE("apt->context_token=%p\n", info->context_token);
4934
4935 return S_OK;
4936 }
4937
4938 /***********************************************************************
4939 * CoGetDefaultContext [OLE32.@]
4940 */
4941 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
4942 {
4943 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
4944 return E_NOINTERFACE;
4945 }
4946
4947 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4948 {
4949 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4950 HKEY hkey;
4951 HRESULT hres;
4952
4953 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4954 if (SUCCEEDED(hres))
4955 {
4956 struct class_reg_data regdata;
4957 WCHAR dllpath[MAX_PATH+1];
4958
4959 regdata.u.hkey = hkey;
4960 regdata.hkey = TRUE;
4961
4962 if (COM_RegReadPath(&regdata, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4963 {
4964 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4965 if (!strcmpiW(dllpath, wszOle32))
4966 {
4967 RegCloseKey(hkey);
4968 return HandlerCF_Create(rclsid, riid, ppv);
4969 }
4970 }
4971 else
4972 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4973 RegCloseKey(hkey);
4974 }
4975
4976 return CLASS_E_CLASSNOTAVAILABLE;
4977 }
4978
4979 /***********************************************************************
4980 * DllMain (OLE32.@)
4981 */
4982 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
4983 {
4984 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
4985
4986 switch(fdwReason) {
4987 case DLL_PROCESS_ATTACH:
4988 hProxyDll = hinstDLL;
4989 COMPOBJ_InitProcess();
4990 break;
4991
4992 case DLL_PROCESS_DETACH:
4993 if (reserved) break;
4994 release_std_git();
4995 COMPOBJ_UninitProcess();
4996 RPC_UnregisterAllChannelHooks();
4997 COMPOBJ_DllList_Free();
4998 DeleteCriticalSection(&csRegisteredClassList);
4999 DeleteCriticalSection(&csApartment);
5000 break;
5001
5002 case DLL_THREAD_DETACH:
5003 COM_TlsDestroy();
5004 break;
5005 }
5006 return TRUE;
5007 }
5008
5009 /***********************************************************************
5010 * DllRegisterServer (OLE32.@)
5011 */
5012 HRESULT WINAPI DllRegisterServer(void)
5013 {
5014 return OLE32_DllRegisterServer();
5015 }
5016
5017 /***********************************************************************
5018 * DllUnregisterServer (OLE32.@)
5019 */
5020 HRESULT WINAPI DllUnregisterServer(void)
5021 {
5022 return OLE32_DllUnregisterServer();
5023 }