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