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