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