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
26 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
27 * Therefore do not test against COINIT_MULTITHREADED
29 * TODO list: (items bunched together depend on each other)
31 * - Rewrite the CoLockObjectExternal code, it does totally the wrong
32 * thing currently (should be controlling the stub manager)
34 * - Free the ReservedForOle data in DllMain(THREAD_DETACH)
36 * - Implement the service control manager (in rpcss) to keep track
37 * of registered class objects: ISCM::ServerRegisterClsid et al
38 * - Implement the OXID resolver so we don't need magic pipe names for
39 * clients and servers to meet up
40 * - Flip our marshalling on top of the RPC runtime transport API,
41 * so we no longer use named pipes to communicate
42 * - Rework threading so re-entrant calls don't need to be sent on
44 * - Implement RPC thread affinity (should fix InstallShield painting
47 * - Make our custom marshalling use NDR to be wire compatible with
62 #define NONAMELESSUNION
63 #define NONAMELESSSTRUCT
75 #include "wine/unicode.h"
77 #include "ole32_main.h"
78 #include "compobj_private.h"
80 #include "wine/debug.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(ole);
84 typedef LPCSTR LPCOLESTR16;
86 /****************************************************************************
87 * This section defines variables internal to the COM module.
89 * TODO: Most of these things will have to be made thread-safe.
92 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
93 static void COM_RevokeAllClasses(void);
94 static void COM_ExternalLockFreeList(void);
96 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
98 APARTMENT *MTA; /* protected by csApartment */
99 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
101 static CRITICAL_SECTION csApartment;
102 static CRITICAL_SECTION_DEBUG critsect_debug =
105 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
106 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
108 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
111 * This lock count counts the number of times CoInitialize is called. It is
112 * decreased every time CoUninitialize is called. When it hits 0, the COM
113 * libraries are freed
115 static LONG s_COMLockCount = 0;
118 * This linked list contains the list of registered class objects. These
119 * are mostly used to register the factories for out-of-proc servers of OLE
122 * TODO: Make this data structure aware of inter-process communication. This
123 * means that parts of this will be exported to the Wine Server.
125 typedef struct tagRegisteredClass
127 CLSID classIdentifier;
128 LPUNKNOWN classObject;
132 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
133 struct tagRegisteredClass* nextClass;
136 static RegisteredClass* firstRegisteredClass = NULL;
138 static CRITICAL_SECTION csRegisteredClassList;
139 static CRITICAL_SECTION_DEBUG class_cs_debug =
141 0, 0, &csRegisteredClassList,
142 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
143 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
145 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
147 /*****************************************************************************
148 * This section contains OpenDllList definitions
150 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
151 * other functions that do LoadLibrary _without_ giving back a HMODULE.
152 * Without this list these handles would never be freed.
154 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
155 * next unload-call but not before 600 sec.
158 typedef struct tagOpenDll {
160 struct tagOpenDll *next;
163 static OpenDll *openDllList = NULL; /* linked list of open dlls */
165 static CRITICAL_SECTION csOpenDllList;
166 static CRITICAL_SECTION_DEBUG dll_cs_debug =
168 0, 0, &csOpenDllList,
169 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
170 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
172 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
174 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
175 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
177 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
178 static void COMPOBJ_DllList_FreeUnused(int Timeout);
180 void COMPOBJ_InitProcess( void )
184 /* Dispatching to the correct thread in an apartment is done through
185 * window messages rather than RPC transports. When an interface is
186 * marshalled into another apartment in the same process, a window of the
187 * following class is created. The *caller* of CoMarshalInterface (ie the
188 * application) is responsible for pumping the message loop in that thread.
189 * The WM_USER messages which point to the RPCs are then dispatched to
190 * COM_AptWndProc by the user's code from the apartment in which the interface
193 memset(&wclass, 0, sizeof(wclass));
194 wclass.lpfnWndProc = &COM_AptWndProc;
195 wclass.hInstance = OLE32_hInstance;
196 wclass.lpszClassName = aptWinClass;
197 RegisterClassA(&wclass);
200 void COMPOBJ_UninitProcess( void )
202 UnregisterClassA(aptWinClass, OLE32_hInstance);
205 void COM_TlsDestroy()
207 struct oletls *info = NtCurrentTeb()->ReservedForOle;
210 if (info->apt) COM_ApartmentRelease(info->apt);
211 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
212 if (info->state) IUnknown_Release(info->state);
213 HeapFree(GetProcessHeap(), 0, info);
214 NtCurrentTeb()->ReservedForOle = NULL;
218 /******************************************************************************
222 /* creates an apartment structure which stores OLE apartment-local
224 APARTMENT* COM_CreateApartment(DWORD model)
226 APARTMENT *apt = COM_CurrentApt();
230 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
231 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
234 EnterCriticalSection(&csApartment);
235 if (!(model & COINIT_APARTMENTTHREADED) && MTA) /* See note 1 above */
237 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
239 COM_ApartmentAddRef(apt);
241 LeaveCriticalSection(&csApartment);
243 COM_CurrentInfo()->apt = apt;
247 TRACE("creating new apartment, model=%ld\n", model);
249 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
250 apt->tid = GetCurrentThreadId();
251 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
252 GetCurrentProcess(), &apt->thread,
253 THREAD_ALL_ACCESS, FALSE, 0);
255 list_init(&apt->proxies);
256 list_init(&apt->stubmgrs);
259 apt->remunk_exported = FALSE;
261 InitializeCriticalSection(&apt->cs);
265 if (model & COINIT_APARTMENTTHREADED)
267 /* FIXME: should be randomly generated by in an RPC call to rpcss */
268 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
269 apt->win = CreateWindowA(aptWinClass, NULL, 0,
271 0, 0, OLE32_hInstance, NULL);
275 /* FIXME: should be randomly generated by in an RPC call to rpcss */
276 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
280 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
282 list_add_head(&apts, &apt->entry);
283 LeaveCriticalSection(&csApartment);
285 COM_CurrentInfo()->apt = apt;
291 DWORD COM_ApartmentAddRef(struct apartment *apt)
293 return InterlockedIncrement(&apt->refs);
296 DWORD COM_ApartmentRelease(struct apartment *apt)
300 EnterCriticalSection(&csApartment);
302 ret = InterlockedDecrement(&apt->refs);
303 /* destruction stuff that needs to happen under csApartment CS */
306 if (apt == MTA) MTA = NULL;
307 list_remove(&apt->entry);
310 LeaveCriticalSection(&csApartment);
314 struct list *cursor, *cursor2;
316 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
318 MARSHAL_Disconnect_Proxies(apt);
320 if (apt->win) DestroyWindow(apt->win);
322 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
324 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
325 /* release the implicit reference given by the fact that the
326 * stub has external references (it must do since it is in the
327 * stub manager list in the apartment and all non-apartment users
328 * must have a ref on the apartment and so it cannot be destroyed).
330 stub_manager_int_release(stubmgr);
333 /* if this assert fires, then another thread took a reference to a
334 * stub manager without taking a reference to the containing
335 * apartment, which it must do. */
336 assert(list_empty(&apt->stubmgrs));
338 if (apt->filter) IUnknown_Release(apt->filter);
340 DeleteCriticalSection(&apt->cs);
341 CloseHandle(apt->thread);
342 HeapFree(GetProcessHeap(), 0, apt);
348 /* The given OXID must be local to this process: you cannot use
349 * apartment windows to send RPCs to other processes. This all needs
352 * The ref parameter is here mostly to ensure people remember that
353 * they get one, you should normally take a ref for thread safety.
355 APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
357 APARTMENT *result = NULL;
360 EnterCriticalSection(&csApartment);
361 LIST_FOR_EACH( cursor, &apts )
363 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
364 if (apt->oxid == oxid)
367 if (ref) COM_ApartmentAddRef(result);
371 LeaveCriticalSection(&csApartment);
376 /* gets the apartment which has a given creator thread ID. The caller must
377 * release the reference from the apartment as soon as the apartment pointer
378 * is no longer required. */
379 APARTMENT *COM_ApartmentFromTID(DWORD tid)
381 APARTMENT *result = NULL;
384 EnterCriticalSection(&csApartment);
385 LIST_FOR_EACH( cursor, &apts )
387 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
391 COM_ApartmentAddRef(result);
395 LeaveCriticalSection(&csApartment);
400 HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
404 apt = COM_ApartmentFromOXID(oxid, ref);
405 if (!apt) return NULL;
410 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
411 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
413 return DefWindowProcA(hWnd, msg, wParam, lParam);
416 /*****************************************************************************
417 * This section contains OpenDllList implemantation
420 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
427 EnterCriticalSection( &csOpenDllList );
429 if (openDllList == NULL) {
430 /* empty list -- add first node */
431 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
432 openDllList->hLibrary=hLibrary;
433 openDllList->next = NULL;
435 /* search for this dll */
437 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
438 if (ptr->hLibrary == hLibrary) {
444 /* dll not found, add it */
446 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
447 openDllList->hLibrary = hLibrary;
448 openDllList->next = tmp;
452 LeaveCriticalSection( &csOpenDllList );
455 static void COMPOBJ_DllList_FreeUnused(int Timeout)
457 OpenDll *curr, *next, *prev = NULL;
458 typedef HRESULT(*DllCanUnloadNowFunc)(void);
459 DllCanUnloadNowFunc DllCanUnloadNow;
463 EnterCriticalSection( &csOpenDllList );
465 for (curr = openDllList; curr != NULL; ) {
466 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
468 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
471 TRACE("freeing %p\n", curr->hLibrary);
472 FreeLibrary(curr->hLibrary);
474 HeapFree(GetProcessHeap(), 0, curr);
475 if (curr == openDllList) {
488 LeaveCriticalSection( &csOpenDllList );
491 /******************************************************************************
492 * CoBuildVersion [OLE32.@]
493 * CoBuildVersion [COMPOBJ.1]
495 * Gets the build version of the DLL.
500 * Current build version, hiword is majornumber, loword is minornumber
502 DWORD WINAPI CoBuildVersion(void)
504 TRACE("Returning version %d, build %d.\n", rmm, rup);
505 return (rmm<<16)+rup;
508 /******************************************************************************
509 * CoInitialize [OLE32.@]
511 * Initializes the COM libraries by calling CoInitializeEx with
512 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
515 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
518 * Success: S_OK if not already initialized, S_FALSE otherwise.
519 * Failure: HRESULT code.
524 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
527 * Just delegate to the newer method.
529 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
532 /******************************************************************************
533 * CoInitializeEx [OLE32.@]
535 * Initializes the COM libraries.
538 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
539 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
542 * S_OK if successful,
543 * S_FALSE if this function was called already.
544 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
549 * The behavior used to set the IMalloc used for memory management is
551 * The dwCoInit parameter must specify of of the following apartment
553 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
554 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
555 * The parameter may also specify zero or more of the following flags:
556 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
557 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
562 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
567 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
569 if (lpReserved!=NULL)
571 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
575 * Check the lock count. If this is the first time going through the initialize
576 * process, we have to initialize the libraries.
578 * And crank-up that lock count.
580 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
583 * Initialize the various COM libraries and data structures.
585 TRACE("() - Initializing the COM libraries\n");
587 /* we may need to defer this until after apartment initialisation */
588 RunningObjectTableImpl_Initialize();
591 if (!(apt = COM_CurrentInfo()->apt))
593 apt = COM_CreateApartment(dwCoInit);
594 if (!apt) return E_OUTOFMEMORY;
596 else if (dwCoInit != apt->model)
598 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
599 code then we are probably using the wrong threading model to implement that API. */
600 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
601 return RPC_E_CHANGED_MODE;
606 COM_CurrentInfo()->inits++;
611 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
612 pending RPCs are ignored. Non-COM messages are discarded at this point.
614 void COM_FlushMessageQueue(void)
617 APARTMENT *apt = COM_CurrentApt();
619 if (!apt || !apt->win) return;
621 TRACE("Flushing STA message queue\n");
623 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
625 if (message.hwnd != apt->win)
627 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
631 TranslateMessage(&message);
632 DispatchMessageA(&message);
636 /***********************************************************************
637 * CoUninitialize [OLE32.@]
639 * This method will decrement the refcount on the current apartment, freeing
640 * the resources associated with it if it is the last thread in the apartment.
641 * If the last apartment is freed, the function will additionally release
642 * any COM resources associated with the process.
652 void WINAPI CoUninitialize(void)
654 struct oletls * info = COM_CurrentInfo();
659 /* will only happen on OOM */
665 ERR("Mismatched CoUninitialize\n");
671 COM_ApartmentRelease(info->apt);
676 * Decrease the reference count.
677 * If we are back to 0 locks on the COM library, make sure we free
678 * all the associated data structures.
680 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
683 TRACE("() - Releasing the COM libraries\n");
685 RunningObjectTableImpl_UnInitialize();
687 /* Release the references to the registered class objects */
688 COM_RevokeAllClasses();
690 /* This will free the loaded COM Dlls */
691 CoFreeAllLibraries();
693 /* This will free list of external references to COM objects */
694 COM_ExternalLockFreeList();
696 /* This ensures we deal with any pending RPCs */
697 COM_FlushMessageQueue();
699 else if (lCOMRefCnt<1) {
700 ERR( "CoUninitialize() - not CoInitialized.\n" );
701 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
705 /******************************************************************************
706 * CoDisconnectObject [OLE32.@]
707 * CoDisconnectObject [COMPOBJ.15]
709 * Disconnects all connections to this object from remote processes. Dispatches
710 * pending RPCs while blocking new RPCs from occurring, and then calls
711 * IMarshal::DisconnectObject on the given object.
713 * Typically called when the object server is forced to shut down, for instance by
717 * lpUnk [I] The object whose stub should be disconnected.
718 * reserved [I] Reserved. Should be set to 0.
722 * Failure: HRESULT code.
725 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
727 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
729 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
733 /******************************************************************************
734 * CoCreateGuid [OLE32.@]
736 * Simply forwards to UuidCreate in RPCRT4.
739 * pguid [O] Points to the GUID to initialize.
743 * Failure: HRESULT code.
748 HRESULT WINAPI CoCreateGuid(GUID *pguid)
750 return UuidCreate(pguid);
753 /******************************************************************************
754 * CLSIDFromString [OLE32.@]
755 * IIDFromString [OLE32.@]
757 * Converts a unique identifier from its string representation into
761 * idstr [I] The string representation of the GUID.
762 * id [O] GUID converted from the string.
766 * CO_E_CLASSSTRING if idstr is not a valid CLSID
770 * In Windows, if idstr is not a valid CLSID string then it gets
771 * treated as a ProgID. Wine currently doesn't do this. If idstr is
772 * NULL it's treated as an all-zero GUID.
777 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
779 const BYTE *s = (const BYTE *) idstr;
784 s = "{00000000-0000-0000-0000-000000000000}";
785 else { /* validate the CLSID string */
788 return CO_E_CLASSSTRING;
790 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
791 return CO_E_CLASSSTRING;
793 for (i=1; i<37; i++) {
794 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
795 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
796 ((s[i] >= 'a') && (s[i] <= 'f')) ||
797 ((s[i] >= 'A') && (s[i] <= 'F'))))
798 return CO_E_CLASSSTRING;
802 TRACE("%s -> %p\n", s, id);
804 /* quick lookup table */
805 memset(table, 0, 256);
807 for (i = 0; i < 10; i++) {
810 for (i = 0; i < 6; i++) {
811 table['A' + i] = i+10;
812 table['a' + i] = i+10;
815 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
817 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
818 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
819 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
820 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
822 /* these are just sequential bytes */
823 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
824 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
825 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
826 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
827 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
828 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
829 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
830 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
835 /*****************************************************************************/
837 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
842 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
843 return CO_E_CLASSSTRING;
846 ret = __CLSIDFromStringA(xid,id);
847 if(ret != S_OK) { /* It appears a ProgID is also valid */
848 ret = CLSIDFromProgID(idstr, id);
853 /* Converts a GUID into the respective string representation. */
854 HRESULT WINE_StringFromCLSID(
855 const CLSID *id, /* [in] GUID to be converted */
856 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
858 static const char *hex = "0123456789ABCDEF";
863 { ERR("called with id=Null\n");
868 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
869 id->Data1, id->Data2, id->Data3,
870 id->Data4[0], id->Data4[1]);
874 for (i = 2; i < 8; i++) {
875 *s++ = hex[id->Data4[i]>>4];
876 *s++ = hex[id->Data4[i] & 0xf];
882 TRACE("%p->%s\n", id, idstr);
888 /******************************************************************************
889 * StringFromCLSID [OLE32.@]
890 * StringFromIID [OLE32.@]
892 * Converts a GUID into the respective string representation.
893 * The target string is allocated using the OLE IMalloc.
896 * id [I] the GUID to be converted.
897 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
904 * StringFromGUID2, CLSIDFromString
906 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
912 if ((ret = CoGetMalloc(0,&mllc)))
915 ret=WINE_StringFromCLSID(id,buf);
917 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
918 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
919 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
924 /******************************************************************************
925 * StringFromGUID2 [OLE32.@]
926 * StringFromGUID2 [COMPOBJ.76]
928 * Modified version of StringFromCLSID that allows you to specify max
932 * id [I] GUID to convert to string.
933 * str [O] Buffer where the result will be stored.
934 * cmax [I] Size of the buffer in characters.
937 * Success: The length of the resulting string in characters.
940 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
944 if (WINE_StringFromCLSID(id,xguid))
946 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
949 /******************************************************************************
950 * ProgIDFromCLSID [OLE32.@]
952 * Converts a class id into the respective program ID.
955 * clsid [I] Class ID, as found in registry.
956 * lplpszProgID [O] Associated ProgID.
961 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
963 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
965 char strCLSID[50], *buf, *buf2;
971 WINE_StringFromCLSID(clsid, strCLSID);
973 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
974 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
975 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
976 ret = REGDB_E_CLASSNOTREG;
978 HeapFree(GetProcessHeap(), 0, buf);
982 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
984 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
985 ret = REGDB_E_CLASSNOTREG;
989 if (CoGetMalloc(0,&mllc))
993 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
994 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
995 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
998 HeapFree(GetProcessHeap(), 0, buf2);
1005 HRESULT WINAPI CLSIDFromProgID16(
1006 LPCOLESTR16 progid, /* [in] program id as found in registry */
1007 LPCLSID riid /* [out] associated CLSID */
1014 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1015 sprintf(buf,"%s\\CLSID",progid);
1016 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1017 HeapFree(GetProcessHeap(),0,buf);
1018 return CO_E_CLASSSTRING;
1020 HeapFree(GetProcessHeap(),0,buf);
1021 buf2len = sizeof(buf2);
1022 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1024 return CO_E_CLASSSTRING;
1027 return __CLSIDFromStringA(buf2,riid);
1030 /******************************************************************************
1031 * CLSIDFromProgID [OLE32.@]
1032 * CLSIDFromProgID [COMPOBJ.61]
1034 * Converts a program id into the respective GUID.
1037 * progid [I] Unicode program ID, as found in registry.
1038 * riid [O] Associated CLSID.
1042 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1044 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1046 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1048 DWORD buf2len = sizeof(buf2);
1051 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1052 strcpyW( buf, progid );
1053 strcatW( buf, clsidW );
1054 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1056 HeapFree(GetProcessHeap(),0,buf);
1057 return CO_E_CLASSSTRING;
1059 HeapFree(GetProcessHeap(),0,buf);
1061 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1064 return CO_E_CLASSSTRING;
1067 return __CLSIDFromStringA(buf2,riid);
1072 /*****************************************************************************
1073 * CoGetPSClsid [OLE32.@]
1075 * Retrieves the CLSID of the proxy/stub factory that implements
1076 * IPSFactoryBuffer for the specified interface.
1079 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1080 * pclsid [O] Where to store returned proxy/stub CLSID.
1085 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1089 * The standard marshaller activates the object with the CLSID
1090 * returned and uses the CreateProxy and CreateStub methods on its
1091 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1094 * CoGetPSClsid determines this CLSID by searching the
1095 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1096 * in the registry and any interface id registered by
1097 * CoRegisterPSClsid within the current process.
1101 * We only search the registry, not ids registered with
1102 * CoRegisterPSClsid.
1103 * Also, native returns S_OK for interfaces with an key in HKCR\Interface, but
1104 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1105 * considered a bug in native unless an application depends on this (unlikely).
1107 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1109 char *buf, buf2[40];
1113 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1115 /* Get the input iid as a string */
1116 WINE_StringFromCLSID(riid, buf2);
1117 /* Allocate memory for the registry key we will construct.
1118 (length of iid string plus constant length of static text */
1119 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1121 return E_OUTOFMEMORY;
1123 /* Construct the registry key we want */
1124 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1126 /* Open the key.. */
1127 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1129 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1130 HeapFree(GetProcessHeap(),0,buf);
1131 return REGDB_E_IIDNOTREG;
1133 HeapFree(GetProcessHeap(),0,buf);
1135 /* ... Once we have the key, query the registry to get the
1136 value of CLSID as a string, and convert it into a
1137 proper CLSID structure to be passed back to the app */
1138 buf2len = sizeof(buf2);
1139 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1142 return REGDB_E_IIDNOTREG;
1146 /* We have the CLSid we want back from the registry as a string, so
1147 lets convert it into a CLSID structure */
1148 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR)
1149 return REGDB_E_IIDNOTREG;
1151 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1157 /***********************************************************************
1158 * WriteClassStm (OLE32.@)
1160 * Writes a CLSID to a stream.
1163 * pStm [I] Stream to write to.
1164 * rclsid [I] CLSID to write.
1168 * Failure: HRESULT code.
1170 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1172 TRACE("(%p,%p)\n",pStm,rclsid);
1175 return E_INVALIDARG;
1177 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1180 /***********************************************************************
1181 * ReadClassStm (OLE32.@)
1183 * Reads a CLSID from a stream.
1186 * pStm [I] Stream to read from.
1187 * rclsid [O] CLSID to read.
1191 * Failure: HRESULT code.
1193 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1198 TRACE("(%p,%p)\n",pStm,pclsid);
1201 return E_INVALIDARG;
1203 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1208 if (nbByte != sizeof(CLSID))
1216 * COM_GetRegisteredClassObject
1218 * This internal method is used to scan the registered class list to
1219 * find a class object.
1222 * rclsid Class ID of the class to find.
1223 * dwClsContext Class context to match.
1224 * ppv [out] returns a pointer to the class object. Complying
1225 * to normal COM usage, this method will increase the
1226 * reference count on this object.
1228 static HRESULT COM_GetRegisteredClassObject(
1233 HRESULT hr = S_FALSE;
1234 RegisteredClass* curClass;
1236 EnterCriticalSection( &csRegisteredClassList );
1244 * Iterate through the whole list and try to match the class ID.
1246 curClass = firstRegisteredClass;
1248 while (curClass != 0)
1251 * Check if we have a match on the class ID.
1253 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1256 * Since we don't do out-of process or DCOM just right away, let's ignore the
1261 * We have a match, return the pointer to the class object.
1263 *ppUnk = curClass->classObject;
1265 IUnknown_AddRef(curClass->classObject);
1272 * Step to the next class in the list.
1274 curClass = curClass->nextClass;
1278 LeaveCriticalSection( &csRegisteredClassList );
1280 * If we get to here, we haven't found our class.
1285 /******************************************************************************
1286 * CoRegisterClassObject [OLE32.@]
1288 * Registers the class object for a given class ID. Servers housed in EXE
1289 * files use this method instead of exporting DllGetClassObject to allow
1290 * other code to connect to their objects.
1293 * rclsid [I] CLSID of the object to register.
1294 * pUnk [I] IUnknown of the object.
1295 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1296 * flags [I] REGCLS flags indicating how connections are made.
1297 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1301 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1302 * CO_E_OBJISREG if the object is already registered. We should not return this.
1305 * CoRevokeClassObject, CoGetClassObject
1308 * MSDN claims that multiple interface registrations are legal, but we
1309 * can't do that with our current implementation.
1311 HRESULT WINAPI CoRegisterClassObject(
1316 LPDWORD lpdwRegister)
1318 RegisteredClass* newClass;
1319 LPUNKNOWN foundObject;
1322 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1323 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1325 if ( (lpdwRegister==0) || (pUnk==0) )
1326 return E_INVALIDARG;
1328 if (!COM_CurrentApt())
1330 ERR("COM was not initialized\n");
1331 return CO_E_NOTINITIALIZED;
1337 * First, check if the class is already registered.
1338 * If it is, this should cause an error.
1340 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1342 IUnknown_Release(foundObject);
1343 return CO_E_OBJISREG;
1346 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1347 if ( newClass == NULL )
1348 return E_OUTOFMEMORY;
1350 EnterCriticalSection( &csRegisteredClassList );
1352 newClass->classIdentifier = *rclsid;
1353 newClass->runContext = dwClsContext;
1354 newClass->connectFlags = flags;
1356 * Use the address of the chain node as the cookie since we are sure it's
1357 * unique. FIXME: not on 64-bit platforms.
1359 newClass->dwCookie = (DWORD)newClass;
1360 newClass->nextClass = firstRegisteredClass;
1363 * Since we're making a copy of the object pointer, we have to increase its
1366 newClass->classObject = pUnk;
1367 IUnknown_AddRef(newClass->classObject);
1369 firstRegisteredClass = newClass;
1370 LeaveCriticalSection( &csRegisteredClassList );
1372 *lpdwRegister = newClass->dwCookie;
1374 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1375 IClassFactory *classfac;
1377 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1378 (LPVOID*)&classfac);
1381 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1383 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1384 IUnknown_Release(classfac);
1387 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1388 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1389 MSHLFLAGS_TABLESTRONG);
1391 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1392 IUnknown_Release(classfac);
1396 IUnknown_Release(classfac);
1398 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1403 /***********************************************************************
1404 * CoRevokeClassObject [OLE32.@]
1406 * Removes a class object from the class registry.
1409 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1413 * Failure: HRESULT code.
1416 * CoRegisterClassObject
1418 HRESULT WINAPI CoRevokeClassObject(
1421 HRESULT hr = E_INVALIDARG;
1422 RegisteredClass** prevClassLink;
1423 RegisteredClass* curClass;
1425 TRACE("(%08lx)\n",dwRegister);
1427 EnterCriticalSection( &csRegisteredClassList );
1430 * Iterate through the whole list and try to match the cookie.
1432 curClass = firstRegisteredClass;
1433 prevClassLink = &firstRegisteredClass;
1435 while (curClass != 0)
1438 * Check if we have a match on the cookie.
1440 if (curClass->dwCookie == dwRegister)
1443 * Remove the class from the chain.
1445 *prevClassLink = curClass->nextClass;
1448 * Release the reference to the class object.
1450 IUnknown_Release(curClass->classObject);
1452 if (curClass->pMarshaledData)
1455 memset(&zero, 0, sizeof(zero));
1456 /* FIXME: stop local server thread */
1457 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1458 CoReleaseMarshalData(curClass->pMarshaledData);
1462 * Free the memory used by the chain node.
1464 HeapFree(GetProcessHeap(), 0, curClass);
1471 * Step to the next class in the list.
1473 prevClassLink = &(curClass->nextClass);
1474 curClass = curClass->nextClass;
1478 LeaveCriticalSection( &csRegisteredClassList );
1480 * If we get to here, we haven't found our class.
1485 /***********************************************************************
1486 * compobj_RegReadPath [internal]
1488 * Reads a registry value and expands it when necessary
1490 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1496 DWORD dwLength = dstlen;
1498 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1499 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1500 if (keytype == REG_EXPAND_SZ) {
1501 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1503 lstrcpynA(dst, src, dstlen);
1511 /***********************************************************************
1512 * CoGetClassObject [COMPOBJ.7]
1513 * CoGetClassObject [OLE32.@]
1515 * FIXME. If request allows of several options and there is a failure
1516 * with one (other than not being registered) do we try the
1517 * others or return failure? (E.g. inprocess is registered but
1518 * the DLL is not found but the server version works)
1520 HRESULT WINAPI CoGetClassObject(
1521 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1522 REFIID iid, LPVOID *ppv
1524 LPUNKNOWN regClassObject;
1525 HRESULT hres = E_UNEXPECTED;
1528 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1529 DllGetClassObjectFunc DllGetClassObject;
1531 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1533 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1536 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1537 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1541 * First, try and see if we can't match the class ID with one of the
1542 * registered classes.
1544 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1547 * Get the required interface from the retrieved pointer.
1549 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1552 * Since QI got another reference on the pointer, we want to release the
1553 * one we already have. If QI was unsuccessful, this will release the object. This
1554 * is good since we are not returning it in the "out" parameter.
1556 IUnknown_Release(regClassObject);
1561 /* first try: in-process */
1562 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1563 char keyname[MAX_PATH];
1564 char dllpath[MAX_PATH+1];
1566 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1568 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1569 /* failure: CLSID is not found in registry */
1570 WARN("class %s not registered inproc\n", xclsid);
1571 hres = REGDB_E_CLASSNOTREG;
1573 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1574 /* failure: DLL could not be loaded */
1575 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1576 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1577 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1578 /* failure: the dll did not export DllGetClassObject */
1579 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1580 FreeLibrary( hLibrary );
1581 hres = CO_E_DLLNOTFOUND;
1583 /* OK: get the ClassObject */
1584 COMPOBJ_DLLList_Add( hLibrary );
1585 return DllGetClassObject(rclsid, iid, ppv);
1590 /* Next try out of process */
1591 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1593 return create_marshalled_proxy(rclsid,iid,ppv);
1596 /* Finally try remote: this requires networked DCOM (a lot of work) */
1597 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1599 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1600 hres = E_NOINTERFACE;
1605 /***********************************************************************
1606 * CoResumeClassObjects (OLE32.@)
1608 * Resumes all class objects registered with REGCLS_SUSPENDED.
1612 * Failure: HRESULT code.
1614 HRESULT WINAPI CoResumeClassObjects(void)
1620 /***********************************************************************
1621 * GetClassFile (OLE32.@)
1623 * This function supplies the CLSID associated with the given filename.
1625 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1629 int nbElm, length, i;
1631 LPOLESTR *pathDec=0,absFile=0,progId=0;
1633 static const WCHAR bkslashW[] = {'\\',0};
1634 static const WCHAR dotW[] = {'.',0};
1636 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1638 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1639 if((StgIsStorageFile(filePathName))==S_OK){
1641 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1644 res=ReadClassStg(pstg,pclsid);
1646 IStorage_Release(pstg);
1650 /* if the file is not a storage object then attemps to match various bits in the file against a
1651 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1654 for(i=0;i<nFileTypes;i++)
1656 for(i=0;j<nPatternsForType;j++){
1661 pat=ReadPatternFromRegistry(i,j);
1662 hFile=CreateFileW(filePathName,,,,,,hFile);
1663 SetFilePosition(hFile,pat.offset);
1664 ReadFile(hFile,buf,pat.size,&r,NULL);
1665 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1667 *pclsid=ReadCLSIDFromRegistry(i);
1673 /* if the above strategies fail then search for the extension key in the registry */
1675 /* get the last element (absolute file) in the path name */
1676 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1677 absFile=pathDec[nbElm-1];
1679 /* failed if the path represente a directory and not an absolute file name*/
1680 if (!lstrcmpW(absFile, bkslashW))
1681 return MK_E_INVALIDEXTENSION;
1683 /* get the extension of the file */
1685 length=lstrlenW(absFile);
1686 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1689 if (!extension || !lstrcmpW(extension, dotW))
1690 return MK_E_INVALIDEXTENSION;
1692 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1694 /* get the progId associated to the extension */
1695 progId = CoTaskMemAlloc(sizeProgId);
1696 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1698 if (res==ERROR_SUCCESS)
1699 /* return the clsid associated to the progId */
1700 res= CLSIDFromProgID(progId,pclsid);
1702 for(i=0; pathDec[i]!=NULL;i++)
1703 CoTaskMemFree(pathDec[i]);
1704 CoTaskMemFree(pathDec);
1706 CoTaskMemFree(progId);
1708 if (res==ERROR_SUCCESS)
1711 return MK_E_INVALIDEXTENSION;
1713 /***********************************************************************
1714 * CoCreateInstance [COMPOBJ.13]
1715 * CoCreateInstance [OLE32.@]
1717 HRESULT WINAPI CoCreateInstance(
1719 LPUNKNOWN pUnkOuter,
1725 LPCLASSFACTORY lpclf = 0;
1727 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1736 * Initialize the "out" parameter
1741 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1742 * Rather than create a class factory, we can just check for it here
1744 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1745 if (StdGlobalInterfaceTableInstance == NULL)
1746 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1747 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1748 if (hres) return hres;
1750 TRACE("Retrieved GIT (%p)\n", *ppv);
1755 * Get a class factory to construct the object we want.
1757 hres = CoGetClassObject(rclsid,
1764 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1765 debugstr_guid(rclsid),hres);
1770 * Create the object and don't forget to release the factory
1772 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1773 IClassFactory_Release(lpclf);
1775 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1776 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1781 /***********************************************************************
1782 * CoCreateInstanceEx [OLE32.@]
1784 HRESULT WINAPI CoCreateInstanceEx(
1786 LPUNKNOWN pUnkOuter,
1788 COSERVERINFO* pServerInfo,
1792 IUnknown* pUnk = NULL;
1795 ULONG successCount = 0;
1800 if ( (cmq==0) || (pResults==NULL))
1801 return E_INVALIDARG;
1803 if (pServerInfo!=NULL)
1804 FIXME("() non-NULL pServerInfo not supported!\n");
1807 * Initialize all the "out" parameters.
1809 for (index = 0; index < cmq; index++)
1811 pResults[index].pItf = NULL;
1812 pResults[index].hr = E_NOINTERFACE;
1816 * Get the object and get its IUnknown pointer.
1818 hr = CoCreateInstance(rclsid,
1828 * Then, query for all the interfaces requested.
1830 for (index = 0; index < cmq; index++)
1832 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1833 pResults[index].pIID,
1834 (VOID**)&(pResults[index].pItf));
1836 if (pResults[index].hr == S_OK)
1841 * Release our temporary unknown pointer.
1843 IUnknown_Release(pUnk);
1845 if (successCount == 0)
1846 return E_NOINTERFACE;
1848 if (successCount!=cmq)
1849 return CO_S_NOTALLINTERFACES;
1854 /***********************************************************************
1855 * CoLoadLibrary (OLE32.@)
1860 * lpszLibName [I] Path to library.
1861 * bAutoFree [I] Whether the library should automatically be freed.
1864 * Success: Handle to loaded library.
1868 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1870 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1872 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1874 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1877 /***********************************************************************
1878 * CoFreeLibrary [OLE32.@]
1880 * Unloads a library from memory.
1883 * hLibrary [I] Handle to library to unload.
1889 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1891 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1893 FreeLibrary(hLibrary);
1897 /***********************************************************************
1898 * CoFreeAllLibraries [OLE32.@]
1900 * Function for backwards compatibility only. Does nothing.
1906 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1908 void WINAPI CoFreeAllLibraries(void)
1914 /***********************************************************************
1915 * CoFreeUnusedLibraries [OLE32.@]
1916 * CoFreeUnusedLibraries [COMPOBJ.17]
1918 * Frees any unused libraries. Unused are identified as those that return
1919 * S_OK from their DllCanUnloadNow function.
1925 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1927 void WINAPI CoFreeUnusedLibraries(void)
1929 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1930 * through the main apartment's thread to call DllCanUnloadNow */
1931 COMPOBJ_DllList_FreeUnused(0);
1934 /***********************************************************************
1935 * CoFileTimeNow [OLE32.@]
1936 * CoFileTimeNow [COMPOBJ.82]
1938 * Retrieves the current time in FILETIME format.
1941 * lpFileTime [O] The current time.
1946 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1948 GetSystemTimeAsFileTime( lpFileTime );
1952 static void COM_RevokeAllClasses()
1954 EnterCriticalSection( &csRegisteredClassList );
1956 while (firstRegisteredClass!=0)
1958 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1961 LeaveCriticalSection( &csRegisteredClassList );
1964 /****************************************************************************
1965 * COM External Lock methods implementation
1967 * This api provides a linked list to managed external references to
1970 * The public interface consists of three calls:
1971 * COM_ExternalLockAddRef
1972 * COM_ExternalLockRelease
1973 * COM_ExternalLockFreeList
1976 #define EL_END_OF_LIST 0
1977 #define EL_NOT_FOUND 0
1980 * Declaration of the static structure that manage the
1981 * external lock to COM objects.
1983 typedef struct COM_ExternalLock COM_ExternalLock;
1984 typedef struct COM_ExternalLockList COM_ExternalLockList;
1986 struct COM_ExternalLock
1988 IUnknown *pUnk; /* IUnknown referenced */
1989 ULONG uRefCount; /* external lock counter to IUnknown object*/
1990 COM_ExternalLock *next; /* Pointer to next element in list */
1993 struct COM_ExternalLockList
1995 COM_ExternalLock *head; /* head of list */
1999 * Declaration and initialization of the static structure that manages
2000 * the external lock to COM objects.
2002 static COM_ExternalLockList elList = { EL_END_OF_LIST };
2005 * Private methods used to managed the linked list
2009 static COM_ExternalLock* COM_ExternalLockLocate(
2010 COM_ExternalLock *element,
2013 /****************************************************************************
2014 * Internal - Insert a new IUnknown* to the linked list
2016 static BOOL COM_ExternalLockInsert(
2019 COM_ExternalLock *newLock = NULL;
2020 COM_ExternalLock *previousHead = NULL;
2023 * Allocate space for the new storage object
2025 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
2027 if (newLock!=NULL) {
2028 if ( elList.head == EL_END_OF_LIST ) {
2029 elList.head = newLock; /* The list is empty */
2031 /* insert does it at the head */
2032 previousHead = elList.head;
2033 elList.head = newLock;
2036 /* Set new list item data member */
2037 newLock->pUnk = pUnk;
2038 newLock->uRefCount = 1;
2039 newLock->next = previousHead;
2046 /****************************************************************************
2047 * Internal - Method that removes an item from the linked list.
2049 static void COM_ExternalLockDelete(
2050 COM_ExternalLock *itemList)
2052 COM_ExternalLock *current = elList.head;
2054 if ( current == itemList ) {
2055 /* this section handles the deletion of the first node */
2056 elList.head = itemList->next;
2057 HeapFree( GetProcessHeap(), 0, itemList);
2060 if ( current->next == itemList ){ /* We found the item to free */
2061 current->next = itemList->next; /* readjust the list pointers */
2062 HeapFree( GetProcessHeap(), 0, itemList);
2066 /* Skip to the next item */
2067 current = current->next;
2069 } while ( current != EL_END_OF_LIST );
2073 /****************************************************************************
2074 * Internal - Recursivity agent for IUnknownExternalLockList_Find
2076 * NOTES: how long can the list be ?? (recursive!!!)
2078 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
2080 if ( element == EL_END_OF_LIST )
2081 return EL_NOT_FOUND;
2082 else if ( element->pUnk == pUnk ) /* We found it */
2084 else /* Not the right guy, keep on looking */
2085 return COM_ExternalLockLocate( element->next, pUnk);
2088 /****************************************************************************
2089 * Public - Method that increments the count for a IUnknown* in the linked
2090 * list. The item is inserted if not already in the list.
2092 static void COM_ExternalLockAddRef(IUnknown *pUnk)
2094 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2097 * Add an external lock to the object. If it was already externally
2098 * locked, just increase the reference count. If it was not.
2099 * add the item to the list.
2101 if ( externalLock == EL_NOT_FOUND )
2102 COM_ExternalLockInsert(pUnk);
2104 externalLock->uRefCount++;
2107 * Add an internal lock to the object
2109 IUnknown_AddRef(pUnk);
2112 /****************************************************************************
2113 * Public - Method that decrements the count for a IUnknown* in the linked
2114 * list. The item is removed from the list if its count end up at zero or if
2117 static void COM_ExternalLockRelease(
2121 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2123 if ( externalLock != EL_NOT_FOUND ) {
2125 externalLock->uRefCount--; /* release external locks */
2126 IUnknown_Release(pUnk); /* release local locks as well */
2128 if ( bRelAll == FALSE ) break; /* perform single release */
2130 } while ( externalLock->uRefCount > 0 );
2132 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
2133 COM_ExternalLockDelete(externalLock);
2136 /****************************************************************************
2137 * Public - Method that frees the content of the list.
2139 static void COM_ExternalLockFreeList()
2141 COM_ExternalLock *head;
2143 head = elList.head; /* grab it by the head */
2144 while ( head != EL_END_OF_LIST ) {
2145 COM_ExternalLockDelete(head); /* get rid of the head stuff */
2146 head = elList.head; /* get the new head... */
2150 /****************************************************************************
2151 * Public - Method that dump the content of the list.
2153 void COM_ExternalLockDump()
2155 COM_ExternalLock *current = elList.head;
2157 DPRINTF("\nExternal lock list contains:\n");
2159 while ( current != EL_END_OF_LIST ) {
2160 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
2162 /* Skip to the next item */
2163 current = current->next;
2167 /******************************************************************************
2168 * CoLockObjectExternal [OLE32.@]
2170 * Increments or decrements the external reference count of a stub object.
2173 * pUnk [I] Stub object.
2174 * fLock [I] If TRUE then increments the external ref-count,
2175 * otherwise decrements.
2176 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2177 * calling CoDisconnectObject.
2181 * Failure: HRESULT code.
2183 HRESULT WINAPI CoLockObjectExternal(
2184 LPUNKNOWN pUnk, /* */
2185 BOOL fLock, /* [in] do lock */
2186 BOOL fLastUnlockReleases) /* [in] unlock all */
2188 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2189 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2193 * Increment the external lock coutner, COM_ExternalLockAddRef also
2194 * increment the object's internal lock counter.
2196 COM_ExternalLockAddRef( pUnk);
2199 * Decrement the external lock coutner, COM_ExternalLockRelease also
2200 * decrement the object's internal lock counter.
2202 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
2208 /***********************************************************************
2209 * CoInitializeWOW (OLE32.@)
2211 * WOW equivalent of CoInitialize?
2220 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2222 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2226 /***********************************************************************
2227 * CoGetState [OLE32.@]
2229 * Retrieves the thread state object previously stored by CoSetState().
2232 * ppv [I] Address where pointer to object will be stored.
2236 * Failure: E_OUTOFMEMORY.
2239 * Crashes on all invalid ppv addresses, including NULL.
2240 * If the function returns a non-NULL object then the caller must release its
2241 * reference on the object when the object is no longer required.
2246 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2248 struct oletls *info = COM_CurrentInfo();
2249 if (!info) return E_OUTOFMEMORY;
2255 IUnknown_AddRef(info->state);
2257 TRACE("apt->state=%p\n", info->state);
2263 /***********************************************************************
2264 * CoSetState [OLE32.@]
2266 * Sets the thread state object.
2269 * pv [I] Pointer to state object to be stored.
2272 * The system keeps a reference on the object while the object stored.
2276 * Failure: E_OUTOFMEMORY.
2278 HRESULT WINAPI CoSetState(IUnknown * pv)
2280 struct oletls *info = COM_CurrentInfo();
2281 if (!info) return E_OUTOFMEMORY;
2283 if (pv) IUnknown_AddRef(pv);
2287 TRACE("-- release %p now\n", info->state);
2288 IUnknown_Release(info->state);
2297 /******************************************************************************
2298 * OleGetAutoConvert [OLE32.@]
2300 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2308 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2309 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2311 res = REGDB_E_CLASSNOTREG;
2315 /* we can just query for the default value of AutoConvertTo key like that,
2316 without opening the AutoConvertTo key and querying for NULL (default) */
2317 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2319 res = REGDB_E_KEYMISSING;
2322 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2323 CLSIDFromString(wbuf,pClsidNew);
2325 if (hkey) RegCloseKey(hkey);
2329 /******************************************************************************
2330 * CoTreatAsClass [OLE32.@]
2332 * Sets the TreatAs value of a class.
2335 * clsidOld [I] Class to set TreatAs value on.
2336 * clsidNew [I] The class the clsidOld should be treated as.
2340 * Failure: HRESULT code.
2345 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2349 char szClsidNew[39];
2351 char auto_treat_as[39];
2352 LONG auto_treat_as_size = sizeof(auto_treat_as);
2355 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2356 WINE_StringFromCLSID(clsidNew, szClsidNew);
2357 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2359 res = REGDB_E_CLASSNOTREG;
2362 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2364 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2365 !__CLSIDFromStringA(auto_treat_as, &id))
2367 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2369 res = REGDB_E_WRITEREGDB;
2375 RegDeleteKeyA(hkey, "TreatAs");
2379 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2381 res = REGDB_E_WRITEREGDB;
2386 if (hkey) RegCloseKey(hkey);
2390 /******************************************************************************
2391 * CoGetTreatAsClass [OLE32.@]
2393 * Gets the TreatAs value of a class.
2396 * clsidOld [I] Class to get the TreatAs value of.
2397 * clsidNew [I] The class the clsidOld should be treated as.
2401 * Failure: HRESULT code.
2406 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2409 char buf[200], szClsidNew[200];
2411 LONG len = sizeof(szClsidNew);
2413 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2414 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2415 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2417 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2419 res = REGDB_E_CLASSNOTREG;
2422 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2427 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2429 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2431 if (hkey) RegCloseKey(hkey);
2436 /******************************************************************************
2437 * CoGetCurrentProcess [OLE32.@]
2438 * CoGetCurrentProcess [COMPOBJ.34]
2440 * Gets the current process ID.
2443 * The current process ID.
2446 * Is DWORD really the correct return type for this function?
2448 DWORD WINAPI CoGetCurrentProcess(void)
2450 return GetCurrentProcessId();
2453 /******************************************************************************
2454 * CoRegisterMessageFilter [OLE32.@]
2456 * Registers a message filter.
2459 * lpMessageFilter [I] Pointer to interface.
2460 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2464 * Failure: HRESULT code.
2466 HRESULT WINAPI CoRegisterMessageFilter(
2467 LPMESSAGEFILTER lpMessageFilter,
2468 LPMESSAGEFILTER *lplpMessageFilter)
2471 if (lplpMessageFilter) {
2472 *lplpMessageFilter = NULL;
2477 /***********************************************************************
2478 * CoIsOle1Class [OLE32.@]
2480 * Determines whether the specified class an OLE v1 class.
2483 * clsid [I] Class to test.
2486 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2488 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2490 FIXME("%s\n", debugstr_guid(clsid));
2494 /***********************************************************************
2495 * IsEqualGUID [OLE32.@]
2497 * Compares two Unique Identifiers.
2500 * rguid1 [I] The first GUID to compare.
2501 * rguid2 [I] The other GUID to compare.
2507 BOOL WINAPI IsEqualGUID(
2511 return !memcmp(rguid1,rguid2,sizeof(GUID));
2514 /***********************************************************************
2515 * CoInitializeSecurity [OLE32.@]
2517 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2518 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2519 void* pReserved1, DWORD dwAuthnLevel,
2520 DWORD dwImpLevel, void* pReserved2,
2521 DWORD dwCapabilities, void* pReserved3)
2523 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2524 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2525 dwCapabilities, pReserved3);
2529 /***********************************************************************
2530 * CoSuspendClassObjects [OLE32.@]
2532 * Suspends all registered class objects to prevent further requests coming in
2533 * for those objects.
2537 * Failure: HRESULT code.
2539 HRESULT WINAPI CoSuspendClassObjects(void)
2545 /***********************************************************************
2546 * CoAddRefServerProcess [OLE32.@]
2548 * Helper function for incrementing the reference count of a local-server
2552 * New reference count.
2554 ULONG WINAPI CoAddRefServerProcess(void)
2560 /***********************************************************************
2561 * CoReleaseServerProcess [OLE32.@]
2563 * Helper function for decrementing the reference count of a local-server
2567 * New reference count.
2569 ULONG WINAPI CoReleaseServerProcess(void)
2575 /***********************************************************************
2576 * CoQueryProxyBlanket [OLE32.@]
2578 * Retrieves the security settings being used by a proxy.
2581 * pProxy [I] Pointer to the proxy object.
2582 * pAuthnSvc [O] The type of authentication service.
2583 * pAuthzSvc [O] The type of authorization service.
2584 * ppServerPrincName [O] Optional. The server prinicple name.
2585 * pAuthnLevel [O] The authentication level.
2586 * pImpLevel [O] The impersonation level.
2587 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2588 * pCapabilities [O] Flags affecting the security behaviour.
2592 * Failure: HRESULT code.
2595 * CoCopyProxy, CoSetProxyBlanket.
2597 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2598 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2599 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2601 IClientSecurity *pCliSec;
2604 TRACE("%p\n", pProxy);
2606 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2609 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2610 pAuthzSvc, ppServerPrincName,
2611 pAuthnLevel, pImpLevel, ppAuthInfo,
2613 IClientSecurity_Release(pCliSec);
2616 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2620 /***********************************************************************
2621 * CoSetProxyBlanket [OLE32.@]
2623 * Sets the security settings for a proxy.
2626 * pProxy [I] Pointer to the proxy object.
2627 * AuthnSvc [I] The type of authentication service.
2628 * AuthzSvc [I] The type of authorization service.
2629 * pServerPrincName [I] The server prinicple name.
2630 * AuthnLevel [I] The authentication level.
2631 * ImpLevel [I] The impersonation level.
2632 * pAuthInfo [I] Information specific to the authorization/authentication service.
2633 * Capabilities [I] Flags affecting the security behaviour.
2637 * Failure: HRESULT code.
2640 * CoQueryProxyBlanket, CoCopyProxy.
2642 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2643 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2644 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2646 IClientSecurity *pCliSec;
2649 TRACE("%p\n", pProxy);
2651 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2654 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2655 AuthzSvc, pServerPrincName,
2656 AuthnLevel, ImpLevel, pAuthInfo,
2658 IClientSecurity_Release(pCliSec);
2661 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2665 /***********************************************************************
2666 * CoCopyProxy [OLE32.@]
2671 * pProxy [I] Pointer to the proxy object.
2672 * ppCopy [O] Copy of the proxy.
2676 * Failure: HRESULT code.
2679 * CoQueryProxyBlanket, CoSetProxyBlanket.
2681 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2683 IClientSecurity *pCliSec;
2686 TRACE("%p\n", pProxy);
2688 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2691 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2692 IClientSecurity_Release(pCliSec);
2695 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);