Rewrote FindMimeFromData to pass tests.
[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  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  * Note
26  * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
27  *    Therefore do not test against COINIT_MULTITHREADED
28  *
29  * TODO list:           (items bunched together depend on each other)
30  *
31  *   - Implement the service control manager (in rpcss) to keep track
32  *     of registered class objects: ISCM::ServerRegisterClsid et al
33  *   - Implement the OXID resolver so we don't need magic endpoint names for
34  *     clients and servers to meet up
35  *
36  *   - Pump the message loop during RPC calls.
37  *   - Call IMessageFilter functions.
38  *
39  *   - Make all ole interface marshaling use NDR to be wire compatible with
40  *     native DCOM
41  *   - Use & interpret ORPCTHIS & ORPCTHAT.
42  *
43  */
44
45 #include "config.h"
46
47 #include <stdlib.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <assert.h>
52
53 #define COBJMACROS
54 #define NONAMELESSUNION
55 #define NONAMELESSSTRUCT
56
57 #include "windef.h"
58 #include "winbase.h"
59 #include "winuser.h"
60 #include "objbase.h"
61 #include "ole2.h"
62 #include "ole2ver.h"
63 #include "rpc.h"
64 #include "winerror.h"
65 #include "winreg.h"
66 #include "wownt32.h"
67 #include "wine/unicode.h"
68 #include "objbase.h"
69 #include "compobj_private.h"
70
71 #include "wine/debug.h"
72
73 WINE_DEFAULT_DEBUG_CHANNEL(ole);
74
75 typedef LPCSTR LPCOLESTR16;
76
77 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
78
79 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
80
81 /****************************************************************************
82  * This section defines variables internal to the COM module.
83  *
84  * TODO: Most of these things will have to be made thread-safe.
85  */
86
87 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN*  ppUnk);
88 static void COM_RevokeAllClasses(void);
89
90 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
91
92 APARTMENT *MTA; /* protected by csApartment */
93 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
94
95 static CRITICAL_SECTION csApartment;
96 static CRITICAL_SECTION_DEBUG critsect_debug =
97 {
98     0, 0, &csApartment,
99     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
100       0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
101 };
102 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
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 */
219 static APARTMENT *apartment_construct(DWORD model)
220 {
221     APARTMENT *apt;
222
223     TRACE("creating new apartment, model=%ld\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     apt->ipidc = 0;
231     apt->refs = 1;
232     apt->remunk_exported = FALSE;
233     apt->oidc = 1;
234     InitializeCriticalSection(&apt->cs);
235     DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
236
237     apt->model = model;
238
239     if (model & COINIT_APARTMENTTHREADED)
240     {
241         /* FIXME: should be randomly generated by in an RPC call to rpcss */
242         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
243         apt->win = CreateWindowW(wszAptWinClass, NULL, 0,
244                                  0, 0, 0, 0,
245                                  0, 0, OLE32_hInstance, NULL);
246     }
247     else
248     {
249         /* FIXME: should be randomly generated by in an RPC call to rpcss */
250         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
251     }
252
253     TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
254
255     /* the locking here is not currently needed for the MTA case, but it
256      * doesn't hurt and makes the code simpler */
257     EnterCriticalSection(&csApartment);
258     list_add_head(&apts, &apt->entry);
259     LeaveCriticalSection(&csApartment);
260
261     return apt;
262 }
263
264 /* gets and existing apartment if one exists or otherwise creates an apartment
265  * structure which stores OLE apartment-local information and stores a pointer
266  * to it in the thread-local storage */
267 static APARTMENT *apartment_get_or_create(DWORD model)
268 {
269     APARTMENT *apt = COM_CurrentApt();
270
271     if (!apt)
272     {
273         if (model & COINIT_APARTMENTTHREADED)
274         {
275             apt = apartment_construct(model);
276             COM_CurrentInfo()->apt = apt;
277         }
278         else
279         {
280             EnterCriticalSection(&csApartment);
281
282             /* The multi-threaded apartment (MTA) contains zero or more threads interacting
283              * with free threaded (ie thread safe) COM objects. There is only ever one MTA
284              * in a process */
285             if (MTA)
286             {
287                 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
288                 apartment_addref(MTA);
289             }
290             else
291                 MTA = apartment_construct(model);
292
293             apt = MTA;
294             COM_CurrentInfo()->apt = apt;
295
296             LeaveCriticalSection(&csApartment);
297         }
298     }
299
300     return apt;
301 }
302
303 DWORD apartment_addref(struct apartment *apt)
304 {
305     DWORD refs = InterlockedIncrement(&apt->refs);
306     TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
307     return refs;
308 }
309
310 DWORD apartment_release(struct apartment *apt)
311 {
312     DWORD ret;
313
314     EnterCriticalSection(&csApartment);
315
316     ret = InterlockedDecrement(&apt->refs);
317     TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
318     /* destruction stuff that needs to happen under csApartment CS */
319     if (ret == 0)
320     {
321         if (apt == MTA) MTA = NULL;
322         list_remove(&apt->entry);
323     }
324
325     LeaveCriticalSection(&csApartment);
326
327     if (ret == 0)
328     {
329         struct list *cursor, *cursor2;
330
331         TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
332
333         /* no locking is needed for this apartment, because no other thread
334          * can access it at this point */
335
336         apartment_disconnectproxies(apt);
337
338         if (apt->win) DestroyWindow(apt->win);
339
340         LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
341         {
342             struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
343             /* release the implicit reference given by the fact that the
344              * stub has external references (it must do since it is in the
345              * stub manager list in the apartment and all non-apartment users
346              * must have a ref on the apartment and so it cannot be destroyed).
347              */
348             stub_manager_int_release(stubmgr);
349         }
350
351         /* if this assert fires, then another thread took a reference to a
352          * stub manager without taking a reference to the containing
353          * apartment, which it must do. */
354         assert(list_empty(&apt->stubmgrs));
355
356         if (apt->filter) IUnknown_Release(apt->filter);
357
358         DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
359         DeleteCriticalSection(&apt->cs);
360
361         HeapFree(GetProcessHeap(), 0, apt);
362     }
363
364     return ret;
365 }
366
367 /* The given OXID must be local to this process: 
368  *
369  * The ref parameter is here mostly to ensure people remember that
370  * they get one, you should normally take a ref for thread safety.
371  */
372 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
373 {
374     APARTMENT *result = NULL;
375     struct list *cursor;
376
377     EnterCriticalSection(&csApartment);
378     LIST_FOR_EACH( cursor, &apts )
379     {
380         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
381         if (apt->oxid == oxid)
382         {
383             result = apt;
384             if (ref) apartment_addref(result);
385             break;
386         }
387     }
388     LeaveCriticalSection(&csApartment);
389
390     return result;
391 }
392
393 /* gets the apartment which has a given creator thread ID. The caller must
394  * release the reference from the apartment as soon as the apartment pointer
395  * is no longer required. */
396 APARTMENT *apartment_findfromtid(DWORD tid)
397 {
398     APARTMENT *result = NULL;
399     struct list *cursor;
400
401     EnterCriticalSection(&csApartment);
402     LIST_FOR_EACH( cursor, &apts )
403     {
404         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
405         if (apt->tid == tid)
406         {
407             result = apt;
408             apartment_addref(result);
409             break;
410         }
411     }
412     LeaveCriticalSection(&csApartment);
413
414     return result;
415 }
416
417 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
418 {
419     switch (msg)
420     {
421     case DM_EXECUTERPC:
422         return RPC_ExecuteCall((struct dispatch_params *)lParam);
423     default:
424         return DefWindowProcW(hWnd, msg, wParam, lParam);
425     }
426 }
427
428 /*****************************************************************************
429  * This section contains OpenDllList implemantation
430  */
431
432 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
433 {
434     OpenDll *ptr;
435     OpenDll *tmp;
436
437     TRACE("\n");
438
439     EnterCriticalSection( &csOpenDllList );
440
441     if (openDllList == NULL) {
442         /* empty list -- add first node */
443         openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
444         openDllList->hLibrary=hLibrary;
445         openDllList->next = NULL;
446     } else {
447         /* search for this dll */
448         int found = FALSE;
449         for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
450             if (ptr->hLibrary == hLibrary) {
451                 found = TRUE;
452                 break;
453             }
454         }
455         if (!found) {
456             /* dll not found, add it */
457             tmp = openDllList;
458             openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
459             openDllList->hLibrary = hLibrary;
460             openDllList->next = tmp;
461         }
462     }
463
464     LeaveCriticalSection( &csOpenDllList );
465 }
466
467 static void COMPOBJ_DllList_FreeUnused(int Timeout)
468 {
469     OpenDll *curr, *next, *prev = NULL;
470     typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
471     DllCanUnloadNowFunc DllCanUnloadNow;
472
473     TRACE("\n");
474
475     EnterCriticalSection( &csOpenDllList );
476
477     for (curr = openDllList; curr != NULL; ) {
478         DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
479
480         if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
481             next = curr->next;
482
483             TRACE("freeing %p\n", curr->hLibrary);
484             FreeLibrary(curr->hLibrary);
485
486             HeapFree(GetProcessHeap(), 0, curr);
487             if (curr == openDllList) {
488                 openDllList = next;
489             } else {
490               prev->next = next;
491             }
492
493             curr = next;
494         } else {
495             prev = curr;
496             curr = curr->next;
497         }
498     }
499
500     LeaveCriticalSection( &csOpenDllList );
501 }
502
503 /******************************************************************************
504  *           CoBuildVersion [OLE32.@]
505  *           CoBuildVersion [COMPOBJ.1]
506  *
507  * Gets the build version of the DLL.
508  *
509  * PARAMS
510  *
511  * RETURNS
512  *      Current build version, hiword is majornumber, loword is minornumber
513  */
514 DWORD WINAPI CoBuildVersion(void)
515 {
516     TRACE("Returning version %d, build %d.\n", rmm, rup);
517     return (rmm<<16)+rup;
518 }
519
520 /******************************************************************************
521  *              CoInitialize    [OLE32.@]
522  *
523  * Initializes the COM libraries by calling CoInitializeEx with
524  * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
525  *
526  * PARAMS
527  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
528  *
529  * RETURNS
530  *  Success: S_OK if not already initialized, S_FALSE otherwise.
531  *  Failure: HRESULT code.
532  *
533  * SEE ALSO
534  *   CoInitializeEx
535  */
536 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
537 {
538   /*
539    * Just delegate to the newer method.
540    */
541   return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
542 }
543
544 /******************************************************************************
545  *              CoInitializeEx  [OLE32.@]
546  *
547  * Initializes the COM libraries.
548  *
549  * PARAMS
550  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
551  *  dwCoInit   [I] One or more flags from the COINIT enumeration. See notes.
552  *
553  * RETURNS
554  *  S_OK               if successful,
555  *  S_FALSE            if this function was called already.
556  *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
557  *                     threading model.
558  *
559  * NOTES
560  *
561  * The behavior used to set the IMalloc used for memory management is
562  * obsolete.
563  * The dwCoInit parameter must specify of of the following apartment
564  * threading models:
565  *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
566  *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
567  * The parameter may also specify zero or more of the following flags:
568  *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
569  *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
570  *
571  * SEE ALSO
572  *   CoUninitialize
573  */
574 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
575 {
576   HRESULT hr = S_OK;
577   APARTMENT *apt;
578
579   TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
580
581   if (lpReserved!=NULL)
582   {
583     ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
584   }
585
586   /*
587    * Check the lock count. If this is the first time going through the initialize
588    * process, we have to initialize the libraries.
589    *
590    * And crank-up that lock count.
591    */
592   if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
593   {
594     /*
595      * Initialize the various COM libraries and data structures.
596      */
597     TRACE("() - Initializing the COM libraries\n");
598
599     /* we may need to defer this until after apartment initialisation */
600     RunningObjectTableImpl_Initialize();
601   }
602
603   if (!(apt = COM_CurrentInfo()->apt))
604   {
605     apt = apartment_get_or_create(dwCoInit);
606     if (!apt) return E_OUTOFMEMORY;
607   }
608   else if (dwCoInit != apt->model)
609   {
610     /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
611        code then we are probably using the wrong threading model to implement that API. */
612     ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
613     return RPC_E_CHANGED_MODE;
614   }
615   else
616     hr = S_FALSE;
617
618   COM_CurrentInfo()->inits++;
619
620   return hr;
621 }
622
623 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
624    pending RPCs are ignored. Non-COM messages are discarded at this point.
625  */
626 static void COM_FlushMessageQueue(void)
627 {
628     MSG message;
629     APARTMENT *apt = COM_CurrentApt();
630
631     if (!apt || !apt->win) return;
632
633     TRACE("Flushing STA message queue\n");
634
635     while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
636     {
637         if (message.hwnd != apt->win)
638         {
639             WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
640             continue;
641         }
642
643         TranslateMessage(&message);
644         DispatchMessageA(&message);
645     }
646 }
647
648 /***********************************************************************
649  *           CoUninitialize   [OLE32.@]
650  *
651  * This method will decrement the refcount on the current apartment, freeing
652  * the resources associated with it if it is the last thread in the apartment.
653  * If the last apartment is freed, the function will additionally release
654  * any COM resources associated with the process.
655  *
656  * PARAMS
657  *
658  * RETURNS
659  *  Nothing.
660  *
661  * SEE ALSO
662  *   CoInitializeEx
663  */
664 void WINAPI CoUninitialize(void)
665 {
666   struct oletls * info = COM_CurrentInfo();
667   LONG lCOMRefCnt;
668
669   TRACE("()\n");
670
671   /* will only happen on OOM */
672   if (!info) return;
673
674   /* sanity check */
675   if (!info->inits)
676   {
677     ERR("Mismatched CoUninitialize\n");
678     return;
679   }
680
681   if (!--info->inits)
682   {
683     apartment_release(info->apt);
684     info->apt = NULL;
685   }
686
687   /*
688    * Decrease the reference count.
689    * If we are back to 0 locks on the COM library, make sure we free
690    * all the associated data structures.
691    */
692   lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
693   if (lCOMRefCnt==1)
694   {
695     TRACE("() - Releasing the COM libraries\n");
696
697     RunningObjectTableImpl_UnInitialize();
698
699     /* Release the references to the registered class objects */
700     COM_RevokeAllClasses();
701
702     /* This will free the loaded COM Dlls  */
703     CoFreeAllLibraries();
704
705     /* This ensures we deal with any pending RPCs */
706     COM_FlushMessageQueue();
707   }
708   else if (lCOMRefCnt<1) {
709     ERR( "CoUninitialize() - not CoInitialized.\n" );
710     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
711   }
712 }
713
714 /******************************************************************************
715  *              CoDisconnectObject      [OLE32.@]
716  *              CoDisconnectObject      [COMPOBJ.15]
717  *
718  * Disconnects all connections to this object from remote processes. Dispatches
719  * pending RPCs while blocking new RPCs from occurring, and then calls
720  * IMarshal::DisconnectObject on the given object.
721  *
722  * Typically called when the object server is forced to shut down, for instance by
723  * the user.
724  *
725  * PARAMS
726  *  lpUnk    [I] The object whose stub should be disconnected.
727  *  reserved [I] Reserved. Should be set to 0.
728  *
729  * RETURNS
730  *  Success: S_OK.
731  *  Failure: HRESULT code.
732  *
733  * SEE ALSO
734  *  CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
735  */
736 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
737 {
738     HRESULT hr;
739     IMarshal *marshal;
740     APARTMENT *apt;
741
742     TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
743
744     hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
745     if (hr == S_OK)
746     {
747         hr = IMarshal_DisconnectObject(marshal, reserved);
748         IMarshal_Release(marshal);
749         return hr;
750     }
751
752     apt = COM_CurrentApt();
753     if (!apt)
754         return CO_E_NOTINITIALIZED;
755
756     apartment_disconnectobject(apt, lpUnk);
757
758     /* Note: native is pretty broken here because it just silently
759      * fails, without returning an appropriate error code if the object was
760      * not found, making apps think that the object was disconnected, when
761      * it actually wasn't */
762
763     return S_OK;
764 }
765
766 /******************************************************************************
767  *              CoCreateGuid [OLE32.@]
768  *
769  * Simply forwards to UuidCreate in RPCRT4.
770  *
771  * PARAMS
772  *  pguid [O] Points to the GUID to initialize.
773  *
774  * RETURNS
775  *  Success: S_OK.
776  *  Failure: HRESULT code.
777  *
778  * SEE ALSO
779  *   UuidCreate
780  */
781 HRESULT WINAPI CoCreateGuid(GUID *pguid)
782 {
783     return UuidCreate(pguid);
784 }
785
786 /******************************************************************************
787  *              CLSIDFromString [OLE32.@]
788  *              IIDFromString   [OLE32.@]
789  *
790  * Converts a unique identifier from its string representation into
791  * the GUID struct.
792  *
793  * PARAMS
794  *  idstr [I] The string representation of the GUID.
795  *  id    [O] GUID converted from the string.
796  *
797  * RETURNS
798  *   S_OK on success
799  *   CO_E_CLASSSTRING if idstr is not a valid CLSID
800  *
801  * BUGS
802  *
803  * In Windows, if idstr is not a valid CLSID string then it gets
804  * treated as a ProgID. Wine currently doesn't do this. If idstr is
805  * NULL it's treated as an all-zero GUID.
806  *
807  * SEE ALSO
808  *  StringFromCLSID
809  */
810 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
811 {
812   const BYTE *s;
813   int   i;
814   BYTE table[256];
815
816   if (!idstr) {
817     memset( id, 0, sizeof (CLSID) );
818     return S_OK;
819   }
820
821   /* validate the CLSID string */
822   if (strlen(idstr) != 38)
823     return CO_E_CLASSSTRING;
824
825   s = (const BYTE *) idstr;
826   if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
827     return CO_E_CLASSSTRING;
828
829   for (i=1; i<37; i++) {
830     if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
831     if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
832           ((s[i] >= 'a') && (s[i] <= 'f'))  ||
833           ((s[i] >= 'A') && (s[i] <= 'F'))))
834        return CO_E_CLASSSTRING;
835   }
836
837   TRACE("%s -> %p\n", s, id);
838
839   /* quick lookup table */
840   memset(table, 0, 256);
841
842   for (i = 0; i < 10; i++) {
843     table['0' + i] = i;
844   }
845   for (i = 0; i < 6; i++) {
846     table['A' + i] = i+10;
847     table['a' + i] = i+10;
848   }
849
850   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
851
852   id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
853                table[s[5]] << 12 | table[s[6]] << 8  | table[s[7]] << 4  | table[s[8]]);
854   id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
855   id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
856
857   /* these are just sequential bytes */
858   id->Data4[0] = table[s[20]] << 4 | table[s[21]];
859   id->Data4[1] = table[s[22]] << 4 | table[s[23]];
860   id->Data4[2] = table[s[25]] << 4 | table[s[26]];
861   id->Data4[3] = table[s[27]] << 4 | table[s[28]];
862   id->Data4[4] = table[s[29]] << 4 | table[s[30]];
863   id->Data4[5] = table[s[31]] << 4 | table[s[32]];
864   id->Data4[6] = table[s[33]] << 4 | table[s[34]];
865   id->Data4[7] = table[s[35]] << 4 | table[s[36]];
866
867   return S_OK;
868 }
869
870 /*****************************************************************************/
871
872 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
873 {
874     char xid[40];
875     HRESULT ret;
876
877     if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
878         return CO_E_CLASSSTRING;
879
880
881     ret = __CLSIDFromStringA(xid,id);
882     if(ret != S_OK) { /* It appears a ProgID is also valid */
883         ret = CLSIDFromProgID(idstr, id);
884     }
885     return ret;
886 }
887
888 /* Converts a GUID into the respective string representation. */
889 HRESULT WINE_StringFromCLSID(
890         const CLSID *id,        /* [in] GUID to be converted */
891         LPSTR idstr             /* [out] pointer to buffer to contain converted guid */
892 ) {
893   static const char *hex = "0123456789ABCDEF";
894   char *s;
895   int   i;
896
897   if (!id)
898         { ERR("called with id=Null\n");
899           *idstr = 0x00;
900           return E_FAIL;
901         }
902
903   sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
904           id->Data1, id->Data2, id->Data3,
905           id->Data4[0], id->Data4[1]);
906   s = &idstr[25];
907
908   /* 6 hex bytes */
909   for (i = 2; i < 8; i++) {
910     *s++ = hex[id->Data4[i]>>4];
911     *s++ = hex[id->Data4[i] & 0xf];
912   }
913
914   *s++ = '}';
915   *s++ = '\0';
916
917   TRACE("%p->%s\n", id, idstr);
918
919   return S_OK;
920 }
921
922
923 /******************************************************************************
924  *              StringFromCLSID [OLE32.@]
925  *              StringFromIID   [OLE32.@]
926  *
927  * Converts a GUID into the respective string representation.
928  * The target string is allocated using the OLE IMalloc.
929  *
930  * PARAMS
931  *  id    [I] the GUID to be converted.
932  *  idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
933  *
934  * RETURNS
935  *   S_OK
936  *   E_FAIL
937  *
938  * SEE ALSO
939  *  StringFromGUID2, CLSIDFromString
940  */
941 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
942 {
943         char            buf[80];
944         HRESULT       ret;
945         LPMALLOC        mllc;
946
947         if ((ret = CoGetMalloc(0,&mllc)))
948                 return ret;
949
950         ret=WINE_StringFromCLSID(id,buf);
951         if (!ret) {
952             DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
953             *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
954             MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
955         }
956         return ret;
957 }
958
959 /******************************************************************************
960  *              StringFromGUID2 [OLE32.@]
961  *              StringFromGUID2 [COMPOBJ.76]
962  *
963  * Modified version of StringFromCLSID that allows you to specify max
964  * buffer size.
965  *
966  * PARAMS
967  *  id   [I] GUID to convert to string.
968  *  str  [O] Buffer where the result will be stored.
969  *  cmax [I] Size of the buffer in characters.
970  *
971  * RETURNS
972  *      Success: The length of the resulting string in characters.
973  *  Failure: 0.
974  */
975 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
976 {
977   char          xguid[80];
978
979   if (WINE_StringFromCLSID(id,xguid))
980         return 0;
981   return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
982 }
983
984 /* open HKCR\\CLSID\\{string form of clsid} key */
985 DWORD COM_OpenKeyForCLSID(REFCLSID clsid, REGSAM access, HKEY *key)
986 {
987     static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
988     WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
989     strcpyW(path, wszCLSIDSlash);
990     StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
991     return RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, access, key);
992 }
993
994 /******************************************************************************
995  *               ProgIDFromCLSID [OLE32.@]
996  *
997  * Converts a class id into the respective program ID.
998  *
999  * PARAMS
1000  *  clsid        [I] Class ID, as found in registry.
1001  *  lplpszProgID [O] Associated ProgID.
1002  *
1003  * RETURNS
1004  *   S_OK
1005  *   E_OUTOFMEMORY
1006  *   REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1007  */
1008 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1009 {
1010   static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1011   HKEY     hkey = NULL;
1012   HKEY     hkey_clsid;
1013   HRESULT  ret = S_OK;
1014
1015   if (ERROR_SUCCESS != COM_OpenKeyForCLSID(clsid, KEY_READ, &hkey_clsid))
1016     ret = REGDB_E_CLASSNOTREG;
1017
1018   if (ret == S_OK)
1019   {
1020     if (RegOpenKeyExW(hkey_clsid, wszProgID, 0, KEY_READ, &hkey))
1021       ret = REGDB_E_CLASSNOTREG;
1022     RegCloseKey(hkey_clsid);
1023   }
1024
1025   if (ret == S_OK)
1026   {
1027     LONG progidlen = 0;
1028
1029     if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1030       ret = REGDB_E_CLASSNOTREG;
1031
1032     if (ret == S_OK)
1033     {
1034       *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1035       if (*lplpszProgID)
1036       {
1037         if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen))
1038           ret = REGDB_E_CLASSNOTREG;
1039       }
1040       else
1041         ret = E_OUTOFMEMORY;
1042     }
1043   }
1044
1045   RegCloseKey(hkey);
1046   return ret;
1047 }
1048
1049 /******************************************************************************
1050  *              CLSIDFromProgID [COMPOBJ.61]
1051  *
1052  * Converts a program ID into the respective GUID.
1053  *
1054  * PARAMS
1055  *  progid       [I] program id as found in registry
1056  *  riid         [O] associated CLSID
1057  *
1058  * RETURNS
1059  *      Success: S_OK
1060  *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1061  */
1062 HRESULT WINAPI CLSIDFromProgID16(LPCOLESTR16 progid, LPCLSID riid)
1063 {
1064         char    *buf,buf2[80];
1065         LONG    buf2len;
1066         HRESULT err;
1067         HKEY    xhkey;
1068
1069         buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1070         sprintf(buf,"%s\\CLSID",progid);
1071         if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1072                 HeapFree(GetProcessHeap(),0,buf);
1073                 return CO_E_CLASSSTRING;
1074         }
1075         HeapFree(GetProcessHeap(),0,buf);
1076         buf2len = sizeof(buf2);
1077         if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1078                 RegCloseKey(xhkey);
1079                 return CO_E_CLASSSTRING;
1080         }
1081         RegCloseKey(xhkey);
1082         return __CLSIDFromStringA(buf2,riid);
1083 }
1084
1085 /******************************************************************************
1086  *              CLSIDFromProgID [OLE32.@]
1087  *
1088  * Converts a program id into the respective GUID.
1089  *
1090  * PARAMS
1091  *  progid [I] Unicode program ID, as found in registry.
1092  *  riid   [O] Associated CLSID.
1093  *
1094  * RETURNS
1095  *      Success: S_OK
1096  *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1097  */
1098 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1099 {
1100     static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1101     WCHAR buf2[CHARS_IN_GUID];
1102     LONG buf2len = sizeof(buf2);
1103     HKEY xhkey;
1104
1105     WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1106     strcpyW( buf, progid );
1107     strcatW( buf, clsidW );
1108     if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1109     {
1110         HeapFree(GetProcessHeap(),0,buf);
1111         return CO_E_CLASSSTRING;
1112     }
1113     HeapFree(GetProcessHeap(),0,buf);
1114
1115     if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1116     {
1117         RegCloseKey(xhkey);
1118         return CO_E_CLASSSTRING;
1119     }
1120     RegCloseKey(xhkey);
1121     return CLSIDFromString(buf2,riid);
1122 }
1123
1124
1125
1126 /*****************************************************************************
1127  *             CoGetPSClsid [OLE32.@]
1128  *
1129  * Retrieves the CLSID of the proxy/stub factory that implements
1130  * IPSFactoryBuffer for the specified interface.
1131  *
1132  * PARAMS
1133  *  riid   [I] Interface whose proxy/stub CLSID is to be returned.
1134  *  pclsid [O] Where to store returned proxy/stub CLSID.
1135  * 
1136  * RETURNS
1137  *   S_OK
1138  *   E_OUTOFMEMORY
1139  *   REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1140  *
1141  * NOTES
1142  *
1143  * The standard marshaller activates the object with the CLSID
1144  * returned and uses the CreateProxy and CreateStub methods on its
1145  * IPSFactoryBuffer interface to construct the proxies and stubs for a
1146  * given object.
1147  *
1148  * CoGetPSClsid determines this CLSID by searching the
1149  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1150  * in the registry and any interface id registered by
1151  * CoRegisterPSClsid within the current process.
1152  *
1153  * BUGS
1154  *
1155  * We only search the registry, not ids registered with
1156  * CoRegisterPSClsid.
1157  * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1158  * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1159  * considered a bug in native unless an application depends on this (unlikely).
1160  */
1161 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1162 {
1163     static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1164     static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1165     WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1166     WCHAR value[CHARS_IN_GUID];
1167     LONG len;
1168     HKEY hkey;
1169
1170     TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1171
1172     /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1173     strcpyW(path, wszInterface);
1174     StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1175     strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1176
1177     /* Open the key.. */
1178     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1179     {
1180         WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1181         return REGDB_E_IIDNOTREG;
1182     }
1183
1184     /* ... Once we have the key, query the registry to get the
1185        value of CLSID as a string, and convert it into a
1186        proper CLSID structure to be passed back to the app */
1187     len = sizeof(value);
1188     if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1189     {
1190         RegCloseKey(hkey);
1191         return REGDB_E_IIDNOTREG;
1192     }
1193     RegCloseKey(hkey);
1194
1195     /* We have the CLSid we want back from the registry as a string, so
1196        lets convert it into a CLSID structure */
1197     if (CLSIDFromString(value, pclsid) != NOERROR)
1198         return REGDB_E_IIDNOTREG;
1199
1200     TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1201     return S_OK;
1202 }
1203
1204
1205
1206 /***********************************************************************
1207  *              WriteClassStm (OLE32.@)
1208  *
1209  * Writes a CLSID to a stream.
1210  *
1211  * PARAMS
1212  *  pStm   [I] Stream to write to.
1213  *  rclsid [I] CLSID to write.
1214  *
1215  * RETURNS
1216  *  Success: S_OK.
1217  *  Failure: HRESULT code.
1218  */
1219 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1220 {
1221     TRACE("(%p,%p)\n",pStm,rclsid);
1222
1223     if (rclsid==NULL)
1224         return E_INVALIDARG;
1225
1226     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1227 }
1228
1229 /***********************************************************************
1230  *              ReadClassStm (OLE32.@)
1231  *
1232  * Reads a CLSID from a stream.
1233  *
1234  * PARAMS
1235  *  pStm   [I] Stream to read from.
1236  *  rclsid [O] CLSID to read.
1237  *
1238  * RETURNS
1239  *  Success: S_OK.
1240  *  Failure: HRESULT code.
1241  */
1242 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1243 {
1244     ULONG nbByte;
1245     HRESULT res;
1246
1247     TRACE("(%p,%p)\n",pStm,pclsid);
1248
1249     if (pclsid==NULL)
1250         return E_INVALIDARG;
1251
1252     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1253
1254     if (FAILED(res))
1255         return res;
1256
1257     if (nbByte != sizeof(CLSID))
1258         return S_FALSE;
1259     else
1260         return S_OK;
1261 }
1262
1263
1264 /***
1265  * COM_GetRegisteredClassObject
1266  *
1267  * This internal method is used to scan the registered class list to
1268  * find a class object.
1269  *
1270  * Params:
1271  *   rclsid        Class ID of the class to find.
1272  *   dwClsContext  Class context to match.
1273  *   ppv           [out] returns a pointer to the class object. Complying
1274  *                 to normal COM usage, this method will increase the
1275  *                 reference count on this object.
1276  */
1277 static HRESULT COM_GetRegisteredClassObject(
1278         REFCLSID    rclsid,
1279         DWORD       dwClsContext,
1280         LPUNKNOWN*  ppUnk)
1281 {
1282   HRESULT hr = S_FALSE;
1283   RegisteredClass* curClass;
1284
1285   EnterCriticalSection( &csRegisteredClassList );
1286
1287   /*
1288    * Sanity check
1289    */
1290   assert(ppUnk!=0);
1291
1292   /*
1293    * Iterate through the whole list and try to match the class ID.
1294    */
1295   curClass = firstRegisteredClass;
1296
1297   while (curClass != 0)
1298   {
1299     /*
1300      * Check if we have a match on the class ID.
1301      */
1302     if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1303     {
1304       /*
1305        * Since we don't do out-of process or DCOM just right away, let's ignore the
1306        * class context.
1307        */
1308
1309       /*
1310        * We have a match, return the pointer to the class object.
1311        */
1312       *ppUnk = curClass->classObject;
1313
1314       IUnknown_AddRef(curClass->classObject);
1315
1316       hr = S_OK;
1317       goto end;
1318     }
1319
1320     /*
1321      * Step to the next class in the list.
1322      */
1323     curClass = curClass->nextClass;
1324   }
1325
1326 end:
1327   LeaveCriticalSection( &csRegisteredClassList );
1328   /*
1329    * If we get to here, we haven't found our class.
1330    */
1331   return hr;
1332 }
1333
1334 /******************************************************************************
1335  *              CoRegisterClassObject   [OLE32.@]
1336  *
1337  * Registers the class object for a given class ID. Servers housed in EXE
1338  * files use this method instead of exporting DllGetClassObject to allow
1339  * other code to connect to their objects.
1340  *
1341  * PARAMS
1342  *  rclsid       [I] CLSID of the object to register.
1343  *  pUnk         [I] IUnknown of the object.
1344  *  dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1345  *  flags        [I] REGCLS flags indicating how connections are made.
1346  *  lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1347  *
1348  * RETURNS
1349  *   S_OK on success,
1350  *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
1351  *   CO_E_OBJISREG if the object is already registered. We should not return this.
1352  *
1353  * SEE ALSO
1354  *   CoRevokeClassObject, CoGetClassObject
1355  *
1356  * BUGS
1357  *  MSDN claims that multiple interface registrations are legal, but we
1358  *  can't do that with our current implementation.
1359  */
1360 HRESULT WINAPI CoRegisterClassObject(
1361     REFCLSID rclsid,
1362     LPUNKNOWN pUnk,
1363     DWORD dwClsContext,
1364     DWORD flags,
1365     LPDWORD lpdwRegister)
1366 {
1367   RegisteredClass* newClass;
1368   LPUNKNOWN        foundObject;
1369   HRESULT          hr;
1370
1371   TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1372         debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1373
1374   if ( (lpdwRegister==0) || (pUnk==0) )
1375     return E_INVALIDARG;
1376
1377   if (!COM_CurrentApt())
1378   {
1379       ERR("COM was not initialized\n");
1380       return CO_E_NOTINITIALIZED;
1381   }
1382
1383   *lpdwRegister = 0;
1384
1385   /*
1386    * First, check if the class is already registered.
1387    * If it is, this should cause an error.
1388    */
1389   hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1390   if (hr == S_OK) {
1391     IUnknown_Release(foundObject);
1392     return CO_E_OBJISREG;
1393   }
1394
1395   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1396   if ( newClass == NULL )
1397     return E_OUTOFMEMORY;
1398
1399   EnterCriticalSection( &csRegisteredClassList );
1400
1401   newClass->classIdentifier = *rclsid;
1402   newClass->runContext      = dwClsContext;
1403   newClass->connectFlags    = flags;
1404   newClass->pMarshaledData  = NULL;
1405
1406   /*
1407    * Use the address of the chain node as the cookie since we are sure it's
1408    * unique. FIXME: not on 64-bit platforms.
1409    */
1410   newClass->dwCookie        = (DWORD)newClass;
1411   newClass->nextClass       = firstRegisteredClass;
1412
1413   /*
1414    * Since we're making a copy of the object pointer, we have to increase its
1415    * reference count.
1416    */
1417   newClass->classObject     = pUnk;
1418   IUnknown_AddRef(newClass->classObject);
1419
1420   firstRegisteredClass = newClass;
1421   LeaveCriticalSection( &csRegisteredClassList );
1422
1423   *lpdwRegister = newClass->dwCookie;
1424
1425   if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1426       IClassFactory *classfac;
1427
1428       hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1429                                    (LPVOID*)&classfac);
1430       if (hr) return hr;
1431
1432       hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1433       if (hr) {
1434           FIXME("Failed to create stream on hglobal, %lx\n", hr);
1435           IUnknown_Release(classfac);
1436           return hr;
1437       }
1438       hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1439                               (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1440                               MSHLFLAGS_TABLESTRONG);
1441       if (hr) {
1442           FIXME("CoMarshalInterface failed, %lx!\n",hr);
1443           IUnknown_Release(classfac);
1444           return hr;
1445       }
1446
1447       IUnknown_Release(classfac);
1448
1449       RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1450   }
1451   return S_OK;
1452 }
1453
1454 /***********************************************************************
1455  *           CoRevokeClassObject [OLE32.@]
1456  *
1457  * Removes a class object from the class registry.
1458  *
1459  * PARAMS
1460  *  dwRegister [I] Cookie returned from CoRegisterClassObject().
1461  *
1462  * RETURNS
1463  *  Success: S_OK.
1464  *  Failure: HRESULT code.
1465  *
1466  * SEE ALSO
1467  *  CoRegisterClassObject
1468  */
1469 HRESULT WINAPI CoRevokeClassObject(
1470         DWORD dwRegister)
1471 {
1472   HRESULT hr = E_INVALIDARG;
1473   RegisteredClass** prevClassLink;
1474   RegisteredClass*  curClass;
1475
1476   TRACE("(%08lx)\n",dwRegister);
1477
1478   EnterCriticalSection( &csRegisteredClassList );
1479
1480   /*
1481    * Iterate through the whole list and try to match the cookie.
1482    */
1483   curClass      = firstRegisteredClass;
1484   prevClassLink = &firstRegisteredClass;
1485
1486   while (curClass != 0)
1487   {
1488     /*
1489      * Check if we have a match on the cookie.
1490      */
1491     if (curClass->dwCookie == dwRegister)
1492     {
1493       /*
1494        * Remove the class from the chain.
1495        */
1496       *prevClassLink = curClass->nextClass;
1497
1498       /*
1499        * Release the reference to the class object.
1500        */
1501       IUnknown_Release(curClass->classObject);
1502
1503       if (curClass->pMarshaledData)
1504       {
1505         LARGE_INTEGER zero;
1506         memset(&zero, 0, sizeof(zero));
1507         /* FIXME: stop local server thread */
1508         IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1509         CoReleaseMarshalData(curClass->pMarshaledData);
1510       }
1511
1512       /*
1513        * Free the memory used by the chain node.
1514        */
1515       HeapFree(GetProcessHeap(), 0, curClass);
1516
1517       hr = S_OK;
1518       goto end;
1519     }
1520
1521     /*
1522      * Step to the next class in the list.
1523      */
1524     prevClassLink = &(curClass->nextClass);
1525     curClass      = curClass->nextClass;
1526   }
1527
1528 end:
1529   LeaveCriticalSection( &csRegisteredClassList );
1530   /*
1531    * If we get to here, we haven't found our class.
1532    */
1533   return hr;
1534 }
1535
1536 /***********************************************************************
1537  *      COM_RegReadPath [internal]
1538  *
1539  *      Reads a registry value and expands it when necessary
1540  */
1541 HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1542 {
1543         HRESULT hres;
1544         HKEY key;
1545         DWORD keytype;
1546         WCHAR src[MAX_PATH];
1547         DWORD dwLength = dstlen * sizeof(WCHAR);
1548
1549         if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1550           if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1551             if (keytype == REG_EXPAND_SZ) {
1552               if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1553             } else {
1554               lstrcpynW(dst, src, dstlen);
1555             }
1556           }
1557           RegCloseKey (key);
1558         }
1559         return hres;
1560 }
1561
1562 /***********************************************************************
1563  *           CoGetClassObject [OLE32.@]
1564  *
1565  * FIXME.  If request allows of several options and there is a failure
1566  *         with one (other than not being registered) do we try the
1567  *         others or return failure?  (E.g. inprocess is registered but
1568  *         the DLL is not found but the server version works)
1569  */
1570 HRESULT WINAPI CoGetClassObject(
1571     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1572     REFIID iid, LPVOID *ppv)
1573 {
1574     LPUNKNOWN   regClassObject;
1575     HRESULT     hres = E_UNEXPECTED;
1576
1577     TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1578
1579     if (pServerInfo) {
1580         FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1581         FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1582     }
1583
1584     /*
1585      * First, try and see if we can't match the class ID with one of the
1586      * registered classes.
1587      */
1588     if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1589     {
1590       /* Get the required interface from the retrieved pointer. */
1591       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1592
1593       /*
1594        * Since QI got another reference on the pointer, we want to release the
1595        * one we already have. If QI was unsuccessful, this will release the object. This
1596        * is good since we are not returning it in the "out" parameter.
1597        */
1598       IUnknown_Release(regClassObject);
1599
1600       return hres;
1601     }
1602
1603     /* first try: in-process */
1604     if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext)
1605     {
1606         static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1607         HINSTANCE hLibrary;
1608         typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1609         DllGetClassObjectFunc DllGetClassObject;
1610         WCHAR dllpath[MAX_PATH+1];
1611         HKEY hkey;
1612
1613         if (ERROR_SUCCESS != COM_OpenKeyForCLSID(rclsid, KEY_READ, &hkey))
1614         {
1615             ERR("class %s not registered\n", debugstr_guid(rclsid));
1616             hres = REGDB_E_CLASSNOTREG;
1617         }
1618
1619         if (COM_RegReadPath(hkey, wszInprocServer32, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1620         {
1621             /* failure: CLSID is not found in registry */
1622             WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1623             hres = REGDB_E_CLASSNOTREG;
1624         }
1625         else
1626         {
1627             if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1628             {
1629                 /* failure: DLL could not be loaded */
1630                 ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(dllpath));
1631                 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1632             }
1633             else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1634             {
1635                 /* failure: the dll did not export DllGetClassObject */
1636                 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1637                 FreeLibrary( hLibrary );
1638                 hres = CO_E_DLLNOTFOUND;
1639             }
1640             else
1641             {
1642                 /* OK: get the ClassObject */
1643                 COMPOBJ_DLLList_Add( hLibrary );
1644                 return DllGetClassObject(rclsid, iid, ppv);
1645             }
1646         }
1647     }
1648
1649     /* Next try out of process */
1650     if (CLSCTX_LOCAL_SERVER & dwClsContext)
1651     {
1652         return RPC_GetLocalClassObject(rclsid,iid,ppv);
1653     }
1654
1655     /* Finally try remote: this requires networked DCOM (a lot of work) */
1656     if (CLSCTX_REMOTE_SERVER & dwClsContext)
1657     {
1658         FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1659         hres = E_NOINTERFACE;
1660     }
1661
1662     return hres;
1663 }
1664
1665 /***********************************************************************
1666  *           CoGetClassObject [COMPOBJ.7]
1667  *
1668  */
1669 HRESULT WINAPI CoGetClassObject16(
1670     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1671     REFIID iid, LPVOID *ppv)
1672 {
1673     FIXME(", stub!\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1674
1675     if (pServerInfo) {
1676         FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1677         FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1678     }
1679     return E_NOTIMPL;
1680 }
1681 /***********************************************************************
1682  *        CoResumeClassObjects (OLE32.@)
1683  *
1684  * Resumes all class objects registered with REGCLS_SUSPENDED.
1685  *
1686  * RETURNS
1687  *  Success: S_OK.
1688  *  Failure: HRESULT code.
1689  */
1690 HRESULT WINAPI CoResumeClassObjects(void)
1691 {
1692        FIXME("stub\n");
1693         return S_OK;
1694 }
1695
1696 /***********************************************************************
1697  *        GetClassFile (OLE32.@)
1698  *
1699  * This function supplies the CLSID associated with the given filename.
1700  */
1701 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1702 {
1703     IStorage *pstg=0;
1704     HRESULT res;
1705     int nbElm, length, i;
1706     LONG sizeProgId;
1707     LPOLESTR *pathDec=0,absFile=0,progId=0;
1708     LPWSTR extension;
1709     static const WCHAR bkslashW[] = {'\\',0};
1710     static const WCHAR dotW[] = {'.',0};
1711
1712     TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1713
1714     /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1715     if((StgIsStorageFile(filePathName))==S_OK){
1716
1717         res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1718
1719         if (SUCCEEDED(res))
1720             res=ReadClassStg(pstg,pclsid);
1721
1722         IStorage_Release(pstg);
1723
1724         return res;
1725     }
1726     /* if the file is not a storage object then attemps to match various bits in the file against a
1727        pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1728        this case
1729
1730      for(i=0;i<nFileTypes;i++)
1731
1732         for(i=0;j<nPatternsForType;j++){
1733
1734             PATTERN pat;
1735             HANDLE  hFile;
1736
1737             pat=ReadPatternFromRegistry(i,j);
1738             hFile=CreateFileW(filePathName,,,,,,hFile);
1739             SetFilePosition(hFile,pat.offset);
1740             ReadFile(hFile,buf,pat.size,&r,NULL);
1741             if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1742
1743                 *pclsid=ReadCLSIDFromRegistry(i);
1744                 return S_OK;
1745             }
1746         }
1747      */
1748
1749     /* if the above strategies fail then search for the extension key in the registry */
1750
1751     /* get the last element (absolute file) in the path name */
1752     nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1753     absFile=pathDec[nbElm-1];
1754
1755     /* failed if the path represente a directory and not an absolute file name*/
1756     if (!lstrcmpW(absFile, bkslashW))
1757         return MK_E_INVALIDEXTENSION;
1758
1759     /* get the extension of the file */
1760     extension = NULL;
1761     length=lstrlenW(absFile);
1762     for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1763         /* nothing */;
1764
1765     if (!extension || !lstrcmpW(extension, dotW))
1766         return MK_E_INVALIDEXTENSION;
1767
1768     res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1769
1770     /* get the progId associated to the extension */
1771     progId = CoTaskMemAlloc(sizeProgId);
1772     res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1773
1774     if (res==ERROR_SUCCESS)
1775         /* return the clsid associated to the progId */
1776         res= CLSIDFromProgID(progId,pclsid);
1777
1778     for(i=0; pathDec[i]!=NULL;i++)
1779         CoTaskMemFree(pathDec[i]);
1780     CoTaskMemFree(pathDec);
1781
1782     CoTaskMemFree(progId);
1783
1784     if (res==ERROR_SUCCESS)
1785         return res;
1786
1787     return MK_E_INVALIDEXTENSION;
1788 }
1789
1790 /***********************************************************************
1791  *           CoCreateInstance [OLE32.@]
1792  */
1793 HRESULT WINAPI CoCreateInstance(
1794         REFCLSID rclsid,
1795         LPUNKNOWN pUnkOuter,
1796         DWORD dwClsContext,
1797         REFIID iid,
1798         LPVOID *ppv)
1799 {
1800   HRESULT hres;
1801   LPCLASSFACTORY lpclf = 0;
1802
1803   if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1804
1805   /*
1806    * Sanity check
1807    */
1808   if (ppv==0)
1809     return E_POINTER;
1810
1811   /*
1812    * Initialize the "out" parameter
1813    */
1814   *ppv = 0;
1815
1816   /*
1817    * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1818    * Rather than create a class factory, we can just check for it here
1819    */
1820   if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1821     if (StdGlobalInterfaceTableInstance == NULL)
1822       StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1823     hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1824     if (hres) return hres;
1825
1826     TRACE("Retrieved GIT (%p)\n", *ppv);
1827     return S_OK;
1828   }
1829
1830   /*
1831    * Get a class factory to construct the object we want.
1832    */
1833   hres = CoGetClassObject(rclsid,
1834                           dwClsContext,
1835                           NULL,
1836                           &IID_IClassFactory,
1837                           (LPVOID)&lpclf);
1838
1839   if (FAILED(hres)) {
1840     FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1841           debugstr_guid(rclsid),hres);
1842     return hres;
1843   }
1844
1845   /*
1846    * Create the object and don't forget to release the factory
1847    */
1848         hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1849         IClassFactory_Release(lpclf);
1850         if(FAILED(hres))
1851           FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1852                 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1853
1854         return hres;
1855 }
1856
1857 /***********************************************************************
1858  *           CoCreateInstance [COMPOBJ.13]
1859  */
1860 HRESULT WINAPI CoCreateInstance16(
1861         REFCLSID rclsid,
1862         LPUNKNOWN pUnkOuter,
1863         DWORD dwClsContext,
1864         REFIID iid,
1865         LPVOID *ppv)
1866 {
1867   FIXME("(%s, %p, %lx, %s, %p), stub!\n", 
1868         debugstr_guid(rclsid), pUnkOuter, dwClsContext, debugstr_guid(iid),
1869         ppv
1870   );
1871   return E_NOTIMPL;
1872 }
1873
1874 /***********************************************************************
1875  *           CoCreateInstanceEx [OLE32.@]
1876  */
1877 HRESULT WINAPI CoCreateInstanceEx(
1878   REFCLSID      rclsid,
1879   LPUNKNOWN     pUnkOuter,
1880   DWORD         dwClsContext,
1881   COSERVERINFO* pServerInfo,
1882   ULONG         cmq,
1883   MULTI_QI*     pResults)
1884 {
1885   IUnknown* pUnk = NULL;
1886   HRESULT   hr;
1887   ULONG     index;
1888   ULONG     successCount = 0;
1889
1890   /*
1891    * Sanity check
1892    */
1893   if ( (cmq==0) || (pResults==NULL))
1894     return E_INVALIDARG;
1895
1896   if (pServerInfo!=NULL)
1897     FIXME("() non-NULL pServerInfo not supported!\n");
1898
1899   /*
1900    * Initialize all the "out" parameters.
1901    */
1902   for (index = 0; index < cmq; index++)
1903   {
1904     pResults[index].pItf = NULL;
1905     pResults[index].hr   = E_NOINTERFACE;
1906   }
1907
1908   /*
1909    * Get the object and get its IUnknown pointer.
1910    */
1911   hr = CoCreateInstance(rclsid,
1912                         pUnkOuter,
1913                         dwClsContext,
1914                         &IID_IUnknown,
1915                         (VOID**)&pUnk);
1916
1917   if (hr)
1918     return hr;
1919
1920   /*
1921    * Then, query for all the interfaces requested.
1922    */
1923   for (index = 0; index < cmq; index++)
1924   {
1925     pResults[index].hr = IUnknown_QueryInterface(pUnk,
1926                                                  pResults[index].pIID,
1927                                                  (VOID**)&(pResults[index].pItf));
1928
1929     if (pResults[index].hr == S_OK)
1930       successCount++;
1931   }
1932
1933   /*
1934    * Release our temporary unknown pointer.
1935    */
1936   IUnknown_Release(pUnk);
1937
1938   if (successCount == 0)
1939     return E_NOINTERFACE;
1940
1941   if (successCount!=cmq)
1942     return CO_S_NOTALLINTERFACES;
1943
1944   return S_OK;
1945 }
1946
1947 /***********************************************************************
1948  *           CoLoadLibrary (OLE32.@)
1949  *
1950  * Loads a library.
1951  *
1952  * PARAMS
1953  *  lpszLibName [I] Path to library.
1954  *  bAutoFree   [I] Whether the library should automatically be freed.
1955  *
1956  * RETURNS
1957  *  Success: Handle to loaded library.
1958  *  Failure: NULL.
1959  *
1960  * SEE ALSO
1961  *  CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1962  */
1963 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1964 {
1965     TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1966
1967     return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1968 }
1969
1970 /***********************************************************************
1971  *           CoFreeLibrary [OLE32.@]
1972  *
1973  * Unloads a library from memory.
1974  *
1975  * PARAMS
1976  *  hLibrary [I] Handle to library to unload.
1977  *
1978  * RETURNS
1979  *  Nothing
1980  *
1981  * SEE ALSO
1982  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1983  */
1984 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1985 {
1986     FreeLibrary(hLibrary);
1987 }
1988
1989
1990 /***********************************************************************
1991  *           CoFreeAllLibraries [OLE32.@]
1992  *
1993  * Function for backwards compatibility only. Does nothing.
1994  *
1995  * RETURNS
1996  *  Nothing.
1997  *
1998  * SEE ALSO
1999  *  CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2000  */
2001 void WINAPI CoFreeAllLibraries(void)
2002 {
2003     /* NOP */
2004 }
2005
2006
2007 /***********************************************************************
2008  *           CoFreeUnusedLibraries [OLE32.@]
2009  *           CoFreeUnusedLibraries [COMPOBJ.17]
2010  *
2011  * Frees any unused libraries. Unused are identified as those that return
2012  * S_OK from their DllCanUnloadNow function.
2013  *
2014  * RETURNS
2015  *  Nothing.
2016  *
2017  * SEE ALSO
2018  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2019  */
2020 void WINAPI CoFreeUnusedLibraries(void)
2021 {
2022     /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2023      * through the main apartment's thread to call DllCanUnloadNow */
2024     COMPOBJ_DllList_FreeUnused(0);
2025 }
2026
2027 /***********************************************************************
2028  *           CoFileTimeNow [OLE32.@]
2029  *           CoFileTimeNow [COMPOBJ.82]
2030  *
2031  * Retrieves the current time in FILETIME format.
2032  *
2033  * PARAMS
2034  *  lpFileTime [O] The current time.
2035  *
2036  * RETURNS
2037  *      S_OK.
2038  */
2039 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2040 {
2041     GetSystemTimeAsFileTime( lpFileTime );
2042     return S_OK;
2043 }
2044
2045 static void COM_RevokeAllClasses()
2046 {
2047   EnterCriticalSection( &csRegisteredClassList );
2048
2049   while (firstRegisteredClass!=0)
2050   {
2051     CoRevokeClassObject(firstRegisteredClass->dwCookie);
2052   }
2053
2054   LeaveCriticalSection( &csRegisteredClassList );
2055 }
2056
2057 /******************************************************************************
2058  *              CoLockObjectExternal    [OLE32.@]
2059  *
2060  * Increments or decrements the external reference count of a stub object.
2061  *
2062  * PARAMS
2063  *  pUnk                [I] Stub object.
2064  *  fLock               [I] If TRUE then increments the external ref-count,
2065  *                          otherwise decrements.
2066  *  fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2067  *                          calling CoDisconnectObject.
2068  *
2069  * RETURNS
2070  *  Success: S_OK.
2071  *  Failure: HRESULT code.
2072  */
2073 HRESULT WINAPI CoLockObjectExternal(
2074     LPUNKNOWN pUnk,
2075     BOOL fLock,
2076     BOOL fLastUnlockReleases)
2077 {
2078     struct stub_manager *stubmgr;
2079     struct apartment *apt;
2080
2081     TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2082           pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2083
2084     apt = COM_CurrentApt();
2085     if (!apt) return CO_E_NOTINITIALIZED;
2086
2087     stubmgr = get_stub_manager_from_object(apt, pUnk);
2088     
2089     if (stubmgr)
2090     {
2091         if (fLock)
2092             stub_manager_ext_addref(stubmgr, 1);
2093         else
2094             stub_manager_ext_release(stubmgr, 1);
2095         
2096         stub_manager_int_release(stubmgr);
2097
2098         return S_OK;
2099     }
2100     else
2101     {
2102         WARN("stub object not found %p\n", pUnk);
2103         /* Note: native is pretty broken here because it just silently
2104          * fails, without returning an appropriate error code, making apps
2105          * think that the object was disconnected, when it actually wasn't */
2106         return S_OK;
2107     }
2108 }
2109
2110 /***********************************************************************
2111  *           CoInitializeWOW (OLE32.@)
2112  *
2113  * WOW equivalent of CoInitialize?
2114  *
2115  * PARAMS
2116  *  x [I] Unknown.
2117  *  y [I] Unknown.
2118  *
2119  * RETURNS
2120  *  Unknown.
2121  */
2122 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2123 {
2124     FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2125     return 0;
2126 }
2127
2128 /***********************************************************************
2129  *           CoGetState [OLE32.@]
2130  *
2131  * Retrieves the thread state object previously stored by CoSetState().
2132  *
2133  * PARAMS
2134  *  ppv [I] Address where pointer to object will be stored.
2135  *
2136  * RETURNS
2137  *  Success: S_OK.
2138  *  Failure: E_OUTOFMEMORY.
2139  *
2140  * NOTES
2141  *  Crashes on all invalid ppv addresses, including NULL.
2142  *  If the function returns a non-NULL object then the caller must release its
2143  *  reference on the object when the object is no longer required.
2144  *
2145  * SEE ALSO
2146  *  CoSetState().
2147  */
2148 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2149 {
2150     struct oletls *info = COM_CurrentInfo();
2151     if (!info) return E_OUTOFMEMORY;
2152
2153     *ppv = NULL;
2154
2155     if (info->state)
2156     {
2157         IUnknown_AddRef(info->state);
2158         *ppv = info->state;
2159         TRACE("apt->state=%p\n", info->state);
2160     }
2161
2162     return S_OK;
2163 }
2164
2165 /***********************************************************************
2166  *           CoSetState [OLE32.@]
2167  *
2168  * Sets the thread state object.
2169  *
2170  * PARAMS
2171  *  pv [I] Pointer to state object to be stored.
2172  *
2173  * NOTES
2174  *  The system keeps a reference on the object while the object stored.
2175  *
2176  * RETURNS
2177  *  Success: S_OK.
2178  *  Failure: E_OUTOFMEMORY.
2179  */
2180 HRESULT WINAPI CoSetState(IUnknown * pv)
2181 {
2182     struct oletls *info = COM_CurrentInfo();
2183     if (!info) return E_OUTOFMEMORY;
2184
2185     if (pv) IUnknown_AddRef(pv);
2186
2187     if (info->state)
2188     {
2189         TRACE("-- release %p now\n", info->state);
2190         IUnknown_Release(info->state);
2191     }
2192
2193     info->state = pv;
2194
2195     return S_OK;
2196 }
2197
2198
2199 /******************************************************************************
2200  *              OleGetAutoConvert        [OLE32.@]
2201  */
2202 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2203 {
2204     static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2205     HKEY hkey = NULL;
2206     WCHAR buf[CHARS_IN_GUID];
2207     LONG len;
2208     HRESULT res = S_OK;
2209
2210     if (ERROR_SUCCESS != COM_OpenKeyForCLSID(clsidOld, KEY_READ, &hkey))
2211     {
2212         res = REGDB_E_CLASSNOTREG;
2213         goto done;
2214     }
2215
2216     len = sizeof(buf);
2217     /* we can just query for the default value of AutoConvertTo key like that,
2218        without opening the AutoConvertTo key and querying for NULL (default) */
2219     if (RegQueryValueW(hkey, wszAutoConvertTo, buf, &len))
2220     {
2221         res = REGDB_E_KEYMISSING;
2222         goto done;
2223     }
2224     res = CLSIDFromString(buf, pClsidNew);
2225 done:
2226     if (hkey) RegCloseKey(hkey);
2227     return res;
2228 }
2229
2230 /******************************************************************************
2231  *              CoTreatAsClass        [OLE32.@]
2232  *
2233  * Sets the TreatAs value of a class.
2234  *
2235  * PARAMS
2236  *  clsidOld [I] Class to set TreatAs value on.
2237  *  clsidNew [I] The class the clsidOld should be treated as.
2238  *
2239  * RETURNS
2240  *  Success: S_OK.
2241  *  Failure: HRESULT code.
2242  *
2243  * SEE ALSO
2244  *  CoGetTreatAsClass
2245  */
2246 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2247 {
2248     static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2249     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2250     HKEY hkey = NULL;
2251     WCHAR szClsidNew[CHARS_IN_GUID];
2252     HRESULT res = S_OK;
2253     WCHAR auto_treat_as[CHARS_IN_GUID];
2254     LONG auto_treat_as_size = sizeof(auto_treat_as);
2255     CLSID id;
2256
2257     if (ERROR_SUCCESS != COM_OpenKeyForCLSID(clsidOld, KEY_READ | KEY_WRITE, &hkey))
2258     {
2259         res = REGDB_E_CLASSNOTREG;
2260         goto done;
2261     }
2262     if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2263     {
2264        if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2265            !CLSIDFromString(auto_treat_as, &id))
2266        {
2267            if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2268            {
2269                res = REGDB_E_WRITEREGDB;
2270                goto done;
2271            }
2272        }
2273        else
2274        {
2275            RegDeleteKeyW(hkey, wszTreatAs);
2276            goto done;
2277        }
2278     }
2279     else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2280              !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2281     {
2282         res = REGDB_E_WRITEREGDB;
2283         goto done;
2284     }
2285
2286 done:
2287     if (hkey) RegCloseKey(hkey);
2288     return res;
2289 }
2290
2291 /******************************************************************************
2292  *              CoGetTreatAsClass        [OLE32.@]
2293  *
2294  * Gets the TreatAs value of a class.
2295  *
2296  * PARAMS
2297  *  clsidOld [I] Class to get the TreatAs value of.
2298  *  clsidNew [I] The class the clsidOld should be treated as.
2299  *
2300  * RETURNS
2301  *  Success: S_OK.
2302  *  Failure: HRESULT code.
2303  *
2304  * SEE ALSO
2305  *  CoSetTreatAsClass
2306  */
2307 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2308 {
2309     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2310     HKEY hkey = NULL;
2311     WCHAR szClsidNew[CHARS_IN_GUID];
2312     HRESULT res = S_OK;
2313     LONG len = sizeof(szClsidNew);
2314
2315     FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2316     memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2317
2318     if (COM_OpenKeyForCLSID(clsidOld, KEY_READ, &hkey))
2319     {
2320         res = REGDB_E_CLASSNOTREG;
2321         goto done;
2322     }
2323     if (RegQueryValueW(hkey, wszTreatAs, szClsidNew, &len))
2324     {
2325         res = S_FALSE;
2326         goto done;
2327     }
2328     res = CLSIDFromString(szClsidNew,clsidNew);
2329     if (FAILED(res))
2330         ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2331 done:
2332     if (hkey) RegCloseKey(hkey);
2333     return res;
2334 }
2335
2336 /******************************************************************************
2337  *              CoGetCurrentProcess     [OLE32.@]
2338  *              CoGetCurrentProcess     [COMPOBJ.34]
2339  *
2340  * Gets the current process ID.
2341  *
2342  * RETURNS
2343  *  The current process ID.
2344  *
2345  * NOTES
2346  *   Is DWORD really the correct return type for this function?
2347  */
2348 DWORD WINAPI CoGetCurrentProcess(void)
2349 {
2350         return GetCurrentProcessId();
2351 }
2352
2353 /******************************************************************************
2354  *              CoRegisterMessageFilter [OLE32.@]
2355  *
2356  * Registers a message filter.
2357  *
2358  * PARAMS
2359  *  lpMessageFilter [I] Pointer to interface.
2360  *  lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2361  *
2362  * RETURNS
2363  *  Success: S_OK.
2364  *  Failure: HRESULT code.
2365  */
2366 HRESULT WINAPI CoRegisterMessageFilter(
2367     LPMESSAGEFILTER lpMessageFilter,
2368     LPMESSAGEFILTER *lplpMessageFilter)
2369 {
2370     FIXME("stub\n");
2371     if (lplpMessageFilter) {
2372         *lplpMessageFilter = NULL;
2373     }
2374     return S_OK;
2375 }
2376
2377 /***********************************************************************
2378  *           CoIsOle1Class [OLE32.@]
2379  *
2380  * Determines whether the specified class an OLE v1 class.
2381  *
2382  * PARAMS
2383  *  clsid [I] Class to test.
2384  *
2385  * RETURNS
2386  *  TRUE if the class is an OLE v1 class, or FALSE otherwise.
2387  */
2388 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2389 {
2390   FIXME("%s\n", debugstr_guid(clsid));
2391   return FALSE;
2392 }
2393
2394 /***********************************************************************
2395  *           IsEqualGUID [OLE32.@]
2396  *
2397  * Compares two Unique Identifiers.
2398  *
2399  * PARAMS
2400  *  rguid1 [I] The first GUID to compare.
2401  *  rguid2 [I] The other GUID to compare.
2402  *
2403  * RETURNS
2404  *      TRUE if equal
2405  */
2406 #undef IsEqualGUID
2407 BOOL WINAPI IsEqualGUID(
2408      REFGUID rguid1,
2409      REFGUID rguid2)
2410 {
2411     return !memcmp(rguid1,rguid2,sizeof(GUID));
2412 }
2413
2414 /***********************************************************************
2415  *           CoInitializeSecurity [OLE32.@]
2416  */
2417 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2418                                     SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2419                                     void* pReserved1, DWORD dwAuthnLevel,
2420                                     DWORD dwImpLevel, void* pReserved2,
2421                                     DWORD dwCapabilities, void* pReserved3)
2422 {
2423   FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2424         asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2425         dwCapabilities, pReserved3);
2426   return S_OK;
2427 }
2428
2429 /***********************************************************************
2430  *           CoSuspendClassObjects [OLE32.@]
2431  *
2432  * Suspends all registered class objects to prevent further requests coming in
2433  * for those objects.
2434  *
2435  * RETURNS
2436  *  Success: S_OK.
2437  *  Failure: HRESULT code.
2438  */
2439 HRESULT WINAPI CoSuspendClassObjects(void)
2440 {
2441     FIXME("\n");
2442     return S_OK;
2443 }
2444
2445 /***********************************************************************
2446  *           CoAddRefServerProcess [OLE32.@]
2447  *
2448  * Helper function for incrementing the reference count of a local-server
2449  * process.
2450  *
2451  * RETURNS
2452  *  New reference count.
2453  */
2454 ULONG WINAPI CoAddRefServerProcess(void)
2455 {
2456     FIXME("\n");
2457     return 2;
2458 }
2459
2460 /***********************************************************************
2461  *           CoReleaseServerProcess [OLE32.@]
2462  *
2463  * Helper function for decrementing the reference count of a local-server
2464  * process.
2465  *
2466  * RETURNS
2467  *  New reference count.
2468  */
2469 ULONG WINAPI CoReleaseServerProcess(void)
2470 {
2471     FIXME("\n");
2472     return 1;
2473 }
2474
2475 /***********************************************************************
2476  *           CoIsHandlerConnected [OLE32.@]
2477  *
2478  * Determines whether a proxy is connected to a remote stub.
2479  *
2480  * PARAMS
2481  *  pUnk [I] Pointer to object that may or may not be connected.
2482  *
2483  * RETURNS
2484  *  TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2485  *  FALSE otherwise.
2486  */
2487 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2488 {
2489     FIXME("%p\n", pUnk);
2490
2491     return TRUE;
2492 }
2493
2494 /***********************************************************************
2495  *           CoAllowSetForegroundWindow [OLE32.@]
2496  *
2497  */
2498 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2499 {
2500     FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2501     return S_OK;
2502 }
2503  
2504 /***********************************************************************
2505  *           CoQueryProxyBlanket [OLE32.@]
2506  *
2507  * Retrieves the security settings being used by a proxy.
2508  *
2509  * PARAMS
2510  *  pProxy        [I] Pointer to the proxy object.
2511  *  pAuthnSvc     [O] The type of authentication service.
2512  *  pAuthzSvc     [O] The type of authorization service.
2513  *  ppServerPrincName [O] Optional. The server prinicple name.
2514  *  pAuthnLevel   [O] The authentication level.
2515  *  pImpLevel     [O] The impersonation level.
2516  *  ppAuthInfo    [O] Information specific to the authorization/authentication service.
2517  *  pCapabilities [O] Flags affecting the security behaviour.
2518  *
2519  * RETURNS
2520  *  Success: S_OK.
2521  *  Failure: HRESULT code.
2522  *
2523  * SEE ALSO
2524  *  CoCopyProxy, CoSetProxyBlanket.
2525  */
2526 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2527     DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2528     DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2529 {
2530     IClientSecurity *pCliSec;
2531     HRESULT hr;
2532
2533     TRACE("%p\n", pProxy);
2534
2535     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2536     if (SUCCEEDED(hr))
2537     {
2538         hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2539                                           pAuthzSvc, ppServerPrincName,
2540                                           pAuthnLevel, pImpLevel, ppAuthInfo,
2541                                           pCapabilities);
2542         IClientSecurity_Release(pCliSec);
2543     }
2544
2545     if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2546     return hr;
2547 }
2548
2549 /***********************************************************************
2550  *           CoSetProxyBlanket [OLE32.@]
2551  *
2552  * Sets the security settings for a proxy.
2553  *
2554  * PARAMS
2555  *  pProxy       [I] Pointer to the proxy object.
2556  *  AuthnSvc     [I] The type of authentication service.
2557  *  AuthzSvc     [I] The type of authorization service.
2558  *  pServerPrincName [I] The server prinicple name.
2559  *  AuthnLevel   [I] The authentication level.
2560  *  ImpLevel     [I] The impersonation level.
2561  *  pAuthInfo    [I] Information specific to the authorization/authentication service.
2562  *  Capabilities [I] Flags affecting the security behaviour.
2563  *
2564  * RETURNS
2565  *  Success: S_OK.
2566  *  Failure: HRESULT code.
2567  *
2568  * SEE ALSO
2569  *  CoQueryProxyBlanket, CoCopyProxy.
2570  */
2571 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2572     DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2573     DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2574 {
2575     IClientSecurity *pCliSec;
2576     HRESULT hr;
2577
2578     TRACE("%p\n", pProxy);
2579
2580     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2581     if (SUCCEEDED(hr))
2582     {
2583         hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2584                                         AuthzSvc, pServerPrincName,
2585                                         AuthnLevel, ImpLevel, pAuthInfo,
2586                                         Capabilities);
2587         IClientSecurity_Release(pCliSec);
2588     }
2589
2590     if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2591     return hr;
2592 }
2593
2594 /***********************************************************************
2595  *           CoCopyProxy [OLE32.@]
2596  *
2597  * Copies a proxy.
2598  *
2599  * PARAMS
2600  *  pProxy [I] Pointer to the proxy object.
2601  *  ppCopy [O] Copy of the proxy.
2602  *
2603  * RETURNS
2604  *  Success: S_OK.
2605  *  Failure: HRESULT code.
2606  *
2607  * SEE ALSO
2608  *  CoQueryProxyBlanket, CoSetProxyBlanket.
2609  */
2610 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2611 {
2612     IClientSecurity *pCliSec;
2613     HRESULT hr;
2614
2615     TRACE("%p\n", pProxy);
2616
2617     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2618     if (SUCCEEDED(hr))
2619     {
2620         hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2621         IClientSecurity_Release(pCliSec);
2622     }
2623
2624     if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2625     return hr;
2626 }
2627
2628
2629 /***********************************************************************
2630  *           CoWaitForMultipleHandles [OLE32.@]
2631  *
2632  * Waits for one or more handles to become signaled.
2633  *
2634  * PARAMS
2635  *  dwFlags   [I] Flags. See notes.
2636  *  dwTimeout [I] Timeout in milliseconds.
2637  *  cHandles  [I] Number of handles pointed to by pHandles.
2638  *  pHandles  [I] Handles to wait for.
2639  *  lpdwindex [O] Index of handle that was signaled.
2640  *
2641  * RETURNS
2642  *  Success: S_OK.
2643  *  Failure: RPC_S_CALLPENDING on timeout.
2644  *
2645  * NOTES
2646  *
2647  * The dwFlags parameter can be zero or more of the following:
2648  *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2649  *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2650  *
2651  * SEE ALSO
2652  *  MsgWaitForMultipleObjects, WaitForMultipleObjects.
2653  */
2654 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2655     ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2656 {
2657     HRESULT hr = S_OK;
2658     DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2659                        (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2660     DWORD start_time = GetTickCount();
2661
2662     TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2663         pHandles, lpdwindex);
2664
2665     while (TRUE)
2666     {
2667         DWORD now = GetTickCount();
2668         DWORD res;
2669         
2670         if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2671         {
2672             hr = RPC_S_CALLPENDING;
2673             break;
2674         }
2675
2676         TRACE("waiting for rpc completion or window message\n");
2677
2678         res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2679             (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2680             QS_ALLINPUT, wait_flags);
2681
2682         if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
2683         {
2684             MSG msg;
2685             while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2686             {
2687                 /* FIXME: filter the messages here */
2688                 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2689                 TranslateMessage(&msg);
2690                 DispatchMessageW(&msg);
2691             }
2692         }
2693         else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2694         {
2695             /* handle signaled, store index */
2696             *lpdwindex = (res - WAIT_OBJECT_0);
2697             break;
2698         }
2699         else if (res == WAIT_TIMEOUT)
2700         {
2701             hr = RPC_S_CALLPENDING;
2702             break;
2703         }
2704         else
2705         {
2706             ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2707             hr = E_UNEXPECTED;
2708             break;
2709         }
2710     }
2711     TRACE("-- 0x%08lx\n", hr);
2712     return hr;
2713 }
2714
2715 /***********************************************************************
2716  *              DllMain (OLE32.@)
2717  */
2718 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2719 {
2720     TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2721
2722     switch(fdwReason) {
2723     case DLL_PROCESS_ATTACH:
2724         OLE32_hInstance = hinstDLL;
2725         COMPOBJ_InitProcess();
2726         if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2727         break;
2728
2729     case DLL_PROCESS_DETACH:
2730         if (TRACE_ON(ole)) CoRevokeMallocSpy();
2731         COMPOBJ_UninitProcess();
2732         OLE32_hInstance = 0;
2733         break;
2734
2735     case DLL_THREAD_DETACH:
2736         COM_TlsDestroy();
2737         break;
2738     }
2739     return TRUE;
2740 }
2741
2742 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */