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
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
45 #include "wine/unicode.h"
47 #include "ole32_main.h"
48 #include "compobj_private.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
54 /****************************************************************************
55 * This section defines variables internal to the COM module.
57 * TODO: Most of these things will have to be made thread-safe.
59 HINSTANCE COMPOBJ_hInstance32
= 0;
61 static HRESULT
COM_GetRegisteredClassObject(REFCLSID rclsid
, DWORD dwClsContext
, LPUNKNOWN
* ppUnk
);
62 static void COM_RevokeAllClasses();
63 static void COM_ExternalLockFreeList();
65 const CLSID CLSID_StdGlobalInterfaceTable
= { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
69 static CRITICAL_SECTION csApartment
;
70 static CRITICAL_SECTION_DEBUG critsect_debug
=
73 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
74 0, 0, { 0, (DWORD
)(__FILE__
": csApartment") }
76 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
79 * This lock count counts the number of times CoInitialize is called. It is
80 * decreased every time CoUninitialize is called. When it hits 0, the COM
83 static LONG s_COMLockCount
= 0;
86 * This linked list contains the list of registered class objects. These
87 * are mostly used to register the factories for out-of-proc servers of OLE
90 * TODO: Make this data structure aware of inter-process communication. This
91 * means that parts of this will be exported to the Wine Server.
93 typedef struct tagRegisteredClass
95 CLSID classIdentifier
;
96 LPUNKNOWN classObject
;
100 HANDLE hThread
; /* only for localserver */
101 struct tagRegisteredClass
* nextClass
;
104 static RegisteredClass
* firstRegisteredClass
= NULL
;
106 static CRITICAL_SECTION csRegisteredClassList
;
107 static CRITICAL_SECTION_DEBUG class_cs_debug
=
109 0, 0, &csRegisteredClassList
,
110 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
111 0, 0, { 0, (DWORD
)(__FILE__
": csRegisteredClassList") }
113 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
115 /*****************************************************************************
116 * This section contains OpenDllList definitions
118 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
119 * other functions what do LoadLibrary _without_ giving back a HMODULE.
120 * Without this list these handles would be freed never.
122 * FIXME: a DLL what says OK whenn asked for unloading is unloaded in the
123 * next unload-call but not before 600 sec.
126 typedef struct tagOpenDll
{
128 struct tagOpenDll
*next
;
131 static OpenDll
*openDllList
= NULL
; /* linked list of open dlls */
133 static CRITICAL_SECTION csOpenDllList
;
134 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
136 0, 0, &csOpenDllList
,
137 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
138 0, 0, { 0, (DWORD
)(__FILE__
": csOpenDllList") }
140 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
142 static const char aptWinClass
[] = "WINE_OLE32_APT_CLASS";
143 static LRESULT CALLBACK
COM_AptWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
145 static void COMPOBJ_DLLList_Add(HANDLE hLibrary
);
146 static void COMPOBJ_DllList_FreeUnused(int Timeout
);
149 /******************************************************************************
150 * Initialize/Unitialize threading stuff.
152 void COMPOBJ_InitProcess( void )
156 memset(&wclass
, 0, sizeof(wclass
));
157 wclass
.lpfnWndProc
= &COM_AptWndProc
;
158 wclass
.hInstance
= OLE32_hInstance
;
159 wclass
.lpszClassName
= aptWinClass
;
160 RegisterClassA(&wclass
);
163 void COMPOBJ_UninitProcess( void )
165 UnregisterClassA(aptWinClass
, OLE32_hInstance
);
168 /******************************************************************************
171 static void COM_InitMTA(void)
173 /* FIXME: how does windoze create OXIDs?
174 * this method will only work for local RPC */
175 MTA
.oxid
= ((OXID
)GetCurrentProcessId() << 32);
176 InitializeCriticalSection(&MTA
.cs
);
179 static void COM_UninitMTA(void)
181 DeleteCriticalSection(&MTA
.cs
);
185 static APARTMENT
* COM_CreateApartment(DWORD model
)
189 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(APARTMENT
));
191 apt
->tid
= GetCurrentThreadId();
192 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
193 GetCurrentProcess(), &apt
->thread
,
194 THREAD_ALL_ACCESS
, FALSE
, 0);
195 if (model
& COINIT_APARTMENTTHREADED
) {
196 /* FIXME: how does windoze create OXIDs? */
197 apt
->oxid
= MTA
.oxid
| GetCurrentThreadId();
198 apt
->win
= CreateWindowA(aptWinClass
, NULL
, 0,
200 0, 0, OLE32_hInstance
, NULL
);
201 InitializeCriticalSection(&apt
->cs
);
205 apt
->oxid
= MTA
.oxid
;
207 EnterCriticalSection(&csApartment
);
208 if (apts
) apts
->prev
= apt
;
211 LeaveCriticalSection(&csApartment
);
212 NtCurrentTeb()->ReservedForOle
= apt
;
216 static void COM_DestroyApartment(APARTMENT
*apt
)
218 EnterCriticalSection(&csApartment
);
219 if (apt
->prev
) apt
->prev
->next
= apt
->next
;
220 if (apt
->next
) apt
->next
->prev
= apt
->prev
;
221 if (apts
== apt
) apts
= apt
->next
;
222 apt
->prev
= NULL
; apt
->next
= NULL
;
223 LeaveCriticalSection(&csApartment
);
224 if (apt
->model
& COINIT_APARTMENTTHREADED
) {
225 if (apt
->win
) DestroyWindow(apt
->win
);
226 DeleteCriticalSection(&apt
->cs
);
228 CloseHandle(apt
->thread
);
229 HeapFree(GetProcessHeap(), 0, apt
);
232 HWND
COM_GetApartmentWin(OXID oxid
)
237 EnterCriticalSection(&csApartment
);
239 while (apt
&& apt
->oxid
!= oxid
) apt
= apt
->next
;
240 if (apt
) win
= apt
->win
;
241 LeaveCriticalSection(&csApartment
);
245 static LRESULT CALLBACK
COM_AptWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
247 return DefWindowProcA(hWnd
, msg
, wParam
, lParam
);
250 /*****************************************************************************
251 * This section contains OpenDllList implemantation
254 static void COMPOBJ_DLLList_Add(HANDLE hLibrary
)
261 EnterCriticalSection( &csOpenDllList
);
263 if (openDllList
== NULL
) {
264 /* empty list -- add first node */
265 openDllList
= (OpenDll
*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
266 openDllList
->hLibrary
=hLibrary
;
267 openDllList
->next
= NULL
;
269 /* search for this dll */
271 for (ptr
= openDllList
; ptr
->next
!= NULL
; ptr
=ptr
->next
) {
272 if (ptr
->hLibrary
== hLibrary
) {
278 /* dll not found, add it */
280 openDllList
= (OpenDll
*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
281 openDllList
->hLibrary
= hLibrary
;
282 openDllList
->next
= tmp
;
286 LeaveCriticalSection( &csOpenDllList
);
289 static void COMPOBJ_DllList_FreeUnused(int Timeout
)
291 OpenDll
*curr
, *next
, *prev
= NULL
;
292 typedef HRESULT(*DllCanUnloadNowFunc
)(void);
293 DllCanUnloadNowFunc DllCanUnloadNow
;
297 EnterCriticalSection( &csOpenDllList
);
299 for (curr
= openDllList
; curr
!= NULL
; ) {
300 DllCanUnloadNow
= (DllCanUnloadNowFunc
) GetProcAddress(curr
->hLibrary
, "DllCanUnloadNow");
302 if ( (DllCanUnloadNow
!= NULL
) && (DllCanUnloadNow() == S_OK
) ) {
305 TRACE("freeing %p\n", curr
->hLibrary
);
306 FreeLibrary(curr
->hLibrary
);
308 HeapFree(GetProcessHeap(), 0, curr
);
309 if (curr
== openDllList
) {
322 LeaveCriticalSection( &csOpenDllList
);
325 /******************************************************************************
326 * CoBuildVersion [COMPOBJ.1]
327 * CoBuildVersion [OLE32.4]
330 * Current build version, hiword is majornumber, loword is minornumber
332 DWORD WINAPI
CoBuildVersion(void)
334 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
335 return (rmm
<<16)+rup
;
338 /******************************************************************************
339 * CoInitialize [OLE32.26]
341 * Initializes the COM libraries.
345 HRESULT WINAPI
CoInitialize(
346 LPVOID lpReserved
/* [in] pointer to win32 malloc interface
347 (obsolete, should be NULL) */
351 * Just delegate to the newer method.
353 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
356 /******************************************************************************
357 * CoInitializeEx [OLE32.163]
359 * Initializes the COM libraries. The behavior used to set the win32 IMalloc
360 * used for memory management is obsolete.
363 * S_OK if successful,
364 * S_FALSE if this function was called already.
365 * RPC_E_CHANGED_MODE if a previous call to CoInitialize specified another
368 HRESULT WINAPI
CoInitializeEx(
369 LPVOID lpReserved
, /* [in] pointer to win32 malloc interface
370 (obsolete, should be NULL) */
371 DWORD dwCoInit
/* [in] A value from COINIT specifies the threading model */
377 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
379 if (lpReserved
!=NULL
)
381 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
384 apt
= NtCurrentTeb()->ReservedForOle
;
385 if (apt
&& dwCoInit
!= apt
->model
) return RPC_E_CHANGED_MODE
;
386 hr
= apt
? S_FALSE
: S_OK
;
389 * Check the lock count. If this is the first time going through the initialize
390 * process, we have to initialize the libraries.
392 * And crank-up that lock count.
394 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
397 * Initialize the various COM libraries and data structures.
399 TRACE("() - Initializing the COM libraries\n");
403 RunningObjectTableImpl_Initialize();
406 if (!apt
) apt
= COM_CreateApartment(dwCoInit
);
408 InterlockedIncrement(&apt
->inits
);
409 if (hr
== S_OK
) NtCurrentTeb()->ReservedForOle
= apt
;
414 /***********************************************************************
415 * CoUninitialize [OLE32.47]
417 * This method will release the COM libraries.
419 * See the windows documentation for more details.
421 void WINAPI
CoUninitialize(void)
428 apt
= NtCurrentTeb()->ReservedForOle
;
430 if (InterlockedDecrement(&apt
->inits
)==0) {
431 NtCurrentTeb()->ReservedForOle
= NULL
;
432 COM_DestroyApartment(apt
);
437 * Decrease the reference count.
438 * If we are back to 0 locks on the COM library, make sure we free
439 * all the associated data structures.
441 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
445 * Release the various COM libraries and data structures.
447 TRACE("() - Releasing the COM libraries\n");
449 RunningObjectTableImpl_UnInitialize();
451 * Release the references to the registered class objects.
453 COM_RevokeAllClasses();
456 * This will free the loaded COM Dlls.
458 CoFreeAllLibraries();
461 * This will free list of external references to COM objects.
463 COM_ExternalLockFreeList();
467 else if (lCOMRefCnt
<1) {
468 ERR( "CoUninitialize() - not CoInitialized.\n" );
469 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
473 /******************************************************************************
474 * CoDisconnectObject [COMPOBJ.15]
475 * CoDisconnectObject [OLE32.8]
477 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
479 TRACE("(%p, %lx)\n",lpUnk
,reserved
);
483 /******************************************************************************
484 * CoCreateGuid[OLE32.6]
487 HRESULT WINAPI
CoCreateGuid(
488 GUID
*pguid
/* [out] points to the GUID to initialize */
490 return UuidCreate(pguid
);
493 /******************************************************************************
494 * CLSIDFromString [OLE32.3]
495 * IIDFromString [OLE32.74]
496 * Converts a unique identifier from its string representation into
500 * If idstr is not a valid CLSID string then it gets treated as a ProgID
505 HRESULT WINAPI
__CLSIDFromStringA(
506 LPCSTR idstr
, /* [in] string representation of guid */
507 CLSID
*id
) /* [out] GUID converted from string */
509 BYTE
*s
= (BYTE
*) idstr
;
514 s
= "{00000000-0000-0000-0000-000000000000}";
515 else { /* validate the CLSID string */
518 return CO_E_CLASSSTRING
;
520 if ((s
[0]!='{') || (s
[9]!='-') || (s
[14]!='-') || (s
[19]!='-') || (s
[24]!='-') || (s
[37]!='}'))
521 return CO_E_CLASSSTRING
;
523 for (i
=1; i
<37; i
++) {
524 if ((i
== 9)||(i
== 14)||(i
== 19)||(i
== 24)) continue;
525 if (!(((s
[i
] >= '0') && (s
[i
] <= '9')) ||
526 ((s
[i
] >= 'a') && (s
[i
] <= 'f')) ||
527 ((s
[i
] >= 'A') && (s
[i
] <= 'F'))))
528 return CO_E_CLASSSTRING
;
532 TRACE("%s -> %p\n", s
, id
);
534 /* quick lookup table */
535 memset(table
, 0, 256);
537 for (i
= 0; i
< 10; i
++) {
540 for (i
= 0; i
< 6; i
++) {
541 table
['A' + i
] = i
+10;
542 table
['a' + i
] = i
+10;
545 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
547 id
->Data1
= (table
[s
[1]] << 28 | table
[s
[2]] << 24 | table
[s
[3]] << 20 | table
[s
[4]] << 16 |
548 table
[s
[5]] << 12 | table
[s
[6]] << 8 | table
[s
[7]] << 4 | table
[s
[8]]);
549 id
->Data2
= table
[s
[10]] << 12 | table
[s
[11]] << 8 | table
[s
[12]] << 4 | table
[s
[13]];
550 id
->Data3
= table
[s
[15]] << 12 | table
[s
[16]] << 8 | table
[s
[17]] << 4 | table
[s
[18]];
552 /* these are just sequential bytes */
553 id
->Data4
[0] = table
[s
[20]] << 4 | table
[s
[21]];
554 id
->Data4
[1] = table
[s
[22]] << 4 | table
[s
[23]];
555 id
->Data4
[2] = table
[s
[25]] << 4 | table
[s
[26]];
556 id
->Data4
[3] = table
[s
[27]] << 4 | table
[s
[28]];
557 id
->Data4
[4] = table
[s
[29]] << 4 | table
[s
[30]];
558 id
->Data4
[5] = table
[s
[31]] << 4 | table
[s
[32]];
559 id
->Data4
[6] = table
[s
[33]] << 4 | table
[s
[34]];
560 id
->Data4
[7] = table
[s
[35]] << 4 | table
[s
[36]];
565 /*****************************************************************************/
567 HRESULT WINAPI
CLSIDFromString(
568 LPCOLESTR idstr
, /* [in] string representation of GUID */
569 CLSID
*id
) /* [out] GUID represented by above string */
574 if (!WideCharToMultiByte( CP_ACP
, 0, idstr
, -1, xid
, sizeof(xid
), NULL
, NULL
))
575 return CO_E_CLASSSTRING
;
578 ret
= __CLSIDFromStringA(xid
,id
);
579 if(ret
!= S_OK
) { /* It appears a ProgID is also valid */
580 ret
= CLSIDFromProgID(idstr
, id
);
585 /******************************************************************************
586 * WINE_StringFromCLSID [Internal]
587 * Converts a GUID into the respective string representation.
592 * the string representation and HRESULT
594 HRESULT
WINE_StringFromCLSID(
595 const CLSID
*id
, /* [in] GUID to be converted */
596 LPSTR idstr
/* [out] pointer to buffer to contain converted guid */
598 static const char *hex
= "0123456789ABCDEF";
603 { ERR("called with id=Null\n");
608 sprintf(idstr
, "{%08lX-%04X-%04X-%02X%02X-",
609 id
->Data1
, id
->Data2
, id
->Data3
,
610 id
->Data4
[0], id
->Data4
[1]);
614 for (i
= 2; i
< 8; i
++) {
615 *s
++ = hex
[id
->Data4
[i
]>>4];
616 *s
++ = hex
[id
->Data4
[i
] & 0xf];
622 TRACE("%p->%s\n", id
, idstr
);
628 /******************************************************************************
629 * StringFromCLSID [OLE32.151]
630 * StringFromIID [OLE32.153]
631 * Converts a GUID into the respective string representation.
632 * The target string is allocated using the OLE IMalloc.
634 * the string representation and HRESULT
636 HRESULT WINAPI
StringFromCLSID(
637 REFCLSID id
, /* [in] the GUID to be converted */
638 LPOLESTR
*idstr
/* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
644 if ((ret
=CoGetMalloc(0,&mllc
)))
647 ret
=WINE_StringFromCLSID(id
,buf
);
649 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, buf
, -1, NULL
, 0 );
650 *idstr
= IMalloc_Alloc( mllc
, len
* sizeof(WCHAR
) );
651 MultiByteToWideChar( CP_ACP
, 0, buf
, -1, *idstr
, len
);
656 /******************************************************************************
657 * StringFromGUID2 [COMPOBJ.76]
658 * StringFromGUID2 [OLE32.152]
660 * Converts a global unique identifier into a string of an API-
661 * specified fixed format. (The usual {.....} stuff.)
664 * The (UNICODE) string representation of the GUID in 'str'
665 * The length of the resulting string, 0 if there was any problem.
668 StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
672 if (WINE_StringFromCLSID(id
,xguid
))
674 return MultiByteToWideChar( CP_ACP
, 0, xguid
, -1, str
, cmax
);
677 /******************************************************************************
678 * ProgIDFromCLSID [OLE32.133]
679 * Converts a class id into the respective Program ID. (By using a registry lookup)
680 * RETURNS S_OK on success
681 * riid associated with the progid
684 HRESULT WINAPI
ProgIDFromCLSID(
685 REFCLSID clsid
, /* [in] class id as found in registry */
686 LPOLESTR
*lplpszProgID
/* [out] associated Prog ID */
689 char strCLSID
[50], *buf
, *buf2
;
695 WINE_StringFromCLSID(clsid
, strCLSID
);
697 buf
= HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID
)+14);
698 sprintf(buf
,"CLSID\\%s\\ProgID", strCLSID
);
699 if (RegOpenKeyA(HKEY_CLASSES_ROOT
, buf
, &xhkey
))
700 ret
= REGDB_E_CLASSNOTREG
;
702 HeapFree(GetProcessHeap(), 0, buf
);
706 buf2
= HeapAlloc(GetProcessHeap(), 0, 255);
708 if (RegQueryValueA(xhkey
, NULL
, buf2
, &buf2len
))
709 ret
= REGDB_E_CLASSNOTREG
;
713 if (CoGetMalloc(0,&mllc
))
717 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, buf2
, -1, NULL
, 0 );
718 *lplpszProgID
= IMalloc_Alloc(mllc
, len
* sizeof(WCHAR
) );
719 MultiByteToWideChar( CP_ACP
, 0, buf2
, -1, *lplpszProgID
, len
);
722 HeapFree(GetProcessHeap(), 0, buf2
);
729 /******************************************************************************
730 * CLSIDFromProgID [COMPOBJ.61]
731 * Converts a program id into the respective GUID. (By using a registry lookup)
733 * riid associated with the progid
735 HRESULT WINAPI
CLSIDFromProgID16(
736 LPCOLESTR16 progid
, /* [in] program id as found in registry */
737 LPCLSID riid
/* [out] associated CLSID */
744 buf
= HeapAlloc(GetProcessHeap(),0,strlen(progid
)+8);
745 sprintf(buf
,"%s\\CLSID",progid
);
746 if ((err
=RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&xhkey
))) {
747 HeapFree(GetProcessHeap(),0,buf
);
748 return CO_E_CLASSSTRING
;
750 HeapFree(GetProcessHeap(),0,buf
);
751 buf2len
= sizeof(buf2
);
752 if ((err
=RegQueryValueA(xhkey
,NULL
,buf2
,&buf2len
))) {
754 return CO_E_CLASSSTRING
;
757 return __CLSIDFromStringA(buf2
,riid
);
760 /******************************************************************************
761 * CLSIDFromProgID [OLE32.2]
762 * Converts a program id into the respective GUID. (By using a registry lookup)
764 * riid associated with the progid
766 HRESULT WINAPI
CLSIDFromProgID(
767 LPCOLESTR progid
, /* [in] program id as found in registry */
768 LPCLSID riid
) /* [out] associated CLSID */
770 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
772 DWORD buf2len
= sizeof(buf2
);
775 WCHAR
*buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
776 strcpyW( buf
, progid
);
777 strcatW( buf
, clsidW
);
778 if (RegOpenKeyW(HKEY_CLASSES_ROOT
,buf
,&xhkey
))
780 HeapFree(GetProcessHeap(),0,buf
);
781 return CO_E_CLASSSTRING
;
783 HeapFree(GetProcessHeap(),0,buf
);
785 if (RegQueryValueA(xhkey
,NULL
,buf2
,&buf2len
))
788 return CO_E_CLASSSTRING
;
791 return __CLSIDFromStringA(buf2
,riid
);
796 /*****************************************************************************
797 * CoGetPSClsid [OLE32.22]
799 * This function returns the CLSID of the DLL that implements the proxy and stub
800 * for the specified interface.
802 * It determines this by searching the
803 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
804 * and any interface id registered by CoRegisterPSClsid within the current process.
806 * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
808 HRESULT WINAPI
CoGetPSClsid(
809 REFIID riid
, /* [in] Interface whose proxy/stub CLSID is to be returned */
810 CLSID
*pclsid
) /* [out] Where to store returned proxy/stub CLSID */
816 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
818 /* Get the input iid as a string */
819 WINE_StringFromCLSID(riid
, buf2
);
820 /* Allocate memory for the registry key we will construct.
821 (length of iid string plus constant length of static text */
822 buf
= HeapAlloc(GetProcessHeap(), 0, strlen(buf2
)+27);
825 return (E_OUTOFMEMORY
);
828 /* Construct the registry key we want */
829 sprintf(buf
,"Interface\\%s\\ProxyStubClsid32", buf2
);
832 if (RegOpenKeyA(HKEY_CLASSES_ROOT
, buf
, &xhkey
))
834 HeapFree(GetProcessHeap(),0,buf
);
835 return (E_INVALIDARG
);
837 HeapFree(GetProcessHeap(),0,buf
);
839 /* ... Once we have the key, query the registry to get the
840 value of CLSID as a string, and convert it into a
841 proper CLSID structure to be passed back to the app */
842 buf2len
= sizeof(buf2
);
843 if ( (RegQueryValueA(xhkey
,NULL
,buf2
,&buf2len
)) )
850 /* We have the CLSid we want back from the registry as a string, so
851 lets convert it into a CLSID structure */
852 if ( (__CLSIDFromStringA(buf2
,pclsid
)) != NOERROR
) {
856 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
862 /***********************************************************************
863 * WriteClassStm (OLE32.159)
865 * This function write a CLSID on stream
867 HRESULT WINAPI
WriteClassStm(IStream
*pStm
,REFCLSID rclsid
)
869 TRACE("(%p,%p)\n",pStm
,rclsid
);
874 return IStream_Write(pStm
,rclsid
,sizeof(CLSID
),NULL
);
877 /***********************************************************************
878 * ReadClassStm (OLE32.135)
880 * This function read a CLSID from a stream
882 HRESULT WINAPI
ReadClassStm(IStream
*pStm
,CLSID
*pclsid
)
887 TRACE("(%p,%p)\n",pStm
,pclsid
);
892 res
= IStream_Read(pStm
,(void*)pclsid
,sizeof(CLSID
),&nbByte
);
897 if (nbByte
!= sizeof(CLSID
))
905 * COM_GetRegisteredClassObject
907 * This internal method is used to scan the registered class list to
908 * find a class object.
911 * rclsid Class ID of the class to find.
912 * dwClsContext Class context to match.
913 * ppv [out] returns a pointer to the class object. Complying
914 * to normal COM usage, this method will increase the
915 * reference count on this object.
917 static HRESULT
COM_GetRegisteredClassObject(
922 HRESULT hr
= S_FALSE
;
923 RegisteredClass
* curClass
;
925 EnterCriticalSection( &csRegisteredClassList
);
933 * Iterate through the whole list and try to match the class ID.
935 curClass
= firstRegisteredClass
;
937 while (curClass
!= 0)
940 * Check if we have a match on the class ID.
942 if (IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
945 * Since we don't do out-of process or DCOM just right away, let's ignore the
950 * We have a match, return the pointer to the class object.
952 *ppUnk
= curClass
->classObject
;
954 IUnknown_AddRef(curClass
->classObject
);
961 * Step to the next class in the list.
963 curClass
= curClass
->nextClass
;
967 LeaveCriticalSection( &csRegisteredClassList
);
969 * If we get to here, we haven't found our class.
975 _LocalServerThread(LPVOID param
) {
978 RegisteredClass
*newClass
= (RegisteredClass
*)param
;
982 unsigned char *buffer
;
984 IClassFactory
*classfac
;
985 LARGE_INTEGER seekto
;
986 ULARGE_INTEGER newpos
;
989 TRACE("Starting threader for %s.\n",debugstr_guid(&newClass
->classIdentifier
));
990 strcpy(pipefn
,PIPEPREF
);
991 WINE_StringFromCLSID(&newClass
->classIdentifier
,pipefn
+strlen(PIPEPREF
));
993 hres
= IUnknown_QueryInterface(newClass
->classObject
,&IID_IClassFactory
,(LPVOID
*)&classfac
);
994 if (hres
) return hres
;
996 hres
= CreateStreamOnHGlobal(0,TRUE
,&pStm
);
998 FIXME("Failed to create stream on hglobal.\n");
1001 hres
= CoMarshalInterface(pStm
,&IID_IClassFactory
,(LPVOID
)classfac
,0,NULL
,0);
1003 FIXME("CoMarshalInterface failed, %lx!\n",hres
);
1006 hres
= IStream_Stat(pStm
,&ststg
,0);
1007 if (hres
) return hres
;
1009 buflen
= ststg
.cbSize
.s
.LowPart
;
1010 buffer
= HeapAlloc(GetProcessHeap(),0,buflen
);
1011 seekto
.s
.LowPart
= 0;
1012 seekto
.s
.HighPart
= 0;
1013 hres
= IStream_Seek(pStm
,seekto
,SEEK_SET
,&newpos
);
1015 FIXME("IStream_Seek failed, %lx\n",hres
);
1018 hres
= IStream_Read(pStm
,buffer
,buflen
,&res
);
1020 FIXME("Stream Read failed, %lx\n",hres
);
1023 IStream_Release(pStm
);
1026 hPipe
= CreateNamedPipeA(
1029 PIPE_TYPE_BYTE
|PIPE_WAIT
,
1030 PIPE_UNLIMITED_INSTANCES
,
1033 NMPWAIT_USE_DEFAULT_WAIT
,
1036 if (hPipe
== INVALID_HANDLE_VALUE
) {
1037 FIXME("pipe creation failed for %s, le is %lx\n",pipefn
,GetLastError());
1040 if (!ConnectNamedPipe(hPipe
,NULL
)) {
1041 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1045 WriteFile(hPipe
,buffer
,buflen
,&res
,NULL
);
1051 /******************************************************************************
1052 * CoRegisterClassObject [OLE32.36]
1054 * This method will register the class object for a given class ID.
1056 * See the Windows documentation for more details.
1058 HRESULT WINAPI
CoRegisterClassObject(
1061 DWORD dwClsContext
, /* [in] CLSCTX flags indicating the context in which to run the executable */
1062 DWORD flags
, /* [in] REGCLS flags indicating how connections are made */
1063 LPDWORD lpdwRegister
1066 RegisteredClass
* newClass
;
1067 LPUNKNOWN foundObject
;
1070 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1071 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
1073 if ( (lpdwRegister
==0) || (pUnk
==0) )
1074 return E_INVALIDARG
;
1079 * First, check if the class is already registered.
1080 * If it is, this should cause an error.
1082 hr
= COM_GetRegisteredClassObject(rclsid
, dwClsContext
, &foundObject
);
1084 IUnknown_Release(foundObject
);
1085 return CO_E_OBJISREG
;
1088 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
1089 if ( newClass
== NULL
)
1090 return E_OUTOFMEMORY
;
1092 EnterCriticalSection( &csRegisteredClassList
);
1094 newClass
->classIdentifier
= *rclsid
;
1095 newClass
->runContext
= dwClsContext
;
1096 newClass
->connectFlags
= flags
;
1098 * Use the address of the chain node as the cookie since we are sure it's
1101 newClass
->dwCookie
= (DWORD
)newClass
;
1102 newClass
->nextClass
= firstRegisteredClass
;
1105 * Since we're making a copy of the object pointer, we have to increase its
1108 newClass
->classObject
= pUnk
;
1109 IUnknown_AddRef(newClass
->classObject
);
1111 firstRegisteredClass
= newClass
;
1112 LeaveCriticalSection( &csRegisteredClassList
);
1114 *lpdwRegister
= newClass
->dwCookie
;
1116 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
1120 newClass
->hThread
=CreateThread(NULL
,0,_LocalServerThread
,newClass
,0,&tid
);
1125 /***********************************************************************
1126 * CoRevokeClassObject [OLE32.40]
1128 * This method will remove a class object from the class registry
1130 * See the Windows documentation for more details.
1132 HRESULT WINAPI
CoRevokeClassObject(
1135 HRESULT hr
= E_INVALIDARG
;
1136 RegisteredClass
** prevClassLink
;
1137 RegisteredClass
* curClass
;
1139 TRACE("(%08lx)\n",dwRegister
);
1141 EnterCriticalSection( &csRegisteredClassList
);
1144 * Iterate through the whole list and try to match the cookie.
1146 curClass
= firstRegisteredClass
;
1147 prevClassLink
= &firstRegisteredClass
;
1149 while (curClass
!= 0)
1152 * Check if we have a match on the cookie.
1154 if (curClass
->dwCookie
== dwRegister
)
1157 * Remove the class from the chain.
1159 *prevClassLink
= curClass
->nextClass
;
1162 * Release the reference to the class object.
1164 IUnknown_Release(curClass
->classObject
);
1167 * Free the memory used by the chain node.
1169 HeapFree(GetProcessHeap(), 0, curClass
);
1176 * Step to the next class in the list.
1178 prevClassLink
= &(curClass
->nextClass
);
1179 curClass
= curClass
->nextClass
;
1183 LeaveCriticalSection( &csRegisteredClassList
);
1185 * If we get to here, we haven't found our class.
1190 /***********************************************************************
1191 * compobj_RegReadPath [internal]
1193 * Reads a registry value and expands it when nessesary
1195 HRESULT
compobj_RegReadPath(char * keyname
, char * valuename
, char * dst
, int dstlen
)
1201 DWORD dwLength
= dstlen
;
1203 if((hres
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &key
)) == ERROR_SUCCESS
) {
1204 if( (hres
= RegQueryValueExA(key
, NULL
, NULL
, &keytype
, (LPBYTE
)src
, &dwLength
)) == ERROR_SUCCESS
) {
1205 if (keytype
== REG_EXPAND_SZ
) {
1206 if (dstlen
<= ExpandEnvironmentStringsA(src
, dst
, dstlen
)) hres
= ERROR_MORE_DATA
;
1208 strncpy(dst
, src
, dstlen
);
1216 /***********************************************************************
1217 * CoGetClassObject [COMPOBJ.7]
1218 * CoGetClassObject [OLE32.16]
1220 * FIXME. If request allows of several options and there is a failure
1221 * with one (other than not being registered) do we try the
1222 * others or return failure? (E.g. inprocess is registered but
1223 * the DLL is not found but the server version works)
1225 HRESULT WINAPI
CoGetClassObject(
1226 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
1227 REFIID iid
, LPVOID
*ppv
1229 LPUNKNOWN regClassObject
;
1230 HRESULT hres
= E_UNEXPECTED
;
1233 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
1234 DllGetClassObjectFunc DllGetClassObject
;
1236 WINE_StringFromCLSID((LPCLSID
)rclsid
,xclsid
);
1238 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
1241 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo
->pwszName
));
1242 FIXME("\t\tpAuthInfo=%p\n",pServerInfo
->pAuthInfo
);
1246 * First, try and see if we can't match the class ID with one of the
1247 * registered classes.
1249 if (S_OK
== COM_GetRegisteredClassObject(rclsid
, dwClsContext
, ®ClassObject
))
1252 * Get the required interface from the retrieved pointer.
1254 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
1257 * Since QI got another reference on the pointer, we want to release the
1258 * one we already have. If QI was unsuccessful, this will release the object. This
1259 * is good since we are not returning it in the "out" parameter.
1261 IUnknown_Release(regClassObject
);
1266 /* first try: in-process */
1267 if ((CLSCTX_INPROC_SERVER
| CLSCTX_INPROC_HANDLER
) & dwClsContext
) {
1268 char keyname
[MAX_PATH
];
1269 char dllpath
[MAX_PATH
+1];
1271 sprintf(keyname
,"CLSID\\%s\\InprocServer32",xclsid
);
1273 if ( compobj_RegReadPath(keyname
, NULL
, dllpath
, sizeof(dllpath
)) != ERROR_SUCCESS
) {
1274 /* failure: CLSID is not found in registry */
1275 WARN("class %s not registred\n", xclsid
);
1276 hres
= REGDB_E_CLASSNOTREG
;
1278 if ((hLibrary
= LoadLibraryExA(dllpath
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
)) == 0) {
1279 /* failure: DLL could not be loaded */
1280 ERR("couldn't load InprocServer32 dll %s\n", dllpath
);
1281 hres
= E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1282 } else if (!(DllGetClassObject
= (DllGetClassObjectFunc
)GetProcAddress(hLibrary
, "DllGetClassObject"))) {
1283 /* failure: the dll did not export DllGetClassObject */
1284 ERR("couldn't find function DllGetClassObject in %s\n", dllpath
);
1285 FreeLibrary( hLibrary
);
1286 hres
= CO_E_DLLNOTFOUND
;
1288 /* OK: get the ClassObject */
1289 COMPOBJ_DLLList_Add( hLibrary
);
1290 return DllGetClassObject(rclsid
, iid
, ppv
);
1295 /* Next try out of process */
1296 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
1298 return create_marshalled_proxy(rclsid
,iid
,ppv
);
1301 /* Finally try remote */
1302 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
1304 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1305 hres
= E_NOINTERFACE
;
1310 /***********************************************************************
1311 * CoResumeClassObjects (OLE32.173)
1313 * Resumes classobjects registered with REGCLS suspended
1315 HRESULT WINAPI
CoResumeClassObjects(void)
1321 /***********************************************************************
1322 * GetClassFile (OLE32.67)
1324 * This function supplies the CLSID associated with the given filename.
1326 HRESULT WINAPI
GetClassFile(LPCOLESTR filePathName
,CLSID
*pclsid
)
1330 int nbElm
, length
, i
;
1332 LPOLESTR
*pathDec
=0,absFile
=0,progId
=0;
1334 static const WCHAR bkslashW
[] = {'\\',0};
1335 static const WCHAR dotW
[] = {'.',0};
1337 TRACE("%s, %p\n", debugstr_w(filePathName
), pclsid
);
1339 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1340 if((StgIsStorageFile(filePathName
))==S_OK
){
1342 res
=StgOpenStorage(filePathName
,NULL
,STGM_READ
| STGM_SHARE_DENY_WRITE
,NULL
,0,&pstg
);
1345 res
=ReadClassStg(pstg
,pclsid
);
1347 IStorage_Release(pstg
);
1351 /* if the file is not a storage object then attemps to match various bits in the file against a
1352 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1355 for(i=0;i<nFileTypes;i++)
1357 for(i=0;j<nPatternsForType;j++){
1362 pat=ReadPatternFromRegistry(i,j);
1363 hFile=CreateFileW(filePathName,,,,,,hFile);
1364 SetFilePosition(hFile,pat.offset);
1365 ReadFile(hFile,buf,pat.size,NULL,NULL);
1366 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1368 *pclsid=ReadCLSIDFromRegistry(i);
1374 /* if the obove strategies fail then search for the extension key in the registry */
1376 /* get the last element (absolute file) in the path name */
1377 nbElm
=FileMonikerImpl_DecomposePath(filePathName
,&pathDec
);
1378 absFile
=pathDec
[nbElm
-1];
1380 /* failed if the path represente a directory and not an absolute file name*/
1381 if (!lstrcmpW(absFile
, bkslashW
))
1382 return MK_E_INVALIDEXTENSION
;
1384 /* get the extension of the file */
1386 length
=lstrlenW(absFile
);
1387 for(i
= length
-1; (i
>= 0) && *(extension
= &absFile
[i
]) != '.'; i
--)
1390 if (!extension
|| !lstrcmpW(extension
, dotW
))
1391 return MK_E_INVALIDEXTENSION
;
1393 res
=RegQueryValueW(HKEY_CLASSES_ROOT
, extension
, NULL
, &sizeProgId
);
1395 /* get the progId associated to the extension */
1396 progId
= CoTaskMemAlloc(sizeProgId
);
1397 res
= RegQueryValueW(HKEY_CLASSES_ROOT
, extension
, progId
, &sizeProgId
);
1399 if (res
==ERROR_SUCCESS
)
1400 /* return the clsid associated to the progId */
1401 res
= CLSIDFromProgID(progId
,pclsid
);
1403 for(i
=0; pathDec
[i
]!=NULL
;i
++)
1404 CoTaskMemFree(pathDec
[i
]);
1405 CoTaskMemFree(pathDec
);
1407 CoTaskMemFree(progId
);
1409 if (res
==ERROR_SUCCESS
)
1412 return MK_E_INVALIDEXTENSION
;
1414 /***********************************************************************
1415 * CoCreateInstance [COMPOBJ.13]
1416 * CoCreateInstance [OLE32.7]
1418 HRESULT WINAPI
CoCreateInstance(
1420 LPUNKNOWN pUnkOuter
,
1426 LPCLASSFACTORY lpclf
= 0;
1435 * Initialize the "out" parameter
1440 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1441 * Rather than create a class factory, we can just check for it here
1443 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
)) {
1444 if (StdGlobalInterfaceTableInstance
== NULL
)
1445 StdGlobalInterfaceTableInstance
= StdGlobalInterfaceTable_Construct();
1446 hres
= IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable
*) StdGlobalInterfaceTableInstance
, iid
, ppv
);
1447 if (hres
) return hres
;
1449 TRACE("Retrieved GIT (%p)\n", *ppv
);
1454 * Get a class factory to construct the object we want.
1456 hres
= CoGetClassObject(rclsid
,
1463 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1464 debugstr_guid(rclsid
),hres
);
1469 * Create the object and don't forget to release the factory
1471 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
1472 IClassFactory_Release(lpclf
);
1474 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1475 debugstr_guid(iid
), debugstr_guid(rclsid
),hres
);
1480 /***********************************************************************
1481 * CoCreateInstanceEx [OLE32.165]
1483 HRESULT WINAPI
CoCreateInstanceEx(
1485 LPUNKNOWN pUnkOuter
,
1487 COSERVERINFO
* pServerInfo
,
1491 IUnknown
* pUnk
= NULL
;
1494 int successCount
= 0;
1499 if ( (cmq
==0) || (pResults
==NULL
))
1500 return E_INVALIDARG
;
1502 if (pServerInfo
!=NULL
)
1503 FIXME("() non-NULL pServerInfo not supported!\n");
1506 * Initialize all the "out" parameters.
1508 for (index
= 0; index
< cmq
; index
++)
1510 pResults
[index
].pItf
= NULL
;
1511 pResults
[index
].hr
= E_NOINTERFACE
;
1515 * Get the object and get its IUnknown pointer.
1517 hr
= CoCreateInstance(rclsid
,
1527 * Then, query for all the interfaces requested.
1529 for (index
= 0; index
< cmq
; index
++)
1531 pResults
[index
].hr
= IUnknown_QueryInterface(pUnk
,
1532 pResults
[index
].pIID
,
1533 (VOID
**)&(pResults
[index
].pItf
));
1535 if (pResults
[index
].hr
== S_OK
)
1540 * Release our temporary unknown pointer.
1542 IUnknown_Release(pUnk
);
1544 if (successCount
== 0)
1545 return E_NOINTERFACE
;
1547 if (successCount
!=cmq
)
1548 return CO_S_NOTALLINTERFACES
;
1553 /***********************************************************************
1554 * CoLoadLibrary (OLE32.30)
1556 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
1558 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
1560 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
1563 /***********************************************************************
1564 * CoFreeLibrary [OLE32.13]
1566 * NOTES: don't belive the docu
1568 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
1570 FreeLibrary(hLibrary
);
1574 /***********************************************************************
1575 * CoFreeAllLibraries [OLE32.12]
1577 * NOTES: don't belive the docu
1579 void WINAPI
CoFreeAllLibraries(void)
1585 /***********************************************************************
1586 * CoFreeUnusedLibraries [COMPOBJ.17]
1587 * CoFreeUnusedLibraries [OLE32.14]
1589 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1590 * through the main apartment's thread to call DllCanUnloadNow
1592 void WINAPI
CoFreeUnusedLibraries(void)
1594 COMPOBJ_DllList_FreeUnused(0);
1597 /***********************************************************************
1598 * CoFileTimeNow [COMPOBJ.82]
1599 * CoFileTimeNow [OLE32.10]
1602 * the current system time in lpFileTime
1604 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
) /* [out] the current time */
1606 GetSystemTimeAsFileTime( lpFileTime
);
1610 /***********************************************************************
1611 * CoLoadLibrary (OLE32.30)
1613 static void COM_RevokeAllClasses()
1615 EnterCriticalSection( &csRegisteredClassList
);
1617 while (firstRegisteredClass
!=0)
1619 CoRevokeClassObject(firstRegisteredClass
->dwCookie
);
1622 LeaveCriticalSection( &csRegisteredClassList
);
1625 /****************************************************************************
1626 * COM External Lock methods implementation
1628 * This api provides a linked list to managed external references to
1631 * The public interface consists of three calls:
1632 * COM_ExternalLockAddRef
1633 * COM_ExternalLockRelease
1634 * COM_ExternalLockFreeList
1637 #define EL_END_OF_LIST 0
1638 #define EL_NOT_FOUND 0
1641 * Declaration of the static structure that manage the
1642 * external lock to COM objects.
1644 typedef struct COM_ExternalLock COM_ExternalLock
;
1645 typedef struct COM_ExternalLockList COM_ExternalLockList
;
1647 struct COM_ExternalLock
1649 IUnknown
*pUnk
; /* IUnknown referenced */
1650 ULONG uRefCount
; /* external lock counter to IUnknown object*/
1651 COM_ExternalLock
*next
; /* Pointer to next element in list */
1654 struct COM_ExternalLockList
1656 COM_ExternalLock
*head
; /* head of list */
1660 * Declaration and initialization of the static structure that manages
1661 * the external lock to COM objects.
1663 static COM_ExternalLockList elList
= { EL_END_OF_LIST
};
1666 * Private methods used to managed the linked list
1670 static COM_ExternalLock
* COM_ExternalLockLocate(
1671 COM_ExternalLock
*element
,
1674 /****************************************************************************
1675 * Internal - Insert a new IUnknown* to the linked list
1677 static BOOL
COM_ExternalLockInsert(
1680 COM_ExternalLock
*newLock
= NULL
;
1681 COM_ExternalLock
*previousHead
= NULL
;
1684 * Allocate space for the new storage object
1686 newLock
= HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock
));
1688 if (newLock
!=NULL
) {
1689 if ( elList
.head
== EL_END_OF_LIST
) {
1690 elList
.head
= newLock
; /* The list is empty */
1692 /* insert does it at the head */
1693 previousHead
= elList
.head
;
1694 elList
.head
= newLock
;
1697 /* Set new list item data member */
1698 newLock
->pUnk
= pUnk
;
1699 newLock
->uRefCount
= 1;
1700 newLock
->next
= previousHead
;
1707 /****************************************************************************
1708 * Internal - Method that removes an item from the linked list.
1710 static void COM_ExternalLockDelete(
1711 COM_ExternalLock
*itemList
)
1713 COM_ExternalLock
*current
= elList
.head
;
1715 if ( current
== itemList
) {
1716 /* this section handles the deletion of the first node */
1717 elList
.head
= itemList
->next
;
1718 HeapFree( GetProcessHeap(), 0, itemList
);
1721 if ( current
->next
== itemList
){ /* We found the item to free */
1722 current
->next
= itemList
->next
; /* readjust the list pointers */
1723 HeapFree( GetProcessHeap(), 0, itemList
);
1727 /* Skip to the next item */
1728 current
= current
->next
;
1730 } while ( current
!= EL_END_OF_LIST
);
1734 /****************************************************************************
1735 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1737 * NOTES: how long can the list be ?? (recursive!!!)
1739 static COM_ExternalLock
* COM_ExternalLockLocate( COM_ExternalLock
*element
, IUnknown
*pUnk
)
1741 if ( element
== EL_END_OF_LIST
)
1742 return EL_NOT_FOUND
;
1743 else if ( element
->pUnk
== pUnk
) /* We found it */
1745 else /* Not the right guy, keep on looking */
1746 return COM_ExternalLockLocate( element
->next
, pUnk
);
1749 /****************************************************************************
1750 * Public - Method that increments the count for a IUnknown* in the linked
1751 * list. The item is inserted if not already in the list.
1753 static void COM_ExternalLockAddRef(IUnknown
*pUnk
)
1755 COM_ExternalLock
*externalLock
= COM_ExternalLockLocate(elList
.head
, pUnk
);
1758 * Add an external lock to the object. If it was already externally
1759 * locked, just increase the reference count. If it was not.
1760 * add the item to the list.
1762 if ( externalLock
== EL_NOT_FOUND
)
1763 COM_ExternalLockInsert(pUnk
);
1765 externalLock
->uRefCount
++;
1768 * Add an internal lock to the object
1770 IUnknown_AddRef(pUnk
);
1773 /****************************************************************************
1774 * Public - Method that decrements the count for a IUnknown* in the linked
1775 * list. The item is removed from the list if its count end up at zero or if
1778 static void COM_ExternalLockRelease(
1782 COM_ExternalLock
*externalLock
= COM_ExternalLockLocate(elList
.head
, pUnk
);
1784 if ( externalLock
!= EL_NOT_FOUND
) {
1786 externalLock
->uRefCount
--; /* release external locks */
1787 IUnknown_Release(pUnk
); /* release local locks as well */
1789 if ( bRelAll
== FALSE
) break; /* perform single release */
1791 } while ( externalLock
->uRefCount
> 0 );
1793 if ( externalLock
->uRefCount
== 0 ) /* get rid of the list entry */
1794 COM_ExternalLockDelete(externalLock
);
1797 /****************************************************************************
1798 * Public - Method that frees the content of the list.
1800 static void COM_ExternalLockFreeList()
1802 COM_ExternalLock
*head
;
1804 head
= elList
.head
; /* grab it by the head */
1805 while ( head
!= EL_END_OF_LIST
) {
1806 COM_ExternalLockDelete(head
); /* get rid of the head stuff */
1807 head
= elList
.head
; /* get the new head... */
1811 /****************************************************************************
1812 * Public - Method that dump the content of the list.
1814 void COM_ExternalLockDump()
1816 COM_ExternalLock
*current
= elList
.head
;
1818 DPRINTF("\nExternal lock list contains:\n");
1820 while ( current
!= EL_END_OF_LIST
) {
1821 DPRINTF( "\t%p with %lu references count.\n", current
->pUnk
, current
->uRefCount
);
1823 /* Skip to the next item */
1824 current
= current
->next
;
1828 /******************************************************************************
1829 * CoLockObjectExternal [OLE32.31]
1831 HRESULT WINAPI
CoLockObjectExternal(
1832 LPUNKNOWN pUnk
, /* [in] object to be locked */
1833 BOOL fLock
, /* [in] do lock */
1834 BOOL fLastUnlockReleases
) /* [in] unlock all */
1839 * Increment the external lock coutner, COM_ExternalLockAddRef also
1840 * increment the object's internal lock counter.
1842 COM_ExternalLockAddRef( pUnk
);
1845 * Decrement the external lock coutner, COM_ExternalLockRelease also
1846 * decrement the object's internal lock counter.
1848 COM_ExternalLockRelease( pUnk
, fLastUnlockReleases
);
1854 /***********************************************************************
1855 * CoInitializeWOW (OLE32.27)
1857 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
) {
1858 FIXME("(0x%08lx,0x%08lx),stub!\n",x
,y
);
1862 static IUnknown
* pUnkState
= 0; /* FIXME: thread local */
1863 static int nStatCounter
= 0; /* global */
1864 static HMODULE hOleAut32
= 0; /* global */
1866 /***********************************************************************
1867 * CoGetState [OLE32.24]
1869 * NOTES: might be incomplete
1871 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
1876 IUnknown_AddRef(pUnkState
);
1878 FIXME("-- %p\n", *ppv
);
1886 /***********************************************************************
1887 * CoSetState [OLE32.42]
1889 * NOTES: FIXME: protect this with a crst
1891 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
1893 FIXME("(%p),stub!\n", pv
);
1896 IUnknown_AddRef(pv
);
1898 if (nStatCounter
== 1) LoadLibraryA("OLEAUT32.DLL");
1902 TRACE("-- release %p now\n", pUnkState
);
1903 IUnknown_Release(pUnkState
);
1905 if (!nStatCounter
) FreeLibrary(hOleAut32
);
1912 /******************************************************************************
1913 * OleGetAutoConvert [OLE32.104]
1915 HRESULT WINAPI
OleGetAutoConvert(REFCLSID clsidOld
, LPCLSID pClsidNew
)
1923 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
1924 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
1926 res
= REGDB_E_CLASSNOTREG
;
1930 /* we can just query for the default value of AutoConvertTo key like that,
1931 without opening the AutoConvertTo key and querying for NULL (default) */
1932 if (RegQueryValueA(hkey
,"AutoConvertTo",buf
,&len
))
1934 res
= REGDB_E_KEYMISSING
;
1937 MultiByteToWideChar( CP_ACP
, 0, buf
, -1, wbuf
, sizeof(wbuf
)/sizeof(WCHAR
) );
1938 CLSIDFromString(wbuf
,pClsidNew
);
1940 if (hkey
) RegCloseKey(hkey
);
1944 /******************************************************************************
1945 * OleSetAutoConvert [OLE32.126]
1947 HRESULT WINAPI
OleSetAutoConvert(REFCLSID clsidOld
, REFCLSID clsidNew
)
1950 char buf
[200], szClsidNew
[200];
1953 TRACE("(%s,%s)\n", debugstr_guid(clsidOld
), debugstr_guid(clsidNew
));
1954 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
1955 WINE_StringFromCLSID(clsidNew
, szClsidNew
);
1956 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
1958 res
= REGDB_E_CLASSNOTREG
;
1961 if (RegSetValueA(hkey
, "AutoConvertTo", REG_SZ
, szClsidNew
, strlen(szClsidNew
)+1))
1963 res
= REGDB_E_WRITEREGDB
;
1968 if (hkey
) RegCloseKey(hkey
);
1972 /******************************************************************************
1973 * OleDoAutoConvert [OLE32.100]
1975 HRESULT WINAPI
OleDoAutoConvert(IStorage
*pStg
, LPCLSID pClsidNew
)
1977 FIXME("(%p,%p) : stub\n",pStg
,pClsidNew
);
1981 /******************************************************************************
1982 * CoTreatAsClass [OLE32.46]
1984 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
1987 char buf
[200], szClsidNew
[200];
1990 FIXME("(%s,%s)\n", debugstr_guid(clsidOld
), debugstr_guid(clsidNew
));
1991 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
1992 WINE_StringFromCLSID(clsidNew
, szClsidNew
);
1993 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
1995 res
= REGDB_E_CLASSNOTREG
;
1998 if (RegSetValueA(hkey
, "AutoTreatAs", REG_SZ
, szClsidNew
, strlen(szClsidNew
)+1))
2000 res
= REGDB_E_WRITEREGDB
;
2005 if (hkey
) RegCloseKey(hkey
);
2009 /******************************************************************************
2010 * CoGetTreatAsClass [OLE32.25]
2012 * Reads the TreatAs value from a class.
2014 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
2017 char buf
[200], szClsidNew
[200];
2019 LONG len
= sizeof(szClsidNew
);
2021 FIXME("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
2022 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
2023 memcpy(clsidNew
,clsidOld
,sizeof(CLSID
)); /* copy over old value */
2025 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
2027 res
= REGDB_E_CLASSNOTREG
;
2030 if (RegQueryValueA(hkey
, "TreatAs", szClsidNew
, &len
))
2035 res
= __CLSIDFromStringA(szClsidNew
,clsidNew
);
2037 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew
,res
);
2039 if (hkey
) RegCloseKey(hkey
);
2044 /***********************************************************************
2045 * IsEqualGUID [OLE32.76]
2047 * Compares two Unique Identifiers.
2053 BOOL WINAPI
IsEqualGUID(
2054 REFGUID rguid1
, /* [in] unique id 1 */
2055 REFGUID rguid2
/* [in] unique id 2 */
2058 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
2061 /***********************************************************************
2062 * CoInitializeSecurity [OLE32.164]
2064 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
2065 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
2066 void* pReserved1
, DWORD dwAuthnLevel
,
2067 DWORD dwImpLevel
, void* pReserved2
,
2068 DWORD dwCapabilities
, void* pReserved3
)
2070 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc
, cAuthSvc
,
2071 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
2072 dwCapabilities
, pReserved3
);