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