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