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