Fixed a few problems caused by the new objidl.idl.
[wine/testsucceed.git] / dlls / ole32 / compobj.c
blob8ded0bc2d56139d27eb514c13e0c4094b615571b
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 #include "windef.h"
33 #include "objbase.h"
34 #include "ole2.h"
35 #include "ole2ver.h"
36 #include "rpc.h"
37 #include "winerror.h"
38 #include "winreg.h"
39 #include "wownt32.h"
40 #include "wine/unicode.h"
41 #include "objbase.h"
42 #include "compobj_private.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(ole);
48 /****************************************************************************
49 * This section defines variables internal to the COM module.
51 * TODO: Most of these things will have to be made thread-safe.
53 HINSTANCE COMPOBJ_hInstance32 = 0;
55 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
56 static void COM_RevokeAllClasses();
57 static void COM_ExternalLockFreeList();
59 /*****************************************************************************
60 * Appartment management stuff
62 * NOTE:
63 * per Thread values are stored in the TEB on offset 0xF80
65 * see www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm
69 typedef struct {
70 unsigned char threadingModell; /* we use the COINIT flags */
71 unsigned long threadID;
72 long AppartmentLockCount;
73 } OleAppartmentData;
75 typedef struct {
76 OleAppartmentData *AppartmentData;
77 } OleThreadData;
79 /* not jet used
80 static CRITICAL_SECTION csAppartmentData = CRITICAL_SECTION_INIT("csAppartmentData");
83 * the first STA created in a process is the main STA
86 /* not jet used
87 static OleAppartmentData * mainSTA;
91 * a Process can only have one MTA
94 /* not jet used
95 static OleAppartmentData * processMTA;
100 * This lock count counts the number of times CoInitialize is called. It is
101 * decreased every time CoUninitialize is called. When it hits 0, the COM
102 * libraries are freed
104 static LONG s_COMLockCount = 0;
107 * This linked list contains the list of registered class objects. These
108 * are mostly used to register the factories for out-of-proc servers of OLE
109 * objects.
111 * TODO: Make this data structure aware of inter-process communication. This
112 * means that parts of this will be exported to the Wine Server.
114 typedef struct tagRegisteredClass
116 CLSID classIdentifier;
117 LPUNKNOWN classObject;
118 DWORD runContext;
119 DWORD connectFlags;
120 DWORD dwCookie;
121 HANDLE hThread; /* only for localserver */
122 struct tagRegisteredClass* nextClass;
123 } RegisteredClass;
125 static CRITICAL_SECTION csRegisteredClassList = CRITICAL_SECTION_INIT("csRegisteredClassList");
126 static RegisteredClass* firstRegisteredClass = NULL;
128 /*****************************************************************************
129 * This section contains OpenDllList definitions
131 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
132 * other functions what do LoadLibrary _without_ giving back a HMODULE.
133 * Without this list these handles would be freed never.
135 * FIXME: a DLL what says OK whenn asked for unloading is unloaded in the
136 * next unload-call but not before 600 sec.
139 typedef struct tagOpenDll {
140 HINSTANCE hLibrary;
141 struct tagOpenDll *next;
142 } OpenDll;
144 static CRITICAL_SECTION csOpenDllList = CRITICAL_SECTION_INIT("csOpenDllList");
145 static OpenDll *openDllList = NULL; /* linked list of open dlls */
147 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
148 static void COMPOBJ_DllList_FreeUnused(int Timeout);
151 /******************************************************************************
152 * Initialize/Uninitialize critical sections.
154 void COMPOBJ_InitProcess( void )
158 void COMPOBJ_UninitProcess( void )
162 /*****************************************************************************
163 * This section contains OpenDllList implemantation
166 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
168 OpenDll *ptr;
169 OpenDll *tmp;
171 TRACE("\n");
173 EnterCriticalSection( &csOpenDllList );
175 if (openDllList == NULL) {
176 /* empty list -- add first node */
177 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
178 openDllList->hLibrary=hLibrary;
179 openDllList->next = NULL;
180 } else {
181 /* search for this dll */
182 int found = FALSE;
183 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
184 if (ptr->hLibrary == hLibrary) {
185 found = TRUE;
186 break;
189 if (!found) {
190 /* dll not found, add it */
191 tmp = openDllList;
192 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
193 openDllList->hLibrary = hLibrary;
194 openDllList->next = tmp;
198 LeaveCriticalSection( &csOpenDllList );
201 static void COMPOBJ_DllList_FreeUnused(int Timeout)
203 OpenDll *curr, *next, *prev = NULL;
204 typedef HRESULT(*DllCanUnloadNowFunc)(void);
205 DllCanUnloadNowFunc DllCanUnloadNow;
207 TRACE("\n");
209 EnterCriticalSection( &csOpenDllList );
211 for (curr = openDllList; curr != NULL; ) {
212 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
214 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
215 next = curr->next;
217 TRACE("freeing %p\n", curr->hLibrary);
218 FreeLibrary(curr->hLibrary);
220 HeapFree(GetProcessHeap(), 0, curr);
221 if (curr == openDllList) {
222 openDllList = next;
223 } else {
224 prev->next = next;
227 curr = next;
228 } else {
229 prev = curr;
230 curr = curr->next;
234 LeaveCriticalSection( &csOpenDllList );
237 /******************************************************************************
238 * CoBuildVersion [COMPOBJ.1]
239 * CoBuildVersion [OLE32.4]
241 * RETURNS
242 * Current build version, hiword is majornumber, loword is minornumber
244 DWORD WINAPI CoBuildVersion(void)
246 TRACE("Returning version %d, build %d.\n", rmm, rup);
247 return (rmm<<16)+rup;
250 /******************************************************************************
251 * CoInitialize [OLE32.26]
253 * Initializes the COM libraries.
255 * See CoInitializeEx
257 HRESULT WINAPI CoInitialize(
258 LPVOID lpReserved /* [in] pointer to win32 malloc interface
259 (obsolete, should be NULL) */
263 * Just delegate to the newer method.
265 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
268 /******************************************************************************
269 * CoInitializeEx [OLE32.163]
271 * Initializes the COM libraries. The behavior used to set the win32 IMalloc
272 * used for memory management is obsolete.
274 * RETURNS
275 * S_OK if successful,
276 * S_FALSE if this function was called already.
277 * RPC_E_CHANGED_MODE if a previous call to CoInitialize specified another
278 * threading model.
280 * BUGS
281 * Only the single threaded model is supported. As a result RPC_E_CHANGED_MODE
282 * is never returned.
284 * See the windows documentation for more details.
286 HRESULT WINAPI CoInitializeEx(
287 LPVOID lpReserved, /* [in] pointer to win32 malloc interface
288 (obsolete, should be NULL) */
289 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
292 HRESULT hr;
294 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
296 if (lpReserved!=NULL)
298 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
302 * Check for unsupported features.
304 if (dwCoInit!=COINIT_APARTMENTTHREADED)
306 FIXME(":(%p,%x): unsupported flag %x\n", lpReserved, (int)dwCoInit, (int)dwCoInit);
307 /* Hope for the best and continue anyway */
311 * Check the lock count. If this is the first time going through the initialize
312 * process, we have to initialize the libraries.
314 * And crank-up that lock count.
316 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
319 * Initialize the various COM libraries and data structures.
321 TRACE("() - Initializing the COM libraries\n");
324 RunningObjectTableImpl_Initialize();
326 hr = S_OK;
328 else
329 hr = S_FALSE;
331 return hr;
334 /***********************************************************************
335 * CoUninitialize [OLE32.47]
337 * This method will release the COM libraries.
339 * See the windows documentation for more details.
341 void WINAPI CoUninitialize(void)
343 LONG lCOMRefCnt;
344 TRACE("()\n");
347 * Decrease the reference count.
348 * If we are back to 0 locks on the COM library, make sure we free
349 * all the associated data structures.
351 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
352 if (lCOMRefCnt==1)
355 * Release the various COM libraries and data structures.
357 TRACE("() - Releasing the COM libraries\n");
359 RunningObjectTableImpl_UnInitialize();
361 * Release the references to the registered class objects.
363 COM_RevokeAllClasses();
366 * This will free the loaded COM Dlls.
368 CoFreeAllLibraries();
371 * This will free list of external references to COM objects.
373 COM_ExternalLockFreeList();
376 else if (lCOMRefCnt<1) {
377 ERR( "CoUninitialize() - not CoInitialized.\n" );
378 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
382 /******************************************************************************
383 * CoDisconnectObject [COMPOBJ.15]
384 * CoDisconnectObject [OLE32.8]
386 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
388 TRACE("(%p, %lx)\n",lpUnk,reserved);
389 return S_OK;
392 /******************************************************************************
393 * CoCreateGuid[OLE32.6]
396 HRESULT WINAPI CoCreateGuid(
397 GUID *pguid /* [out] points to the GUID to initialize */
399 return UuidCreate(pguid);
402 /******************************************************************************
403 * CLSIDFromString [OLE32.3]
404 * IIDFromString [OLE32.74]
405 * Converts a unique identifier from its string representation into
406 * the GUID struct.
408 * UNDOCUMENTED
409 * If idstr is not a valid CLSID string then it gets treated as a ProgID
411 * RETURNS
412 * the converted GUID
414 HRESULT WINAPI __CLSIDFromStringA(
415 LPCSTR idstr, /* [in] string representation of guid */
416 CLSID *id) /* [out] GUID converted from string */
418 BYTE *s = (BYTE *) idstr;
419 int i;
420 BYTE table[256];
422 if (!s)
423 s = "{00000000-0000-0000-0000-000000000000}";
424 else { /* validate the CLSID string */
426 if (strlen(s) != 38)
427 return CO_E_CLASSSTRING;
429 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
430 return CO_E_CLASSSTRING;
432 for (i=1; i<37; i++) {
433 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
434 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
435 ((s[i] >= 'a') && (s[i] <= 'f')) ||
436 ((s[i] >= 'A') && (s[i] <= 'F'))))
437 return CO_E_CLASSSTRING;
441 TRACE("%s -> %p\n", s, id);
443 /* quick lookup table */
444 memset(table, 0, 256);
446 for (i = 0; i < 10; i++) {
447 table['0' + i] = i;
449 for (i = 0; i < 6; i++) {
450 table['A' + i] = i+10;
451 table['a' + i] = i+10;
454 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
456 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
457 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
458 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
459 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
461 /* these are just sequential bytes */
462 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
463 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
464 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
465 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
466 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
467 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
468 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
469 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
471 return S_OK;
474 /*****************************************************************************/
476 HRESULT WINAPI CLSIDFromString(
477 LPCOLESTR idstr, /* [in] string representation of GUID */
478 CLSID *id ) /* [out] GUID represented by above string */
480 char xid[40];
481 HRESULT ret;
483 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
484 return CO_E_CLASSSTRING;
487 ret = __CLSIDFromStringA(xid,id);
488 if(ret != S_OK) { /* It appears a ProgID is also valid */
489 ret = CLSIDFromProgID(idstr, id);
491 return ret;
494 /******************************************************************************
495 * WINE_StringFromCLSID [Internal]
496 * Converts a GUID into the respective string representation.
498 * NOTES
500 * RETURNS
501 * the string representation and HRESULT
503 HRESULT WINE_StringFromCLSID(
504 const CLSID *id, /* [in] GUID to be converted */
505 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
507 static const char *hex = "0123456789ABCDEF";
508 char *s;
509 int i;
511 if (!id)
512 { ERR("called with id=Null\n");
513 *idstr = 0x00;
514 return E_FAIL;
517 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
518 id->Data1, id->Data2, id->Data3,
519 id->Data4[0], id->Data4[1]);
520 s = &idstr[25];
522 /* 6 hex bytes */
523 for (i = 2; i < 8; i++) {
524 *s++ = hex[id->Data4[i]>>4];
525 *s++ = hex[id->Data4[i] & 0xf];
528 *s++ = '}';
529 *s++ = '\0';
531 TRACE("%p->%s\n", id, idstr);
533 return S_OK;
537 /******************************************************************************
538 * StringFromCLSID [OLE32.151]
539 * StringFromIID [OLE32.153]
540 * Converts a GUID into the respective string representation.
541 * The target string is allocated using the OLE IMalloc.
542 * RETURNS
543 * the string representation and HRESULT
545 HRESULT WINAPI StringFromCLSID(
546 REFCLSID id, /* [in] the GUID to be converted */
547 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
549 char buf[80];
550 HRESULT ret;
551 LPMALLOC mllc;
553 if ((ret=CoGetMalloc(0,&mllc)))
554 return ret;
556 ret=WINE_StringFromCLSID(id,buf);
557 if (!ret) {
558 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
559 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
560 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
562 return ret;
565 /******************************************************************************
566 * StringFromGUID2 [COMPOBJ.76]
567 * StringFromGUID2 [OLE32.152]
569 * Converts a global unique identifier into a string of an API-
570 * specified fixed format. (The usual {.....} stuff.)
572 * RETURNS
573 * The (UNICODE) string representation of the GUID in 'str'
574 * The length of the resulting string, 0 if there was any problem.
576 INT WINAPI
577 StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
579 char xguid[80];
581 if (WINE_StringFromCLSID(id,xguid))
582 return 0;
583 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
586 /******************************************************************************
587 * ProgIDFromCLSID [OLE32.133]
588 * Converts a class id into the respective Program ID. (By using a registry lookup)
589 * RETURNS S_OK on success
590 * riid associated with the progid
593 HRESULT WINAPI ProgIDFromCLSID(
594 REFCLSID clsid, /* [in] class id as found in registry */
595 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
598 char strCLSID[50], *buf, *buf2;
599 DWORD buf2len;
600 HKEY xhkey;
601 LPMALLOC mllc;
602 HRESULT ret = S_OK;
604 WINE_StringFromCLSID(clsid, strCLSID);
606 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
607 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
608 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
609 ret = REGDB_E_CLASSNOTREG;
611 HeapFree(GetProcessHeap(), 0, buf);
613 if (ret == S_OK)
615 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
616 buf2len = 255;
617 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
618 ret = REGDB_E_CLASSNOTREG;
620 if (ret == S_OK)
622 if (CoGetMalloc(0,&mllc))
623 ret = E_OUTOFMEMORY;
624 else
626 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
627 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
628 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
631 HeapFree(GetProcessHeap(), 0, buf2);
634 RegCloseKey(xhkey);
635 return ret;
638 /******************************************************************************
639 * CLSIDFromProgID [OLE32.2]
640 * Converts a program id into the respective GUID. (By using a registry lookup)
641 * RETURNS
642 * riid associated with the progid
644 HRESULT WINAPI CLSIDFromProgID(
645 LPCOLESTR progid, /* [in] program id as found in registry */
646 LPCLSID riid ) /* [out] associated CLSID */
648 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
649 char buf2[80];
650 DWORD buf2len = sizeof(buf2);
651 HKEY xhkey;
653 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
654 strcpyW( buf, progid );
655 strcatW( buf, clsidW );
656 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
658 HeapFree(GetProcessHeap(),0,buf);
659 return CO_E_CLASSSTRING;
661 HeapFree(GetProcessHeap(),0,buf);
663 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
665 RegCloseKey(xhkey);
666 return CO_E_CLASSSTRING;
668 RegCloseKey(xhkey);
669 return __CLSIDFromStringA(buf2,riid);
674 /*****************************************************************************
675 * CoGetPSClsid [OLE32.22]
677 * This function returns the CLSID of the DLL that implements the proxy and stub
678 * for the specified interface.
680 * It determines this by searching the
681 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
682 * and any interface id registered by CoRegisterPSClsid within the current process.
684 * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
686 HRESULT WINAPI CoGetPSClsid(
687 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
688 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
690 char *buf, buf2[40];
691 DWORD buf2len;
692 HKEY xhkey;
694 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
696 /* Get the input iid as a string */
697 WINE_StringFromCLSID(riid, buf2);
698 /* Allocate memory for the registry key we will construct.
699 (length of iid string plus constant length of static text */
700 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
701 if (buf == NULL)
703 return (E_OUTOFMEMORY);
706 /* Construct the registry key we want */
707 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
709 /* Open the key.. */
710 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
712 HeapFree(GetProcessHeap(),0,buf);
713 return (E_INVALIDARG);
715 HeapFree(GetProcessHeap(),0,buf);
717 /* ... Once we have the key, query the registry to get the
718 value of CLSID as a string, and convert it into a
719 proper CLSID structure to be passed back to the app */
720 buf2len = sizeof(buf2);
721 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
723 RegCloseKey(xhkey);
724 return E_INVALIDARG;
726 RegCloseKey(xhkey);
728 /* We have the CLSid we want back from the registry as a string, so
729 lets convert it into a CLSID structure */
730 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
731 return E_INVALIDARG;
734 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
735 return (S_OK);
740 /***********************************************************************
741 * WriteClassStm (OLE32.159)
743 * This function write a CLSID on stream
745 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
747 TRACE("(%p,%p)\n",pStm,rclsid);
749 if (rclsid==NULL)
750 return E_INVALIDARG;
752 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
755 /***********************************************************************
756 * ReadClassStm (OLE32.135)
758 * This function read a CLSID from a stream
760 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
762 ULONG nbByte;
763 HRESULT res;
765 TRACE("(%p,%p)\n",pStm,pclsid);
767 if (pclsid==NULL)
768 return E_INVALIDARG;
770 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
772 if (FAILED(res))
773 return res;
775 if (nbByte != sizeof(CLSID))
776 return S_FALSE;
777 else
778 return S_OK;
782 /***
783 * COM_GetRegisteredClassObject
785 * This internal method is used to scan the registered class list to
786 * find a class object.
788 * Params:
789 * rclsid Class ID of the class to find.
790 * dwClsContext Class context to match.
791 * ppv [out] returns a pointer to the class object. Complying
792 * to normal COM usage, this method will increase the
793 * reference count on this object.
795 static HRESULT COM_GetRegisteredClassObject(
796 REFCLSID rclsid,
797 DWORD dwClsContext,
798 LPUNKNOWN* ppUnk)
800 HRESULT hr = S_FALSE;
801 RegisteredClass* curClass;
803 EnterCriticalSection( &csRegisteredClassList );
806 * Sanity check
808 assert(ppUnk!=0);
811 * Iterate through the whole list and try to match the class ID.
813 curClass = firstRegisteredClass;
815 while (curClass != 0)
818 * Check if we have a match on the class ID.
820 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
823 * Since we don't do out-of process or DCOM just right away, let's ignore the
824 * class context.
828 * We have a match, return the pointer to the class object.
830 *ppUnk = curClass->classObject;
832 IUnknown_AddRef(curClass->classObject);
834 hr = S_OK;
835 goto end;
839 * Step to the next class in the list.
841 curClass = curClass->nextClass;
844 end:
845 LeaveCriticalSection( &csRegisteredClassList );
847 * If we get to here, we haven't found our class.
849 return hr;
852 static DWORD WINAPI
853 _LocalServerThread(LPVOID param) {
854 HANDLE hPipe;
855 char pipefn[200];
856 RegisteredClass *newClass = (RegisteredClass*)param;
857 HRESULT hres;
858 IStream *pStm;
859 STATSTG ststg;
860 unsigned char *buffer;
861 int buflen;
862 IClassFactory *classfac;
863 LARGE_INTEGER seekto;
864 ULARGE_INTEGER newpos;
865 ULONG res;
867 TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier));
868 strcpy(pipefn,PIPEPREF);
869 WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
871 hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
872 if (hres) return hres;
874 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
875 if (hres) {
876 FIXME("Failed to create stream on hglobal.\n");
877 return hres;
879 hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
880 if (hres) {
881 FIXME("CoMarshalInterface failed, %lx!\n",hres);
882 return hres;
884 hres = IStream_Stat(pStm,&ststg,0);
885 if (hres) return hres;
887 buflen = ststg.cbSize.s.LowPart;
888 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
889 seekto.s.LowPart = 0;
890 seekto.s.HighPart = 0;
891 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
892 if (hres) {
893 FIXME("IStream_Seek failed, %lx\n",hres);
894 return hres;
896 hres = IStream_Read(pStm,buffer,buflen,&res);
897 if (hres) {
898 FIXME("Stream Read failed, %lx\n",hres);
899 return hres;
901 IStream_Release(pStm);
903 while (1) {
904 hPipe = CreateNamedPipeA(
905 pipefn,
906 PIPE_ACCESS_DUPLEX,
907 PIPE_TYPE_BYTE|PIPE_WAIT,
908 PIPE_UNLIMITED_INSTANCES,
909 4096,
910 4096,
911 NMPWAIT_USE_DEFAULT_WAIT,
912 NULL
914 if (hPipe == INVALID_HANDLE_VALUE) {
915 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
916 return 1;
918 if (!ConnectNamedPipe(hPipe,NULL)) {
919 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
920 CloseHandle(hPipe);
921 continue;
923 WriteFile(hPipe,buffer,buflen,&res,NULL);
924 CloseHandle(hPipe);
926 return 0;
929 /******************************************************************************
930 * CoRegisterClassObject [OLE32.36]
932 * This method will register the class object for a given class ID.
934 * See the Windows documentation for more details.
936 HRESULT WINAPI CoRegisterClassObject(
937 REFCLSID rclsid,
938 LPUNKNOWN pUnk,
939 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
940 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
941 LPDWORD lpdwRegister
944 RegisteredClass* newClass;
945 LPUNKNOWN foundObject;
946 HRESULT hr;
948 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
949 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
951 if ( (lpdwRegister==0) || (pUnk==0) )
952 return E_INVALIDARG;
954 *lpdwRegister = 0;
957 * First, check if the class is already registered.
958 * If it is, this should cause an error.
960 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
961 if (hr == S_OK) {
962 IUnknown_Release(foundObject);
963 return CO_E_OBJISREG;
966 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
967 if ( newClass == NULL )
968 return E_OUTOFMEMORY;
970 EnterCriticalSection( &csRegisteredClassList );
972 newClass->classIdentifier = *rclsid;
973 newClass->runContext = dwClsContext;
974 newClass->connectFlags = flags;
976 * Use the address of the chain node as the cookie since we are sure it's
977 * unique.
979 newClass->dwCookie = (DWORD)newClass;
980 newClass->nextClass = firstRegisteredClass;
983 * Since we're making a copy of the object pointer, we have to increase its
984 * reference count.
986 newClass->classObject = pUnk;
987 IUnknown_AddRef(newClass->classObject);
989 firstRegisteredClass = newClass;
990 LeaveCriticalSection( &csRegisteredClassList );
992 *lpdwRegister = newClass->dwCookie;
994 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
995 DWORD tid;
997 STUBMGR_Start();
998 newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1000 return S_OK;
1003 /***********************************************************************
1004 * CoRevokeClassObject [OLE32.40]
1006 * This method will remove a class object from the class registry
1008 * See the Windows documentation for more details.
1010 HRESULT WINAPI CoRevokeClassObject(
1011 DWORD dwRegister)
1013 HRESULT hr = E_INVALIDARG;
1014 RegisteredClass** prevClassLink;
1015 RegisteredClass* curClass;
1017 TRACE("(%08lx)\n",dwRegister);
1019 EnterCriticalSection( &csRegisteredClassList );
1022 * Iterate through the whole list and try to match the cookie.
1024 curClass = firstRegisteredClass;
1025 prevClassLink = &firstRegisteredClass;
1027 while (curClass != 0)
1030 * Check if we have a match on the cookie.
1032 if (curClass->dwCookie == dwRegister)
1035 * Remove the class from the chain.
1037 *prevClassLink = curClass->nextClass;
1040 * Release the reference to the class object.
1042 IUnknown_Release(curClass->classObject);
1045 * Free the memory used by the chain node.
1047 HeapFree(GetProcessHeap(), 0, curClass);
1049 hr = S_OK;
1050 goto end;
1054 * Step to the next class in the list.
1056 prevClassLink = &(curClass->nextClass);
1057 curClass = curClass->nextClass;
1060 end:
1061 LeaveCriticalSection( &csRegisteredClassList );
1063 * If we get to here, we haven't found our class.
1065 return hr;
1068 /***********************************************************************
1069 * compobj_RegReadPath [internal]
1071 * Reads a registry value and expands it when nessesary
1073 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, int dstlen)
1075 HRESULT hres;
1076 HKEY key;
1077 DWORD keytype;
1078 char src[MAX_PATH];
1079 DWORD dwLength = dstlen;
1081 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1082 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1083 if (keytype == REG_EXPAND_SZ) {
1084 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1085 } else {
1086 strncpy(dst, src, dstlen);
1089 RegCloseKey (key);
1091 return hres;
1094 /***********************************************************************
1095 * CoGetClassObject [COMPOBJ.7]
1096 * CoGetClassObject [OLE32.16]
1098 * FIXME. If request allows of several options and there is a failure
1099 * with one (other than not being registered) do we try the
1100 * others or return failure? (E.g. inprocess is registered but
1101 * the DLL is not found but the server version works)
1103 HRESULT WINAPI CoGetClassObject(
1104 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1105 REFIID iid, LPVOID *ppv
1107 LPUNKNOWN regClassObject;
1108 HRESULT hres = E_UNEXPECTED;
1109 char xclsid[80];
1110 HINSTANCE hLibrary;
1111 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1112 DllGetClassObjectFunc DllGetClassObject;
1114 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1116 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1118 if (pServerInfo) {
1119 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1120 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1124 * First, try and see if we can't match the class ID with one of the
1125 * registered classes.
1127 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1130 * Get the required interface from the retrieved pointer.
1132 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1135 * Since QI got another reference on the pointer, we want to release the
1136 * one we already have. If QI was unsuccessful, this will release the object. This
1137 * is good since we are not returning it in the "out" parameter.
1139 IUnknown_Release(regClassObject);
1141 return hres;
1144 /* first try: in-process */
1145 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1146 char keyname[MAX_PATH];
1147 char dllpath[MAX_PATH+1];
1149 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1151 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1152 /* failure: CLSID is not found in registry */
1153 WARN("class %s not registred\n", xclsid);
1154 hres = REGDB_E_CLASSNOTREG;
1155 } else {
1156 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1157 /* failure: DLL could not be loaded */
1158 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1159 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1160 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1161 /* failure: the dll did not export DllGetClassObject */
1162 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1163 FreeLibrary( hLibrary );
1164 hres = CO_E_DLLNOTFOUND;
1165 } else {
1166 /* OK: get the ClassObject */
1167 COMPOBJ_DLLList_Add( hLibrary );
1168 return DllGetClassObject(rclsid, iid, ppv);
1173 /* Next try out of process */
1174 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1176 return create_marshalled_proxy(rclsid,iid,ppv);
1179 /* Finally try remote */
1180 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1182 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1183 hres = E_NOINTERFACE;
1186 return hres;
1188 /***********************************************************************
1189 * CoResumeClassObjects (OLE32.173)
1191 * Resumes classobjects registered with REGCLS suspended
1193 HRESULT WINAPI CoResumeClassObjects(void)
1195 FIXME("\n");
1196 return S_OK;
1199 /***********************************************************************
1200 * GetClassFile (OLE32.67)
1202 * This function supplies the CLSID associated with the given filename.
1204 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1206 IStorage *pstg=0;
1207 HRESULT res;
1208 int nbElm, length, i;
1209 LONG sizeProgId;
1210 LPOLESTR *pathDec=0,absFile=0,progId=0;
1211 LPWSTR extension;
1212 static const WCHAR bkslashW[] = {'\\',0};
1213 static const WCHAR dotW[] = {'.',0};
1215 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1217 /* if the file contain a storage object the return the CLSID writen by IStorage_SetClass method*/
1218 if((StgIsStorageFile(filePathName))==S_OK){
1220 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1222 if (SUCCEEDED(res))
1223 res=ReadClassStg(pstg,pclsid);
1225 IStorage_Release(pstg);
1227 return res;
1229 /* if the file is not a storage object then attemps to match various bits in the file against a
1230 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1231 this case
1233 for(i=0;i<nFileTypes;i++)
1235 for(i=0;j<nPatternsForType;j++){
1237 PATTERN pat;
1238 HANDLE hFile;
1240 pat=ReadPatternFromRegistry(i,j);
1241 hFile=CreateFileW(filePathName,,,,,,hFile);
1242 SetFilePosition(hFile,pat.offset);
1243 ReadFile(hFile,buf,pat.size,NULL,NULL);
1244 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1246 *pclsid=ReadCLSIDFromRegistry(i);
1247 return S_OK;
1252 /* if the obove strategies fail then search for the extension key in the registry */
1254 /* get the last element (absolute file) in the path name */
1255 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1256 absFile=pathDec[nbElm-1];
1258 /* failed if the path represente a directory and not an absolute file name*/
1259 if (!lstrcmpW(absFile, bkslashW))
1260 return MK_E_INVALIDEXTENSION;
1262 /* get the extension of the file */
1263 extension = NULL;
1264 length=lstrlenW(absFile);
1265 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1266 /* nothing */;
1268 if (!extension || !lstrcmpW(extension, dotW))
1269 return MK_E_INVALIDEXTENSION;
1271 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1273 /* get the progId associated to the extension */
1274 progId = CoTaskMemAlloc(sizeProgId);
1275 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1277 if (res==ERROR_SUCCESS)
1278 /* return the clsid associated to the progId */
1279 res= CLSIDFromProgID(progId,pclsid);
1281 for(i=0; pathDec[i]!=NULL;i++)
1282 CoTaskMemFree(pathDec[i]);
1283 CoTaskMemFree(pathDec);
1285 CoTaskMemFree(progId);
1287 if (res==ERROR_SUCCESS)
1288 return res;
1290 return MK_E_INVALIDEXTENSION;
1292 /***********************************************************************
1293 * CoCreateInstance [COMPOBJ.13]
1294 * CoCreateInstance [OLE32.7]
1296 HRESULT WINAPI CoCreateInstance(
1297 REFCLSID rclsid,
1298 LPUNKNOWN pUnkOuter,
1299 DWORD dwClsContext,
1300 REFIID iid,
1301 LPVOID *ppv)
1303 HRESULT hres;
1304 LPCLASSFACTORY lpclf = 0;
1307 * Sanity check
1309 if (ppv==0)
1310 return E_POINTER;
1313 * Initialize the "out" parameter
1315 *ppv = 0;
1318 * Get a class factory to construct the object we want.
1320 hres = CoGetClassObject(rclsid,
1321 dwClsContext,
1322 NULL,
1323 &IID_IClassFactory,
1324 (LPVOID)&lpclf);
1326 if (FAILED(hres)) {
1327 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1328 debugstr_guid(rclsid),hres);
1329 return hres;
1333 * Create the object and don't forget to release the factory
1335 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1336 IClassFactory_Release(lpclf);
1337 if(FAILED(hres))
1338 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1339 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1341 return hres;
1344 /***********************************************************************
1345 * CoCreateInstanceEx [OLE32.165]
1347 HRESULT WINAPI CoCreateInstanceEx(
1348 REFCLSID rclsid,
1349 LPUNKNOWN pUnkOuter,
1350 DWORD dwClsContext,
1351 COSERVERINFO* pServerInfo,
1352 ULONG cmq,
1353 MULTI_QI* pResults)
1355 IUnknown* pUnk = NULL;
1356 HRESULT hr;
1357 ULONG index;
1358 int successCount = 0;
1361 * Sanity check
1363 if ( (cmq==0) || (pResults==NULL))
1364 return E_INVALIDARG;
1366 if (pServerInfo!=NULL)
1367 FIXME("() non-NULL pServerInfo not supported!\n");
1370 * Initialize all the "out" parameters.
1372 for (index = 0; index < cmq; index++)
1374 pResults[index].pItf = NULL;
1375 pResults[index].hr = E_NOINTERFACE;
1379 * Get the object and get its IUnknown pointer.
1381 hr = CoCreateInstance(rclsid,
1382 pUnkOuter,
1383 dwClsContext,
1384 &IID_IUnknown,
1385 (VOID**)&pUnk);
1387 if (hr)
1388 return hr;
1391 * Then, query for all the interfaces requested.
1393 for (index = 0; index < cmq; index++)
1395 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1396 pResults[index].pIID,
1397 (VOID**)&(pResults[index].pItf));
1399 if (pResults[index].hr == S_OK)
1400 successCount++;
1404 * Release our temporary unknown pointer.
1406 IUnknown_Release(pUnk);
1408 if (successCount == 0)
1409 return E_NOINTERFACE;
1411 if (successCount!=cmq)
1412 return CO_S_NOTALLINTERFACES;
1414 return S_OK;
1417 /***********************************************************************
1418 * CoLoadLibrary (OLE32.30)
1420 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1422 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1424 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1427 /***********************************************************************
1428 * CoFreeLibrary [OLE32.13]
1430 * NOTES: don't belive the docu
1432 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1434 FreeLibrary(hLibrary);
1438 /***********************************************************************
1439 * CoFreeAllLibraries [OLE32.12]
1441 * NOTES: don't belive the docu
1443 void WINAPI CoFreeAllLibraries(void)
1445 /* NOP */
1449 /***********************************************************************
1450 * CoFreeUnusedLibraries [COMPOBJ.17]
1451 * CoFreeUnusedLibraries [OLE32.14]
1453 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1454 * through the main apartment's thread to call DllCanUnloadNow
1456 void WINAPI CoFreeUnusedLibraries(void)
1458 COMPOBJ_DllList_FreeUnused(0);
1461 /***********************************************************************
1462 * CoFileTimeNow [COMPOBJ.82]
1463 * CoFileTimeNow [OLE32.10]
1465 * RETURNS
1466 * the current system time in lpFileTime
1468 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1470 GetSystemTimeAsFileTime( lpFileTime );
1471 return S_OK;
1474 /***********************************************************************
1475 * CoLoadLibrary (OLE32.30)
1477 static void COM_RevokeAllClasses()
1479 EnterCriticalSection( &csRegisteredClassList );
1481 while (firstRegisteredClass!=0)
1483 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1486 LeaveCriticalSection( &csRegisteredClassList );
1489 /****************************************************************************
1490 * COM External Lock methods implementation
1492 * This api provides a linked list to managed external references to
1493 * COM objects.
1495 * The public interface consists of three calls:
1496 * COM_ExternalLockAddRef
1497 * COM_ExternalLockRelease
1498 * COM_ExternalLockFreeList
1501 #define EL_END_OF_LIST 0
1502 #define EL_NOT_FOUND 0
1505 * Declaration of the static structure that manage the
1506 * external lock to COM objects.
1508 typedef struct COM_ExternalLock COM_ExternalLock;
1509 typedef struct COM_ExternalLockList COM_ExternalLockList;
1511 struct COM_ExternalLock
1513 IUnknown *pUnk; /* IUnknown referenced */
1514 ULONG uRefCount; /* external lock counter to IUnknown object*/
1515 COM_ExternalLock *next; /* Pointer to next element in list */
1518 struct COM_ExternalLockList
1520 COM_ExternalLock *head; /* head of list */
1524 * Declaration and initialization of the static structure that manages
1525 * the external lock to COM objects.
1527 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1530 * Private methods used to managed the linked list
1534 static COM_ExternalLock* COM_ExternalLockLocate(
1535 COM_ExternalLock *element,
1536 IUnknown *pUnk);
1538 /****************************************************************************
1539 * Internal - Insert a new IUnknown* to the linked list
1541 static BOOL COM_ExternalLockInsert(
1542 IUnknown *pUnk)
1544 COM_ExternalLock *newLock = NULL;
1545 COM_ExternalLock *previousHead = NULL;
1548 * Allocate space for the new storage object
1550 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1552 if (newLock!=NULL) {
1553 if ( elList.head == EL_END_OF_LIST ) {
1554 elList.head = newLock; /* The list is empty */
1555 } else {
1556 /* insert does it at the head */
1557 previousHead = elList.head;
1558 elList.head = newLock;
1561 /* Set new list item data member */
1562 newLock->pUnk = pUnk;
1563 newLock->uRefCount = 1;
1564 newLock->next = previousHead;
1566 return TRUE;
1568 return FALSE;
1571 /****************************************************************************
1572 * Internal - Method that removes an item from the linked list.
1574 static void COM_ExternalLockDelete(
1575 COM_ExternalLock *itemList)
1577 COM_ExternalLock *current = elList.head;
1579 if ( current == itemList ) {
1580 /* this section handles the deletion of the first node */
1581 elList.head = itemList->next;
1582 HeapFree( GetProcessHeap(), 0, itemList);
1583 } else {
1584 do {
1585 if ( current->next == itemList ){ /* We found the item to free */
1586 current->next = itemList->next; /* readjust the list pointers */
1587 HeapFree( GetProcessHeap(), 0, itemList);
1588 break;
1591 /* Skip to the next item */
1592 current = current->next;
1594 } while ( current != EL_END_OF_LIST );
1598 /****************************************************************************
1599 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1601 * NOTES: how long can the list be ?? (recursive!!!)
1603 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1605 if ( element == EL_END_OF_LIST )
1606 return EL_NOT_FOUND;
1607 else if ( element->pUnk == pUnk ) /* We found it */
1608 return element;
1609 else /* Not the right guy, keep on looking */
1610 return COM_ExternalLockLocate( element->next, pUnk);
1613 /****************************************************************************
1614 * Public - Method that increments the count for a IUnknown* in the linked
1615 * list. The item is inserted if not already in the list.
1617 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1619 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1622 * Add an external lock to the object. If it was already externally
1623 * locked, just increase the reference count. If it was not.
1624 * add the item to the list.
1626 if ( externalLock == EL_NOT_FOUND )
1627 COM_ExternalLockInsert(pUnk);
1628 else
1629 externalLock->uRefCount++;
1632 * Add an internal lock to the object
1634 IUnknown_AddRef(pUnk);
1637 /****************************************************************************
1638 * Public - Method that decrements the count for a IUnknown* in the linked
1639 * list. The item is removed from the list if its count end up at zero or if
1640 * bRelAll is TRUE.
1642 static void COM_ExternalLockRelease(
1643 IUnknown *pUnk,
1644 BOOL bRelAll)
1646 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1648 if ( externalLock != EL_NOT_FOUND ) {
1649 do {
1650 externalLock->uRefCount--; /* release external locks */
1651 IUnknown_Release(pUnk); /* release local locks as well */
1653 if ( bRelAll == FALSE ) break; /* perform single release */
1655 } while ( externalLock->uRefCount > 0 );
1657 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1658 COM_ExternalLockDelete(externalLock);
1661 /****************************************************************************
1662 * Public - Method that frees the content of the list.
1664 static void COM_ExternalLockFreeList()
1666 COM_ExternalLock *head;
1668 head = elList.head; /* grab it by the head */
1669 while ( head != EL_END_OF_LIST ) {
1670 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1671 head = elList.head; /* get the new head... */
1675 /****************************************************************************
1676 * Public - Method that dump the content of the list.
1678 void COM_ExternalLockDump()
1680 COM_ExternalLock *current = elList.head;
1682 DPRINTF("\nExternal lock list contains:\n");
1684 while ( current != EL_END_OF_LIST ) {
1685 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1687 /* Skip to the next item */
1688 current = current->next;
1692 /******************************************************************************
1693 * CoLockObjectExternal [OLE32.31]
1695 HRESULT WINAPI CoLockObjectExternal(
1696 LPUNKNOWN pUnk, /* [in] object to be locked */
1697 BOOL fLock, /* [in] do lock */
1698 BOOL fLastUnlockReleases) /* [in] unlock all */
1701 if (fLock) {
1703 * Increment the external lock coutner, COM_ExternalLockAddRef also
1704 * increment the object's internal lock counter.
1706 COM_ExternalLockAddRef( pUnk);
1707 } else {
1709 * Decrement the external lock coutner, COM_ExternalLockRelease also
1710 * decrement the object's internal lock counter.
1712 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1715 return S_OK;
1718 /***********************************************************************
1719 * CoInitializeWOW (OLE32.27)
1721 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1722 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
1723 return 0;
1726 static IUnknown * pUnkState = 0; /* FIXME: thread local */
1727 static int nStatCounter = 0; /* global */
1728 static HMODULE hOleAut32 = 0; /* global */
1730 /***********************************************************************
1731 * CoGetState [OLE32.24]
1733 * NOTES: might be incomplete
1735 HRESULT WINAPI CoGetState(IUnknown ** ppv)
1737 FIXME("\n");
1739 if(pUnkState) {
1740 IUnknown_AddRef(pUnkState);
1741 *ppv = pUnkState;
1742 FIXME("-- %p\n", *ppv);
1743 return S_OK;
1745 *ppv = NULL;
1746 return E_FAIL;
1750 /***********************************************************************
1751 * CoSetState [OLE32.42]
1753 * NOTES: FIXME: protect this with a crst
1755 HRESULT WINAPI CoSetState(IUnknown * pv)
1757 FIXME("(%p),stub!\n", pv);
1759 if (pv) {
1760 IUnknown_AddRef(pv);
1761 nStatCounter++;
1762 if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL");
1765 if (pUnkState) {
1766 TRACE("-- release %p now\n", pUnkState);
1767 IUnknown_Release(pUnkState);
1768 nStatCounter--;
1769 if (!nStatCounter) FreeLibrary(hOleAut32);
1771 pUnkState = pv;
1772 return S_OK;
1776 /******************************************************************************
1777 * OleGetAutoConvert [OLE32.104]
1779 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
1781 HKEY hkey = 0;
1782 char buf[200];
1783 WCHAR wbuf[200];
1784 DWORD len;
1785 HRESULT res = S_OK;
1787 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
1788 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
1790 res = REGDB_E_CLASSNOTREG;
1791 goto done;
1793 len = 200;
1794 /* we can just query for the default value of AutoConvertTo key like that,
1795 without opening the AutoConvertTo key and querying for NULL (default) */
1796 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
1798 res = REGDB_E_KEYMISSING;
1799 goto done;
1801 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
1802 CLSIDFromString(wbuf,pClsidNew);
1803 done:
1804 if (hkey) RegCloseKey(hkey);
1805 return res;
1808 /******************************************************************************
1809 * OleSetAutoConvert [OLE32.126]
1811 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
1813 HKEY hkey = 0;
1814 char buf[200], szClsidNew[200];
1815 HRESULT res = S_OK;
1817 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
1818 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
1819 WINE_StringFromCLSID(clsidNew, szClsidNew);
1820 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
1822 res = REGDB_E_CLASSNOTREG;
1823 goto done;
1825 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
1827 res = REGDB_E_WRITEREGDB;
1828 goto done;
1831 done:
1832 if (hkey) RegCloseKey(hkey);
1833 return res;
1836 /******************************************************************************
1837 * CoTreatAsClass [OLE32.46]
1839 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
1841 HKEY hkey = 0;
1842 char buf[200], szClsidNew[200];
1843 HRESULT res = S_OK;
1845 FIXME("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
1846 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
1847 WINE_StringFromCLSID(clsidNew, szClsidNew);
1848 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
1850 res = REGDB_E_CLASSNOTREG;
1851 goto done;
1853 if (RegSetValueA(hkey, "AutoTreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
1855 res = REGDB_E_WRITEREGDB;
1856 goto done;
1859 done:
1860 if (hkey) RegCloseKey(hkey);
1861 return res;
1865 /***********************************************************************
1866 * IsEqualGUID [OLE32.76]
1868 * Compares two Unique Identifiers.
1870 * RETURNS
1871 * TRUE if equal
1873 #undef IsEqualGUID
1874 BOOL WINAPI IsEqualGUID(
1875 REFGUID rguid1, /* [in] unique id 1 */
1876 REFGUID rguid2 /* [in] unique id 2 */
1879 return !memcmp(rguid1,rguid2,sizeof(GUID));
1882 /***********************************************************************
1883 * CoInitializeSecurity [OLE32.164]
1885 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
1886 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
1887 void* pReserved1, DWORD dwAuthnLevel,
1888 DWORD dwImpLevel, void* pReserved2,
1889 DWORD dwCapabilities, void* pReserved3)
1891 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
1892 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
1893 dwCapabilities, pReserved3);
1894 return S_OK;