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