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