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