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 * - Implement the service control manager (in rpcss) to keep track
35 * of registered class objects: ISCM::ServerRegisterClsid et al
36 * - Implement the OXID resolver so we don't need magic pipe names for
37 * clients and servers to meet up
38 * - Flip our marshalling on top of the RPC runtime transport API,
39 * so we no longer use named pipes to communicate
40 * - Implement RPC thread affinity (should fix InstallShield painting
43 * - Make all ole interface marshaling use NDR to be wire compatible with
45 * - Use & interpret ORPCTHIS & ORPCTHAT.
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
71 #include "wine/unicode.h"
73 #include "ole32_main.h"
74 #include "compobj_private.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(ole);
80 typedef LPCSTR LPCOLESTR16;
82 /****************************************************************************
83 * This section defines variables internal to the COM module.
85 * TODO: Most of these things will have to be made thread-safe.
88 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
89 static void COM_RevokeAllClasses(void);
90 static void COM_ExternalLockFreeList(void);
92 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
94 APARTMENT *MTA; /* protected by csApartment */
95 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
97 static CRITICAL_SECTION csApartment;
98 static CRITICAL_SECTION_DEBUG critsect_debug =
101 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
102 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
104 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
107 * This lock count counts the number of times CoInitialize is called. It is
108 * decreased every time CoUninitialize is called. When it hits 0, the COM
109 * libraries are freed
111 static LONG s_COMLockCount = 0;
114 * This linked list contains the list of registered class objects. These
115 * are mostly used to register the factories for out-of-proc servers of OLE
118 * TODO: Make this data structure aware of inter-process communication. This
119 * means that parts of this will be exported to the Wine Server.
121 typedef struct tagRegisteredClass
123 CLSID classIdentifier;
124 LPUNKNOWN classObject;
128 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
129 struct tagRegisteredClass* nextClass;
132 static RegisteredClass* firstRegisteredClass = NULL;
134 static CRITICAL_SECTION csRegisteredClassList;
135 static CRITICAL_SECTION_DEBUG class_cs_debug =
137 0, 0, &csRegisteredClassList,
138 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
139 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
141 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
143 /*****************************************************************************
144 * This section contains OpenDllList definitions
146 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
147 * other functions that do LoadLibrary _without_ giving back a HMODULE.
148 * Without this list these handles would never be freed.
150 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
151 * next unload-call but not before 600 sec.
154 typedef struct tagOpenDll {
156 struct tagOpenDll *next;
159 static OpenDll *openDllList = NULL; /* linked list of open dlls */
161 static CRITICAL_SECTION csOpenDllList;
162 static CRITICAL_SECTION_DEBUG dll_cs_debug =
164 0, 0, &csOpenDllList,
165 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
166 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
168 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
170 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
171 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
173 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
174 static void COMPOBJ_DllList_FreeUnused(int Timeout);
176 void COMPOBJ_InitProcess( void )
180 /* Dispatching to the correct thread in an apartment is done through
181 * window messages rather than RPC transports. When an interface is
182 * marshalled into another apartment in the same process, a window of the
183 * following class is created. The *caller* of CoMarshalInterface (ie the
184 * application) is responsible for pumping the message loop in that thread.
185 * The WM_USER messages which point to the RPCs are then dispatched to
186 * COM_AptWndProc by the user's code from the apartment in which the interface
189 memset(&wclass, 0, sizeof(wclass));
190 wclass.lpfnWndProc = &COM_AptWndProc;
191 wclass.hInstance = OLE32_hInstance;
192 wclass.lpszClassName = aptWinClass;
193 RegisterClassA(&wclass);
196 void COMPOBJ_UninitProcess( void )
198 UnregisterClassA(aptWinClass, OLE32_hInstance);
201 void COM_TlsDestroy()
203 struct oletls *info = NtCurrentTeb()->ReservedForOle;
206 if (info->apt) COM_ApartmentRelease(info->apt);
207 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
208 if (info->state) IUnknown_Release(info->state);
209 HeapFree(GetProcessHeap(), 0, info);
210 NtCurrentTeb()->ReservedForOle = NULL;
214 /******************************************************************************
218 /* allocates memory and fills in the necessary fields for a new apartment
220 static APARTMENT *apartment_construct(DWORD model)
224 TRACE("creating new apartment, model=%ld\n", model);
226 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
227 apt->tid = GetCurrentThreadId();
228 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
229 GetCurrentProcess(), &apt->thread,
230 THREAD_ALL_ACCESS, FALSE, 0);
232 list_init(&apt->proxies);
233 list_init(&apt->stubmgrs);
236 apt->remunk_exported = FALSE;
238 InitializeCriticalSection(&apt->cs);
242 if (model & COINIT_APARTMENTTHREADED)
244 /* FIXME: should be randomly generated by in an RPC call to rpcss */
245 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
246 apt->win = CreateWindowA(aptWinClass, NULL, 0,
248 0, 0, OLE32_hInstance, NULL);
252 /* FIXME: should be randomly generated by in an RPC call to rpcss */
253 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
256 apt->shutdown_event = CreateEventW(NULL, TRUE, FALSE, NULL);
258 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
260 /* the locking here is not currently needed for the MTA case, but it
261 * doesn't hurt and makes the code simpler */
262 EnterCriticalSection(&csApartment);
263 list_add_head(&apts, &apt->entry);
264 LeaveCriticalSection(&csApartment);
269 /* gets and existing apartment if one exists or otherwise creates an apartment
270 * structure which stores OLE apartment-local information and stores a pointer
271 * to it in the thread-local storage */
272 static APARTMENT *get_or_create_apartment(DWORD model)
274 APARTMENT *apt = COM_CurrentApt();
278 if (model & COINIT_APARTMENTTHREADED)
280 apt = apartment_construct(model);
281 COM_CurrentInfo()->apt = apt;
285 EnterCriticalSection(&csApartment);
287 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
288 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
292 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
293 COM_ApartmentAddRef(MTA);
296 MTA = apartment_construct(model);
299 COM_CurrentInfo()->apt = apt;
301 LeaveCriticalSection(&csApartment);
308 DWORD COM_ApartmentAddRef(struct apartment *apt)
310 DWORD refs = InterlockedIncrement(&apt->refs);
311 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
315 DWORD COM_ApartmentRelease(struct apartment *apt)
319 EnterCriticalSection(&csApartment);
321 ret = InterlockedDecrement(&apt->refs);
322 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
323 /* destruction stuff that needs to happen under csApartment CS */
326 if (apt == MTA) MTA = NULL;
327 list_remove(&apt->entry);
330 LeaveCriticalSection(&csApartment);
334 struct list *cursor, *cursor2;
336 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
338 MARSHAL_Disconnect_Proxies(apt);
340 if (apt->win) DestroyWindow(apt->win);
342 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
344 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
345 /* release the implicit reference given by the fact that the
346 * stub has external references (it must do since it is in the
347 * stub manager list in the apartment and all non-apartment users
348 * must have a ref on the apartment and so it cannot be destroyed).
350 stub_manager_int_release(stubmgr);
353 /* if this assert fires, then another thread took a reference to a
354 * stub manager without taking a reference to the containing
355 * apartment, which it must do. */
356 assert(list_empty(&apt->stubmgrs));
358 if (apt->filter) IUnknown_Release(apt->filter);
360 DeleteCriticalSection(&apt->cs);
361 SetEvent(apt->shutdown_event);
362 CloseHandle(apt->shutdown_event);
363 CloseHandle(apt->thread);
364 HeapFree(GetProcessHeap(), 0, apt);
370 /* The given OXID must be local to this process: you cannot use
371 * apartment windows to send RPCs to other processes. This all needs
374 * The ref parameter is here mostly to ensure people remember that
375 * they get one, you should normally take a ref for thread safety.
377 APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
379 APARTMENT *result = NULL;
382 EnterCriticalSection(&csApartment);
383 LIST_FOR_EACH( cursor, &apts )
385 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
386 if (apt->oxid == oxid)
389 if (ref) COM_ApartmentAddRef(result);
393 LeaveCriticalSection(&csApartment);
398 /* gets the apartment which has a given creator thread ID. The caller must
399 * release the reference from the apartment as soon as the apartment pointer
400 * is no longer required. */
401 APARTMENT *COM_ApartmentFromTID(DWORD tid)
403 APARTMENT *result = NULL;
406 EnterCriticalSection(&csApartment);
407 LIST_FOR_EACH( cursor, &apts )
409 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
413 COM_ApartmentAddRef(result);
417 LeaveCriticalSection(&csApartment);
422 HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
426 apt = COM_ApartmentFromOXID(oxid, ref);
427 if (!apt) return NULL;
432 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
433 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
435 return DefWindowProcA(hWnd, msg, wParam, lParam);
438 /*****************************************************************************
439 * This section contains OpenDllList implemantation
442 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
449 EnterCriticalSection( &csOpenDllList );
451 if (openDllList == NULL) {
452 /* empty list -- add first node */
453 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
454 openDllList->hLibrary=hLibrary;
455 openDllList->next = NULL;
457 /* search for this dll */
459 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
460 if (ptr->hLibrary == hLibrary) {
466 /* dll not found, add it */
468 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
469 openDllList->hLibrary = hLibrary;
470 openDllList->next = tmp;
474 LeaveCriticalSection( &csOpenDllList );
477 static void COMPOBJ_DllList_FreeUnused(int Timeout)
479 OpenDll *curr, *next, *prev = NULL;
480 typedef HRESULT(*DllCanUnloadNowFunc)(void);
481 DllCanUnloadNowFunc DllCanUnloadNow;
485 EnterCriticalSection( &csOpenDllList );
487 for (curr = openDllList; curr != NULL; ) {
488 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
490 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
493 TRACE("freeing %p\n", curr->hLibrary);
494 FreeLibrary(curr->hLibrary);
496 HeapFree(GetProcessHeap(), 0, curr);
497 if (curr == openDllList) {
510 LeaveCriticalSection( &csOpenDllList );
513 /******************************************************************************
514 * CoBuildVersion [OLE32.@]
515 * CoBuildVersion [COMPOBJ.1]
517 * Gets the build version of the DLL.
522 * Current build version, hiword is majornumber, loword is minornumber
524 DWORD WINAPI CoBuildVersion(void)
526 TRACE("Returning version %d, build %d.\n", rmm, rup);
527 return (rmm<<16)+rup;
530 /******************************************************************************
531 * CoInitialize [OLE32.@]
533 * Initializes the COM libraries by calling CoInitializeEx with
534 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
537 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
540 * Success: S_OK if not already initialized, S_FALSE otherwise.
541 * Failure: HRESULT code.
546 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
549 * Just delegate to the newer method.
551 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
554 /******************************************************************************
555 * CoInitializeEx [OLE32.@]
557 * Initializes the COM libraries.
560 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
561 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
564 * S_OK if successful,
565 * S_FALSE if this function was called already.
566 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
571 * The behavior used to set the IMalloc used for memory management is
573 * The dwCoInit parameter must specify of of the following apartment
575 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
576 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
577 * The parameter may also specify zero or more of the following flags:
578 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
579 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
584 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
589 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
591 if (lpReserved!=NULL)
593 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
597 * Check the lock count. If this is the first time going through the initialize
598 * process, we have to initialize the libraries.
600 * And crank-up that lock count.
602 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
605 * Initialize the various COM libraries and data structures.
607 TRACE("() - Initializing the COM libraries\n");
609 /* we may need to defer this until after apartment initialisation */
610 RunningObjectTableImpl_Initialize();
613 if (!(apt = COM_CurrentInfo()->apt))
615 apt = get_or_create_apartment(dwCoInit);
616 if (!apt) return E_OUTOFMEMORY;
618 else if (dwCoInit != apt->model)
620 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
621 code then we are probably using the wrong threading model to implement that API. */
622 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
623 return RPC_E_CHANGED_MODE;
628 COM_CurrentInfo()->inits++;
633 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
634 pending RPCs are ignored. Non-COM messages are discarded at this point.
636 void COM_FlushMessageQueue(void)
639 APARTMENT *apt = COM_CurrentApt();
641 if (!apt || !apt->win) return;
643 TRACE("Flushing STA message queue\n");
645 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
647 if (message.hwnd != apt->win)
649 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
653 TranslateMessage(&message);
654 DispatchMessageA(&message);
658 /***********************************************************************
659 * CoUninitialize [OLE32.@]
661 * This method will decrement the refcount on the current apartment, freeing
662 * the resources associated with it if it is the last thread in the apartment.
663 * If the last apartment is freed, the function will additionally release
664 * any COM resources associated with the process.
674 void WINAPI CoUninitialize(void)
676 struct oletls * info = COM_CurrentInfo();
681 /* will only happen on OOM */
687 ERR("Mismatched CoUninitialize\n");
693 COM_ApartmentRelease(info->apt);
698 * Decrease the reference count.
699 * If we are back to 0 locks on the COM library, make sure we free
700 * all the associated data structures.
702 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
705 TRACE("() - Releasing the COM libraries\n");
707 RunningObjectTableImpl_UnInitialize();
709 /* Release the references to the registered class objects */
710 COM_RevokeAllClasses();
712 /* This will free the loaded COM Dlls */
713 CoFreeAllLibraries();
715 /* This will free list of external references to COM objects */
716 COM_ExternalLockFreeList();
718 /* This ensures we deal with any pending RPCs */
719 COM_FlushMessageQueue();
721 else if (lCOMRefCnt<1) {
722 ERR( "CoUninitialize() - not CoInitialized.\n" );
723 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
727 /******************************************************************************
728 * CoDisconnectObject [OLE32.@]
729 * CoDisconnectObject [COMPOBJ.15]
731 * Disconnects all connections to this object from remote processes. Dispatches
732 * pending RPCs while blocking new RPCs from occurring, and then calls
733 * IMarshal::DisconnectObject on the given object.
735 * Typically called when the object server is forced to shut down, for instance by
739 * lpUnk [I] The object whose stub should be disconnected.
740 * reserved [I] Reserved. Should be set to 0.
744 * Failure: HRESULT code.
747 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
749 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
751 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
755 /******************************************************************************
756 * CoCreateGuid [OLE32.@]
758 * Simply forwards to UuidCreate in RPCRT4.
761 * pguid [O] Points to the GUID to initialize.
765 * Failure: HRESULT code.
770 HRESULT WINAPI CoCreateGuid(GUID *pguid)
772 return UuidCreate(pguid);
775 /******************************************************************************
776 * CLSIDFromString [OLE32.@]
777 * IIDFromString [OLE32.@]
779 * Converts a unique identifier from its string representation into
783 * idstr [I] The string representation of the GUID.
784 * id [O] GUID converted from the string.
788 * CO_E_CLASSSTRING if idstr is not a valid CLSID
792 * In Windows, if idstr is not a valid CLSID string then it gets
793 * treated as a ProgID. Wine currently doesn't do this. If idstr is
794 * NULL it's treated as an all-zero GUID.
799 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
801 const BYTE *s = (const BYTE *) idstr;
806 s = "{00000000-0000-0000-0000-000000000000}";
807 else { /* validate the CLSID string */
810 return CO_E_CLASSSTRING;
812 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
813 return CO_E_CLASSSTRING;
815 for (i=1; i<37; i++) {
816 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
817 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
818 ((s[i] >= 'a') && (s[i] <= 'f')) ||
819 ((s[i] >= 'A') && (s[i] <= 'F'))))
820 return CO_E_CLASSSTRING;
824 TRACE("%s -> %p\n", s, id);
826 /* quick lookup table */
827 memset(table, 0, 256);
829 for (i = 0; i < 10; i++) {
832 for (i = 0; i < 6; i++) {
833 table['A' + i] = i+10;
834 table['a' + i] = i+10;
837 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
839 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
840 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
841 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
842 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
844 /* these are just sequential bytes */
845 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
846 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
847 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
848 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
849 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
850 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
851 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
852 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
857 /*****************************************************************************/
859 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
864 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
865 return CO_E_CLASSSTRING;
868 ret = __CLSIDFromStringA(xid,id);
869 if(ret != S_OK) { /* It appears a ProgID is also valid */
870 ret = CLSIDFromProgID(idstr, id);
875 /* Converts a GUID into the respective string representation. */
876 HRESULT WINE_StringFromCLSID(
877 const CLSID *id, /* [in] GUID to be converted */
878 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
880 static const char *hex = "0123456789ABCDEF";
885 { ERR("called with id=Null\n");
890 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
891 id->Data1, id->Data2, id->Data3,
892 id->Data4[0], id->Data4[1]);
896 for (i = 2; i < 8; i++) {
897 *s++ = hex[id->Data4[i]>>4];
898 *s++ = hex[id->Data4[i] & 0xf];
904 TRACE("%p->%s\n", id, idstr);
910 /******************************************************************************
911 * StringFromCLSID [OLE32.@]
912 * StringFromIID [OLE32.@]
914 * Converts a GUID into the respective string representation.
915 * The target string is allocated using the OLE IMalloc.
918 * id [I] the GUID to be converted.
919 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
926 * StringFromGUID2, CLSIDFromString
928 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
934 if ((ret = CoGetMalloc(0,&mllc)))
937 ret=WINE_StringFromCLSID(id,buf);
939 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
940 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
941 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
946 /******************************************************************************
947 * StringFromGUID2 [OLE32.@]
948 * StringFromGUID2 [COMPOBJ.76]
950 * Modified version of StringFromCLSID that allows you to specify max
954 * id [I] GUID to convert to string.
955 * str [O] Buffer where the result will be stored.
956 * cmax [I] Size of the buffer in characters.
959 * Success: The length of the resulting string in characters.
962 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
966 if (WINE_StringFromCLSID(id,xguid))
968 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
971 /******************************************************************************
972 * ProgIDFromCLSID [OLE32.@]
974 * Converts a class id into the respective program ID.
977 * clsid [I] Class ID, as found in registry.
978 * lplpszProgID [O] Associated ProgID.
983 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
985 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
987 char strCLSID[50], *buf, *buf2;
993 WINE_StringFromCLSID(clsid, strCLSID);
995 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
996 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
997 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
998 ret = REGDB_E_CLASSNOTREG;
1000 HeapFree(GetProcessHeap(), 0, buf);
1004 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
1006 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
1007 ret = REGDB_E_CLASSNOTREG;
1011 if (CoGetMalloc(0,&mllc))
1012 ret = E_OUTOFMEMORY;
1015 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
1016 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
1017 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
1020 HeapFree(GetProcessHeap(), 0, buf2);
1027 HRESULT WINAPI CLSIDFromProgID16(
1028 LPCOLESTR16 progid, /* [in] program id as found in registry */
1029 LPCLSID riid /* [out] associated CLSID */
1036 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1037 sprintf(buf,"%s\\CLSID",progid);
1038 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1039 HeapFree(GetProcessHeap(),0,buf);
1040 return CO_E_CLASSSTRING;
1042 HeapFree(GetProcessHeap(),0,buf);
1043 buf2len = sizeof(buf2);
1044 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1046 return CO_E_CLASSSTRING;
1049 return __CLSIDFromStringA(buf2,riid);
1052 /******************************************************************************
1053 * CLSIDFromProgID [OLE32.@]
1054 * CLSIDFromProgID [COMPOBJ.61]
1056 * Converts a program id into the respective GUID.
1059 * progid [I] Unicode program ID, as found in registry.
1060 * riid [O] Associated CLSID.
1064 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1066 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1068 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1070 DWORD buf2len = sizeof(buf2);
1073 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1074 strcpyW( buf, progid );
1075 strcatW( buf, clsidW );
1076 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1078 HeapFree(GetProcessHeap(),0,buf);
1079 return CO_E_CLASSSTRING;
1081 HeapFree(GetProcessHeap(),0,buf);
1083 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1086 return CO_E_CLASSSTRING;
1089 return __CLSIDFromStringA(buf2,riid);
1094 /*****************************************************************************
1095 * CoGetPSClsid [OLE32.@]
1097 * Retrieves the CLSID of the proxy/stub factory that implements
1098 * IPSFactoryBuffer for the specified interface.
1101 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1102 * pclsid [O] Where to store returned proxy/stub CLSID.
1107 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1111 * The standard marshaller activates the object with the CLSID
1112 * returned and uses the CreateProxy and CreateStub methods on its
1113 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1116 * CoGetPSClsid determines this CLSID by searching the
1117 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1118 * in the registry and any interface id registered by
1119 * CoRegisterPSClsid within the current process.
1123 * We only search the registry, not ids registered with
1124 * CoRegisterPSClsid.
1125 * Also, native returns S_OK for interfaces with an key in HKCR\Interface, but
1126 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1127 * considered a bug in native unless an application depends on this (unlikely).
1129 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1131 char *buf, buf2[40];
1135 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1137 /* Get the input iid as a string */
1138 WINE_StringFromCLSID(riid, buf2);
1139 /* Allocate memory for the registry key we will construct.
1140 (length of iid string plus constant length of static text */
1141 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1143 return E_OUTOFMEMORY;
1145 /* Construct the registry key we want */
1146 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1148 /* Open the key.. */
1149 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1151 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1152 HeapFree(GetProcessHeap(),0,buf);
1153 return REGDB_E_IIDNOTREG;
1155 HeapFree(GetProcessHeap(),0,buf);
1157 /* ... Once we have the key, query the registry to get the
1158 value of CLSID as a string, and convert it into a
1159 proper CLSID structure to be passed back to the app */
1160 buf2len = sizeof(buf2);
1161 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1164 return REGDB_E_IIDNOTREG;
1168 /* We have the CLSid we want back from the registry as a string, so
1169 lets convert it into a CLSID structure */
1170 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR)
1171 return REGDB_E_IIDNOTREG;
1173 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1179 /***********************************************************************
1180 * WriteClassStm (OLE32.@)
1182 * Writes a CLSID to a stream.
1185 * pStm [I] Stream to write to.
1186 * rclsid [I] CLSID to write.
1190 * Failure: HRESULT code.
1192 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1194 TRACE("(%p,%p)\n",pStm,rclsid);
1197 return E_INVALIDARG;
1199 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1202 /***********************************************************************
1203 * ReadClassStm (OLE32.@)
1205 * Reads a CLSID from a stream.
1208 * pStm [I] Stream to read from.
1209 * rclsid [O] CLSID to read.
1213 * Failure: HRESULT code.
1215 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1220 TRACE("(%p,%p)\n",pStm,pclsid);
1223 return E_INVALIDARG;
1225 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1230 if (nbByte != sizeof(CLSID))
1238 * COM_GetRegisteredClassObject
1240 * This internal method is used to scan the registered class list to
1241 * find a class object.
1244 * rclsid Class ID of the class to find.
1245 * dwClsContext Class context to match.
1246 * ppv [out] returns a pointer to the class object. Complying
1247 * to normal COM usage, this method will increase the
1248 * reference count on this object.
1250 static HRESULT COM_GetRegisteredClassObject(
1255 HRESULT hr = S_FALSE;
1256 RegisteredClass* curClass;
1258 EnterCriticalSection( &csRegisteredClassList );
1266 * Iterate through the whole list and try to match the class ID.
1268 curClass = firstRegisteredClass;
1270 while (curClass != 0)
1273 * Check if we have a match on the class ID.
1275 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1278 * Since we don't do out-of process or DCOM just right away, let's ignore the
1283 * We have a match, return the pointer to the class object.
1285 *ppUnk = curClass->classObject;
1287 IUnknown_AddRef(curClass->classObject);
1294 * Step to the next class in the list.
1296 curClass = curClass->nextClass;
1300 LeaveCriticalSection( &csRegisteredClassList );
1302 * If we get to here, we haven't found our class.
1307 /******************************************************************************
1308 * CoRegisterClassObject [OLE32.@]
1310 * Registers the class object for a given class ID. Servers housed in EXE
1311 * files use this method instead of exporting DllGetClassObject to allow
1312 * other code to connect to their objects.
1315 * rclsid [I] CLSID of the object to register.
1316 * pUnk [I] IUnknown of the object.
1317 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1318 * flags [I] REGCLS flags indicating how connections are made.
1319 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1323 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1324 * CO_E_OBJISREG if the object is already registered. We should not return this.
1327 * CoRevokeClassObject, CoGetClassObject
1330 * MSDN claims that multiple interface registrations are legal, but we
1331 * can't do that with our current implementation.
1333 HRESULT WINAPI CoRegisterClassObject(
1338 LPDWORD lpdwRegister)
1340 RegisteredClass* newClass;
1341 LPUNKNOWN foundObject;
1344 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1345 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1347 if ( (lpdwRegister==0) || (pUnk==0) )
1348 return E_INVALIDARG;
1350 if (!COM_CurrentApt())
1352 ERR("COM was not initialized\n");
1353 return CO_E_NOTINITIALIZED;
1359 * First, check if the class is already registered.
1360 * If it is, this should cause an error.
1362 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1364 IUnknown_Release(foundObject);
1365 return CO_E_OBJISREG;
1368 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1369 if ( newClass == NULL )
1370 return E_OUTOFMEMORY;
1372 EnterCriticalSection( &csRegisteredClassList );
1374 newClass->classIdentifier = *rclsid;
1375 newClass->runContext = dwClsContext;
1376 newClass->connectFlags = flags;
1378 * Use the address of the chain node as the cookie since we are sure it's
1379 * unique. FIXME: not on 64-bit platforms.
1381 newClass->dwCookie = (DWORD)newClass;
1382 newClass->nextClass = firstRegisteredClass;
1385 * Since we're making a copy of the object pointer, we have to increase its
1388 newClass->classObject = pUnk;
1389 IUnknown_AddRef(newClass->classObject);
1391 firstRegisteredClass = newClass;
1392 LeaveCriticalSection( &csRegisteredClassList );
1394 *lpdwRegister = newClass->dwCookie;
1396 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1397 IClassFactory *classfac;
1399 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1400 (LPVOID*)&classfac);
1403 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1405 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1406 IUnknown_Release(classfac);
1409 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1410 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1411 MSHLFLAGS_TABLESTRONG);
1413 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1414 IUnknown_Release(classfac);
1418 IUnknown_Release(classfac);
1420 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1425 /***********************************************************************
1426 * CoRevokeClassObject [OLE32.@]
1428 * Removes a class object from the class registry.
1431 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1435 * Failure: HRESULT code.
1438 * CoRegisterClassObject
1440 HRESULT WINAPI CoRevokeClassObject(
1443 HRESULT hr = E_INVALIDARG;
1444 RegisteredClass** prevClassLink;
1445 RegisteredClass* curClass;
1447 TRACE("(%08lx)\n",dwRegister);
1449 EnterCriticalSection( &csRegisteredClassList );
1452 * Iterate through the whole list and try to match the cookie.
1454 curClass = firstRegisteredClass;
1455 prevClassLink = &firstRegisteredClass;
1457 while (curClass != 0)
1460 * Check if we have a match on the cookie.
1462 if (curClass->dwCookie == dwRegister)
1465 * Remove the class from the chain.
1467 *prevClassLink = curClass->nextClass;
1470 * Release the reference to the class object.
1472 IUnknown_Release(curClass->classObject);
1474 if (curClass->pMarshaledData)
1477 memset(&zero, 0, sizeof(zero));
1478 /* FIXME: stop local server thread */
1479 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1480 CoReleaseMarshalData(curClass->pMarshaledData);
1484 * Free the memory used by the chain node.
1486 HeapFree(GetProcessHeap(), 0, curClass);
1493 * Step to the next class in the list.
1495 prevClassLink = &(curClass->nextClass);
1496 curClass = curClass->nextClass;
1500 LeaveCriticalSection( &csRegisteredClassList );
1502 * If we get to here, we haven't found our class.
1507 /***********************************************************************
1508 * compobj_RegReadPath [internal]
1510 * Reads a registry value and expands it when necessary
1512 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1518 DWORD dwLength = dstlen;
1520 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1521 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1522 if (keytype == REG_EXPAND_SZ) {
1523 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1525 lstrcpynA(dst, src, dstlen);
1533 /***********************************************************************
1534 * CoGetClassObject [COMPOBJ.7]
1535 * CoGetClassObject [OLE32.@]
1537 * FIXME. If request allows of several options and there is a failure
1538 * with one (other than not being registered) do we try the
1539 * others or return failure? (E.g. inprocess is registered but
1540 * the DLL is not found but the server version works)
1542 HRESULT WINAPI CoGetClassObject(
1543 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1544 REFIID iid, LPVOID *ppv
1546 LPUNKNOWN regClassObject;
1547 HRESULT hres = E_UNEXPECTED;
1550 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1551 DllGetClassObjectFunc DllGetClassObject;
1553 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1555 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1558 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1559 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1563 * First, try and see if we can't match the class ID with one of the
1564 * registered classes.
1566 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1569 * Get the required interface from the retrieved pointer.
1571 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1574 * Since QI got another reference on the pointer, we want to release the
1575 * one we already have. If QI was unsuccessful, this will release the object. This
1576 * is good since we are not returning it in the "out" parameter.
1578 IUnknown_Release(regClassObject);
1583 /* first try: in-process */
1584 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1585 char keyname[MAX_PATH];
1586 char dllpath[MAX_PATH+1];
1588 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1590 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1591 /* failure: CLSID is not found in registry */
1592 WARN("class %s not registered inproc\n", xclsid);
1593 hres = REGDB_E_CLASSNOTREG;
1595 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1596 /* failure: DLL could not be loaded */
1597 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1598 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1599 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1600 /* failure: the dll did not export DllGetClassObject */
1601 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1602 FreeLibrary( hLibrary );
1603 hres = CO_E_DLLNOTFOUND;
1605 /* OK: get the ClassObject */
1606 COMPOBJ_DLLList_Add( hLibrary );
1607 return DllGetClassObject(rclsid, iid, ppv);
1612 /* Next try out of process */
1613 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1615 return create_marshalled_proxy(rclsid,iid,ppv);
1618 /* Finally try remote: this requires networked DCOM (a lot of work) */
1619 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1621 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1622 hres = E_NOINTERFACE;
1627 /***********************************************************************
1628 * CoResumeClassObjects (OLE32.@)
1630 * Resumes all class objects registered with REGCLS_SUSPENDED.
1634 * Failure: HRESULT code.
1636 HRESULT WINAPI CoResumeClassObjects(void)
1642 /***********************************************************************
1643 * GetClassFile (OLE32.@)
1645 * This function supplies the CLSID associated with the given filename.
1647 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1651 int nbElm, length, i;
1653 LPOLESTR *pathDec=0,absFile=0,progId=0;
1655 static const WCHAR bkslashW[] = {'\\',0};
1656 static const WCHAR dotW[] = {'.',0};
1658 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1660 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1661 if((StgIsStorageFile(filePathName))==S_OK){
1663 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1666 res=ReadClassStg(pstg,pclsid);
1668 IStorage_Release(pstg);
1672 /* if the file is not a storage object then attemps to match various bits in the file against a
1673 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1676 for(i=0;i<nFileTypes;i++)
1678 for(i=0;j<nPatternsForType;j++){
1683 pat=ReadPatternFromRegistry(i,j);
1684 hFile=CreateFileW(filePathName,,,,,,hFile);
1685 SetFilePosition(hFile,pat.offset);
1686 ReadFile(hFile,buf,pat.size,&r,NULL);
1687 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1689 *pclsid=ReadCLSIDFromRegistry(i);
1695 /* if the above strategies fail then search for the extension key in the registry */
1697 /* get the last element (absolute file) in the path name */
1698 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1699 absFile=pathDec[nbElm-1];
1701 /* failed if the path represente a directory and not an absolute file name*/
1702 if (!lstrcmpW(absFile, bkslashW))
1703 return MK_E_INVALIDEXTENSION;
1705 /* get the extension of the file */
1707 length=lstrlenW(absFile);
1708 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1711 if (!extension || !lstrcmpW(extension, dotW))
1712 return MK_E_INVALIDEXTENSION;
1714 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1716 /* get the progId associated to the extension */
1717 progId = CoTaskMemAlloc(sizeProgId);
1718 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1720 if (res==ERROR_SUCCESS)
1721 /* return the clsid associated to the progId */
1722 res= CLSIDFromProgID(progId,pclsid);
1724 for(i=0; pathDec[i]!=NULL;i++)
1725 CoTaskMemFree(pathDec[i]);
1726 CoTaskMemFree(pathDec);
1728 CoTaskMemFree(progId);
1730 if (res==ERROR_SUCCESS)
1733 return MK_E_INVALIDEXTENSION;
1735 /***********************************************************************
1736 * CoCreateInstance [COMPOBJ.13]
1737 * CoCreateInstance [OLE32.@]
1739 HRESULT WINAPI CoCreateInstance(
1741 LPUNKNOWN pUnkOuter,
1747 LPCLASSFACTORY lpclf = 0;
1749 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1758 * Initialize the "out" parameter
1763 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1764 * Rather than create a class factory, we can just check for it here
1766 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1767 if (StdGlobalInterfaceTableInstance == NULL)
1768 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1769 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1770 if (hres) return hres;
1772 TRACE("Retrieved GIT (%p)\n", *ppv);
1777 * Get a class factory to construct the object we want.
1779 hres = CoGetClassObject(rclsid,
1786 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1787 debugstr_guid(rclsid),hres);
1792 * Create the object and don't forget to release the factory
1794 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1795 IClassFactory_Release(lpclf);
1797 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1798 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1803 /***********************************************************************
1804 * CoCreateInstanceEx [OLE32.@]
1806 HRESULT WINAPI CoCreateInstanceEx(
1808 LPUNKNOWN pUnkOuter,
1810 COSERVERINFO* pServerInfo,
1814 IUnknown* pUnk = NULL;
1817 ULONG successCount = 0;
1822 if ( (cmq==0) || (pResults==NULL))
1823 return E_INVALIDARG;
1825 if (pServerInfo!=NULL)
1826 FIXME("() non-NULL pServerInfo not supported!\n");
1829 * Initialize all the "out" parameters.
1831 for (index = 0; index < cmq; index++)
1833 pResults[index].pItf = NULL;
1834 pResults[index].hr = E_NOINTERFACE;
1838 * Get the object and get its IUnknown pointer.
1840 hr = CoCreateInstance(rclsid,
1850 * Then, query for all the interfaces requested.
1852 for (index = 0; index < cmq; index++)
1854 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1855 pResults[index].pIID,
1856 (VOID**)&(pResults[index].pItf));
1858 if (pResults[index].hr == S_OK)
1863 * Release our temporary unknown pointer.
1865 IUnknown_Release(pUnk);
1867 if (successCount == 0)
1868 return E_NOINTERFACE;
1870 if (successCount!=cmq)
1871 return CO_S_NOTALLINTERFACES;
1876 /***********************************************************************
1877 * CoLoadLibrary (OLE32.@)
1882 * lpszLibName [I] Path to library.
1883 * bAutoFree [I] Whether the library should automatically be freed.
1886 * Success: Handle to loaded library.
1890 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1892 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1894 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1896 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1899 /***********************************************************************
1900 * CoFreeLibrary [OLE32.@]
1902 * Unloads a library from memory.
1905 * hLibrary [I] Handle to library to unload.
1911 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1913 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1915 FreeLibrary(hLibrary);
1919 /***********************************************************************
1920 * CoFreeAllLibraries [OLE32.@]
1922 * Function for backwards compatibility only. Does nothing.
1928 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1930 void WINAPI CoFreeAllLibraries(void)
1936 /***********************************************************************
1937 * CoFreeUnusedLibraries [OLE32.@]
1938 * CoFreeUnusedLibraries [COMPOBJ.17]
1940 * Frees any unused libraries. Unused are identified as those that return
1941 * S_OK from their DllCanUnloadNow function.
1947 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1949 void WINAPI CoFreeUnusedLibraries(void)
1951 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1952 * through the main apartment's thread to call DllCanUnloadNow */
1953 COMPOBJ_DllList_FreeUnused(0);
1956 /***********************************************************************
1957 * CoFileTimeNow [OLE32.@]
1958 * CoFileTimeNow [COMPOBJ.82]
1960 * Retrieves the current time in FILETIME format.
1963 * lpFileTime [O] The current time.
1968 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1970 GetSystemTimeAsFileTime( lpFileTime );
1974 static void COM_RevokeAllClasses()
1976 EnterCriticalSection( &csRegisteredClassList );
1978 while (firstRegisteredClass!=0)
1980 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1983 LeaveCriticalSection( &csRegisteredClassList );
1986 /****************************************************************************
1987 * COM External Lock methods implementation
1989 * This api provides a linked list to managed external references to
1992 * The public interface consists of three calls:
1993 * COM_ExternalLockAddRef
1994 * COM_ExternalLockRelease
1995 * COM_ExternalLockFreeList
1998 #define EL_END_OF_LIST 0
1999 #define EL_NOT_FOUND 0
2002 * Declaration of the static structure that manage the
2003 * external lock to COM objects.
2005 typedef struct COM_ExternalLock COM_ExternalLock;
2006 typedef struct COM_ExternalLockList COM_ExternalLockList;
2008 struct COM_ExternalLock
2010 IUnknown *pUnk; /* IUnknown referenced */
2011 ULONG uRefCount; /* external lock counter to IUnknown object*/
2012 COM_ExternalLock *next; /* Pointer to next element in list */
2015 struct COM_ExternalLockList
2017 COM_ExternalLock *head; /* head of list */
2021 * Declaration and initialization of the static structure that manages
2022 * the external lock to COM objects.
2024 static COM_ExternalLockList elList = { EL_END_OF_LIST };
2027 * Private methods used to managed the linked list
2031 static COM_ExternalLock* COM_ExternalLockLocate(
2032 COM_ExternalLock *element,
2035 /****************************************************************************
2036 * Internal - Insert a new IUnknown* to the linked list
2038 static BOOL COM_ExternalLockInsert(
2041 COM_ExternalLock *newLock = NULL;
2042 COM_ExternalLock *previousHead = NULL;
2045 * Allocate space for the new storage object
2047 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
2049 if (newLock!=NULL) {
2050 if ( elList.head == EL_END_OF_LIST ) {
2051 elList.head = newLock; /* The list is empty */
2053 /* insert does it at the head */
2054 previousHead = elList.head;
2055 elList.head = newLock;
2058 /* Set new list item data member */
2059 newLock->pUnk = pUnk;
2060 newLock->uRefCount = 1;
2061 newLock->next = previousHead;
2068 /****************************************************************************
2069 * Internal - Method that removes an item from the linked list.
2071 static void COM_ExternalLockDelete(
2072 COM_ExternalLock *itemList)
2074 COM_ExternalLock *current = elList.head;
2076 if ( current == itemList ) {
2077 /* this section handles the deletion of the first node */
2078 elList.head = itemList->next;
2079 HeapFree( GetProcessHeap(), 0, itemList);
2082 if ( current->next == itemList ){ /* We found the item to free */
2083 current->next = itemList->next; /* readjust the list pointers */
2084 HeapFree( GetProcessHeap(), 0, itemList);
2088 /* Skip to the next item */
2089 current = current->next;
2091 } while ( current != EL_END_OF_LIST );
2095 /****************************************************************************
2096 * Internal - Recursivity agent for IUnknownExternalLockList_Find
2098 * NOTES: how long can the list be ?? (recursive!!!)
2100 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
2102 if ( element == EL_END_OF_LIST )
2103 return EL_NOT_FOUND;
2104 else if ( element->pUnk == pUnk ) /* We found it */
2106 else /* Not the right guy, keep on looking */
2107 return COM_ExternalLockLocate( element->next, pUnk);
2110 /****************************************************************************
2111 * Public - Method that increments the count for a IUnknown* in the linked
2112 * list. The item is inserted if not already in the list.
2114 static void COM_ExternalLockAddRef(IUnknown *pUnk)
2116 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2119 * Add an external lock to the object. If it was already externally
2120 * locked, just increase the reference count. If it was not.
2121 * add the item to the list.
2123 if ( externalLock == EL_NOT_FOUND )
2124 COM_ExternalLockInsert(pUnk);
2126 externalLock->uRefCount++;
2129 * Add an internal lock to the object
2131 IUnknown_AddRef(pUnk);
2134 /****************************************************************************
2135 * Public - Method that decrements the count for a IUnknown* in the linked
2136 * list. The item is removed from the list if its count end up at zero or if
2139 static void COM_ExternalLockRelease(
2143 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2145 if ( externalLock != EL_NOT_FOUND ) {
2147 externalLock->uRefCount--; /* release external locks */
2148 IUnknown_Release(pUnk); /* release local locks as well */
2150 if ( bRelAll == FALSE ) break; /* perform single release */
2152 } while ( externalLock->uRefCount > 0 );
2154 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
2155 COM_ExternalLockDelete(externalLock);
2158 /****************************************************************************
2159 * Public - Method that frees the content of the list.
2161 static void COM_ExternalLockFreeList()
2163 COM_ExternalLock *head;
2165 head = elList.head; /* grab it by the head */
2166 while ( head != EL_END_OF_LIST ) {
2167 COM_ExternalLockDelete(head); /* get rid of the head stuff */
2168 head = elList.head; /* get the new head... */
2172 /****************************************************************************
2173 * Public - Method that dump the content of the list.
2175 void COM_ExternalLockDump()
2177 COM_ExternalLock *current = elList.head;
2179 DPRINTF("\nExternal lock list contains:\n");
2181 while ( current != EL_END_OF_LIST ) {
2182 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
2184 /* Skip to the next item */
2185 current = current->next;
2189 /******************************************************************************
2190 * CoLockObjectExternal [OLE32.@]
2192 * Increments or decrements the external reference count of a stub object.
2195 * pUnk [I] Stub object.
2196 * fLock [I] If TRUE then increments the external ref-count,
2197 * otherwise decrements.
2198 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2199 * calling CoDisconnectObject.
2203 * Failure: HRESULT code.
2205 HRESULT WINAPI CoLockObjectExternal(
2206 LPUNKNOWN pUnk, /* */
2207 BOOL fLock, /* [in] do lock */
2208 BOOL fLastUnlockReleases) /* [in] unlock all */
2210 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2211 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2215 * Increment the external lock coutner, COM_ExternalLockAddRef also
2216 * increment the object's internal lock counter.
2218 COM_ExternalLockAddRef( pUnk);
2221 * Decrement the external lock coutner, COM_ExternalLockRelease also
2222 * decrement the object's internal lock counter.
2224 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
2230 /***********************************************************************
2231 * CoInitializeWOW (OLE32.@)
2233 * WOW equivalent of CoInitialize?
2242 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2244 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2248 /***********************************************************************
2249 * CoGetState [OLE32.@]
2251 * Retrieves the thread state object previously stored by CoSetState().
2254 * ppv [I] Address where pointer to object will be stored.
2258 * Failure: E_OUTOFMEMORY.
2261 * Crashes on all invalid ppv addresses, including NULL.
2262 * If the function returns a non-NULL object then the caller must release its
2263 * reference on the object when the object is no longer required.
2268 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2270 struct oletls *info = COM_CurrentInfo();
2271 if (!info) return E_OUTOFMEMORY;
2277 IUnknown_AddRef(info->state);
2279 TRACE("apt->state=%p\n", info->state);
2285 /***********************************************************************
2286 * CoSetState [OLE32.@]
2288 * Sets the thread state object.
2291 * pv [I] Pointer to state object to be stored.
2294 * The system keeps a reference on the object while the object stored.
2298 * Failure: E_OUTOFMEMORY.
2300 HRESULT WINAPI CoSetState(IUnknown * pv)
2302 struct oletls *info = COM_CurrentInfo();
2303 if (!info) return E_OUTOFMEMORY;
2305 if (pv) IUnknown_AddRef(pv);
2309 TRACE("-- release %p now\n", info->state);
2310 IUnknown_Release(info->state);
2319 /******************************************************************************
2320 * OleGetAutoConvert [OLE32.@]
2322 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2330 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2331 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2333 res = REGDB_E_CLASSNOTREG;
2337 /* we can just query for the default value of AutoConvertTo key like that,
2338 without opening the AutoConvertTo key and querying for NULL (default) */
2339 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2341 res = REGDB_E_KEYMISSING;
2344 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2345 CLSIDFromString(wbuf,pClsidNew);
2347 if (hkey) RegCloseKey(hkey);
2351 /******************************************************************************
2352 * CoTreatAsClass [OLE32.@]
2354 * Sets the TreatAs value of a class.
2357 * clsidOld [I] Class to set TreatAs value on.
2358 * clsidNew [I] The class the clsidOld should be treated as.
2362 * Failure: HRESULT code.
2367 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2371 char szClsidNew[39];
2373 char auto_treat_as[39];
2374 LONG auto_treat_as_size = sizeof(auto_treat_as);
2377 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2378 WINE_StringFromCLSID(clsidNew, szClsidNew);
2379 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2381 res = REGDB_E_CLASSNOTREG;
2384 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2386 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2387 !__CLSIDFromStringA(auto_treat_as, &id))
2389 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2391 res = REGDB_E_WRITEREGDB;
2397 RegDeleteKeyA(hkey, "TreatAs");
2401 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2403 res = REGDB_E_WRITEREGDB;
2408 if (hkey) RegCloseKey(hkey);
2412 /******************************************************************************
2413 * CoGetTreatAsClass [OLE32.@]
2415 * Gets the TreatAs value of a class.
2418 * clsidOld [I] Class to get the TreatAs value of.
2419 * clsidNew [I] The class the clsidOld should be treated as.
2423 * Failure: HRESULT code.
2428 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2431 char buf[200], szClsidNew[200];
2433 LONG len = sizeof(szClsidNew);
2435 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2436 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2437 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2439 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2441 res = REGDB_E_CLASSNOTREG;
2444 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2449 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2451 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2453 if (hkey) RegCloseKey(hkey);
2458 /******************************************************************************
2459 * CoGetCurrentProcess [OLE32.@]
2460 * CoGetCurrentProcess [COMPOBJ.34]
2462 * Gets the current process ID.
2465 * The current process ID.
2468 * Is DWORD really the correct return type for this function?
2470 DWORD WINAPI CoGetCurrentProcess(void)
2472 return GetCurrentProcessId();
2475 /******************************************************************************
2476 * CoRegisterMessageFilter [OLE32.@]
2478 * Registers a message filter.
2481 * lpMessageFilter [I] Pointer to interface.
2482 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2486 * Failure: HRESULT code.
2488 HRESULT WINAPI CoRegisterMessageFilter(
2489 LPMESSAGEFILTER lpMessageFilter,
2490 LPMESSAGEFILTER *lplpMessageFilter)
2493 if (lplpMessageFilter) {
2494 *lplpMessageFilter = NULL;
2499 /***********************************************************************
2500 * CoIsOle1Class [OLE32.@]
2502 * Determines whether the specified class an OLE v1 class.
2505 * clsid [I] Class to test.
2508 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2510 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2512 FIXME("%s\n", debugstr_guid(clsid));
2516 /***********************************************************************
2517 * IsEqualGUID [OLE32.@]
2519 * Compares two Unique Identifiers.
2522 * rguid1 [I] The first GUID to compare.
2523 * rguid2 [I] The other GUID to compare.
2529 BOOL WINAPI IsEqualGUID(
2533 return !memcmp(rguid1,rguid2,sizeof(GUID));
2536 /***********************************************************************
2537 * CoInitializeSecurity [OLE32.@]
2539 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2540 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2541 void* pReserved1, DWORD dwAuthnLevel,
2542 DWORD dwImpLevel, void* pReserved2,
2543 DWORD dwCapabilities, void* pReserved3)
2545 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2546 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2547 dwCapabilities, pReserved3);
2551 /***********************************************************************
2552 * CoSuspendClassObjects [OLE32.@]
2554 * Suspends all registered class objects to prevent further requests coming in
2555 * for those objects.
2559 * Failure: HRESULT code.
2561 HRESULT WINAPI CoSuspendClassObjects(void)
2567 /***********************************************************************
2568 * CoAddRefServerProcess [OLE32.@]
2570 * Helper function for incrementing the reference count of a local-server
2574 * New reference count.
2576 ULONG WINAPI CoAddRefServerProcess(void)
2582 /***********************************************************************
2583 * CoReleaseServerProcess [OLE32.@]
2585 * Helper function for decrementing the reference count of a local-server
2589 * New reference count.
2591 ULONG WINAPI CoReleaseServerProcess(void)
2597 /***********************************************************************
2598 * CoQueryProxyBlanket [OLE32.@]
2600 * Retrieves the security settings being used by a proxy.
2603 * pProxy [I] Pointer to the proxy object.
2604 * pAuthnSvc [O] The type of authentication service.
2605 * pAuthzSvc [O] The type of authorization service.
2606 * ppServerPrincName [O] Optional. The server prinicple name.
2607 * pAuthnLevel [O] The authentication level.
2608 * pImpLevel [O] The impersonation level.
2609 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2610 * pCapabilities [O] Flags affecting the security behaviour.
2614 * Failure: HRESULT code.
2617 * CoCopyProxy, CoSetProxyBlanket.
2619 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2620 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2621 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2623 IClientSecurity *pCliSec;
2626 TRACE("%p\n", pProxy);
2628 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2631 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2632 pAuthzSvc, ppServerPrincName,
2633 pAuthnLevel, pImpLevel, ppAuthInfo,
2635 IClientSecurity_Release(pCliSec);
2638 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2642 /***********************************************************************
2643 * CoSetProxyBlanket [OLE32.@]
2645 * Sets the security settings for a proxy.
2648 * pProxy [I] Pointer to the proxy object.
2649 * AuthnSvc [I] The type of authentication service.
2650 * AuthzSvc [I] The type of authorization service.
2651 * pServerPrincName [I] The server prinicple name.
2652 * AuthnLevel [I] The authentication level.
2653 * ImpLevel [I] The impersonation level.
2654 * pAuthInfo [I] Information specific to the authorization/authentication service.
2655 * Capabilities [I] Flags affecting the security behaviour.
2659 * Failure: HRESULT code.
2662 * CoQueryProxyBlanket, CoCopyProxy.
2664 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2665 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2666 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2668 IClientSecurity *pCliSec;
2671 TRACE("%p\n", pProxy);
2673 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2676 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2677 AuthzSvc, pServerPrincName,
2678 AuthnLevel, ImpLevel, pAuthInfo,
2680 IClientSecurity_Release(pCliSec);
2683 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2687 /***********************************************************************
2688 * CoCopyProxy [OLE32.@]
2693 * pProxy [I] Pointer to the proxy object.
2694 * ppCopy [O] Copy of the proxy.
2698 * Failure: HRESULT code.
2701 * CoQueryProxyBlanket, CoSetProxyBlanket.
2703 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2705 IClientSecurity *pCliSec;
2708 TRACE("%p\n", pProxy);
2710 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2713 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2714 IClientSecurity_Release(pCliSec);
2717 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);