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