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