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