Define NONAMELESS{STRUCT,UNION} explicitly in the files that need them.
[wine/multimedia.git] / dlls / ole32 / compobj.c
blob3b58b74b88c3377aad04f4fea5467a61373eb829
1 /*
2 * COMPOBJ library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <assert.h>
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "windef.h"
35 #include "objbase.h"
36 #include "ole2.h"
37 #include "ole2ver.h"
38 #include "rpc.h"
39 #include "winerror.h"
40 #include "winreg.h"
41 #include "wownt32.h"
42 #include "wine/unicode.h"
43 #include "objbase.h"
44 #include "compobj_private.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(ole);
50 /****************************************************************************
51 * This section defines variables internal to the COM module.
53 * TODO: Most of these things will have to be made thread-safe.
55 HINSTANCE COMPOBJ_hInstance32 = 0;
57 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
58 static void COM_RevokeAllClasses();
59 static void COM_ExternalLockFreeList();
61 /*****************************************************************************
62 * Appartment management stuff
64 * NOTE:
65 * per Thread values are stored in the TEB on offset 0xF80
67 * see www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm
71 typedef struct {
72 unsigned char threadingModell; /* we use the COINIT flags */
73 unsigned long threadID;
74 long AppartmentLockCount;
75 } OleAppartmentData;
77 typedef struct {
78 OleAppartmentData *AppartmentData;
79 } OleThreadData;
81 /* not jet used
82 static CRITICAL_SECTION csAppartmentData = CRITICAL_SECTION_INIT("csAppartmentData");
85 * the first STA created in a process is the main STA
88 /* not jet used
89 static OleAppartmentData * mainSTA;
93 * a Process can only have one MTA
96 /* not jet used
97 static OleAppartmentData * processMTA;
102 * This lock count counts the number of times CoInitialize is called. It is
103 * decreased every time CoUninitialize is called. When it hits 0, the COM
104 * libraries are freed
106 static LONG s_COMLockCount = 0;
109 * This linked list contains the list of registered class objects. These
110 * are mostly used to register the factories for out-of-proc servers of OLE
111 * objects.
113 * TODO: Make this data structure aware of inter-process communication. This
114 * means that parts of this will be exported to the Wine Server.
116 typedef struct tagRegisteredClass
118 CLSID classIdentifier;
119 LPUNKNOWN classObject;
120 DWORD runContext;
121 DWORD connectFlags;
122 DWORD dwCookie;
123 HANDLE hThread; /* only for localserver */
124 struct tagRegisteredClass* nextClass;
125 } RegisteredClass;
127 static CRITICAL_SECTION csRegisteredClassList = CRITICAL_SECTION_INIT("csRegisteredClassList");
128 static RegisteredClass* firstRegisteredClass = NULL;
130 /*****************************************************************************
131 * This section contains OpenDllList definitions
133 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
134 * other functions what do LoadLibrary _without_ giving back a HMODULE.
135 * Without this list these handles would be freed never.
137 * FIXME: a DLL what says OK whenn asked for unloading is unloaded in the
138 * next unload-call but not before 600 sec.
141 typedef struct tagOpenDll {
142 HINSTANCE hLibrary;
143 struct tagOpenDll *next;
144 } OpenDll;
146 static CRITICAL_SECTION csOpenDllList = CRITICAL_SECTION_INIT("csOpenDllList");
147 static OpenDll *openDllList = NULL; /* linked list of open dlls */
149 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
150 static void COMPOBJ_DllList_FreeUnused(int Timeout);
153 /******************************************************************************
154 * Initialize/Uninitialize critical sections.
156 void COMPOBJ_InitProcess( void )
160 void COMPOBJ_UninitProcess( void )
164 /*****************************************************************************
165 * This section contains OpenDllList implemantation
168 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
170 OpenDll *ptr;
171 OpenDll *tmp;
173 TRACE("\n");
175 EnterCriticalSection( &csOpenDllList );
177 if (openDllList == NULL) {
178 /* empty list -- add first node */
179 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
180 openDllList->hLibrary=hLibrary;
181 openDllList->next = NULL;
182 } else {
183 /* search for this dll */
184 int found = FALSE;
185 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
186 if (ptr->hLibrary == hLibrary) {
187 found = TRUE;
188 break;
191 if (!found) {
192 /* dll not found, add it */
193 tmp = openDllList;
194 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
195 openDllList->hLibrary = hLibrary;
196 openDllList->next = tmp;
200 LeaveCriticalSection( &csOpenDllList );
203 static void COMPOBJ_DllList_FreeUnused(int Timeout)
205 OpenDll *curr, *next, *prev = NULL;
206 typedef HRESULT(*DllCanUnloadNowFunc)(void);
207 DllCanUnloadNowFunc DllCanUnloadNow;
209 TRACE("\n");
211 EnterCriticalSection( &csOpenDllList );
213 for (curr = openDllList; curr != NULL; ) {
214 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
216 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
217 next = curr->next;
219 TRACE("freeing %p\n", curr->hLibrary);
220 FreeLibrary(curr->hLibrary);
222 HeapFree(GetProcessHeap(), 0, curr);
223 if (curr == openDllList) {
224 openDllList = next;
225 } else {
226 prev->next = next;
229 curr = next;
230 } else {
231 prev = curr;
232 curr = curr->next;
236 LeaveCriticalSection( &csOpenDllList );
239 /******************************************************************************
240 * CoBuildVersion [COMPOBJ.1]
241 * CoBuildVersion [OLE32.4]
243 * RETURNS
244 * Current build version, hiword is majornumber, loword is minornumber
246 DWORD WINAPI CoBuildVersion(void)
248 TRACE("Returning version %d, build %d.\n", rmm, rup);
249 return (rmm<<16)+rup;
252 /******************************************************************************
253 * CoInitialize [OLE32.26]
255 * Initializes the COM libraries.
257 * See CoInitializeEx
259 HRESULT WINAPI CoInitialize(
260 LPVOID lpReserved /* [in] pointer to win32 malloc interface
261 (obsolete, should be NULL) */
265 * Just delegate to the newer method.
267 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
270 /******************************************************************************
271 * CoInitializeEx [OLE32.163]
273 * Initializes the COM libraries. The behavior used to set the win32 IMalloc
274 * used for memory management is obsolete.
276 * RETURNS
277 * S_OK if successful,
278 * S_FALSE if this function was called already.
279 * RPC_E_CHANGED_MODE if a previous call to CoInitialize specified another
280 * threading model.
282 * BUGS
283 * Only the single threaded model is supported. As a result RPC_E_CHANGED_MODE
284 * is never returned.
286 * See the windows documentation for more details.
288 HRESULT WINAPI CoInitializeEx(
289 LPVOID lpReserved, /* [in] pointer to win32 malloc interface
290 (obsolete, should be NULL) */
291 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
294 HRESULT hr;
296 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
298 if (lpReserved!=NULL)
300 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
304 * Check for unsupported features.
306 if (dwCoInit!=COINIT_APARTMENTTHREADED)
308 FIXME(":(%p,%x): unsupported flag %x\n", lpReserved, (int)dwCoInit, (int)dwCoInit);
309 /* Hope for the best and continue anyway */
313 * Check the lock count. If this is the first time going through the initialize
314 * process, we have to initialize the libraries.
316 * And crank-up that lock count.
318 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
321 * Initialize the various COM libraries and data structures.
323 TRACE("() - Initializing the COM libraries\n");
326 RunningObjectTableImpl_Initialize();
328 hr = S_OK;
330 else
331 hr = S_FALSE;
333 return hr;
336 /***********************************************************************
337 * CoUninitialize [OLE32.47]
339 * This method will release the COM libraries.
341 * See the windows documentation for more details.
343 void WINAPI CoUninitialize(void)
345 LONG lCOMRefCnt;
346 TRACE("()\n");
349 * Decrease the reference count.
350 * If we are back to 0 locks on the COM library, make sure we free
351 * all the associated data structures.
353 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
354 if (lCOMRefCnt==1)
357 * Release the various COM libraries and data structures.
359 TRACE("() - Releasing the COM libraries\n");
361 RunningObjectTableImpl_UnInitialize();
363 * Release the references to the registered class objects.
365 COM_RevokeAllClasses();
368 * This will free the loaded COM Dlls.
370 CoFreeAllLibraries();
373 * This will free list of external references to COM objects.
375 COM_ExternalLockFreeList();
378 else if (lCOMRefCnt<1) {
379 ERR( "CoUninitialize() - not CoInitialized.\n" );
380 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
384 /******************************************************************************
385 * CoDisconnectObject [COMPOBJ.15]
386 * CoDisconnectObject [OLE32.8]
388 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
390 TRACE("(%p, %lx)\n",lpUnk,reserved);
391 return S_OK;
394 /******************************************************************************
395 * CoCreateGuid[OLE32.6]
398 HRESULT WINAPI CoCreateGuid(
399 GUID *pguid /* [out] points to the GUID to initialize */
401 return UuidCreate(pguid);
404 /******************************************************************************
405 * CLSIDFromString [OLE32.3]
406 * IIDFromString [OLE32.74]
407 * Converts a unique identifier from its string representation into
408 * the GUID struct.
410 * UNDOCUMENTED
411 * If idstr is not a valid CLSID string then it gets treated as a ProgID
413 * RETURNS
414 * the converted GUID
416 HRESULT WINAPI __CLSIDFromStringA(
417 LPCSTR idstr, /* [in] string representation of guid */
418 CLSID *id) /* [out] GUID converted from string */
420 BYTE *s = (BYTE *) idstr;
421 int i;
422 BYTE table[256];
424 if (!s)
425 s = "{00000000-0000-0000-0000-000000000000}";
426 else { /* validate the CLSID string */
428 if (strlen(s) != 38)
429 return CO_E_CLASSSTRING;
431 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
432 return CO_E_CLASSSTRING;
434 for (i=1; i<37; i++) {
435 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
436 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
437 ((s[i] >= 'a') && (s[i] <= 'f')) ||
438 ((s[i] >= 'A') && (s[i] <= 'F'))))
439 return CO_E_CLASSSTRING;
443 TRACE("%s -> %p\n", s, id);
445 /* quick lookup table */
446 memset(table, 0, 256);
448 for (i = 0; i < 10; i++) {
449 table['0' + i] = i;
451 for (i = 0; i < 6; i++) {
452 table['A' + i] = i+10;
453 table['a' + i] = i+10;
456 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
458 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
459 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
460 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
461 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
463 /* these are just sequential bytes */
464 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
465 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
466 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
467 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
468 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
469 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
470 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
471 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
473 return S_OK;
476 /*****************************************************************************/
478 HRESULT WINAPI CLSIDFromString(
479 LPCOLESTR idstr, /* [in] string representation of GUID */
480 CLSID *id ) /* [out] GUID represented by above string */
482 char xid[40];
483 HRESULT ret;
485 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
486 return CO_E_CLASSSTRING;
489 ret = __CLSIDFromStringA(xid,id);
490 if(ret != S_OK) { /* It appears a ProgID is also valid */
491 ret = CLSIDFromProgID(idstr, id);
493 return ret;
496 /******************************************************************************
497 * WINE_StringFromCLSID [Internal]
498 * Converts a GUID into the respective string representation.
500 * NOTES
502 * RETURNS
503 * the string representation and HRESULT
505 HRESULT WINE_StringFromCLSID(
506 const CLSID *id, /* [in] GUID to be converted */
507 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
509 static const char *hex = "0123456789ABCDEF";
510 char *s;
511 int i;
513 if (!id)
514 { ERR("called with id=Null\n");
515 *idstr = 0x00;
516 return E_FAIL;
519 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
520 id->Data1, id->Data2, id->Data3,
521 id->Data4[0], id->Data4[1]);
522 s = &idstr[25];
524 /* 6 hex bytes */
525 for (i = 2; i < 8; i++) {
526 *s++ = hex[id->Data4[i]>>4];
527 *s++ = hex[id->Data4[i] & 0xf];
530 *s++ = '}';
531 *s++ = '\0';
533 TRACE("%p->%s\n", id, idstr);
535 return S_OK;
539 /******************************************************************************
540 * StringFromCLSID [OLE32.151]
541 * StringFromIID [OLE32.153]
542 * Converts a GUID into the respective string representation.
543 * The target string is allocated using the OLE IMalloc.
544 * RETURNS
545 * the string representation and HRESULT
547 HRESULT WINAPI StringFromCLSID(
548 REFCLSID id, /* [in] the GUID to be converted */
549 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
551 char buf[80];
552 HRESULT ret;
553 LPMALLOC mllc;
555 if ((ret=CoGetMalloc(0,&mllc)))
556 return ret;
558 ret=WINE_StringFromCLSID(id,buf);
559 if (!ret) {
560 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
561 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
562 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
564 return ret;
567 /******************************************************************************
568 * StringFromGUID2 [COMPOBJ.76]
569 * StringFromGUID2 [OLE32.152]
571 * Converts a global unique identifier into a string of an API-
572 * specified fixed format. (The usual {.....} stuff.)
574 * RETURNS
575 * The (UNICODE) string representation of the GUID in 'str'
576 * The length of the resulting string, 0 if there was any problem.
578 INT WINAPI
579 StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
581 char xguid[80];
583 if (WINE_StringFromCLSID(id,xguid))
584 return 0;
585 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
588 /******************************************************************************
589 * ProgIDFromCLSID [OLE32.133]
590 * Converts a class id into the respective Program ID. (By using a registry lookup)
591 * RETURNS S_OK on success
592 * riid associated with the progid
595 HRESULT WINAPI ProgIDFromCLSID(
596 REFCLSID clsid, /* [in] class id as found in registry */
597 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
600 char strCLSID[50], *buf, *buf2;
601 DWORD buf2len;
602 HKEY xhkey;
603 LPMALLOC mllc;
604 HRESULT ret = S_OK;
606 WINE_StringFromCLSID(clsid, strCLSID);
608 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
609 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
610 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
611 ret = REGDB_E_CLASSNOTREG;
613 HeapFree(GetProcessHeap(), 0, buf);
615 if (ret == S_OK)
617 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
618 buf2len = 255;
619 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
620 ret = REGDB_E_CLASSNOTREG;
622 if (ret == S_OK)
624 if (CoGetMalloc(0,&mllc))
625 ret = E_OUTOFMEMORY;
626 else
628 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
629 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
630 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
633 HeapFree(GetProcessHeap(), 0, buf2);
636 RegCloseKey(xhkey);
637 return ret;
640 /******************************************************************************
641 * CLSIDFromProgID [OLE32.2]
642 * Converts a program id into the respective GUID. (By using a registry lookup)
643 * RETURNS
644 * riid associated with the progid
646 HRESULT WINAPI CLSIDFromProgID(
647 LPCOLESTR progid, /* [in] program id as found in registry */
648 LPCLSID riid ) /* [out] associated CLSID */
650 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
651 char buf2[80];
652 DWORD buf2len = sizeof(buf2);
653 HKEY xhkey;
655 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
656 strcpyW( buf, progid );
657 strcatW( buf, clsidW );
658 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
660 HeapFree(GetProcessHeap(),0,buf);
661 return CO_E_CLASSSTRING;
663 HeapFree(GetProcessHeap(),0,buf);
665 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
667 RegCloseKey(xhkey);
668 return CO_E_CLASSSTRING;
670 RegCloseKey(xhkey);
671 return __CLSIDFromStringA(buf2,riid);
676 /*****************************************************************************
677 * CoGetPSClsid [OLE32.22]
679 * This function returns the CLSID of the DLL that implements the proxy and stub
680 * for the specified interface.
682 * It determines this by searching the
683 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
684 * and any interface id registered by CoRegisterPSClsid within the current process.
686 * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
688 HRESULT WINAPI CoGetPSClsid(
689 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
690 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
692 char *buf, buf2[40];
693 DWORD buf2len;
694 HKEY xhkey;
696 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
698 /* Get the input iid as a string */
699 WINE_StringFromCLSID(riid, buf2);
700 /* Allocate memory for the registry key we will construct.
701 (length of iid string plus constant length of static text */
702 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
703 if (buf == NULL)
705 return (E_OUTOFMEMORY);
708 /* Construct the registry key we want */
709 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
711 /* Open the key.. */
712 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
714 HeapFree(GetProcessHeap(),0,buf);
715 return (E_INVALIDARG);
717 HeapFree(GetProcessHeap(),0,buf);
719 /* ... Once we have the key, query the registry to get the
720 value of CLSID as a string, and convert it into a
721 proper CLSID structure to be passed back to the app */
722 buf2len = sizeof(buf2);
723 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
725 RegCloseKey(xhkey);
726 return E_INVALIDARG;
728 RegCloseKey(xhkey);
730 /* We have the CLSid we want back from the registry as a string, so
731 lets convert it into a CLSID structure */
732 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
733 return E_INVALIDARG;
736 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
737 return (S_OK);
742 /***********************************************************************
743 * WriteClassStm (OLE32.159)
745 * This function write a CLSID on stream
747 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
749 TRACE("(%p,%p)\n",pStm,rclsid);
751 if (rclsid==NULL)
752 return E_INVALIDARG;
754 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
757 /***********************************************************************
758 * ReadClassStm (OLE32.135)
760 * This function read a CLSID from a stream
762 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
764 ULONG nbByte;
765 HRESULT res;
767 TRACE("(%p,%p)\n",pStm,pclsid);
769 if (pclsid==NULL)
770 return E_INVALIDARG;
772 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
774 if (FAILED(res))
775 return res;
777 if (nbByte != sizeof(CLSID))
778 return S_FALSE;
779 else
780 return S_OK;
784 /***
785 * COM_GetRegisteredClassObject
787 * This internal method is used to scan the registered class list to
788 * find a class object.
790 * Params:
791 * rclsid Class ID of the class to find.
792 * dwClsContext Class context to match.
793 * ppv [out] returns a pointer to the class object. Complying
794 * to normal COM usage, this method will increase the
795 * reference count on this object.
797 static HRESULT COM_GetRegisteredClassObject(
798 REFCLSID rclsid,
799 DWORD dwClsContext,
800 LPUNKNOWN* ppUnk)
802 HRESULT hr = S_FALSE;
803 RegisteredClass* curClass;
805 EnterCriticalSection( &csRegisteredClassList );
808 * Sanity check
810 assert(ppUnk!=0);
813 * Iterate through the whole list and try to match the class ID.
815 curClass = firstRegisteredClass;
817 while (curClass != 0)
820 * Check if we have a match on the class ID.
822 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
825 * Since we don't do out-of process or DCOM just right away, let's ignore the
826 * class context.
830 * We have a match, return the pointer to the class object.
832 *ppUnk = curClass->classObject;
834 IUnknown_AddRef(curClass->classObject);
836 hr = S_OK;
837 goto end;
841 * Step to the next class in the list.
843 curClass = curClass->nextClass;
846 end:
847 LeaveCriticalSection( &csRegisteredClassList );
849 * If we get to here, we haven't found our class.
851 return hr;
854 static DWORD WINAPI
855 _LocalServerThread(LPVOID param) {
856 HANDLE hPipe;
857 char pipefn[200];
858 RegisteredClass *newClass = (RegisteredClass*)param;
859 HRESULT hres;
860 IStream *pStm;
861 STATSTG ststg;
862 unsigned char *buffer;
863 int buflen;
864 IClassFactory *classfac;
865 LARGE_INTEGER seekto;
866 ULARGE_INTEGER newpos;
867 ULONG res;
869 TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier));
870 strcpy(pipefn,PIPEPREF);
871 WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
873 hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
874 if (hres) return hres;
876 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
877 if (hres) {
878 FIXME("Failed to create stream on hglobal.\n");
879 return hres;
881 hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
882 if (hres) {
883 FIXME("CoMarshalInterface failed, %lx!\n",hres);
884 return hres;
886 hres = IStream_Stat(pStm,&ststg,0);
887 if (hres) return hres;
889 buflen = ststg.cbSize.s.LowPart;
890 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
891 seekto.s.LowPart = 0;
892 seekto.s.HighPart = 0;
893 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
894 if (hres) {
895 FIXME("IStream_Seek failed, %lx\n",hres);
896 return hres;
898 hres = IStream_Read(pStm,buffer,buflen,&res);
899 if (hres) {
900 FIXME("Stream Read failed, %lx\n",hres);
901 return hres;
903 IStream_Release(pStm);
905 while (1) {
906 hPipe = CreateNamedPipeA(
907 pipefn,
908 PIPE_ACCESS_DUPLEX,
909 PIPE_TYPE_BYTE|PIPE_WAIT,
910 PIPE_UNLIMITED_INSTANCES,
911 4096,
912 4096,
913 NMPWAIT_USE_DEFAULT_WAIT,
914 NULL
916 if (hPipe == INVALID_HANDLE_VALUE) {
917 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
918 return 1;
920 if (!ConnectNamedPipe(hPipe,NULL)) {
921 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
922 CloseHandle(hPipe);
923 continue;
925 WriteFile(hPipe,buffer,buflen,&res,NULL);
926 CloseHandle(hPipe);
928 return 0;
931 /******************************************************************************
932 * CoRegisterClassObject [OLE32.36]
934 * This method will register the class object for a given class ID.
936 * See the Windows documentation for more details.
938 HRESULT WINAPI CoRegisterClassObject(
939 REFCLSID rclsid,
940 LPUNKNOWN pUnk,
941 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
942 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
943 LPDWORD lpdwRegister
946 RegisteredClass* newClass;
947 LPUNKNOWN foundObject;
948 HRESULT hr;
950 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
951 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
953 if ( (lpdwRegister==0) || (pUnk==0) )
954 return E_INVALIDARG;
956 *lpdwRegister = 0;
959 * First, check if the class is already registered.
960 * If it is, this should cause an error.
962 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
963 if (hr == S_OK) {
964 IUnknown_Release(foundObject);
965 return CO_E_OBJISREG;
968 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
969 if ( newClass == NULL )
970 return E_OUTOFMEMORY;
972 EnterCriticalSection( &csRegisteredClassList );
974 newClass->classIdentifier = *rclsid;
975 newClass->runContext = dwClsContext;
976 newClass->connectFlags = flags;
978 * Use the address of the chain node as the cookie since we are sure it's
979 * unique.
981 newClass->dwCookie = (DWORD)newClass;
982 newClass->nextClass = firstRegisteredClass;
985 * Since we're making a copy of the object pointer, we have to increase its
986 * reference count.
988 newClass->classObject = pUnk;
989 IUnknown_AddRef(newClass->classObject);
991 firstRegisteredClass = newClass;
992 LeaveCriticalSection( &csRegisteredClassList );
994 *lpdwRegister = newClass->dwCookie;
996 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
997 DWORD tid;
999 STUBMGR_Start();
1000 newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1002 return S_OK;
1005 /***********************************************************************
1006 * CoRevokeClassObject [OLE32.40]
1008 * This method will remove a class object from the class registry
1010 * See the Windows documentation for more details.
1012 HRESULT WINAPI CoRevokeClassObject(
1013 DWORD dwRegister)
1015 HRESULT hr = E_INVALIDARG;
1016 RegisteredClass** prevClassLink;
1017 RegisteredClass* curClass;
1019 TRACE("(%08lx)\n",dwRegister);
1021 EnterCriticalSection( &csRegisteredClassList );
1024 * Iterate through the whole list and try to match the cookie.
1026 curClass = firstRegisteredClass;
1027 prevClassLink = &firstRegisteredClass;
1029 while (curClass != 0)
1032 * Check if we have a match on the cookie.
1034 if (curClass->dwCookie == dwRegister)
1037 * Remove the class from the chain.
1039 *prevClassLink = curClass->nextClass;
1042 * Release the reference to the class object.
1044 IUnknown_Release(curClass->classObject);
1047 * Free the memory used by the chain node.
1049 HeapFree(GetProcessHeap(), 0, curClass);
1051 hr = S_OK;
1052 goto end;
1056 * Step to the next class in the list.
1058 prevClassLink = &(curClass->nextClass);
1059 curClass = curClass->nextClass;
1062 end:
1063 LeaveCriticalSection( &csRegisteredClassList );
1065 * If we get to here, we haven't found our class.
1067 return hr;
1070 /***********************************************************************
1071 * compobj_RegReadPath [internal]
1073 * Reads a registry value and expands it when nessesary
1075 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, int dstlen)
1077 HRESULT hres;
1078 HKEY key;
1079 DWORD keytype;
1080 char src[MAX_PATH];
1081 DWORD dwLength = dstlen;
1083 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1084 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1085 if (keytype == REG_EXPAND_SZ) {
1086 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1087 } else {
1088 strncpy(dst, src, dstlen);
1091 RegCloseKey (key);
1093 return hres;
1096 /***********************************************************************
1097 * CoGetClassObject [COMPOBJ.7]
1098 * CoGetClassObject [OLE32.16]
1100 * FIXME. If request allows of several options and there is a failure
1101 * with one (other than not being registered) do we try the
1102 * others or return failure? (E.g. inprocess is registered but
1103 * the DLL is not found but the server version works)
1105 HRESULT WINAPI CoGetClassObject(
1106 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1107 REFIID iid, LPVOID *ppv
1109 LPUNKNOWN regClassObject;
1110 HRESULT hres = E_UNEXPECTED;
1111 char xclsid[80];
1112 HINSTANCE hLibrary;
1113 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1114 DllGetClassObjectFunc DllGetClassObject;
1116 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1118 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1120 if (pServerInfo) {
1121 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1122 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1126 * First, try and see if we can't match the class ID with one of the
1127 * registered classes.
1129 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1132 * Get the required interface from the retrieved pointer.
1134 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1137 * Since QI got another reference on the pointer, we want to release the
1138 * one we already have. If QI was unsuccessful, this will release the object. This
1139 * is good since we are not returning it in the "out" parameter.
1141 IUnknown_Release(regClassObject);
1143 return hres;
1146 /* first try: in-process */
1147 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1148 char keyname[MAX_PATH];
1149 char dllpath[MAX_PATH+1];
1151 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1153 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1154 /* failure: CLSID is not found in registry */
1155 WARN("class %s not registred\n", xclsid);
1156 hres = REGDB_E_CLASSNOTREG;
1157 } else {
1158 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1159 /* failure: DLL could not be loaded */
1160 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1161 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1162 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1163 /* failure: the dll did not export DllGetClassObject */
1164 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1165 FreeLibrary( hLibrary );
1166 hres = CO_E_DLLNOTFOUND;
1167 } else {
1168 /* OK: get the ClassObject */
1169 COMPOBJ_DLLList_Add( hLibrary );
1170 return DllGetClassObject(rclsid, iid, ppv);
1175 /* Next try out of process */
1176 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1178 return create_marshalled_proxy(rclsid,iid,ppv);
1181 /* Finally try remote */
1182 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1184 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1185 hres = E_NOINTERFACE;
1188 return hres;
1190 /***********************************************************************
1191 * CoResumeClassObjects (OLE32.173)
1193 * Resumes classobjects registered with REGCLS suspended
1195 HRESULT WINAPI CoResumeClassObjects(void)
1197 FIXME("\n");
1198 return S_OK;
1201 /***********************************************************************
1202 * GetClassFile (OLE32.67)
1204 * This function supplies the CLSID associated with the given filename.
1206 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1208 IStorage *pstg=0;
1209 HRESULT res;
1210 int nbElm, length, i;
1211 LONG sizeProgId;
1212 LPOLESTR *pathDec=0,absFile=0,progId=0;
1213 LPWSTR extension;
1214 static const WCHAR bkslashW[] = {'\\',0};
1215 static const WCHAR dotW[] = {'.',0};
1217 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1219 /* if the file contain a storage object the return the CLSID writen by IStorage_SetClass method*/
1220 if((StgIsStorageFile(filePathName))==S_OK){
1222 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1224 if (SUCCEEDED(res))
1225 res=ReadClassStg(pstg,pclsid);
1227 IStorage_Release(pstg);
1229 return res;
1231 /* if the file is not a storage object then attemps to match various bits in the file against a
1232 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1233 this case
1235 for(i=0;i<nFileTypes;i++)
1237 for(i=0;j<nPatternsForType;j++){
1239 PATTERN pat;
1240 HANDLE hFile;
1242 pat=ReadPatternFromRegistry(i,j);
1243 hFile=CreateFileW(filePathName,,,,,,hFile);
1244 SetFilePosition(hFile,pat.offset);
1245 ReadFile(hFile,buf,pat.size,NULL,NULL);
1246 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1248 *pclsid=ReadCLSIDFromRegistry(i);
1249 return S_OK;
1254 /* if the obove strategies fail then search for the extension key in the registry */
1256 /* get the last element (absolute file) in the path name */
1257 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1258 absFile=pathDec[nbElm-1];
1260 /* failed if the path represente a directory and not an absolute file name*/
1261 if (!lstrcmpW(absFile, bkslashW))
1262 return MK_E_INVALIDEXTENSION;
1264 /* get the extension of the file */
1265 extension = NULL;
1266 length=lstrlenW(absFile);
1267 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1268 /* nothing */;
1270 if (!extension || !lstrcmpW(extension, dotW))
1271 return MK_E_INVALIDEXTENSION;
1273 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1275 /* get the progId associated to the extension */
1276 progId = CoTaskMemAlloc(sizeProgId);
1277 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1279 if (res==ERROR_SUCCESS)
1280 /* return the clsid associated to the progId */
1281 res= CLSIDFromProgID(progId,pclsid);
1283 for(i=0; pathDec[i]!=NULL;i++)
1284 CoTaskMemFree(pathDec[i]);
1285 CoTaskMemFree(pathDec);
1287 CoTaskMemFree(progId);
1289 if (res==ERROR_SUCCESS)
1290 return res;
1292 return MK_E_INVALIDEXTENSION;
1294 /***********************************************************************
1295 * CoCreateInstance [COMPOBJ.13]
1296 * CoCreateInstance [OLE32.7]
1298 HRESULT WINAPI CoCreateInstance(
1299 REFCLSID rclsid,
1300 LPUNKNOWN pUnkOuter,
1301 DWORD dwClsContext,
1302 REFIID iid,
1303 LPVOID *ppv)
1305 HRESULT hres;
1306 LPCLASSFACTORY lpclf = 0;
1309 * Sanity check
1311 if (ppv==0)
1312 return E_POINTER;
1315 * Initialize the "out" parameter
1317 *ppv = 0;
1320 * Get a class factory to construct the object we want.
1322 hres = CoGetClassObject(rclsid,
1323 dwClsContext,
1324 NULL,
1325 &IID_IClassFactory,
1326 (LPVOID)&lpclf);
1328 if (FAILED(hres)) {
1329 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1330 debugstr_guid(rclsid),hres);
1331 return hres;
1335 * Create the object and don't forget to release the factory
1337 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1338 IClassFactory_Release(lpclf);
1339 if(FAILED(hres))
1340 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1341 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1343 return hres;
1346 /***********************************************************************
1347 * CoCreateInstanceEx [OLE32.165]
1349 HRESULT WINAPI CoCreateInstanceEx(
1350 REFCLSID rclsid,
1351 LPUNKNOWN pUnkOuter,
1352 DWORD dwClsContext,
1353 COSERVERINFO* pServerInfo,
1354 ULONG cmq,
1355 MULTI_QI* pResults)
1357 IUnknown* pUnk = NULL;
1358 HRESULT hr;
1359 ULONG index;
1360 int successCount = 0;
1363 * Sanity check
1365 if ( (cmq==0) || (pResults==NULL))
1366 return E_INVALIDARG;
1368 if (pServerInfo!=NULL)
1369 FIXME("() non-NULL pServerInfo not supported!\n");
1372 * Initialize all the "out" parameters.
1374 for (index = 0; index < cmq; index++)
1376 pResults[index].pItf = NULL;
1377 pResults[index].hr = E_NOINTERFACE;
1381 * Get the object and get its IUnknown pointer.
1383 hr = CoCreateInstance(rclsid,
1384 pUnkOuter,
1385 dwClsContext,
1386 &IID_IUnknown,
1387 (VOID**)&pUnk);
1389 if (hr)
1390 return hr;
1393 * Then, query for all the interfaces requested.
1395 for (index = 0; index < cmq; index++)
1397 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1398 pResults[index].pIID,
1399 (VOID**)&(pResults[index].pItf));
1401 if (pResults[index].hr == S_OK)
1402 successCount++;
1406 * Release our temporary unknown pointer.
1408 IUnknown_Release(pUnk);
1410 if (successCount == 0)
1411 return E_NOINTERFACE;
1413 if (successCount!=cmq)
1414 return CO_S_NOTALLINTERFACES;
1416 return S_OK;
1419 /***********************************************************************
1420 * CoLoadLibrary (OLE32.30)
1422 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1424 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1426 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1429 /***********************************************************************
1430 * CoFreeLibrary [OLE32.13]
1432 * NOTES: don't belive the docu
1434 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1436 FreeLibrary(hLibrary);
1440 /***********************************************************************
1441 * CoFreeAllLibraries [OLE32.12]
1443 * NOTES: don't belive the docu
1445 void WINAPI CoFreeAllLibraries(void)
1447 /* NOP */
1451 /***********************************************************************
1452 * CoFreeUnusedLibraries [COMPOBJ.17]
1453 * CoFreeUnusedLibraries [OLE32.14]
1455 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1456 * through the main apartment's thread to call DllCanUnloadNow
1458 void WINAPI CoFreeUnusedLibraries(void)
1460 COMPOBJ_DllList_FreeUnused(0);
1463 /***********************************************************************
1464 * CoFileTimeNow [COMPOBJ.82]
1465 * CoFileTimeNow [OLE32.10]
1467 * RETURNS
1468 * the current system time in lpFileTime
1470 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1472 GetSystemTimeAsFileTime( lpFileTime );
1473 return S_OK;
1476 /***********************************************************************
1477 * CoLoadLibrary (OLE32.30)
1479 static void COM_RevokeAllClasses()
1481 EnterCriticalSection( &csRegisteredClassList );
1483 while (firstRegisteredClass!=0)
1485 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1488 LeaveCriticalSection( &csRegisteredClassList );
1491 /****************************************************************************
1492 * COM External Lock methods implementation
1494 * This api provides a linked list to managed external references to
1495 * COM objects.
1497 * The public interface consists of three calls:
1498 * COM_ExternalLockAddRef
1499 * COM_ExternalLockRelease
1500 * COM_ExternalLockFreeList
1503 #define EL_END_OF_LIST 0
1504 #define EL_NOT_FOUND 0
1507 * Declaration of the static structure that manage the
1508 * external lock to COM objects.
1510 typedef struct COM_ExternalLock COM_ExternalLock;
1511 typedef struct COM_ExternalLockList COM_ExternalLockList;
1513 struct COM_ExternalLock
1515 IUnknown *pUnk; /* IUnknown referenced */
1516 ULONG uRefCount; /* external lock counter to IUnknown object*/
1517 COM_ExternalLock *next; /* Pointer to next element in list */
1520 struct COM_ExternalLockList
1522 COM_ExternalLock *head; /* head of list */
1526 * Declaration and initialization of the static structure that manages
1527 * the external lock to COM objects.
1529 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1532 * Private methods used to managed the linked list
1536 static COM_ExternalLock* COM_ExternalLockLocate(
1537 COM_ExternalLock *element,
1538 IUnknown *pUnk);
1540 /****************************************************************************
1541 * Internal - Insert a new IUnknown* to the linked list
1543 static BOOL COM_ExternalLockInsert(
1544 IUnknown *pUnk)
1546 COM_ExternalLock *newLock = NULL;
1547 COM_ExternalLock *previousHead = NULL;
1550 * Allocate space for the new storage object
1552 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1554 if (newLock!=NULL) {
1555 if ( elList.head == EL_END_OF_LIST ) {
1556 elList.head = newLock; /* The list is empty */
1557 } else {
1558 /* insert does it at the head */
1559 previousHead = elList.head;
1560 elList.head = newLock;
1563 /* Set new list item data member */
1564 newLock->pUnk = pUnk;
1565 newLock->uRefCount = 1;
1566 newLock->next = previousHead;
1568 return TRUE;
1570 return FALSE;
1573 /****************************************************************************
1574 * Internal - Method that removes an item from the linked list.
1576 static void COM_ExternalLockDelete(
1577 COM_ExternalLock *itemList)
1579 COM_ExternalLock *current = elList.head;
1581 if ( current == itemList ) {
1582 /* this section handles the deletion of the first node */
1583 elList.head = itemList->next;
1584 HeapFree( GetProcessHeap(), 0, itemList);
1585 } else {
1586 do {
1587 if ( current->next == itemList ){ /* We found the item to free */
1588 current->next = itemList->next; /* readjust the list pointers */
1589 HeapFree( GetProcessHeap(), 0, itemList);
1590 break;
1593 /* Skip to the next item */
1594 current = current->next;
1596 } while ( current != EL_END_OF_LIST );
1600 /****************************************************************************
1601 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1603 * NOTES: how long can the list be ?? (recursive!!!)
1605 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1607 if ( element == EL_END_OF_LIST )
1608 return EL_NOT_FOUND;
1609 else if ( element->pUnk == pUnk ) /* We found it */
1610 return element;
1611 else /* Not the right guy, keep on looking */
1612 return COM_ExternalLockLocate( element->next, pUnk);
1615 /****************************************************************************
1616 * Public - Method that increments the count for a IUnknown* in the linked
1617 * list. The item is inserted if not already in the list.
1619 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1621 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1624 * Add an external lock to the object. If it was already externally
1625 * locked, just increase the reference count. If it was not.
1626 * add the item to the list.
1628 if ( externalLock == EL_NOT_FOUND )
1629 COM_ExternalLockInsert(pUnk);
1630 else
1631 externalLock->uRefCount++;
1634 * Add an internal lock to the object
1636 IUnknown_AddRef(pUnk);
1639 /****************************************************************************
1640 * Public - Method that decrements the count for a IUnknown* in the linked
1641 * list. The item is removed from the list if its count end up at zero or if
1642 * bRelAll is TRUE.
1644 static void COM_ExternalLockRelease(
1645 IUnknown *pUnk,
1646 BOOL bRelAll)
1648 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1650 if ( externalLock != EL_NOT_FOUND ) {
1651 do {
1652 externalLock->uRefCount--; /* release external locks */
1653 IUnknown_Release(pUnk); /* release local locks as well */
1655 if ( bRelAll == FALSE ) break; /* perform single release */
1657 } while ( externalLock->uRefCount > 0 );
1659 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1660 COM_ExternalLockDelete(externalLock);
1663 /****************************************************************************
1664 * Public - Method that frees the content of the list.
1666 static void COM_ExternalLockFreeList()
1668 COM_ExternalLock *head;
1670 head = elList.head; /* grab it by the head */
1671 while ( head != EL_END_OF_LIST ) {
1672 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1673 head = elList.head; /* get the new head... */
1677 /****************************************************************************
1678 * Public - Method that dump the content of the list.
1680 void COM_ExternalLockDump()
1682 COM_ExternalLock *current = elList.head;
1684 DPRINTF("\nExternal lock list contains:\n");
1686 while ( current != EL_END_OF_LIST ) {
1687 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1689 /* Skip to the next item */
1690 current = current->next;
1694 /******************************************************************************
1695 * CoLockObjectExternal [OLE32.31]
1697 HRESULT WINAPI CoLockObjectExternal(
1698 LPUNKNOWN pUnk, /* [in] object to be locked */
1699 BOOL fLock, /* [in] do lock */
1700 BOOL fLastUnlockReleases) /* [in] unlock all */
1703 if (fLock) {
1705 * Increment the external lock coutner, COM_ExternalLockAddRef also
1706 * increment the object's internal lock counter.
1708 COM_ExternalLockAddRef( pUnk);
1709 } else {
1711 * Decrement the external lock coutner, COM_ExternalLockRelease also
1712 * decrement the object's internal lock counter.
1714 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1717 return S_OK;
1720 /***********************************************************************
1721 * CoInitializeWOW (OLE32.27)
1723 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1724 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
1725 return 0;
1728 static IUnknown * pUnkState = 0; /* FIXME: thread local */
1729 static int nStatCounter = 0; /* global */
1730 static HMODULE hOleAut32 = 0; /* global */
1732 /***********************************************************************
1733 * CoGetState [OLE32.24]
1735 * NOTES: might be incomplete
1737 HRESULT WINAPI CoGetState(IUnknown ** ppv)
1739 FIXME("\n");
1741 if(pUnkState) {
1742 IUnknown_AddRef(pUnkState);
1743 *ppv = pUnkState;
1744 FIXME("-- %p\n", *ppv);
1745 return S_OK;
1747 *ppv = NULL;
1748 return E_FAIL;
1752 /***********************************************************************
1753 * CoSetState [OLE32.42]
1755 * NOTES: FIXME: protect this with a crst
1757 HRESULT WINAPI CoSetState(IUnknown * pv)
1759 FIXME("(%p),stub!\n", pv);
1761 if (pv) {
1762 IUnknown_AddRef(pv);
1763 nStatCounter++;
1764 if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL");
1767 if (pUnkState) {
1768 TRACE("-- release %p now\n", pUnkState);
1769 IUnknown_Release(pUnkState);
1770 nStatCounter--;
1771 if (!nStatCounter) FreeLibrary(hOleAut32);
1773 pUnkState = pv;
1774 return S_OK;
1778 /******************************************************************************
1779 * OleGetAutoConvert [OLE32.104]
1781 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
1783 HKEY hkey = 0;
1784 char buf[200];
1785 WCHAR wbuf[200];
1786 DWORD len;
1787 HRESULT res = S_OK;
1789 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
1790 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
1792 res = REGDB_E_CLASSNOTREG;
1793 goto done;
1795 len = 200;
1796 /* we can just query for the default value of AutoConvertTo key like that,
1797 without opening the AutoConvertTo key and querying for NULL (default) */
1798 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
1800 res = REGDB_E_KEYMISSING;
1801 goto done;
1803 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
1804 CLSIDFromString(wbuf,pClsidNew);
1805 done:
1806 if (hkey) RegCloseKey(hkey);
1807 return res;
1810 /******************************************************************************
1811 * OleSetAutoConvert [OLE32.126]
1813 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
1815 HKEY hkey = 0;
1816 char buf[200], szClsidNew[200];
1817 HRESULT res = S_OK;
1819 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
1820 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
1821 WINE_StringFromCLSID(clsidNew, szClsidNew);
1822 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
1824 res = REGDB_E_CLASSNOTREG;
1825 goto done;
1827 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
1829 res = REGDB_E_WRITEREGDB;
1830 goto done;
1833 done:
1834 if (hkey) RegCloseKey(hkey);
1835 return res;
1838 /******************************************************************************
1839 * CoTreatAsClass [OLE32.46]
1841 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
1843 HKEY hkey = 0;
1844 char buf[200], szClsidNew[200];
1845 HRESULT res = S_OK;
1847 FIXME("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
1848 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
1849 WINE_StringFromCLSID(clsidNew, szClsidNew);
1850 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
1852 res = REGDB_E_CLASSNOTREG;
1853 goto done;
1855 if (RegSetValueA(hkey, "AutoTreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
1857 res = REGDB_E_WRITEREGDB;
1858 goto done;
1861 done:
1862 if (hkey) RegCloseKey(hkey);
1863 return res;
1867 /***********************************************************************
1868 * IsEqualGUID [OLE32.76]
1870 * Compares two Unique Identifiers.
1872 * RETURNS
1873 * TRUE if equal
1875 #undef IsEqualGUID
1876 BOOL WINAPI IsEqualGUID(
1877 REFGUID rguid1, /* [in] unique id 1 */
1878 REFGUID rguid2 /* [in] unique id 2 */
1881 return !memcmp(rguid1,rguid2,sizeof(GUID));
1884 /***********************************************************************
1885 * CoInitializeSecurity [OLE32.164]
1887 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
1888 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
1889 void* pReserved1, DWORD dwAuthnLevel,
1890 DWORD dwImpLevel, void* pReserved2,
1891 DWORD dwCapabilities, void* pReserved3)
1893 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
1894 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
1895 dwCapabilities, pReserved3);
1896 return S_OK;