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