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
9 * Copyright 2004 Mike Hearn
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
46 #include "wine/unicode.h"
48 #include "ole32_main.h"
49 #include "compobj_private.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
55 typedef LPCSTR LPCOLESTR16
;
57 /****************************************************************************
58 * This section defines variables internal to the COM module.
60 * TODO: Most of these things will have to be made thread-safe.
62 HINSTANCE COMPOBJ_hInstance32
= 0;
64 static HRESULT
COM_GetRegisteredClassObject(REFCLSID rclsid
, DWORD dwClsContext
, LPUNKNOWN
* ppUnk
);
65 static void COM_RevokeAllClasses();
66 static void COM_ExternalLockFreeList();
68 const CLSID CLSID_StdGlobalInterfaceTable
= { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
72 static CRITICAL_SECTION csApartment
;
73 static CRITICAL_SECTION_DEBUG critsect_debug
=
76 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
77 0, 0, { 0, (DWORD
)(__FILE__
": csApartment") }
79 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
82 * This lock count counts the number of times CoInitialize is called. It is
83 * decreased every time CoUninitialize is called. When it hits 0, the COM
86 static LONG s_COMLockCount
= 0;
89 * This linked list contains the list of registered class objects. These
90 * are mostly used to register the factories for out-of-proc servers of OLE
93 * TODO: Make this data structure aware of inter-process communication. This
94 * means that parts of this will be exported to the Wine Server.
96 typedef struct tagRegisteredClass
98 CLSID classIdentifier
;
99 LPUNKNOWN classObject
;
103 HANDLE hThread
; /* only for localserver */
104 struct tagRegisteredClass
* nextClass
;
107 static RegisteredClass
* firstRegisteredClass
= NULL
;
109 static CRITICAL_SECTION csRegisteredClassList
;
110 static CRITICAL_SECTION_DEBUG class_cs_debug
=
112 0, 0, &csRegisteredClassList
,
113 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
114 0, 0, { 0, (DWORD
)(__FILE__
": csRegisteredClassList") }
116 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
118 /*****************************************************************************
119 * This section contains OpenDllList definitions
121 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
122 * other functions that do LoadLibrary _without_ giving back a HMODULE.
123 * Without this list these handles would never be freed.
125 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
126 * next unload-call but not before 600 sec.
129 typedef struct tagOpenDll
{
131 struct tagOpenDll
*next
;
134 static OpenDll
*openDllList
= NULL
; /* linked list of open dlls */
136 static CRITICAL_SECTION csOpenDllList
;
137 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
139 0, 0, &csOpenDllList
,
140 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
141 0, 0, { 0, (DWORD
)(__FILE__
": csOpenDllList") }
143 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
145 static const char aptWinClass
[] = "WINE_OLE32_APT_CLASS";
146 static LRESULT CALLBACK
COM_AptWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
148 static void COMPOBJ_DLLList_Add(HANDLE hLibrary
);
149 static void COMPOBJ_DllList_FreeUnused(int Timeout
);
151 void COMPOBJ_InitProcess( void )
155 /* Dispatching to the correct thread in an apartment is done through
156 * window messages rather than RPC transports. When an interface is
157 * marshalled into another apartment in the same process, a window of the
158 * following class is created. The *caller* of CoMarshalInterface (ie the
159 * application) is responsible for pumping the message loop in that thread.
160 * The WM_USER messages which point to the RPCs are then dispatched to
161 * COM_AptWndProc by the user's code.
163 memset(&wclass
, 0, sizeof(wclass
));
164 wclass
.lpfnWndProc
= &COM_AptWndProc
;
165 wclass
.hInstance
= OLE32_hInstance
;
166 wclass
.lpszClassName
= aptWinClass
;
167 RegisterClassA(&wclass
);
170 void COMPOBJ_UninitProcess( void )
172 UnregisterClassA(aptWinClass
, OLE32_hInstance
);
175 /******************************************************************************
180 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
181 with free threaded (ie thread safe) COM objects. There is only ever one MTA
182 in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
184 static void COM_InitMTA(void)
186 /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
187 within a network. That is, two different MTAs on different machines will have
190 This method of generating an OXID is therefore wrong as it doesn't work across
191 a network, but for local RPC only it's OK. We can distinguish between MTAs and
192 STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
194 MTA
.oxid
= ((OXID
)GetCurrentProcessId() << 32);
195 InitializeCriticalSection(&MTA
.cs
);
198 static void COM_UninitMTA(void)
200 DeleteCriticalSection(&MTA
.cs
);
204 /* creates an apartment structure which stores OLE thread-local
205 * information. Call with COINIT_UNINITIALIZED to create an apartment
206 * that will be initialized with a model later. Note: do not call
207 * with COINIT_UNINITIALIZED if the apartment has already been initialized
208 * with a different COINIT value */
209 APARTMENT
* COM_CreateApartment(DWORD model
)
212 BOOL create
= (NtCurrentTeb()->ReservedForOle
== NULL
);
216 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(APARTMENT
));
217 apt
->tid
= GetCurrentThreadId();
218 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
219 GetCurrentProcess(), &apt
->thread
,
220 THREAD_ALL_ACCESS
, FALSE
, 0);
223 apt
= NtCurrentTeb()->ReservedForOle
;
226 if (model
& COINIT_APARTMENTTHREADED
) {
227 /* FIXME: how does windoze create OXIDs? */
228 apt
->oxid
= MTA
.oxid
| GetCurrentThreadId();
229 apt
->win
= CreateWindowA(aptWinClass
, NULL
, 0,
231 0, 0, OLE32_hInstance
, NULL
);
232 InitializeCriticalSection(&apt
->cs
);
234 else if (!(model
& COINIT_UNINITIALIZED
)) {
236 apt
->oxid
= MTA
.oxid
;
238 EnterCriticalSection(&csApartment
);
241 if (apts
) apts
->prev
= apt
;
245 LeaveCriticalSection(&csApartment
);
246 NtCurrentTeb()->ReservedForOle
= apt
;
250 static void COM_DestroyApartment(APARTMENT
*apt
)
252 EnterCriticalSection(&csApartment
);
253 if (apt
->prev
) apt
->prev
->next
= apt
->next
;
254 if (apt
->next
) apt
->next
->prev
= apt
->prev
;
255 if (apts
== apt
) apts
= apt
->next
;
256 apt
->prev
= NULL
; apt
->next
= NULL
;
257 LeaveCriticalSection(&csApartment
);
258 if (apt
->model
& COINIT_APARTMENTTHREADED
) {
259 if (apt
->win
) DestroyWindow(apt
->win
);
260 DeleteCriticalSection(&apt
->cs
);
262 CloseHandle(apt
->thread
);
263 HeapFree(GetProcessHeap(), 0, apt
);
266 /* The given OXID must be local to this process: you cannot use apartment
267 windows to send RPCs to other processes */
268 HWND
COM_GetApartmentWin(OXID oxid
)
273 EnterCriticalSection(&csApartment
);
275 while (apt
&& apt
->oxid
!= oxid
) apt
= apt
->next
;
276 if (apt
) win
= apt
->win
;
277 LeaveCriticalSection(&csApartment
);
281 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
282 static LRESULT CALLBACK
COM_AptWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
284 return DefWindowProcA(hWnd
, msg
, wParam
, lParam
);
287 /*****************************************************************************
288 * This section contains OpenDllList implemantation
291 static void COMPOBJ_DLLList_Add(HANDLE hLibrary
)
298 EnterCriticalSection( &csOpenDllList
);
300 if (openDllList
== NULL
) {
301 /* empty list -- add first node */
302 openDllList
= (OpenDll
*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
303 openDllList
->hLibrary
=hLibrary
;
304 openDllList
->next
= NULL
;
306 /* search for this dll */
308 for (ptr
= openDllList
; ptr
->next
!= NULL
; ptr
=ptr
->next
) {
309 if (ptr
->hLibrary
== hLibrary
) {
315 /* dll not found, add it */
317 openDllList
= (OpenDll
*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
318 openDllList
->hLibrary
= hLibrary
;
319 openDllList
->next
= tmp
;
323 LeaveCriticalSection( &csOpenDllList
);
326 static void COMPOBJ_DllList_FreeUnused(int Timeout
)
328 OpenDll
*curr
, *next
, *prev
= NULL
;
329 typedef HRESULT(*DllCanUnloadNowFunc
)(void);
330 DllCanUnloadNowFunc DllCanUnloadNow
;
334 EnterCriticalSection( &csOpenDllList
);
336 for (curr
= openDllList
; curr
!= NULL
; ) {
337 DllCanUnloadNow
= (DllCanUnloadNowFunc
) GetProcAddress(curr
->hLibrary
, "DllCanUnloadNow");
339 if ( (DllCanUnloadNow
!= NULL
) && (DllCanUnloadNow() == S_OK
) ) {
342 TRACE("freeing %p\n", curr
->hLibrary
);
343 FreeLibrary(curr
->hLibrary
);
345 HeapFree(GetProcessHeap(), 0, curr
);
346 if (curr
== openDllList
) {
359 LeaveCriticalSection( &csOpenDllList
);
362 /******************************************************************************
363 * CoBuildVersion [COMPOBJ.1]
364 * CoBuildVersion [OLE32.@]
367 * Current build version, hiword is majornumber, loword is minornumber
369 DWORD WINAPI
CoBuildVersion(void)
371 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
372 return (rmm
<<16)+rup
;
375 /******************************************************************************
376 * CoInitialize [OLE32.@]
378 * Initializes the COM libraries.
382 HRESULT WINAPI
CoInitialize(
383 LPVOID lpReserved
/* [in] pointer to win32 malloc interface
384 (obsolete, should be NULL) */
388 * Just delegate to the newer method.
390 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
393 /******************************************************************************
394 * CoInitializeEx [OLE32.@]
396 * Initializes the COM libraries. The behavior used to set the win32 IMalloc
397 * used for memory management is obsolete.
400 * S_OK if successful,
401 * S_FALSE if this function was called already.
402 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
405 HRESULT WINAPI
CoInitializeEx(
406 LPVOID lpReserved
, /* [in] pointer to win32 malloc interface
407 (obsolete, should be NULL) */
408 DWORD dwCoInit
/* [in] A value from COINIT specifies the threading model */
414 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
416 if (lpReserved
!=NULL
)
418 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
421 apt
= NtCurrentTeb()->ReservedForOle
;
422 if (apt
&& !(apt
->model
== COINIT_UNINITIALIZED
))
424 if (dwCoInit
!= apt
->model
)
426 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
427 code then we are probably using the wrong threading model to implement that API. */
428 WARN("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt
->model
, dwCoInit
);
429 return RPC_E_CHANGED_MODE
;
437 * Check the lock count. If this is the first time going through the initialize
438 * process, we have to initialize the libraries.
440 * And crank-up that lock count.
442 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
445 * Initialize the various COM libraries and data structures.
447 TRACE("() - Initializing the COM libraries\n");
451 RunningObjectTableImpl_Initialize();
454 if (!apt
|| apt
->model
== COINIT_UNINITIALIZED
) apt
= COM_CreateApartment(dwCoInit
);
456 InterlockedIncrement(&apt
->inits
);
457 if (hr
== S_OK
) NtCurrentTeb()->ReservedForOle
= apt
;
462 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
463 pending RPCs are ignored. Non-COM messages are discarded at this point.
465 void COM_FlushMessageQueue(void)
468 APARTMENT
*apt
= NtCurrentTeb()->ReservedForOle
;
470 if (!apt
|| !apt
->win
) return;
472 TRACE("Flushing STA message queue\n");
474 while (PeekMessageA(&message
, NULL
, 0, 0, PM_REMOVE
)) {
475 if (message
.hwnd
!= apt
->win
) continue;
476 TranslateMessage(&message
);
477 DispatchMessageA(&message
);
481 /***********************************************************************
482 * CoUninitialize [OLE32.@]
484 * This method will release the COM libraries.
486 * See the windows documentation for more details.
488 void WINAPI
CoUninitialize(void)
495 apt
= NtCurrentTeb()->ReservedForOle
;
497 if (InterlockedDecrement(&apt
->inits
)==0) {
498 NtCurrentTeb()->ReservedForOle
= NULL
;
499 COM_DestroyApartment(apt
);
504 * Decrease the reference count.
505 * If we are back to 0 locks on the COM library, make sure we free
506 * all the associated data structures.
508 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
511 TRACE("() - Releasing the COM libraries\n");
513 RunningObjectTableImpl_UnInitialize();
515 /* Release the references to the registered class objects */
516 COM_RevokeAllClasses();
518 /* This will free the loaded COM Dlls */
519 CoFreeAllLibraries();
521 /* This will free list of external references to COM objects */
522 COM_ExternalLockFreeList();
524 /* This ensures we deal with any pending RPCs */
525 COM_FlushMessageQueue();
529 else if (lCOMRefCnt
<1) {
530 ERR( "CoUninitialize() - not CoInitialized.\n" );
531 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
535 /******************************************************************************
536 * CoDisconnectObject [COMPOBJ.15]
537 * CoDisconnectObject [OLE32.@]
539 * Disconnects all connections to this object from remote processes. Dispatches
540 * pending RPCs while blocking new RPCs from occurring, and then calls
541 * IMarshal::DisconnectObject on the given object.
543 * Typically called when the object server is forced to shut down, for instance by
546 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
548 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk
,reserved
);
552 /******************************************************************************
553 * CoCreateGuid[OLE32.@]
556 HRESULT WINAPI
CoCreateGuid(
557 GUID
*pguid
/* [out] points to the GUID to initialize */
559 return UuidCreate(pguid
);
562 /******************************************************************************
563 * CLSIDFromString [OLE32.@]
564 * IIDFromString [OLE32.@]
565 * Converts a unique identifier from its string representation into
569 * If idstr is not a valid CLSID string then it gets treated as a ProgID
574 HRESULT WINAPI
__CLSIDFromStringA(
575 LPCSTR idstr
, /* [in] string representation of guid */
576 CLSID
*id
) /* [out] GUID converted from string */
578 const BYTE
*s
= (BYTE
*) idstr
;
583 s
= "{00000000-0000-0000-0000-000000000000}";
584 else { /* validate the CLSID string */
587 return CO_E_CLASSSTRING
;
589 if ((s
[0]!='{') || (s
[9]!='-') || (s
[14]!='-') || (s
[19]!='-') || (s
[24]!='-') || (s
[37]!='}'))
590 return CO_E_CLASSSTRING
;
592 for (i
=1; i
<37; i
++) {
593 if ((i
== 9)||(i
== 14)||(i
== 19)||(i
== 24)) continue;
594 if (!(((s
[i
] >= '0') && (s
[i
] <= '9')) ||
595 ((s
[i
] >= 'a') && (s
[i
] <= 'f')) ||
596 ((s
[i
] >= 'A') && (s
[i
] <= 'F'))))
597 return CO_E_CLASSSTRING
;
601 TRACE("%s -> %p\n", s
, id
);
603 /* quick lookup table */
604 memset(table
, 0, 256);
606 for (i
= 0; i
< 10; i
++) {
609 for (i
= 0; i
< 6; i
++) {
610 table
['A' + i
] = i
+10;
611 table
['a' + i
] = i
+10;
614 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
616 id
->Data1
= (table
[s
[1]] << 28 | table
[s
[2]] << 24 | table
[s
[3]] << 20 | table
[s
[4]] << 16 |
617 table
[s
[5]] << 12 | table
[s
[6]] << 8 | table
[s
[7]] << 4 | table
[s
[8]]);
618 id
->Data2
= table
[s
[10]] << 12 | table
[s
[11]] << 8 | table
[s
[12]] << 4 | table
[s
[13]];
619 id
->Data3
= table
[s
[15]] << 12 | table
[s
[16]] << 8 | table
[s
[17]] << 4 | table
[s
[18]];
621 /* these are just sequential bytes */
622 id
->Data4
[0] = table
[s
[20]] << 4 | table
[s
[21]];
623 id
->Data4
[1] = table
[s
[22]] << 4 | table
[s
[23]];
624 id
->Data4
[2] = table
[s
[25]] << 4 | table
[s
[26]];
625 id
->Data4
[3] = table
[s
[27]] << 4 | table
[s
[28]];
626 id
->Data4
[4] = table
[s
[29]] << 4 | table
[s
[30]];
627 id
->Data4
[5] = table
[s
[31]] << 4 | table
[s
[32]];
628 id
->Data4
[6] = table
[s
[33]] << 4 | table
[s
[34]];
629 id
->Data4
[7] = table
[s
[35]] << 4 | table
[s
[36]];
634 /*****************************************************************************/
636 HRESULT WINAPI
CLSIDFromString(
637 LPOLESTR idstr
, /* [in] string representation of GUID */
638 CLSID
*id
) /* [out] GUID represented by above string */
643 if (!WideCharToMultiByte( CP_ACP
, 0, idstr
, -1, xid
, sizeof(xid
), NULL
, NULL
))
644 return CO_E_CLASSSTRING
;
647 ret
= __CLSIDFromStringA(xid
,id
);
648 if(ret
!= S_OK
) { /* It appears a ProgID is also valid */
649 ret
= CLSIDFromProgID(idstr
, id
);
654 /******************************************************************************
655 * WINE_StringFromCLSID [Internal]
656 * Converts a GUID into the respective string representation.
661 * the string representation and HRESULT
663 HRESULT
WINE_StringFromCLSID(
664 const CLSID
*id
, /* [in] GUID to be converted */
665 LPSTR idstr
/* [out] pointer to buffer to contain converted guid */
667 static const char *hex
= "0123456789ABCDEF";
672 { ERR("called with id=Null\n");
677 sprintf(idstr
, "{%08lX-%04X-%04X-%02X%02X-",
678 id
->Data1
, id
->Data2
, id
->Data3
,
679 id
->Data4
[0], id
->Data4
[1]);
683 for (i
= 2; i
< 8; i
++) {
684 *s
++ = hex
[id
->Data4
[i
]>>4];
685 *s
++ = hex
[id
->Data4
[i
] & 0xf];
691 TRACE("%p->%s\n", id
, idstr
);
697 /******************************************************************************
698 * StringFromCLSID [OLE32.@]
699 * StringFromIID [OLE32.@]
700 * Converts a GUID into the respective string representation.
701 * The target string is allocated using the OLE IMalloc.
703 * the string representation and HRESULT
705 HRESULT WINAPI
StringFromCLSID(
706 REFCLSID id
, /* [in] the GUID to be converted */
707 LPOLESTR
*idstr
/* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
713 if ((ret
=CoGetMalloc(0,&mllc
)))
716 ret
=WINE_StringFromCLSID(id
,buf
);
718 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, buf
, -1, NULL
, 0 );
719 *idstr
= IMalloc_Alloc( mllc
, len
* sizeof(WCHAR
) );
720 MultiByteToWideChar( CP_ACP
, 0, buf
, -1, *idstr
, len
);
725 /******************************************************************************
726 * StringFromGUID2 [COMPOBJ.76]
727 * StringFromGUID2 [OLE32.@]
729 * Converts a global unique identifier into a string of an API-
730 * specified fixed format. (The usual {.....} stuff.)
733 * The (UNICODE) string representation of the GUID in 'str'
734 * The length of the resulting string, 0 if there was any problem.
737 StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
741 if (WINE_StringFromCLSID(id
,xguid
))
743 return MultiByteToWideChar( CP_ACP
, 0, xguid
, -1, str
, cmax
);
746 /******************************************************************************
747 * ProgIDFromCLSID [OLE32.@]
748 * Converts a class id into the respective Program ID. (By using a registry lookup)
749 * RETURNS S_OK on success
750 * riid associated with the progid
753 HRESULT WINAPI
ProgIDFromCLSID(
754 REFCLSID clsid
, /* [in] class id as found in registry */
755 LPOLESTR
*lplpszProgID
/* [out] associated Prog ID */
758 char strCLSID
[50], *buf
, *buf2
;
764 WINE_StringFromCLSID(clsid
, strCLSID
);
766 buf
= HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID
)+14);
767 sprintf(buf
,"CLSID\\%s\\ProgID", strCLSID
);
768 if (RegOpenKeyA(HKEY_CLASSES_ROOT
, buf
, &xhkey
))
769 ret
= REGDB_E_CLASSNOTREG
;
771 HeapFree(GetProcessHeap(), 0, buf
);
775 buf2
= HeapAlloc(GetProcessHeap(), 0, 255);
777 if (RegQueryValueA(xhkey
, NULL
, buf2
, &buf2len
))
778 ret
= REGDB_E_CLASSNOTREG
;
782 if (CoGetMalloc(0,&mllc
))
786 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, buf2
, -1, NULL
, 0 );
787 *lplpszProgID
= IMalloc_Alloc(mllc
, len
* sizeof(WCHAR
) );
788 MultiByteToWideChar( CP_ACP
, 0, buf2
, -1, *lplpszProgID
, len
);
791 HeapFree(GetProcessHeap(), 0, buf2
);
798 /******************************************************************************
799 * CLSIDFromProgID [COMPOBJ.61]
800 * Converts a program id into the respective GUID. (By using a registry lookup)
802 * riid associated with the progid
804 HRESULT WINAPI
CLSIDFromProgID16(
805 LPCOLESTR16 progid
, /* [in] program id as found in registry */
806 LPCLSID riid
/* [out] associated CLSID */
813 buf
= HeapAlloc(GetProcessHeap(),0,strlen(progid
)+8);
814 sprintf(buf
,"%s\\CLSID",progid
);
815 if ((err
=RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&xhkey
))) {
816 HeapFree(GetProcessHeap(),0,buf
);
817 return CO_E_CLASSSTRING
;
819 HeapFree(GetProcessHeap(),0,buf
);
820 buf2len
= sizeof(buf2
);
821 if ((err
=RegQueryValueA(xhkey
,NULL
,buf2
,&buf2len
))) {
823 return CO_E_CLASSSTRING
;
826 return __CLSIDFromStringA(buf2
,riid
);
829 /******************************************************************************
830 * CLSIDFromProgID [OLE32.@]
831 * Converts a program id into the respective GUID. (By using a registry lookup)
833 * riid associated with the progid
835 HRESULT WINAPI
CLSIDFromProgID(
836 LPCOLESTR progid
, /* [in] program id as found in registry */
837 LPCLSID riid
) /* [out] associated CLSID */
839 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
841 DWORD buf2len
= sizeof(buf2
);
844 WCHAR
*buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
845 strcpyW( buf
, progid
);
846 strcatW( buf
, clsidW
);
847 if (RegOpenKeyW(HKEY_CLASSES_ROOT
,buf
,&xhkey
))
849 HeapFree(GetProcessHeap(),0,buf
);
850 return CO_E_CLASSSTRING
;
852 HeapFree(GetProcessHeap(),0,buf
);
854 if (RegQueryValueA(xhkey
,NULL
,buf2
,&buf2len
))
857 return CO_E_CLASSSTRING
;
860 return __CLSIDFromStringA(buf2
,riid
);
865 /*****************************************************************************
866 * CoGetPSClsid [OLE32.@]
868 * This function returns the CLSID of the proxy/stub factory that implements IPSFactoryBuffer
869 * for the specified interface.
871 * The standard marshaller activates the object with the CLSID returned and uses the
872 * CreateProxy and CreateStub methods on its IPSFactoryBuffer interface to construct
873 * the proxies and stubs for a given object.
875 * CoGetPSClsid determines this CLSID by searching the
876 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
877 * and any interface id registered by CoRegisterPSClsid within the current process.
879 * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
881 HRESULT WINAPI
CoGetPSClsid(
882 REFIID riid
, /* [in] Interface whose proxy/stub CLSID is to be returned */
883 CLSID
*pclsid
) /* [out] Where to store returned proxy/stub CLSID */
889 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
891 /* Get the input iid as a string */
892 WINE_StringFromCLSID(riid
, buf2
);
893 /* Allocate memory for the registry key we will construct.
894 (length of iid string plus constant length of static text */
895 buf
= HeapAlloc(GetProcessHeap(), 0, strlen(buf2
)+27);
898 return (E_OUTOFMEMORY
);
901 /* Construct the registry key we want */
902 sprintf(buf
,"Interface\\%s\\ProxyStubClsid32", buf2
);
905 if (RegOpenKeyA(HKEY_CLASSES_ROOT
, buf
, &xhkey
))
907 WARN("No PSFactoryBuffer object is registered for this IID\n");
908 HeapFree(GetProcessHeap(),0,buf
);
909 return (E_INVALIDARG
);
911 HeapFree(GetProcessHeap(),0,buf
);
913 /* ... Once we have the key, query the registry to get the
914 value of CLSID as a string, and convert it into a
915 proper CLSID structure to be passed back to the app */
916 buf2len
= sizeof(buf2
);
917 if ( (RegQueryValueA(xhkey
,NULL
,buf2
,&buf2len
)) )
924 /* We have the CLSid we want back from the registry as a string, so
925 lets convert it into a CLSID structure */
926 if ( (__CLSIDFromStringA(buf2
,pclsid
)) != NOERROR
) {
930 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
936 /***********************************************************************
937 * WriteClassStm (OLE32.@)
939 * This function write a CLSID on stream
941 HRESULT WINAPI
WriteClassStm(IStream
*pStm
,REFCLSID rclsid
)
943 TRACE("(%p,%p)\n",pStm
,rclsid
);
948 return IStream_Write(pStm
,rclsid
,sizeof(CLSID
),NULL
);
951 /***********************************************************************
952 * ReadClassStm (OLE32.@)
954 * This function read a CLSID from a stream
956 HRESULT WINAPI
ReadClassStm(IStream
*pStm
,CLSID
*pclsid
)
961 TRACE("(%p,%p)\n",pStm
,pclsid
);
966 res
= IStream_Read(pStm
,(void*)pclsid
,sizeof(CLSID
),&nbByte
);
971 if (nbByte
!= sizeof(CLSID
))
979 * COM_GetRegisteredClassObject
981 * This internal method is used to scan the registered class list to
982 * find a class object.
985 * rclsid Class ID of the class to find.
986 * dwClsContext Class context to match.
987 * ppv [out] returns a pointer to the class object. Complying
988 * to normal COM usage, this method will increase the
989 * reference count on this object.
991 static HRESULT
COM_GetRegisteredClassObject(
996 HRESULT hr
= S_FALSE
;
997 RegisteredClass
* curClass
;
999 EnterCriticalSection( &csRegisteredClassList
);
1007 * Iterate through the whole list and try to match the class ID.
1009 curClass
= firstRegisteredClass
;
1011 while (curClass
!= 0)
1014 * Check if we have a match on the class ID.
1016 if (IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
1019 * Since we don't do out-of process or DCOM just right away, let's ignore the
1024 * We have a match, return the pointer to the class object.
1026 *ppUnk
= curClass
->classObject
;
1028 IUnknown_AddRef(curClass
->classObject
);
1035 * Step to the next class in the list.
1037 curClass
= curClass
->nextClass
;
1041 LeaveCriticalSection( &csRegisteredClassList
);
1043 * If we get to here, we haven't found our class.
1049 _LocalServerThread(LPVOID param
) {
1052 RegisteredClass
*newClass
= (RegisteredClass
*)param
;
1056 unsigned char *buffer
;
1058 IClassFactory
*classfac
;
1059 LARGE_INTEGER seekto
;
1060 ULARGE_INTEGER newpos
;
1063 TRACE("Starting threader for %s.\n",debugstr_guid(&newClass
->classIdentifier
));
1065 strcpy(pipefn
,PIPEPREF
);
1066 WINE_StringFromCLSID(&newClass
->classIdentifier
,pipefn
+strlen(PIPEPREF
));
1068 hPipe
= CreateNamedPipeA( pipefn
, PIPE_ACCESS_DUPLEX
,
1069 PIPE_TYPE_BYTE
|PIPE_WAIT
, PIPE_UNLIMITED_INSTANCES
,
1070 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT
, NULL
);
1071 if (hPipe
== INVALID_HANDLE_VALUE
) {
1072 FIXME("pipe creation failed for %s, le is %lx\n",pipefn
,GetLastError());
1076 if (!ConnectNamedPipe(hPipe
,NULL
)) {
1077 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1081 TRACE("marshalling IClassFactory to client\n");
1083 hres
= IUnknown_QueryInterface(newClass
->classObject
,&IID_IClassFactory
,(LPVOID
*)&classfac
);
1084 if (hres
) return hres
;
1086 hres
= CreateStreamOnHGlobal(0,TRUE
,&pStm
);
1088 FIXME("Failed to create stream on hglobal.\n");
1091 hres
= CoMarshalInterface(pStm
,&IID_IClassFactory
,(LPVOID
)classfac
,0,NULL
,0);
1093 FIXME("CoMarshalInterface failed, %lx!\n",hres
);
1097 IUnknown_Release(classfac
); /* is this right? */
1099 hres
= IStream_Stat(pStm
,&ststg
,0);
1100 if (hres
) return hres
;
1102 buflen
= ststg
.cbSize
.u
.LowPart
;
1103 buffer
= HeapAlloc(GetProcessHeap(),0,buflen
);
1104 seekto
.u
.LowPart
= 0;
1105 seekto
.u
.HighPart
= 0;
1106 hres
= IStream_Seek(pStm
,seekto
,SEEK_SET
,&newpos
);
1108 FIXME("IStream_Seek failed, %lx\n",hres
);
1112 hres
= IStream_Read(pStm
,buffer
,buflen
,&res
);
1114 FIXME("Stream Read failed, %lx\n",hres
);
1118 IStream_Release(pStm
);
1120 WriteFile(hPipe
,buffer
,buflen
,&res
,NULL
);
1121 FlushFileBuffers(hPipe
);
1122 DisconnectNamedPipe(hPipe
);
1124 TRACE("done marshalling IClassFactory\n");
1130 /******************************************************************************
1131 * CoRegisterClassObject [OLE32.@]
1133 * This method will register the class object for a given class ID. Servers housed
1134 * in EXE files use this method instead of exporting DllGetClassObject to allow other
1135 * code to connect to their objects.
1137 * When a class object (an object which implements IClassFactory) is registered in
1138 * this way, a new thread is started which listens for connections on a named pipe
1139 * specific to the registered CLSID. When something else connects to it, it writes
1140 * out the marshalled IClassFactory interface to the pipe. The code on the other end
1141 * uses this buffer to unmarshal the class factory, and can then call methods on it.
1143 * In Windows, such objects are registered with the RPC endpoint mapper, not with
1144 * a unique named pipe.
1146 * See the Windows documentation for more details.
1148 HRESULT WINAPI
CoRegisterClassObject(
1151 DWORD dwClsContext
, /* [in] CLSCTX flags indicating the context in which to run the executable */
1152 DWORD flags
, /* [in] REGCLS flags indicating how connections are made */
1153 LPDWORD lpdwRegister
1156 RegisteredClass
* newClass
;
1157 LPUNKNOWN foundObject
;
1160 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1161 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
1163 if ( (lpdwRegister
==0) || (pUnk
==0) )
1164 return E_INVALIDARG
;
1169 * First, check if the class is already registered.
1170 * If it is, this should cause an error.
1172 * MSDN claims that multiple interface registrations are legal, but we can't do that with
1173 * our current implementation.
1175 hr
= COM_GetRegisteredClassObject(rclsid
, dwClsContext
, &foundObject
);
1177 IUnknown_Release(foundObject
);
1178 return CO_E_OBJISREG
;
1181 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
1182 if ( newClass
== NULL
)
1183 return E_OUTOFMEMORY
;
1185 EnterCriticalSection( &csRegisteredClassList
);
1187 newClass
->classIdentifier
= *rclsid
;
1188 newClass
->runContext
= dwClsContext
;
1189 newClass
->connectFlags
= flags
;
1191 * Use the address of the chain node as the cookie since we are sure it's
1194 newClass
->dwCookie
= (DWORD
)newClass
;
1195 newClass
->nextClass
= firstRegisteredClass
;
1198 * Since we're making a copy of the object pointer, we have to increase its
1201 newClass
->classObject
= pUnk
;
1202 IUnknown_AddRef(newClass
->classObject
);
1204 firstRegisteredClass
= newClass
;
1205 LeaveCriticalSection( &csRegisteredClassList
);
1207 *lpdwRegister
= newClass
->dwCookie
;
1209 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
1213 newClass
->hThread
=CreateThread(NULL
,0,_LocalServerThread
,newClass
,0,&tid
);
1218 /***********************************************************************
1219 * CoRevokeClassObject [OLE32.@]
1221 * This method will remove a class object from the class registry
1223 * See the Windows documentation for more details.
1225 HRESULT WINAPI
CoRevokeClassObject(
1228 HRESULT hr
= E_INVALIDARG
;
1229 RegisteredClass
** prevClassLink
;
1230 RegisteredClass
* curClass
;
1232 TRACE("(%08lx)\n",dwRegister
);
1234 EnterCriticalSection( &csRegisteredClassList
);
1237 * Iterate through the whole list and try to match the cookie.
1239 curClass
= firstRegisteredClass
;
1240 prevClassLink
= &firstRegisteredClass
;
1242 while (curClass
!= 0)
1245 * Check if we have a match on the cookie.
1247 if (curClass
->dwCookie
== dwRegister
)
1250 * Remove the class from the chain.
1252 *prevClassLink
= curClass
->nextClass
;
1255 * Release the reference to the class object.
1257 IUnknown_Release(curClass
->classObject
);
1260 * Free the memory used by the chain node.
1262 HeapFree(GetProcessHeap(), 0, curClass
);
1269 * Step to the next class in the list.
1271 prevClassLink
= &(curClass
->nextClass
);
1272 curClass
= curClass
->nextClass
;
1276 LeaveCriticalSection( &csRegisteredClassList
);
1278 * If we get to here, we haven't found our class.
1283 /***********************************************************************
1284 * compobj_RegReadPath [internal]
1286 * Reads a registry value and expands it when necessary
1288 HRESULT
compobj_RegReadPath(char * keyname
, char * valuename
, char * dst
, int dstlen
)
1294 DWORD dwLength
= dstlen
;
1296 if((hres
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &key
)) == ERROR_SUCCESS
) {
1297 if( (hres
= RegQueryValueExA(key
, NULL
, NULL
, &keytype
, (LPBYTE
)src
, &dwLength
)) == ERROR_SUCCESS
) {
1298 if (keytype
== REG_EXPAND_SZ
) {
1299 if (dstlen
<= ExpandEnvironmentStringsA(src
, dst
, dstlen
)) hres
= ERROR_MORE_DATA
;
1301 strncpy(dst
, src
, dstlen
);
1309 /***********************************************************************
1310 * CoGetClassObject [COMPOBJ.7]
1311 * CoGetClassObject [OLE32.@]
1313 * FIXME. If request allows of several options and there is a failure
1314 * with one (other than not being registered) do we try the
1315 * others or return failure? (E.g. inprocess is registered but
1316 * the DLL is not found but the server version works)
1318 HRESULT WINAPI
CoGetClassObject(
1319 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
1320 REFIID iid
, LPVOID
*ppv
1322 LPUNKNOWN regClassObject
;
1323 HRESULT hres
= E_UNEXPECTED
;
1326 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
1327 DllGetClassObjectFunc DllGetClassObject
;
1329 WINE_StringFromCLSID((LPCLSID
)rclsid
,xclsid
);
1331 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
1334 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo
->pwszName
));
1335 FIXME("\t\tpAuthInfo=%p\n",pServerInfo
->pAuthInfo
);
1339 * First, try and see if we can't match the class ID with one of the
1340 * registered classes.
1342 if (S_OK
== COM_GetRegisteredClassObject(rclsid
, dwClsContext
, ®ClassObject
))
1345 * Get the required interface from the retrieved pointer.
1347 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
1350 * Since QI got another reference on the pointer, we want to release the
1351 * one we already have. If QI was unsuccessful, this will release the object. This
1352 * is good since we are not returning it in the "out" parameter.
1354 IUnknown_Release(regClassObject
);
1359 /* first try: in-process */
1360 if ((CLSCTX_INPROC_SERVER
| CLSCTX_INPROC_HANDLER
) & dwClsContext
) {
1361 char keyname
[MAX_PATH
];
1362 char dllpath
[MAX_PATH
+1];
1364 sprintf(keyname
,"CLSID\\%s\\InprocServer32",xclsid
);
1366 if ( compobj_RegReadPath(keyname
, NULL
, dllpath
, sizeof(dllpath
)) != ERROR_SUCCESS
) {
1367 /* failure: CLSID is not found in registry */
1368 WARN("class %s not registered inproc\n", xclsid
);
1369 hres
= REGDB_E_CLASSNOTREG
;
1371 if ((hLibrary
= LoadLibraryExA(dllpath
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
)) == 0) {
1372 /* failure: DLL could not be loaded */
1373 ERR("couldn't load InprocServer32 dll %s\n", dllpath
);
1374 hres
= E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1375 } else if (!(DllGetClassObject
= (DllGetClassObjectFunc
)GetProcAddress(hLibrary
, "DllGetClassObject"))) {
1376 /* failure: the dll did not export DllGetClassObject */
1377 ERR("couldn't find function DllGetClassObject in %s\n", dllpath
);
1378 FreeLibrary( hLibrary
);
1379 hres
= CO_E_DLLNOTFOUND
;
1381 /* OK: get the ClassObject */
1382 COMPOBJ_DLLList_Add( hLibrary
);
1383 return DllGetClassObject(rclsid
, iid
, ppv
);
1388 /* Next try out of process */
1389 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
1391 return create_marshalled_proxy(rclsid
,iid
,ppv
);
1394 /* Finally try remote: this requires networked DCOM (a lot of work) */
1395 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
1397 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1398 hres
= E_NOINTERFACE
;
1403 /***********************************************************************
1404 * CoResumeClassObjects (OLE32.@)
1406 * Resumes classobjects registered with REGCLS suspended
1408 HRESULT WINAPI
CoResumeClassObjects(void)
1414 /***********************************************************************
1415 * GetClassFile (OLE32.@)
1417 * This function supplies the CLSID associated with the given filename.
1419 HRESULT WINAPI
GetClassFile(LPCOLESTR filePathName
,CLSID
*pclsid
)
1423 int nbElm
, length
, i
;
1425 LPOLESTR
*pathDec
=0,absFile
=0,progId
=0;
1427 static const WCHAR bkslashW
[] = {'\\',0};
1428 static const WCHAR dotW
[] = {'.',0};
1430 TRACE("%s, %p\n", debugstr_w(filePathName
), pclsid
);
1432 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1433 if((StgIsStorageFile(filePathName
))==S_OK
){
1435 res
=StgOpenStorage(filePathName
,NULL
,STGM_READ
| STGM_SHARE_DENY_WRITE
,NULL
,0,&pstg
);
1438 res
=ReadClassStg(pstg
,pclsid
);
1440 IStorage_Release(pstg
);
1444 /* if the file is not a storage object then attemps to match various bits in the file against a
1445 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1448 for(i=0;i<nFileTypes;i++)
1450 for(i=0;j<nPatternsForType;j++){
1455 pat=ReadPatternFromRegistry(i,j);
1456 hFile=CreateFileW(filePathName,,,,,,hFile);
1457 SetFilePosition(hFile,pat.offset);
1458 ReadFile(hFile,buf,pat.size,NULL,NULL);
1459 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1461 *pclsid=ReadCLSIDFromRegistry(i);
1467 /* if the above strategies fail then search for the extension key in the registry */
1469 /* get the last element (absolute file) in the path name */
1470 nbElm
=FileMonikerImpl_DecomposePath(filePathName
,&pathDec
);
1471 absFile
=pathDec
[nbElm
-1];
1473 /* failed if the path represente a directory and not an absolute file name*/
1474 if (!lstrcmpW(absFile
, bkslashW
))
1475 return MK_E_INVALIDEXTENSION
;
1477 /* get the extension of the file */
1479 length
=lstrlenW(absFile
);
1480 for(i
= length
-1; (i
>= 0) && *(extension
= &absFile
[i
]) != '.'; i
--)
1483 if (!extension
|| !lstrcmpW(extension
, dotW
))
1484 return MK_E_INVALIDEXTENSION
;
1486 res
=RegQueryValueW(HKEY_CLASSES_ROOT
, extension
, NULL
, &sizeProgId
);
1488 /* get the progId associated to the extension */
1489 progId
= CoTaskMemAlloc(sizeProgId
);
1490 res
= RegQueryValueW(HKEY_CLASSES_ROOT
, extension
, progId
, &sizeProgId
);
1492 if (res
==ERROR_SUCCESS
)
1493 /* return the clsid associated to the progId */
1494 res
= CLSIDFromProgID(progId
,pclsid
);
1496 for(i
=0; pathDec
[i
]!=NULL
;i
++)
1497 CoTaskMemFree(pathDec
[i
]);
1498 CoTaskMemFree(pathDec
);
1500 CoTaskMemFree(progId
);
1502 if (res
==ERROR_SUCCESS
)
1505 return MK_E_INVALIDEXTENSION
;
1507 /***********************************************************************
1508 * CoCreateInstance [COMPOBJ.13]
1509 * CoCreateInstance [OLE32.@]
1511 HRESULT WINAPI
CoCreateInstance(
1513 LPUNKNOWN pUnkOuter
,
1519 LPCLASSFACTORY lpclf
= 0;
1528 * Initialize the "out" parameter
1533 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1534 * Rather than create a class factory, we can just check for it here
1536 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
)) {
1537 if (StdGlobalInterfaceTableInstance
== NULL
)
1538 StdGlobalInterfaceTableInstance
= StdGlobalInterfaceTable_Construct();
1539 hres
= IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable
*) StdGlobalInterfaceTableInstance
, iid
, ppv
);
1540 if (hres
) return hres
;
1542 TRACE("Retrieved GIT (%p)\n", *ppv
);
1547 * Get a class factory to construct the object we want.
1549 hres
= CoGetClassObject(rclsid
,
1556 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1557 debugstr_guid(rclsid
),hres
);
1562 * Create the object and don't forget to release the factory
1564 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
1565 IClassFactory_Release(lpclf
);
1567 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1568 debugstr_guid(iid
), debugstr_guid(rclsid
),hres
);
1573 /***********************************************************************
1574 * CoCreateInstanceEx [OLE32.@]
1576 HRESULT WINAPI
CoCreateInstanceEx(
1578 LPUNKNOWN pUnkOuter
,
1580 COSERVERINFO
* pServerInfo
,
1584 IUnknown
* pUnk
= NULL
;
1587 int successCount
= 0;
1592 if ( (cmq
==0) || (pResults
==NULL
))
1593 return E_INVALIDARG
;
1595 if (pServerInfo
!=NULL
)
1596 FIXME("() non-NULL pServerInfo not supported!\n");
1599 * Initialize all the "out" parameters.
1601 for (index
= 0; index
< cmq
; index
++)
1603 pResults
[index
].pItf
= NULL
;
1604 pResults
[index
].hr
= E_NOINTERFACE
;
1608 * Get the object and get its IUnknown pointer.
1610 hr
= CoCreateInstance(rclsid
,
1620 * Then, query for all the interfaces requested.
1622 for (index
= 0; index
< cmq
; index
++)
1624 pResults
[index
].hr
= IUnknown_QueryInterface(pUnk
,
1625 pResults
[index
].pIID
,
1626 (VOID
**)&(pResults
[index
].pItf
));
1628 if (pResults
[index
].hr
== S_OK
)
1633 * Release our temporary unknown pointer.
1635 IUnknown_Release(pUnk
);
1637 if (successCount
== 0)
1638 return E_NOINTERFACE
;
1640 if (successCount
!=cmq
)
1641 return CO_S_NOTALLINTERFACES
;
1646 /***********************************************************************
1647 * CoLoadLibrary (OLE32.@)
1649 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
1651 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
1653 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
1656 /***********************************************************************
1657 * CoFreeLibrary [OLE32.@]
1659 * NOTES: don't believe the documentation
1661 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
1663 FreeLibrary(hLibrary
);
1667 /***********************************************************************
1668 * CoFreeAllLibraries [OLE32.@]
1670 * NOTES: don't believe the documentation
1672 void WINAPI
CoFreeAllLibraries(void)
1678 /***********************************************************************
1679 * CoFreeUnusedLibraries [COMPOBJ.17]
1680 * CoFreeUnusedLibraries [OLE32.@]
1682 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1683 * through the main apartment's thread to call DllCanUnloadNow
1685 void WINAPI
CoFreeUnusedLibraries(void)
1687 COMPOBJ_DllList_FreeUnused(0);
1690 /***********************************************************************
1691 * CoFileTimeNow [COMPOBJ.82]
1692 * CoFileTimeNow [OLE32.@]
1695 * the current system time in lpFileTime
1697 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
) /* [out] the current time */
1699 GetSystemTimeAsFileTime( lpFileTime
);
1703 /***********************************************************************
1704 * CoLoadLibrary (OLE32.@)
1706 static void COM_RevokeAllClasses()
1708 EnterCriticalSection( &csRegisteredClassList
);
1710 while (firstRegisteredClass
!=0)
1712 CoRevokeClassObject(firstRegisteredClass
->dwCookie
);
1715 LeaveCriticalSection( &csRegisteredClassList
);
1718 /****************************************************************************
1719 * COM External Lock methods implementation
1721 * This api provides a linked list to managed external references to
1724 * The public interface consists of three calls:
1725 * COM_ExternalLockAddRef
1726 * COM_ExternalLockRelease
1727 * COM_ExternalLockFreeList
1730 #define EL_END_OF_LIST 0
1731 #define EL_NOT_FOUND 0
1734 * Declaration of the static structure that manage the
1735 * external lock to COM objects.
1737 typedef struct COM_ExternalLock COM_ExternalLock
;
1738 typedef struct COM_ExternalLockList COM_ExternalLockList
;
1740 struct COM_ExternalLock
1742 IUnknown
*pUnk
; /* IUnknown referenced */
1743 ULONG uRefCount
; /* external lock counter to IUnknown object*/
1744 COM_ExternalLock
*next
; /* Pointer to next element in list */
1747 struct COM_ExternalLockList
1749 COM_ExternalLock
*head
; /* head of list */
1753 * Declaration and initialization of the static structure that manages
1754 * the external lock to COM objects.
1756 static COM_ExternalLockList elList
= { EL_END_OF_LIST
};
1759 * Private methods used to managed the linked list
1763 static COM_ExternalLock
* COM_ExternalLockLocate(
1764 COM_ExternalLock
*element
,
1767 /****************************************************************************
1768 * Internal - Insert a new IUnknown* to the linked list
1770 static BOOL
COM_ExternalLockInsert(
1773 COM_ExternalLock
*newLock
= NULL
;
1774 COM_ExternalLock
*previousHead
= NULL
;
1777 * Allocate space for the new storage object
1779 newLock
= HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock
));
1781 if (newLock
!=NULL
) {
1782 if ( elList
.head
== EL_END_OF_LIST
) {
1783 elList
.head
= newLock
; /* The list is empty */
1785 /* insert does it at the head */
1786 previousHead
= elList
.head
;
1787 elList
.head
= newLock
;
1790 /* Set new list item data member */
1791 newLock
->pUnk
= pUnk
;
1792 newLock
->uRefCount
= 1;
1793 newLock
->next
= previousHead
;
1800 /****************************************************************************
1801 * Internal - Method that removes an item from the linked list.
1803 static void COM_ExternalLockDelete(
1804 COM_ExternalLock
*itemList
)
1806 COM_ExternalLock
*current
= elList
.head
;
1808 if ( current
== itemList
) {
1809 /* this section handles the deletion of the first node */
1810 elList
.head
= itemList
->next
;
1811 HeapFree( GetProcessHeap(), 0, itemList
);
1814 if ( current
->next
== itemList
){ /* We found the item to free */
1815 current
->next
= itemList
->next
; /* readjust the list pointers */
1816 HeapFree( GetProcessHeap(), 0, itemList
);
1820 /* Skip to the next item */
1821 current
= current
->next
;
1823 } while ( current
!= EL_END_OF_LIST
);
1827 /****************************************************************************
1828 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1830 * NOTES: how long can the list be ?? (recursive!!!)
1832 static COM_ExternalLock
* COM_ExternalLockLocate( COM_ExternalLock
*element
, IUnknown
*pUnk
)
1834 if ( element
== EL_END_OF_LIST
)
1835 return EL_NOT_FOUND
;
1836 else if ( element
->pUnk
== pUnk
) /* We found it */
1838 else /* Not the right guy, keep on looking */
1839 return COM_ExternalLockLocate( element
->next
, pUnk
);
1842 /****************************************************************************
1843 * Public - Method that increments the count for a IUnknown* in the linked
1844 * list. The item is inserted if not already in the list.
1846 static void COM_ExternalLockAddRef(IUnknown
*pUnk
)
1848 COM_ExternalLock
*externalLock
= COM_ExternalLockLocate(elList
.head
, pUnk
);
1851 * Add an external lock to the object. If it was already externally
1852 * locked, just increase the reference count. If it was not.
1853 * add the item to the list.
1855 if ( externalLock
== EL_NOT_FOUND
)
1856 COM_ExternalLockInsert(pUnk
);
1858 externalLock
->uRefCount
++;
1861 * Add an internal lock to the object
1863 IUnknown_AddRef(pUnk
);
1866 /****************************************************************************
1867 * Public - Method that decrements the count for a IUnknown* in the linked
1868 * list. The item is removed from the list if its count end up at zero or if
1871 static void COM_ExternalLockRelease(
1875 COM_ExternalLock
*externalLock
= COM_ExternalLockLocate(elList
.head
, pUnk
);
1877 if ( externalLock
!= EL_NOT_FOUND
) {
1879 externalLock
->uRefCount
--; /* release external locks */
1880 IUnknown_Release(pUnk
); /* release local locks as well */
1882 if ( bRelAll
== FALSE
) break; /* perform single release */
1884 } while ( externalLock
->uRefCount
> 0 );
1886 if ( externalLock
->uRefCount
== 0 ) /* get rid of the list entry */
1887 COM_ExternalLockDelete(externalLock
);
1890 /****************************************************************************
1891 * Public - Method that frees the content of the list.
1893 static void COM_ExternalLockFreeList()
1895 COM_ExternalLock
*head
;
1897 head
= elList
.head
; /* grab it by the head */
1898 while ( head
!= EL_END_OF_LIST
) {
1899 COM_ExternalLockDelete(head
); /* get rid of the head stuff */
1900 head
= elList
.head
; /* get the new head... */
1904 /****************************************************************************
1905 * Public - Method that dump the content of the list.
1907 void COM_ExternalLockDump()
1909 COM_ExternalLock
*current
= elList
.head
;
1911 DPRINTF("\nExternal lock list contains:\n");
1913 while ( current
!= EL_END_OF_LIST
) {
1914 DPRINTF( "\t%p with %lu references count.\n", current
->pUnk
, current
->uRefCount
);
1916 /* Skip to the next item */
1917 current
= current
->next
;
1921 /******************************************************************************
1922 * CoLockObjectExternal [OLE32.@]
1924 HRESULT WINAPI
CoLockObjectExternal(
1925 LPUNKNOWN pUnk
, /* [in] object to be locked */
1926 BOOL fLock
, /* [in] do lock */
1927 BOOL fLastUnlockReleases
) /* [in] unlock all */
1932 * Increment the external lock coutner, COM_ExternalLockAddRef also
1933 * increment the object's internal lock counter.
1935 COM_ExternalLockAddRef( pUnk
);
1938 * Decrement the external lock coutner, COM_ExternalLockRelease also
1939 * decrement the object's internal lock counter.
1941 COM_ExternalLockRelease( pUnk
, fLastUnlockReleases
);
1947 /***********************************************************************
1948 * CoInitializeWOW (OLE32.@)
1950 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
) {
1951 FIXME("(0x%08lx,0x%08lx),stub!\n",x
,y
);
1955 static int nStatCounter
= 0; /* global */
1956 static HMODULE hOleAut32
= 0; /* global */
1958 /***********************************************************************
1959 * CoGetState [OLE32.@]
1961 * NOTES: might be incomplete
1963 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
1965 APARTMENT
* apt
= COM_CurrentInfo();
1969 if(apt
&& apt
->state
) {
1970 IUnknown_AddRef(apt
->state
);
1972 FIXME("-- %p\n", *ppv
);
1980 /***********************************************************************
1981 * CoSetState [OLE32.@]
1983 * NOTES: FIXME: protect this with a crst
1985 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
1987 APARTMENT
* apt
= COM_CurrentInfo();
1989 if (!apt
) apt
= COM_CreateApartment(COINIT_UNINITIALIZED
);
1991 FIXME("(%p),stub!\n", pv
);
1994 IUnknown_AddRef(pv
);
1996 if (nStatCounter
== 1) LoadLibraryA("OLEAUT32.DLL");
2000 TRACE("-- release %p now\n", apt
->state
);
2001 IUnknown_Release(apt
->state
);
2003 if (!nStatCounter
) FreeLibrary(hOleAut32
);
2010 /******************************************************************************
2011 * OleGetAutoConvert [OLE32.@]
2013 HRESULT WINAPI
OleGetAutoConvert(REFCLSID clsidOld
, LPCLSID pClsidNew
)
2021 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
2022 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
2024 res
= REGDB_E_CLASSNOTREG
;
2028 /* we can just query for the default value of AutoConvertTo key like that,
2029 without opening the AutoConvertTo key and querying for NULL (default) */
2030 if (RegQueryValueA(hkey
,"AutoConvertTo",buf
,&len
))
2032 res
= REGDB_E_KEYMISSING
;
2035 MultiByteToWideChar( CP_ACP
, 0, buf
, -1, wbuf
, sizeof(wbuf
)/sizeof(WCHAR
) );
2036 CLSIDFromString(wbuf
,pClsidNew
);
2038 if (hkey
) RegCloseKey(hkey
);
2042 /******************************************************************************
2043 * OleSetAutoConvert [OLE32.@]
2045 HRESULT WINAPI
OleSetAutoConvert(REFCLSID clsidOld
, REFCLSID clsidNew
)
2048 char buf
[200], szClsidNew
[200];
2051 TRACE("(%s,%s)\n", debugstr_guid(clsidOld
), debugstr_guid(clsidNew
));
2052 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
2053 WINE_StringFromCLSID(clsidNew
, szClsidNew
);
2054 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
2056 res
= REGDB_E_CLASSNOTREG
;
2059 if (RegSetValueA(hkey
, "AutoConvertTo", REG_SZ
, szClsidNew
, strlen(szClsidNew
)+1))
2061 res
= REGDB_E_WRITEREGDB
;
2066 if (hkey
) RegCloseKey(hkey
);
2070 /******************************************************************************
2071 * OleDoAutoConvert [OLE32.@]
2073 HRESULT WINAPI
OleDoAutoConvert(IStorage
*pStg
, LPCLSID pClsidNew
)
2075 FIXME("(%p,%p) : stub\n",pStg
,pClsidNew
);
2079 /******************************************************************************
2080 * CoTreatAsClass [OLE32.@]
2082 * Sets TreatAs value of a class
2084 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
2088 char szClsidNew
[39];
2090 char auto_treat_as
[39];
2091 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
2094 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
2095 WINE_StringFromCLSID(clsidNew
, szClsidNew
);
2096 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
2098 res
= REGDB_E_CLASSNOTREG
;
2101 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
2103 if (!RegQueryValueA(hkey
, "AutoTreatAs", auto_treat_as
, &auto_treat_as_size
) &&
2104 !__CLSIDFromStringA(auto_treat_as
, &id
))
2106 if (RegSetValueA(hkey
, "TreatAs", REG_SZ
, auto_treat_as
, strlen(auto_treat_as
)+1))
2108 res
= REGDB_E_WRITEREGDB
;
2114 RegDeleteKeyA(hkey
, "TreatAs");
2118 else if (RegSetValueA(hkey
, "TreatAs", REG_SZ
, szClsidNew
, strlen(szClsidNew
)+1))
2120 res
= REGDB_E_WRITEREGDB
;
2125 if (hkey
) RegCloseKey(hkey
);
2129 /******************************************************************************
2130 * CoGetTreatAsClass [OLE32.@]
2132 * Reads the TreatAs value from a class.
2134 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
2137 char buf
[200], szClsidNew
[200];
2139 LONG len
= sizeof(szClsidNew
);
2141 FIXME("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
2142 sprintf(buf
,"CLSID\\");WINE_StringFromCLSID(clsidOld
,&buf
[6]);
2143 memcpy(clsidNew
,clsidOld
,sizeof(CLSID
)); /* copy over old value */
2145 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&hkey
))
2147 res
= REGDB_E_CLASSNOTREG
;
2150 if (RegQueryValueA(hkey
, "TreatAs", szClsidNew
, &len
))
2155 res
= __CLSIDFromStringA(szClsidNew
,clsidNew
);
2157 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew
,res
);
2159 if (hkey
) RegCloseKey(hkey
);
2164 /***********************************************************************
2165 * IsEqualGUID [OLE32.@]
2167 * Compares two Unique Identifiers.
2173 BOOL WINAPI
IsEqualGUID(
2174 REFGUID rguid1
, /* [in] unique id 1 */
2175 REFGUID rguid2
/* [in] unique id 2 */
2178 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
2181 /***********************************************************************
2182 * CoInitializeSecurity [OLE32.@]
2184 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
2185 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
2186 void* pReserved1
, DWORD dwAuthnLevel
,
2187 DWORD dwImpLevel
, void* pReserved2
,
2188 DWORD dwCapabilities
, void* pReserved3
)
2190 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc
, cAuthSvc
,
2191 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
2192 dwCapabilities
, pReserved3
);