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