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