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