~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/ole32/compobj.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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