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