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