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