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