Updated to use the latest COM macros. Defined more interfaces and API
[wine] / ole / 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 "config.h"
11 #ifdef HAVE_UNISTD_H
12 # include <unistd.h>
13 #endif
14 #include <fcntl.h>
15 #include <sys/types.h>
16 #include <sys/time.h>
17 #include <sys/stat.h>
18 #ifdef HAVE_SYS_FILE_H
19 # include <sys/file.h>
20 #endif
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
23 #ifdef HAVE_SYS_SOCKIO_H
24 # include <sys/sockio.h>
25 #endif
26 #ifdef HAVE_NET_IF_H
27 # include <net/if.h>
28 #endif
29 #ifdef HAVE_NETINET_IN_H
30 # include <netinet/in.h>
31 #endif
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 #include <assert.h>
36 #include "windows.h"
37 #include "winerror.h"
38 #include "ole.h"
39 #include "ole2.h"
40 #include "debug.h"
41 #include "file.h"
42 #include "heap.h"
43 #include "ldt.h"
44 #include "winreg.h"
45
46 #include "wine/obj_base.h"
47 #include "wine/obj_misc.h"
48 #include "wine/obj_clientserver.h"
49
50 #include "ifs.h"
51
52 /****************************************************************************
53  *  COM External Lock structures and methods declaration
54  *
55  *  This api provides a linked list to managed external references to 
56  *  COM objects.  
57  *
58  *  The public interface consists of three calls: 
59  *      COM_ExternalLockAddRef
60  *      COM_ExternalLockRelease
61  *      COM_ExternalLockFreeList
62  */
63
64 #define EL_END_OF_LIST 0
65 #define EL_NOT_FOUND   0
66
67 /*
68  * Declaration of the static structure that manage the 
69  * external lock to COM  objects.
70  */
71 typedef struct COM_ExternalLock     COM_ExternalLock;
72 typedef struct COM_ExternalLockList COM_ExternalLockList;
73
74 struct COM_ExternalLock
75 {
76   IUnknown         *pUnk;     /* IUnknown referenced */
77   ULONG            uRefCount; /* external lock counter to IUnknown object*/
78   COM_ExternalLock *next;     /* Pointer to next element in list */
79 };
80
81 struct COM_ExternalLockList
82 {
83   COM_ExternalLock *head;     /* head of list */
84 };
85
86 /*
87  * Declaration and initialization of the static structure that manages
88  * the external lock to COM objects.
89  */
90 static COM_ExternalLockList elList = { EL_END_OF_LIST };
91
92 /*
93  * Public Interface to the external lock list   
94  */
95 static void COM_ExternalLockFreeList();
96 static void COM_ExternalLockAddRef(IUnknown *pUnk);
97 static void COM_ExternalLockRelease(IUnknown *pUnk, BOOL32 bRelAll);
98 void COM_ExternalLockDump(); /* testing purposes, not static to avoid warning */
99
100 /*
101  * Private methods used to managed the linked list   
102  */
103 static BOOL32 COM_ExternalLockInsert(
104   IUnknown *pUnk);
105
106 static void COM_ExternalLockDelete(
107   COM_ExternalLock *element);
108
109 static COM_ExternalLock* COM_ExternalLockFind(
110   IUnknown *pUnk);
111
112 static COM_ExternalLock* COM_ExternalLockLocate(
113   COM_ExternalLock *element,
114   IUnknown         *pUnk);
115
116 /****************************************************************************
117  * This section defines variables internal to the COM module.
118  *
119  * TODO: Most of these things will have to be made thread-safe.
120  */
121 LPMALLOC16 currentMalloc16=NULL;
122 LPMALLOC32 currentMalloc32=NULL;
123
124 HTASK16 hETask = 0;
125 WORD Table_ETask[62];
126
127 /*
128  * This lock count counts the number of times CoInitialize is called. It is
129  * decreased every time CoUninitialize is called. When it hits 0, the COM
130  * libraries are freed
131  */
132 static ULONG s_COMLockCount = 0;
133
134 /*
135  * This linked list contains the list of registered class objects. These
136  * are mostly used to register the factories for out-of-proc servers of OLE
137  * objects.
138  *
139  * TODO: Make this data structure aware of inter-process communication. This
140  *       means that parts of this will be exported to the Wine Server.
141  */
142 typedef struct tagRegisteredClass
143 {
144   CLSID     classIdentifier;
145   LPUNKNOWN classObject;
146   DWORD     runContext;
147   DWORD     connectFlags;
148   DWORD     dwCookie;
149   struct tagRegisteredClass* nextClass;
150 } RegisteredClass;
151
152 static RegisteredClass* firstRegisteredClass = NULL;
153
154 /* this open DLL table belongs in a per process table, but my guess is that
155  * it shouldn't live in the kernel, so I'll put them out here in DLL
156  * space assuming that there is one OLE32 per process.
157  */
158 typedef struct tagOpenDll {
159   char *DllName;                /* really only needed for debugging */
160     HINSTANCE32 hLibrary;       
161     struct tagOpenDll *next;
162 } OpenDll;
163
164 static OpenDll *openDllList = NULL; /* linked list of open dlls */
165
166 /*****************************************************************************
167  * This section contains prototypes to internal methods for this
168  * module
169  */
170 static HRESULT COM_GetRegisteredClassObject(REFCLSID    rclsid,
171                                             DWORD       dwClsContext,
172                                             LPUNKNOWN*  ppUnk);
173
174 static void COM_RevokeAllClasses();
175
176
177 /******************************************************************************
178  *           CoBuildVersion [COMPOBJ.1]
179  *
180  * RETURNS
181  *      Current built version, hiword is majornumber, loword is minornumber
182  */
183 DWORD WINAPI CoBuildVersion(void)
184 {
185     TRACE(ole,"(void)\n");
186     return (rmm<<16)+rup;
187 }
188
189 /******************************************************************************
190  *              CoInitialize16  [COMPOBJ.2]
191  * Set the win16 IMalloc used for memory management
192  */
193 HRESULT WINAPI CoInitialize16(
194         LPVOID lpReserved       /* [in] pointer to win16 malloc interface */
195 ) {
196     currentMalloc16 = (LPMALLOC16)lpReserved;
197     return S_OK;
198 }
199
200 /******************************************************************************
201  *              CoInitialize32  [OLE32.26]
202  *
203  * Initializes the COM libraries.
204  *
205  * See CoInitializeEx32
206  */
207 HRESULT WINAPI CoInitialize32(
208         LPVOID lpReserved       /* [in] pointer to win32 malloc interface
209                                    (obsolete, should be NULL) */
210
211 {
212   /*
213    * Just delegate to the newer method.
214    */
215   return CoInitializeEx32(lpReserved, COINIT_APARTMENTTHREADED);
216 }
217
218 /******************************************************************************
219  *              CoInitializeEx32        [OLE32.163]
220  *
221  * Initializes the COM libraries. The behavior used to set the win32 IMalloc
222  * used for memory management is obsolete.
223  *
224  * RETURNS
225  *  S_OK               if successful,
226  *  S_FALSE            if this function was called already.
227  *  RPC_E_CHANGED_MODE if a previous call to CoInitialize specified another
228  *                      threading model.
229  *
230  * BUGS
231  * Only the single threaded model is supported. As a result RPC_E_CHANGED_MODE 
232  * is never returned.
233  *
234  * See the windows documentation for more details.
235  */
236 HRESULT WINAPI CoInitializeEx32(
237         LPVOID lpReserved,      /* [in] pointer to win32 malloc interface
238                                    (obsolete, should be NULL) */
239         DWORD dwCoInit          /* [in] A value from COINIT specifies the threading model */
240
241 {
242   HRESULT hr;
243
244   TRACE(ole, "(%p, %x)\n", lpReserved, (int)dwCoInit);
245
246   if (lpReserved!=NULL)
247   {
248     ERR(ole,"(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
249   }
250
251   /*
252    * Check for unsupported features.
253    */
254   if (dwCoInit!=COINIT_APARTMENTTHREADED) 
255   {
256     FIXME(ole, ":(%p,%x): unsupported flag %x\n", lpReserved, (int)dwCoInit, (int)dwCoInit);
257     /* Hope for the best and continue anyway */
258   }
259
260   /*
261    * Check the lock count. If this is the first time going through the initialize
262    * process, we have to initialize the libraries.
263    */
264   if (s_COMLockCount==0)
265   {
266     /*
267      * Initialize the various COM libraries and data structures.
268      */
269     TRACE(ole, "() - Initializing the COM libraries\n");
270
271     hr = S_OK;
272   }
273   else
274     hr = S_FALSE;
275
276   /*
277    * Crank-up that lock count.
278    */
279   s_COMLockCount++;
280
281   return hr;
282 }
283
284 /***********************************************************************
285  *           CoUninitialize16   [COMPOBJ.3]
286  * Don't know what it does. 
287  * 3-Nov-98 -- this was originally misspelled, I changed it to what I
288  *   believe is the correct spelling
289  */
290 void WINAPI CoUninitialize16(void)
291 {
292   TRACE(ole,"()\n");
293   CoFreeAllLibraries();
294 }
295
296 /***********************************************************************
297  *           CoUninitialize32   [OLE32.47]
298  *
299  * This method will release the COM libraries.
300  *
301  * See the windows documentation for more details.
302  */
303 void WINAPI CoUninitialize32(void)
304 {
305   TRACE(ole,"()\n");
306   
307   /*
308    * Decrease the reference count.
309    */
310   s_COMLockCount--;
311   
312   /*
313    * If we are back to 0 locks on the COM library, make sure we free
314    * all the associated data structures.
315    */
316   if (s_COMLockCount==0)
317   {
318     /*
319      * Release the various COM libraries and data structures.
320      */
321     TRACE(ole, "() - Releasing the COM libraries\n");
322
323     /*
324      * Release the references to the registered class objects.
325      */
326     COM_RevokeAllClasses();
327
328     /*
329      * This will free the loaded COM Dlls.
330      */
331     CoFreeAllLibraries();
332
333     /*
334      * This will free list of external references to COM objects.
335      */
336     COM_ExternalLockFreeList();
337 }
338 }
339
340 /***********************************************************************
341  *           CoGetMalloc16    [COMPOBJ.4]
342  * RETURNS
343  *      The current win16 IMalloc
344  */
345 HRESULT WINAPI CoGetMalloc16(
346         DWORD dwMemContext,     /* [in] unknown */
347         LPMALLOC16 * lpMalloc   /* [out] current win16 malloc interface */
348 ) {
349     if(!currentMalloc16)
350         currentMalloc16 = IMalloc16_Constructor();
351     *lpMalloc = currentMalloc16;
352     return S_OK;
353 }
354
355 /******************************************************************************
356  *              CoGetMalloc32   [OLE32.20]
357  *
358  * RETURNS
359  *      The current win32 IMalloc
360  */
361 HRESULT WINAPI CoGetMalloc32(
362         DWORD dwMemContext,     /* [in] unknown */
363         LPMALLOC32 *lpMalloc    /* [out] current win32 malloc interface */
364 ) {
365     if(!currentMalloc32)
366         currentMalloc32 = IMalloc32_Constructor();
367     *lpMalloc = currentMalloc32;
368     return S_OK;
369 }
370
371 /***********************************************************************
372  *           CoCreateStandardMalloc16 [COMPOBJ.71]
373  */
374 HRESULT WINAPI CoCreateStandardMalloc16(DWORD dwMemContext,
375                                           LPMALLOC16 *lpMalloc)
376 {
377     /* FIXME: docu says we shouldn't return the same allocator as in
378      * CoGetMalloc16 */
379     *lpMalloc = IMalloc16_Constructor();
380     return S_OK;
381 }
382
383 /******************************************************************************
384  *              CoDisconnectObject      [COMPOBJ.15]
385  */
386 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
387 {
388     TRACE(ole,"%p %lx\n",lpUnk,reserved);
389     return S_OK;
390 }
391
392 /***********************************************************************
393  *           IsEqualGUID16 [COMPOBJ.18]
394  *
395  * Compares two Unique Identifiers.
396  *
397  * RETURNS
398  *      TRUE if equal
399  */
400 BOOL16 WINAPI IsEqualGUID16(
401         GUID* g1,       /* [in] unique id 1 */
402         GUID* g2        /**/
403 ) {
404     return !memcmp( g1, g2, sizeof(GUID) );
405 }
406
407 /***********************************************************************
408  *           IsEqualGUID32 [OLE32.76]
409  *
410  * Compares two Unique Identifiers.
411  *
412  * RETURNS
413  *      TRUE if equal
414  */
415 BOOL32 WINAPI IsEqualGUID32(
416      REFGUID rguid1, /* [in] unique id 1 */
417      REFGUID rguid2  /* [in] unique id 2 */
418      )
419 {
420     return !memcmp(rguid1,rguid2,sizeof(GUID));
421 }
422
423 /******************************************************************************
424  *              CLSIDFromString16       [COMPOBJ.20]
425  * Converts a unique identifier from it's string representation into 
426  * the GUID struct.
427  *
428  * Class id: DWORD-WORD-WORD-BYTES[2]-BYTES[6] 
429  *
430  * RETURNS
431  *      the converted GUID
432  */
433 HRESULT WINAPI CLSIDFromString16(
434         LPCOLESTR16 idstr,      /* [in] string representation of guid */
435         CLSID *id               /* [out] GUID converted from string */
436 ) {
437   BYTE *s = (BYTE *) idstr;
438   BYTE *p;
439   int   i;
440   BYTE table[256];
441
442   TRACE(ole,"%s -> %p\n", idstr, id);
443
444   /* quick lookup table */
445   memset(table, 0, 256);
446
447   for (i = 0; i < 10; i++) {
448     table['0' + i] = i;
449   }
450   for (i = 0; i < 6; i++) {
451     table['A' + i] = i+10;
452     table['a' + i] = i+10;
453   }
454
455   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
456
457   if (strlen(idstr) != 38)
458     return OLE_ERROR_OBJECT;
459
460   p = (BYTE *) id;
461
462   s++;  /* skip leading brace  */
463   for (i = 0; i < 4; i++) {
464     p[3 - i] = table[*s]<<4 | table[*(s+1)];
465     s += 2;
466   }
467   p += 4;
468   s++;  /* skip - */
469
470   for (i = 0; i < 2; i++) {
471     p[1-i] = table[*s]<<4 | table[*(s+1)];
472     s += 2;
473   }
474   p += 2;
475   s++;  /* skip - */
476
477   for (i = 0; i < 2; i++) {
478     p[1-i] = table[*s]<<4 | table[*(s+1)];
479     s += 2;
480   }
481   p += 2;
482   s++;  /* skip - */
483
484   /* these are just sequential bytes */
485   for (i = 0; i < 2; i++) {
486     *p++ = table[*s]<<4 | table[*(s+1)];
487     s += 2;
488   }
489   s++;  /* skip - */
490
491   for (i = 0; i < 6; i++) {
492     *p++ = table[*s]<<4 | table[*(s+1)];
493     s += 2;
494   }
495
496   return S_OK;
497 }
498
499 /******************************************************************************
500  *              CoCreateGuid[OLE32.6]
501  *
502  * Creates a 128bit GUID.
503  * Implemented according the DCE specification for UUID generation.
504  * Code is based upon uuid library in e2fsprogs by Theodore Ts'o.
505  * Copyright (C) 1996, 1997 Theodore Ts'o.
506  *
507  * RETURNS
508  *
509  *  S_OK if successful.
510  */
511 HRESULT WINAPI CoCreateGuid(
512         GUID *pguid /* [out] points to the GUID to initialize */
513 ) {
514    static char has_init = 0;
515    unsigned char a[6];
516    static int                      adjustment = 0;
517    static struct timeval           last = {0, 0};
518    static UINT16                   clock_seq;
519    struct timeval                  tv;
520    unsigned long long              clock_reg;
521    UINT32 clock_high, clock_low;
522    UINT16 temp_clock_seq, temp_clock_mid, temp_clock_hi_and_version;
523 #ifdef HAVE_NET_IF_H
524    int             sd;
525    struct ifreq    ifr, *ifrp;
526    struct ifconf   ifc;
527    char buf[1024];
528    int             n, i;
529 #endif
530    
531    /* Have we already tried to get the MAC address? */
532    if (!has_init) {
533 #ifdef HAVE_NET_IF_H
534       /* BSD 4.4 defines the size of an ifreq to be
535        * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
536        * However, under earlier systems, sa_len isn't present, so
537        *  the size is just sizeof(struct ifreq)
538        */
539 # ifdef HAVE_SA_LEN
540 #  ifndef max
541 #   define max(a,b) ((a) > (b) ? (a) : (b))
542 #  endif
543 #  define ifreq_size(i) max(sizeof(struct ifreq),\
544 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
545 # else
546 #  define ifreq_size(i) sizeof(struct ifreq)
547 # endif /* HAVE_SA_LEN */
548       
549       sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
550       if (sd < 0) {
551          /* if we can't open a socket, just use random numbers */
552          /* set the multicast bit to prevent conflicts with real cards */
553          a[0] = (rand() & 0xff) | 0x80;
554          a[1] = rand() & 0xff;
555          a[2] = rand() & 0xff;
556          a[3] = rand() & 0xff;
557          a[4] = rand() & 0xff;
558          a[5] = rand() & 0xff;
559       } else {
560          memset(buf, 0, sizeof(buf));
561          ifc.ifc_len = sizeof(buf);
562          ifc.ifc_buf = buf;
563          /* get the ifconf interface */
564          if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
565             close(sd);
566             /* no ifconf, so just use random numbers */
567             /* set the multicast bit to prevent conflicts with real cards */
568             a[0] = (rand() & 0xff) | 0x80;
569             a[1] = rand() & 0xff;
570             a[2] = rand() & 0xff;
571             a[3] = rand() & 0xff;
572             a[4] = rand() & 0xff;
573             a[5] = rand() & 0xff;
574          } else {
575             /* loop through the interfaces, looking for a valid one */
576             n = ifc.ifc_len;
577             for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
578                ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
579                strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
580                /* try to get the address for this interface */
581 # ifdef SIOCGIFHWADDR
582                if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
583                    continue;
584                memcpy(a, (unsigned char *)&ifr.ifr_hwaddr.sa_data, 6);
585 # else
586 #  ifdef SIOCGENADDR
587                if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
588                    continue;
589                memcpy(a, (unsigned char *) ifr.ifr_enaddr, 6);
590 #  else
591                /* XXX we don't have a way of getting the hardware address */
592                close(sd);
593                a[0] = 0;
594                break;
595 #  endif /* SIOCGENADDR */
596 # endif /* SIOCGIFHWADDR */
597                /* make sure it's not blank */
598                if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
599                    continue;
600                                                                 
601                goto valid_address;
602             }
603             /* if we didn't find a valid address, make a random one */
604             /* once again, set multicast bit to avoid conflicts */
605             a[0] = (rand() & 0xff) | 0x80;
606             a[1] = rand() & 0xff;
607             a[2] = rand() & 0xff;
608             a[3] = rand() & 0xff;
609             a[4] = rand() & 0xff;
610             a[5] = rand() & 0xff;
611
612             valid_address:
613             close(sd);
614          }
615       }
616 #else
617       /* no networking info, so generate a random address */
618       a[0] = (rand() & 0xff) | 0x80;
619       a[1] = rand() & 0xff;
620       a[2] = rand() & 0xff;
621       a[3] = rand() & 0xff;
622       a[4] = rand() & 0xff;
623       a[5] = rand() & 0xff;
624 #endif /* HAVE_NET_IF_H */
625       has_init = 1;
626    }
627    
628    /* generate time element of GUID */
629    
630    /* Assume that the gettimeofday() has microsecond granularity */
631 #define MAX_ADJUSTMENT 10
632                      
633    try_again:
634    gettimeofday(&tv, 0);
635    if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
636       clock_seq = ((rand() & 0xff) << 8) + (rand() & 0xff);
637       clock_seq &= 0x1FFF;
638       last = tv;
639       last.tv_sec--;
640    }
641    if ((tv.tv_sec < last.tv_sec) ||
642        ((tv.tv_sec == last.tv_sec) &&
643         (tv.tv_usec < last.tv_usec))) {
644       clock_seq = (clock_seq+1) & 0x1FFF;
645       adjustment = 0;
646    } else if ((tv.tv_sec == last.tv_sec) &&
647               (tv.tv_usec == last.tv_usec)) {
648       if (adjustment >= MAX_ADJUSTMENT)
649           goto try_again;
650       adjustment++;
651    } else
652        adjustment = 0;
653    
654    clock_reg = tv.tv_usec*10 + adjustment;
655    clock_reg += ((unsigned long long) tv.tv_sec)*10000000;
656    clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
657    
658    clock_high = clock_reg >> 32;
659    clock_low = clock_reg;
660    temp_clock_seq = clock_seq | 0x8000;
661    temp_clock_mid = (UINT16)clock_high;
662    temp_clock_hi_and_version = (clock_high >> 16) | 0x1000;
663    
664    /* pack the information into the GUID structure */
665    
666    ((unsigned char*)&pguid->Data1)[3] = (unsigned char)clock_low;
667    clock_low >>= 8;
668    ((unsigned char*)&pguid->Data1)[2] = (unsigned char)clock_low;
669    clock_low >>= 8;
670    ((unsigned char*)&pguid->Data1)[1] = (unsigned char)clock_low;
671    clock_low >>= 8;
672    ((unsigned char*)&pguid->Data1)[0] = (unsigned char)clock_low;
673    
674    ((unsigned char*)&pguid->Data2)[1] = (unsigned char)temp_clock_mid;
675    temp_clock_mid >>= 8;
676    ((unsigned char*)&pguid->Data2)[0] = (unsigned char)temp_clock_mid;
677    
678    ((unsigned char*)&pguid->Data3)[1] = (unsigned char)temp_clock_hi_and_version;
679    temp_clock_hi_and_version >>= 8;
680    ((unsigned char*)&pguid->Data3)[0] = (unsigned char)temp_clock_hi_and_version;
681       
682    ((unsigned char*)pguid->Data4)[1] = (unsigned char)temp_clock_seq;
683    temp_clock_seq >>= 8;
684    ((unsigned char*)pguid->Data4)[0] = (unsigned char)temp_clock_seq;
685    
686    ((unsigned char*)pguid->Data4)[2] = a[0];
687    ((unsigned char*)pguid->Data4)[3] = a[1];
688    ((unsigned char*)pguid->Data4)[4] = a[2];
689    ((unsigned char*)pguid->Data4)[5] = a[3];
690    ((unsigned char*)pguid->Data4)[6] = a[4];
691    ((unsigned char*)pguid->Data4)[7] = a[5];
692    
693    TRACE(ole, "%p", pguid);
694    
695    return S_OK;
696 }
697
698 /******************************************************************************
699  *              CLSIDFromString32       [OLE32.3]
700  * Converts a unique identifier from it's string representation into 
701  * the GUID struct.
702  * RETURNS
703  *      the converted GUID
704  */
705 HRESULT WINAPI CLSIDFromString32(
706         LPCOLESTR32 idstr,      /* [in] string representation of GUID */
707         CLSID *id               /* [out] GUID represented by above string */
708 ) {
709     LPOLESTR16      xid = HEAP_strdupWtoA(GetProcessHeap(),0,idstr);
710     OLESTATUS       ret = CLSIDFromString16(xid,id);
711
712     HeapFree(GetProcessHeap(),0,xid);
713     return ret;
714 }
715
716 /******************************************************************************
717  *              WINE_StringFromCLSID    [???]
718  * Converts a GUID into the respective string representation.
719  *
720  * NOTES
721  *
722  * RETURNS
723  *      the string representation and OLESTATUS
724  */
725 HRESULT WINE_StringFromCLSID(
726         const CLSID *id,        /* [in] GUID to be converted */
727         LPSTR idstr             /* [out] pointer to buffer to contain converted guid */
728 ) {
729   static const char *hex = "0123456789ABCDEF";
730   char *s;
731   int   i;
732
733   if (!id)
734         { ERR(ole,"called with id=Null\n");
735           *idstr = 0x00;
736           return E_FAIL;
737         }
738         
739   sprintf(idstr, "{%08lX-%04X-%04X-%02x%02X-",
740           id->Data1, id->Data2, id->Data3,
741           id->Data4[0], id->Data4[1]);
742   s = &idstr[25];
743
744   /* 6 hex bytes */
745   for (i = 2; i < 8; i++) {
746     *s++ = hex[id->Data4[i]>>4];
747     *s++ = hex[id->Data4[i] & 0xf];
748   }
749
750   *s++ = '}';
751   *s++ = '\0';
752
753   TRACE(ole,"%p->%s\n", id, idstr);
754
755   return OLE_OK;
756 }
757
758 /******************************************************************************
759  *              StringFromCLSID16       [COMPOBJ.19]
760  * Converts a GUID into the respective string representation.
761  * The target string is allocated using the OLE IMalloc.
762  * RETURNS
763  *      the string representation and OLESTATUS
764  */
765 HRESULT WINAPI StringFromCLSID16(
766         REFCLSID id,            /* [in] the GUID to be converted */
767         LPOLESTR16 *idstr       /* [out] a pointer to a to-be-allocated segmented pointer pointing to the resulting string */
768
769 ) {
770     LPMALLOC16  mllc;
771     OLESTATUS   ret;
772     DWORD       args[2];
773
774     ret = CoGetMalloc16(0,&mllc);
775     if (ret) return ret;
776
777     args[0] = (DWORD)mllc;
778     args[1] = 40;
779
780     /* No need for a Callback entry, we have WOWCallback16Ex which does
781      * everything we need.
782      */
783     if (!WOWCallback16Ex(
784         (FARPROC16)((ICOM_VTABLE(IMalloc16)*)PTR_SEG_TO_LIN(
785                 ((LPMALLOC16)PTR_SEG_TO_LIN(mllc))->lpvtbl)
786         )->fnAlloc,
787         WCB16_CDECL,
788         2,
789         (LPVOID)args,
790         (LPDWORD)idstr
791     )) {
792         WARN(ole,"CallTo16 IMalloc16 failed\n");
793         return E_FAIL;
794     }
795     return WINE_StringFromCLSID(id,PTR_SEG_TO_LIN(*idstr));
796 }
797
798 /******************************************************************************
799  *              StringFromCLSID32       [OLE32.151]
800  * Converts a GUID into the respective string representation.
801  * The target string is allocated using the OLE IMalloc.
802  * RETURNS
803  *      the string representation and OLESTATUS
804  */
805 HRESULT WINAPI StringFromCLSID32(
806         REFCLSID id,            /* [in] the GUID to be converted */
807         LPOLESTR32 *idstr       /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
808 ) {
809         char            buf[80];
810         OLESTATUS       ret;
811         LPMALLOC32      mllc;
812
813         if ((ret=CoGetMalloc32(0,&mllc)))
814                 return ret;
815
816         ret=WINE_StringFromCLSID(id,buf);
817         if (!ret) {
818                 *idstr = mllc->lpvtbl->fnAlloc(mllc,strlen(buf)*2+2);
819                 lstrcpyAtoW(*idstr,buf);
820         }
821         return ret;
822 }
823
824 /******************************************************************************
825  *              StringFromGUID2 [COMPOBJ.76] [OLE32.152]
826  *
827  * Converts a global unique identifier into a string of an API-
828  * specified fixed format. (The usual {.....} stuff.)
829  *
830  * RETURNS
831  *      The (UNICODE) string representation of the GUID in 'str'
832  *      The length of the resulting string, 0 if there was any problem.
833  */
834 INT32 WINAPI
835 StringFromGUID2(REFGUID id, LPOLESTR32 str, INT32 cmax)
836 {
837   char          xguid[80];
838
839   if (WINE_StringFromCLSID(id,xguid))
840         return 0;
841   if (strlen(xguid)>=cmax)
842         return 0;
843   lstrcpyAtoW(str,xguid);
844   return strlen(xguid);
845 }
846
847 /******************************************************************************
848  *              CLSIDFromProgID16       [COMPOBJ.61]
849  * Converts a program id into the respective GUID. (By using a registry lookup)
850  * RETURNS
851  *      riid associated with the progid
852  */
853 HRESULT WINAPI CLSIDFromProgID16(
854         LPCOLESTR16 progid,     /* [in] program id as found in registry */
855         LPCLSID riid            /* [out] associated CLSID */
856 ) {
857         char    *buf,buf2[80];
858         DWORD   buf2len;
859         HRESULT err;
860         HKEY    xhkey;
861
862         buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
863         sprintf(buf,"%s\\CLSID",progid);
864         if ((err=RegOpenKey32A(HKEY_CLASSES_ROOT,buf,&xhkey))) {
865                 HeapFree(GetProcessHeap(),0,buf);
866                 return OLE_ERROR_GENERIC;
867         }
868         HeapFree(GetProcessHeap(),0,buf);
869         buf2len = sizeof(buf2);
870         if ((err=RegQueryValue32A(xhkey,NULL,buf2,&buf2len))) {
871                 RegCloseKey(xhkey);
872                 return OLE_ERROR_GENERIC;
873         }
874         RegCloseKey(xhkey);
875         return CLSIDFromString16(buf2,riid);
876 }
877
878 /******************************************************************************
879  *              CLSIDFromProgID32       [OLE32.2]
880  * Converts a program id into the respective GUID. (By using a registry lookup)
881  * RETURNS
882  *      riid associated with the progid
883  */
884 HRESULT WINAPI CLSIDFromProgID32(
885         LPCOLESTR32 progid,     /* [in] program id as found in registry */
886         LPCLSID riid            /* [out] associated CLSID */
887 ) {
888         LPOLESTR16 pid = HEAP_strdupWtoA(GetProcessHeap(),0,progid);
889         OLESTATUS       ret = CLSIDFromProgID16(pid,riid);
890
891         HeapFree(GetProcessHeap(),0,pid);
892         return ret;
893 }
894
895 /* FIXME: this function is not declared in the WINELIB headers. But where should it go ? */
896 /***********************************************************************
897  *           LookupETask (COMPOBJ.94)
898  */
899 OLESTATUS WINAPI LookupETask(HTASK16 *hTask,LPVOID p) {
900         FIXME(ole,"(%p,%p),stub!\n",hTask,p);
901         if ((*hTask = GetCurrentTask()) == hETask) {
902                 memcpy(p, Table_ETask, sizeof(Table_ETask));
903         }
904         return 0;
905 }
906
907 /* FIXME: this function is not declared in the WINELIB headers. But where should it go ? */
908 /***********************************************************************
909  *           SetETask (COMPOBJ.95)
910  */
911 OLESTATUS WINAPI SetETask(HTASK16 hTask, LPVOID p) {
912         FIXME(ole,"(%04x,%p),stub!\n",hTask,p);
913         hETask = hTask;
914         return 0;
915 }
916
917 /* FIXME: this function is not declared in the WINELIB headers. But where should it go ? */
918 /***********************************************************************
919  *           CallObjectInWOW (COMPOBJ.201)
920  */
921 OLESTATUS WINAPI CallObjectInWOW(LPVOID p1,LPVOID p2) {
922         FIXME(ole,"(%p,%p),stub!\n",p1,p2);
923         return 0;
924 }
925
926 /******************************************************************************
927  *              CoRegisterClassObject16 [COMPOBJ.5]
928  *
929  * Don't know where it registers it ...
930  */
931 HRESULT WINAPI CoRegisterClassObject16(
932         REFCLSID rclsid,
933         LPUNKNOWN pUnk,
934         DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
935         DWORD flags,        /* [in] REGCLS flags indicating how connections are made */
936         LPDWORD lpdwRegister
937 ) {
938         char    buf[80];
939
940         WINE_StringFromCLSID(rclsid,buf);
941
942         FIXME(ole,"(%s,%p,0x%08lx,0x%08lx,%p),stub\n",
943                 buf,pUnk,dwClsContext,flags,lpdwRegister
944         );
945         return 0;
946 }
947
948 /***
949  * COM_GetRegisteredClassObject
950  *
951  * This internal method is used to scan the registered class list to 
952  * find a class object.
953  *
954  * Params: 
955  *   rclsid        Class ID of the class to find.
956  *   dwClsContext  Class context to match.
957  *   ppv           [out] returns a pointer to the class object. Complying
958  *                 to normal COM usage, this method will increase the
959  *                 reference count on this object.
960  */
961 static HRESULT COM_GetRegisteredClassObject(
962         REFCLSID    rclsid,
963         DWORD       dwClsContext,
964         LPUNKNOWN*  ppUnk)
965 {
966   RegisteredClass* curClass;
967
968   /*
969    * Sanity check
970    */
971   assert(ppUnk!=0);
972
973   /*
974    * Iterate through the whole list and try to match the class ID.
975    */
976   curClass = firstRegisteredClass;
977
978   while (curClass != 0)
979   {
980     /*
981      * Check if we have a match on the class ID.
982      */
983     if (IsEqualGUID32(&(curClass->classIdentifier), rclsid))
984     {
985       /*
986        * Since we don't do out-of process or DCOM just right away, let's ignore the
987        * class context.
988        */
989
990       /*
991        * We have a match, return the pointer to the class object.
992        */
993       *ppUnk = curClass->classObject;
994
995       IUnknown_AddRef(curClass->classObject);
996
997       return S_OK;
998     }
999
1000     /*
1001      * Step to the next class in the list.
1002      */
1003     curClass = curClass->nextClass;
1004   }
1005
1006   /*
1007    * If we get to here, we haven't found our class.
1008    */
1009   return S_FALSE;
1010 }
1011
1012 /******************************************************************************
1013  *              CoRegisterClassObject32 [OLE32.36]
1014  *
1015  * This method will register the class object for a given class ID.
1016  *
1017  * See the Windows documentation for more details.
1018  */
1019 HRESULT WINAPI CoRegisterClassObject32(
1020         REFCLSID rclsid,
1021         LPUNKNOWN pUnk,
1022         DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1023         DWORD flags,        /* [in] REGCLS flags indicating how connections are made */
1024         LPDWORD lpdwRegister
1025
1026 {
1027   RegisteredClass* newClass;
1028   LPUNKNOWN        foundObject;
1029   HRESULT          hr;
1030     char buf[80];
1031
1032     WINE_StringFromCLSID(rclsid,buf);
1033
1034   TRACE(ole,"(%s,%p,0x%08lx,0x%08lx,%p)\n",
1035         buf,pUnk,dwClsContext,flags,lpdwRegister);
1036
1037   /*
1038    * Perform a sanity check on the parameters
1039    */
1040   if ( (lpdwRegister==0) || (pUnk==0) )
1041   {
1042     return E_INVALIDARG;
1043 }
1044
1045   /*
1046    * Initialize the cookie (out parameter)
1047    */
1048   *lpdwRegister = 0;
1049
1050   /*
1051    * First, check if the class is already registered.
1052    * If it is, this should cause an error.
1053    */
1054   hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1055
1056   if (hr == S_OK)
1057   {
1058     /*
1059      * The COM_GetRegisteredClassObject increased the reference count on the
1060      * object so it has to be released.
1061      */
1062     IUnknown_Release(foundObject);
1063
1064     return CO_E_OBJISREG;
1065   }
1066     
1067   /*
1068    * If it is not registered, we must create a new entry for this class and
1069    * append it to the registered class list.
1070    * We use the address of the chain node as the cookie since we are sure it's
1071    * unique.
1072    */
1073   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1074
1075   /*
1076    * Initialize the node.
1077    */
1078   newClass->classIdentifier = *rclsid;
1079   newClass->runContext      = dwClsContext;
1080   newClass->connectFlags    = flags;
1081   newClass->dwCookie        = (DWORD)newClass;
1082   newClass->nextClass       = firstRegisteredClass;
1083
1084   /*
1085    * Since we're making a copy of the object pointer, we have to increase it's
1086    * reference count.
1087    */
1088   newClass->classObject     = pUnk;
1089   IUnknown_AddRef(newClass->classObject);
1090
1091   firstRegisteredClass = newClass;
1092     
1093   /*
1094    * We're successfyl Yippee!
1095    */
1096   return S_OK;
1097 }
1098
1099 /***********************************************************************
1100  *           CoRevokeClassObject32 [OLE32.40]
1101  *
1102  * This method will remove a class object from the class registry
1103  *
1104  * See the Windows documentation for more details.
1105  */
1106 HRESULT WINAPI CoRevokeClassObject32(
1107         DWORD dwRegister) 
1108 {
1109   RegisteredClass** prevClassLink;
1110   RegisteredClass*  curClass;
1111
1112   TRACE(ole,"(%08lx)\n",dwRegister);
1113
1114   /*
1115    * Iterate through the whole list and try to match the cookie.
1116    */
1117   curClass      = firstRegisteredClass;
1118   prevClassLink = &firstRegisteredClass;
1119
1120   while (curClass != 0)
1121   {
1122     /*
1123      * Check if we have a match on the cookie.
1124      */
1125     if (curClass->dwCookie == dwRegister)
1126     {
1127       /*
1128        * Remove the class from the chain.
1129        */
1130       *prevClassLink = curClass->nextClass;
1131
1132       /*
1133        * Release the reference to the class object.
1134        */
1135       IUnknown_Release(curClass->classObject);
1136
1137       /*
1138        * Free the memory used by the chain node.
1139  */
1140       HeapFree(GetProcessHeap(), 0, curClass);
1141
1142     return S_OK;
1143 }
1144
1145     /*
1146      * Step to the next class in the list.
1147      */
1148     prevClassLink = &(curClass->nextClass);
1149     curClass      = curClass->nextClass;
1150   }
1151
1152   /*
1153    * If we get to here, we haven't found our class.
1154    */
1155   return E_INVALIDARG;
1156 }
1157
1158 /***********************************************************************
1159  *           CoGetClassObject [COMPOBJ.7]
1160  */
1161 HRESULT WINAPI CoGetClassObject(REFCLSID rclsid, DWORD dwClsContext,
1162                         LPVOID pvReserved, REFIID iid, LPVOID *ppv)
1163 {
1164     LPUNKNOWN regClassObject;
1165     char xclsid[50],xiid[50];
1166     HRESULT hres = E_UNEXPECTED;
1167
1168     char dllName[MAX_PATH+1];
1169     DWORD dllNameLen = sizeof(dllName);
1170     HINSTANCE32 hLibrary;
1171     typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, 
1172                              REFIID iid, LPVOID *ppv);
1173     DllGetClassObjectFunc DllGetClassObject;
1174
1175     WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1176     WINE_StringFromCLSID((LPCLSID)iid,xiid);
1177     TRACE(ole,"\n\tCLSID:\t%s,\n\tIID:\t%s\n",xclsid,xiid);
1178
1179     /*
1180      * First, try and see if we can't match the class ID with one of the 
1181      * registered classes.
1182      */
1183     if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1184     {
1185       /*
1186        * Get the required interface from the retrieved pointer.
1187        */
1188       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1189
1190       /*
1191        * Since QI got another reference on the pointer, we want to release the
1192        * one we already have. If QI was unsuccessful, this will release the object. This
1193        * is good since we are not returning it in the "out" parameter.
1194        */
1195       IUnknown_Release(regClassObject);
1196
1197       return hres;
1198     }
1199
1200     /* out of process and remote servers not supported yet */
1201     if ((CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER) & dwClsContext) {
1202         FIXME(ole, "CLSCTX_LOCAL_SERVER and CLSCTX_REMOTE_SERVER not supported!\n");
1203         return E_ACCESSDENIED;
1204     }
1205
1206     if ((CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER) & dwClsContext) {
1207         HKEY CLSIDkey,key;
1208
1209         /* lookup CLSID in registry key HKCR/CLSID */
1210         hres = RegOpenKeyEx32A(HKEY_CLASSES_ROOT, "CLSID", 0, 
1211                                KEY_READ, &CLSIDkey);
1212
1213         if (hres != ERROR_SUCCESS)
1214                 return REGDB_E_READREGDB;
1215         hres = RegOpenKeyEx32A(CLSIDkey,xclsid,0,KEY_QUERY_VALUE,&key);
1216         if (hres != ERROR_SUCCESS) {
1217             RegCloseKey(CLSIDkey);
1218             return REGDB_E_CLASSNOTREG;
1219         }
1220         hres = RegQueryValue32A(key, "InprocServer32", dllName, &dllNameLen);
1221         RegCloseKey(key);
1222         RegCloseKey(CLSIDkey);
1223         if (hres != ERROR_SUCCESS)
1224                 return REGDB_E_READREGDB;
1225         TRACE(ole,"found InprocServer32 dll %s\n", dllName);
1226
1227         /* open dll, call DllGetClassFactory */
1228         hLibrary = CoLoadLibrary(dllName, TRUE);
1229         if (hLibrary == 0) {
1230             TRACE(ole,"couldn't load InprocServer32 dll %s\n", dllName);
1231             return E_ACCESSDENIED; /* or should this be CO_E_DLLNOTFOUND? */
1232         }
1233         DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress32(hLibrary, "DllGetClassObject");
1234         if (!DllGetClassObject) {
1235             /* not sure if this should be called here CoFreeLibrary(hLibrary);*/
1236             TRACE(ole,"couldn't find function DllGetClassObject in %s\n", dllName);
1237             return E_ACCESSDENIED;
1238         }
1239
1240         /*
1241          * Ask the DLL for it's class object. (there was a note here about class
1242          * factories but this is good.
1243          */
1244         return DllGetClassObject(rclsid, iid, ppv);
1245     }
1246     return hres;
1247 }
1248
1249 /******************************************************************************
1250  *              CoRegisterMessageFilter16       [COMPOBJ.27]
1251  */
1252 HRESULT WINAPI CoRegisterMessageFilter16(
1253         LPMESSAGEFILTER lpMessageFilter,
1254         LPMESSAGEFILTER *lplpMessageFilter
1255 ) {
1256         FIXME(ole,"(%p,%p),stub!\n",lpMessageFilter,lplpMessageFilter);
1257         return 0;
1258 }
1259
1260 /***********************************************************************
1261  *           CoCreateInstance [COMPOBJ.13, OLE32.7]
1262  */
1263 HRESULT WINAPI CoCreateInstance(
1264         REFCLSID rclsid,
1265         LPUNKNOWN pUnkOuter,
1266         DWORD dwClsContext,
1267         REFIID iid,
1268         LPVOID *ppv) 
1269 {
1270         HRESULT hres;
1271         LPCLASSFACTORY lpclf = 0;
1272
1273   /*
1274    * Sanity check
1275    */
1276   if (ppv==0)
1277     return E_POINTER;
1278
1279   /*
1280    * Initialize the "out" parameter
1281    */
1282   *ppv = 0;
1283   
1284   /*
1285    * Get a class factory to construct the object we want.
1286    */
1287   hres = CoGetClassObject(rclsid,
1288                           dwClsContext,
1289                           NULL,
1290                           &IID_IClassFactory,
1291                           (LPVOID)&lpclf);
1292
1293   if (FAILED(hres))
1294     return hres;
1295
1296   /*
1297    * Create the object and don't forget to release the factory
1298    */
1299         hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1300         IClassFactory_Release(lpclf);
1301
1302         return hres;
1303 }
1304
1305
1306
1307 /***********************************************************************
1308  *           CoFreeLibrary [COMPOBJ.13]
1309  */
1310 void WINAPI CoFreeLibrary(HINSTANCE32 hLibrary)
1311 {
1312     OpenDll *ptr, *prev;
1313     OpenDll *tmp;
1314
1315     /* lookup library in linked list */
1316     prev = NULL;
1317     for (ptr = openDllList; ptr != NULL; ptr=ptr->next) {
1318         if (ptr->hLibrary == hLibrary) {
1319             break;
1320         }
1321         prev = ptr;
1322     }
1323
1324     if (ptr == NULL) {
1325         /* shouldn't happen if user passed in a valid hLibrary */
1326         return;
1327     }
1328     /* assert: ptr points to the library entry to free */
1329
1330     /* free library and remove node from list */
1331     FreeLibrary32(hLibrary);
1332     if (ptr == openDllList) {
1333         tmp = openDllList->next;
1334         HeapFree(GetProcessHeap(), 0, openDllList->DllName);
1335         HeapFree(GetProcessHeap(), 0, openDllList);
1336         openDllList = tmp;
1337     } else {
1338         tmp = ptr->next;
1339         HeapFree(GetProcessHeap(), 0, ptr->DllName);
1340         HeapFree(GetProcessHeap(), 0, ptr);
1341         prev->next = tmp;
1342     }
1343
1344 }
1345
1346
1347 /***********************************************************************
1348  *           CoFreeAllLibraries [COMPOBJ.12]
1349  */
1350 void WINAPI CoFreeAllLibraries(void)
1351 {
1352     OpenDll *ptr, *tmp;
1353
1354     for (ptr = openDllList; ptr != NULL; ) {
1355         tmp=ptr->next;
1356         CoFreeLibrary(ptr->hLibrary);
1357         ptr = tmp;
1358     }
1359 }
1360
1361
1362
1363 /***********************************************************************
1364  *           CoFreeUnusedLibraries [COMPOBJ.17]
1365  */
1366 void WINAPI CoFreeUnusedLibraries(void)
1367 {
1368     OpenDll *ptr, *tmp;
1369     typedef HRESULT(*DllCanUnloadNowFunc)(void);
1370     DllCanUnloadNowFunc DllCanUnloadNow;
1371
1372     for (ptr = openDllList; ptr != NULL; ) {
1373         DllCanUnloadNow = (DllCanUnloadNowFunc)
1374             GetProcAddress32(ptr->hLibrary, "DllCanUnloadNow");
1375         
1376         if (DllCanUnloadNow() == S_OK) {
1377             tmp=ptr->next;
1378             CoFreeLibrary(ptr->hLibrary);
1379             ptr = tmp;
1380         } else {
1381             ptr=ptr->next;
1382         }
1383     }
1384 }
1385
1386 /***********************************************************************
1387  *           CoFileTimeNow [COMPOBJ.82, OLE32.10]
1388  * RETURNS
1389  *      the current system time in lpFileTime
1390  */
1391 HRESULT WINAPI CoFileTimeNow(
1392         FILETIME *lpFileTime    /* [out] the current time */
1393 ) {
1394         DOSFS_UnixTimeToFileTime(time(NULL), lpFileTime, 0);
1395         return S_OK;
1396 }
1397
1398 /***********************************************************************
1399  *           CoTaskMemAlloc (OLE32.43)
1400  * RETURNS
1401  *      pointer to newly allocated block
1402  */
1403 LPVOID WINAPI CoTaskMemAlloc(
1404         ULONG size      /* [in] size of memoryblock to be allocated */
1405 ) {
1406     LPMALLOC32  lpmalloc;
1407     HRESULT     ret = CoGetMalloc32(0,&lpmalloc);
1408
1409     if (ret) 
1410         return NULL;
1411     return lpmalloc->lpvtbl->fnAlloc(lpmalloc,size);
1412 }
1413
1414 /***********************************************************************
1415  *           CoTaskMemFree (OLE32.44)
1416  */
1417 VOID WINAPI CoTaskMemFree(
1418         LPVOID ptr      /* [in] pointer to be freed */
1419 ) {
1420     LPMALLOC32  lpmalloc;
1421     HRESULT     ret = CoGetMalloc32(0,&lpmalloc);
1422
1423     if (ret) return;
1424     lpmalloc->lpvtbl->fnFree(lpmalloc,ptr);
1425 }
1426
1427 /***********************************************************************
1428  *           CoLoadLibrary (OLE32.30)
1429  */
1430 HINSTANCE32 WINAPI CoLoadLibrary(LPOLESTR16 lpszLibName, BOOL32 bAutoFree)
1431 {
1432     HINSTANCE32 hLibrary;
1433     OpenDll *ptr;
1434     OpenDll *tmp;
1435   
1436     TRACE(ole,"CoLoadLibrary(%p, %d\n", lpszLibName, bAutoFree);
1437
1438     hLibrary = LoadLibrary32A(lpszLibName);
1439
1440     if (!bAutoFree)
1441         return hLibrary;
1442
1443     if (openDllList == NULL) {
1444         /* empty list -- add first node */
1445         openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
1446         openDllList->DllName = HEAP_strdupA(GetProcessHeap(), 0, lpszLibName);
1447         openDllList->hLibrary = hLibrary;
1448         openDllList->next = NULL;
1449     } else {
1450         /* search for this dll */
1451         int found = FALSE;
1452         for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
1453             if (ptr->hLibrary == hLibrary) {
1454                 found = TRUE;
1455                 break;
1456             }
1457         }
1458         if (!found) {
1459             /* dll not found, add it */
1460             tmp = openDllList;
1461             openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
1462             openDllList->DllName = HEAP_strdupA(GetProcessHeap(), 0, lpszLibName);
1463             openDllList->hLibrary = hLibrary;
1464             openDllList->next = tmp;
1465         }
1466     }
1467      
1468     return hLibrary;
1469 }
1470
1471 /***********************************************************************
1472  *           CoInitializeWOW (OLE32.27)
1473  */
1474 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1475     FIXME(ole,"(0x%08lx,0x%08lx),stub!\n",x,y);
1476     return 0;
1477 }
1478
1479 /******************************************************************************
1480  *              CoLockObjectExternal16  [COMPOBJ.63]
1481  */
1482 HRESULT WINAPI CoLockObjectExternal16(
1483     LPUNKNOWN pUnk,             /* [in] object to be locked */
1484     BOOL16 fLock,               /* [in] do lock */
1485     BOOL16 fLastUnlockReleases  /* [in] ? */
1486 ) {
1487     FIXME(ole,"(%p,%d,%d),stub!\n",pUnk,fLock,fLastUnlockReleases);
1488     return S_OK;
1489 }
1490
1491 /******************************************************************************
1492  *              CoLockObjectExternal32  [OLE32.31]
1493  */
1494 HRESULT WINAPI CoLockObjectExternal32(
1495     LPUNKNOWN pUnk,             /* [in] object to be locked */
1496     BOOL32 fLock,               /* [in] do lock */
1497     BOOL32 fLastUnlockReleases) /* [in] unlock all */
1498 {
1499
1500   if (fLock) 
1501   {
1502     /* 
1503      * Increment the external lock coutner, COM_ExternalLockAddRef also
1504      * increment the object's internal lock counter.
1505      */
1506     COM_ExternalLockAddRef( pUnk); 
1507   }
1508   else
1509   {
1510     /* 
1511      * Decrement the external lock coutner, COM_ExternalLockRelease also
1512      * decrement the object's internal lock counter.
1513      */
1514     COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1515   }
1516
1517     return S_OK;
1518 }
1519
1520 /***********************************************************************
1521  *           CoGetState16 [COMPOBJ.115]
1522  */
1523 HRESULT WINAPI CoGetState16(LPDWORD state)
1524 {
1525     FIXME(ole, "(%p),stub!\n", state);
1526     *state = 0;
1527     return S_OK;
1528 }
1529 /***********************************************************************
1530  *           CoSetState32 [COM32.42]
1531  */
1532 HRESULT WINAPI CoSetState32(LPDWORD state)
1533 {
1534     FIXME(ole, "(%p),stub!\n", state);
1535     *state = 0;
1536     return S_OK;
1537 }
1538
1539 /***
1540  * COM_RevokeAllClasses
1541  *
1542  * This method is called when the COM libraries are uninitialized to 
1543  * release all the references to the class objects registered with
1544  * the library
1545  */
1546 static void COM_RevokeAllClasses()
1547 {
1548   while (firstRegisteredClass!=0)
1549   {
1550     CoRevokeClassObject32(firstRegisteredClass->dwCookie);
1551   }
1552 }
1553
1554 /****************************************************************************
1555  *  COM External Lock methods implementation
1556  */
1557
1558 /****************************************************************************
1559  * Public - Method that increments the count for a IUnknown* in the linked 
1560  * list.  The item is inserted if not already in the list.
1561  */
1562 static void COM_ExternalLockAddRef(
1563   IUnknown *pUnk)
1564 {
1565   COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk);
1566
1567   if ( externalLock == EL_NOT_FOUND )
1568     COM_ExternalLockInsert(pUnk);
1569   else
1570   {
1571     externalLock->uRefCount++;  /* add an external lock     */
1572     IUnknown_AddRef(pUnk);      /* add a local lock as well */
1573   }
1574 }
1575
1576 /****************************************************************************
1577  * Public - Method that decrements the count for a IUnknown* in the linked 
1578  * list.  The item is removed from the list if its count end up at zero or if
1579  * bRelAll is TRUE.
1580  */
1581 static void COM_ExternalLockRelease(
1582   IUnknown *pUnk,
1583   BOOL32   bRelAll)
1584 {
1585   COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk);
1586
1587   if ( externalLock != EL_NOT_FOUND )
1588   {
1589     do
1590     {
1591       externalLock->uRefCount--;  /* release external locks      */
1592       IUnknown_Release(pUnk);     /* release local locks as well */
1593
1594       if ( bRelAll == FALSE ) 
1595         break;  /* perform single release */
1596
1597     } while ( externalLock->uRefCount > 0 );  
1598
1599     if ( externalLock->uRefCount == 0 )  /* get rid of the list entry */
1600       COM_ExternalLockDelete(externalLock);
1601   }
1602 }
1603 /****************************************************************************
1604  * Public - Method that frees the content of the list.
1605  */
1606 static void COM_ExternalLockFreeList()
1607 {
1608   COM_ExternalLock *head;
1609
1610   do 
1611   {
1612     head = elList.head;               /* grab it be the head             */
1613     COM_ExternalLockDelete(head);     /* get rid of the head stuff       */
1614
1615     head = elList.head;               /* get the new head...             */ 
1616
1617   } while ( head != EL_END_OF_LIST ); /* repeat as long as we have heads */
1618 }
1619
1620 /****************************************************************************
1621  * Public - Method that dump the content of the list.
1622  */
1623 void COM_ExternalLockDump()
1624 {
1625   COM_ExternalLock *current = elList.head;
1626
1627   printf("\nExternal lock list contains:\n");
1628
1629   while ( current != EL_END_OF_LIST )
1630   {
1631     printf( "\t%p with %lu references count.\n", 
1632       current->pUnk, 
1633       current->uRefCount);
1634  
1635     /* Skip to the next item */ 
1636     current = current->next;
1637   } 
1638
1639 }
1640
1641 /****************************************************************************
1642  * Internal - Find a IUnknown* in the linked list
1643  */
1644 static COM_ExternalLock* COM_ExternalLockFind(
1645   IUnknown *pUnk)
1646 {
1647   return COM_ExternalLockLocate(elList.head, pUnk);
1648 }
1649
1650 /****************************************************************************
1651  * Internal - Recursivity agent for IUnknownExternalLockList_Find
1652  */
1653 static COM_ExternalLock* COM_ExternalLockLocate(
1654   COM_ExternalLock *element,
1655   IUnknown         *pUnk)
1656 {
1657   if ( element == EL_END_OF_LIST )  
1658     return EL_NOT_FOUND;
1659
1660   else if ( element->pUnk == pUnk )    /* We found it */
1661     return element;
1662
1663   else                                 /* Not the right guy, keep on looking */ 
1664     return COM_ExternalLockLocate( element->next, pUnk);
1665 }
1666
1667 /****************************************************************************
1668  * Internal - Insert a new IUnknown* to the linked list
1669  */
1670 static BOOL32 COM_ExternalLockInsert(
1671   IUnknown *pUnk)
1672 {
1673   COM_ExternalLock *newLock      = NULL;
1674   COM_ExternalLock *previousHead = NULL;
1675
1676   /*
1677    * Allocate space for the new storage object
1678    */
1679   newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1680
1681   if (newLock!=NULL)
1682   {
1683     if ( elList.head == EL_END_OF_LIST ) 
1684     {
1685       elList.head = newLock;    /* The list is empty */
1686     }
1687     else 
1688     {
1689       /* 
1690        * insert does it at the head
1691        */
1692       previousHead  = elList.head;
1693       elList.head = newLock;
1694     }
1695
1696     /*
1697      * Set new list item data member 
1698      */
1699     newLock->pUnk      = pUnk;
1700     newLock->uRefCount = 1;
1701     newLock->next      = previousHead;
1702     
1703     return TRUE;
1704   }
1705   else
1706     return FALSE;
1707 }
1708
1709 /****************************************************************************
1710  * Internal - Method that removes an item from the linked list.
1711  */
1712 static void COM_ExternalLockDelete(
1713   COM_ExternalLock *itemList)
1714 {
1715   COM_ExternalLock *current = elList.head;
1716
1717   if ( current == itemList )
1718   {
1719     /* 
1720      * this section handles the deletion of the first node 
1721      */
1722     elList.head = itemList->next;
1723     HeapFree( GetProcessHeap(), 0, itemList);  
1724   }
1725   else
1726   {
1727     do 
1728     {
1729       if ( current->next == itemList )   /* We found the item to free  */
1730       {
1731         current->next = itemList->next;  /* readjust the list pointers */
1732   
1733         HeapFree( GetProcessHeap(), 0, itemList);  
1734         break; 
1735       }
1736  
1737       /* Skip to the next item */ 
1738       current = current->next;
1739   
1740     } while ( current != EL_END_OF_LIST );
1741   }
1742 }