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