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 /******************************************************************************
209 /* creates an apartment structure which stores OLE apartment-local
211 APARTMENT* COM_CreateApartment(DWORD model)
213 APARTMENT *apt = COM_CurrentApt();
217 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
218 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
221 EnterCriticalSection(&csApartment);
222 if (!(model & COINIT_APARTMENTTHREADED) && MTA) /* See note 1 above */
224 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
226 COM_ApartmentAddRef(apt);
228 LeaveCriticalSection(&csApartment);
230 COM_CurrentInfo()->apt = apt;
234 TRACE("creating new apartment, model=%ld\n", model);
236 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
237 apt->tid = GetCurrentThreadId();
238 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
239 GetCurrentProcess(), &apt->thread,
240 THREAD_ALL_ACCESS, FALSE, 0);
242 list_init(&apt->proxies);
243 list_init(&apt->stubmgrs);
246 apt->remunk_exported = FALSE;
248 InitializeCriticalSection(&apt->cs);
252 if (model & COINIT_APARTMENTTHREADED)
254 /* FIXME: should be randomly generated by in an RPC call to rpcss */
255 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
256 apt->win = CreateWindowA(aptWinClass, NULL, 0,
258 0, 0, OLE32_hInstance, NULL);
262 /* FIXME: should be randomly generated by in an RPC call to rpcss */
263 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
267 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
269 list_add_head(&apts, &apt->entry);
270 LeaveCriticalSection(&csApartment);
272 COM_CurrentInfo()->apt = apt;
278 DWORD COM_ApartmentAddRef(struct apartment *apt)
280 return InterlockedIncrement(&apt->refs);
283 DWORD COM_ApartmentRelease(struct apartment *apt)
287 EnterCriticalSection(&csApartment);
289 ret = InterlockedDecrement(&apt->refs);
290 /* destruction stuff that needs to happen under csApartment CS */
293 if (apt == MTA) MTA = NULL;
294 list_remove(&apt->entry);
297 LeaveCriticalSection(&csApartment);
301 struct list *cursor, *cursor2;
303 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
305 MARSHAL_Disconnect_Proxies(apt);
307 if (apt->win) DestroyWindow(apt->win);
309 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
311 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
312 /* release the implicit reference given by the fact that the
313 * stub has external references (it must do since it is in the
314 * stub manager list in the apartment and all non-apartment users
315 * must have a ref on the apartment and so it cannot be destroyed).
317 stub_manager_int_release(stubmgr);
320 /* if this assert fires, then another thread took a reference to a
321 * stub manager without taking a reference to the containing
322 * apartment, which it must do. */
323 assert(list_empty(&apt->stubmgrs));
325 if (apt->filter) IUnknown_Release(apt->filter);
327 DeleteCriticalSection(&apt->cs);
328 CloseHandle(apt->thread);
329 HeapFree(GetProcessHeap(), 0, apt);
335 /* The given OXID must be local to this process: you cannot use
336 * apartment windows to send RPCs to other processes. This all needs
339 * The ref parameter is here mostly to ensure people remember that
340 * they get one, you should normally take a ref for thread safety.
342 APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
344 APARTMENT *result = NULL;
347 EnterCriticalSection(&csApartment);
348 LIST_FOR_EACH( cursor, &apts )
350 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
351 if (apt->oxid == oxid)
354 if (ref) COM_ApartmentAddRef(result);
358 LeaveCriticalSection(&csApartment);
363 /* gets the apartment which has a given creator thread ID. The caller must
364 * release the reference from the apartment as soon as the apartment pointer
365 * is no longer required. */
366 APARTMENT *COM_ApartmentFromTID(DWORD tid)
368 APARTMENT *result = NULL;
371 EnterCriticalSection(&csApartment);
372 LIST_FOR_EACH( cursor, &apts )
374 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
378 COM_ApartmentAddRef(result);
382 LeaveCriticalSection(&csApartment);
387 HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
391 apt = COM_ApartmentFromOXID(oxid, ref);
392 if (!apt) return NULL;
397 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
398 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
400 return DefWindowProcA(hWnd, msg, wParam, lParam);
403 /*****************************************************************************
404 * This section contains OpenDllList implemantation
407 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
414 EnterCriticalSection( &csOpenDllList );
416 if (openDllList == NULL) {
417 /* empty list -- add first node */
418 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
419 openDllList->hLibrary=hLibrary;
420 openDllList->next = NULL;
422 /* search for this dll */
424 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
425 if (ptr->hLibrary == hLibrary) {
431 /* dll not found, add it */
433 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
434 openDllList->hLibrary = hLibrary;
435 openDllList->next = tmp;
439 LeaveCriticalSection( &csOpenDllList );
442 static void COMPOBJ_DllList_FreeUnused(int Timeout)
444 OpenDll *curr, *next, *prev = NULL;
445 typedef HRESULT(*DllCanUnloadNowFunc)(void);
446 DllCanUnloadNowFunc DllCanUnloadNow;
450 EnterCriticalSection( &csOpenDllList );
452 for (curr = openDllList; curr != NULL; ) {
453 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
455 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
458 TRACE("freeing %p\n", curr->hLibrary);
459 FreeLibrary(curr->hLibrary);
461 HeapFree(GetProcessHeap(), 0, curr);
462 if (curr == openDllList) {
475 LeaveCriticalSection( &csOpenDllList );
478 /******************************************************************************
479 * CoBuildVersion [OLE32.@]
480 * CoBuildVersion [COMPOBJ.1]
482 * Gets the build version of the DLL.
487 * Current build version, hiword is majornumber, loword is minornumber
489 DWORD WINAPI CoBuildVersion(void)
491 TRACE("Returning version %d, build %d.\n", rmm, rup);
492 return (rmm<<16)+rup;
495 /******************************************************************************
496 * CoInitialize [OLE32.@]
498 * Initializes the COM libraries by calling CoInitializeEx with
499 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
502 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
505 * Success: S_OK if not already initialized, S_FALSE otherwise.
506 * Failure: HRESULT code.
511 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
514 * Just delegate to the newer method.
516 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
519 /******************************************************************************
520 * CoInitializeEx [OLE32.@]
522 * Initializes the COM libraries.
525 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
526 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
529 * S_OK if successful,
530 * S_FALSE if this function was called already.
531 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
536 * The behavior used to set the IMalloc used for memory management is
538 * The dwCoInit parameter must specify of of the following apartment
540 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
541 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
542 * The parameter may also specify zero or more of the following flags:
543 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
544 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
549 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
554 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
556 if (lpReserved!=NULL)
558 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
562 * Check the lock count. If this is the first time going through the initialize
563 * process, we have to initialize the libraries.
565 * And crank-up that lock count.
567 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
570 * Initialize the various COM libraries and data structures.
572 TRACE("() - Initializing the COM libraries\n");
574 /* we may need to defer this until after apartment initialisation */
575 RunningObjectTableImpl_Initialize();
578 if (!(apt = COM_CurrentInfo()->apt))
580 apt = COM_CreateApartment(dwCoInit);
581 if (!apt) return E_OUTOFMEMORY;
583 else if (dwCoInit != apt->model)
585 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
586 code then we are probably using the wrong threading model to implement that API. */
587 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
588 COM_ApartmentRelease(apt);
589 return RPC_E_CHANGED_MODE;
594 COM_CurrentInfo()->inits++;
599 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
600 pending RPCs are ignored. Non-COM messages are discarded at this point.
602 void COM_FlushMessageQueue(void)
605 APARTMENT *apt = COM_CurrentApt();
607 if (!apt || !apt->win) return;
609 TRACE("Flushing STA message queue\n");
611 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
613 if (message.hwnd != apt->win)
615 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
619 TranslateMessage(&message);
620 DispatchMessageA(&message);
624 /***********************************************************************
625 * CoUninitialize [OLE32.@]
627 * This method will decrement the refcount on the current apartment, freeing
628 * the resources associated with it if it is the last thread in the apartment.
629 * If the last apartment is freed, the function will additionally release
630 * any COM resources associated with the process.
640 void WINAPI CoUninitialize(void)
642 struct oletls * info = COM_CurrentInfo();
647 /* will only happen on OOM */
653 ERR("Mismatched CoUninitialize\n");
659 COM_ApartmentRelease(info->apt);
664 * Decrease the reference count.
665 * If we are back to 0 locks on the COM library, make sure we free
666 * all the associated data structures.
668 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
671 TRACE("() - Releasing the COM libraries\n");
673 RunningObjectTableImpl_UnInitialize();
675 /* Release the references to the registered class objects */
676 COM_RevokeAllClasses();
678 /* This will free the loaded COM Dlls */
679 CoFreeAllLibraries();
681 /* This will free list of external references to COM objects */
682 COM_ExternalLockFreeList();
684 /* This ensures we deal with any pending RPCs */
685 COM_FlushMessageQueue();
687 else if (lCOMRefCnt<1) {
688 ERR( "CoUninitialize() - not CoInitialized.\n" );
689 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
693 /******************************************************************************
694 * CoDisconnectObject [OLE32.@]
695 * CoDisconnectObject [COMPOBJ.15]
697 * Disconnects all connections to this object from remote processes. Dispatches
698 * pending RPCs while blocking new RPCs from occurring, and then calls
699 * IMarshal::DisconnectObject on the given object.
701 * Typically called when the object server is forced to shut down, for instance by
705 * lpUnk [I] The object whose stub should be disconnected.
706 * reserved [I] Reserved. Should be set to 0.
710 * Failure: HRESULT code.
713 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
715 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
717 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
721 /******************************************************************************
722 * CoCreateGuid [OLE32.@]
724 * Simply forwards to UuidCreate in RPCRT4.
727 * pguid [O] Points to the GUID to initialize.
731 * Failure: HRESULT code.
736 HRESULT WINAPI CoCreateGuid(GUID *pguid)
738 return UuidCreate(pguid);
741 /******************************************************************************
742 * CLSIDFromString [OLE32.@]
743 * IIDFromString [OLE32.@]
745 * Converts a unique identifier from its string representation into
749 * idstr [I] The string representation of the GUID.
750 * id [O] GUID converted from the string.
754 * CO_E_CLASSSTRING if idstr is not a valid CLSID
758 * In Windows, if idstr is not a valid CLSID string then it gets
759 * treated as a ProgID. Wine currently doesn't do this. If idstr is
760 * NULL it's treated as an all-zero GUID.
765 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
767 const BYTE *s = (const BYTE *) idstr;
772 s = "{00000000-0000-0000-0000-000000000000}";
773 else { /* validate the CLSID string */
776 return CO_E_CLASSSTRING;
778 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
779 return CO_E_CLASSSTRING;
781 for (i=1; i<37; i++) {
782 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
783 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
784 ((s[i] >= 'a') && (s[i] <= 'f')) ||
785 ((s[i] >= 'A') && (s[i] <= 'F'))))
786 return CO_E_CLASSSTRING;
790 TRACE("%s -> %p\n", s, id);
792 /* quick lookup table */
793 memset(table, 0, 256);
795 for (i = 0; i < 10; i++) {
798 for (i = 0; i < 6; i++) {
799 table['A' + i] = i+10;
800 table['a' + i] = i+10;
803 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
805 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
806 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
807 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
808 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
810 /* these are just sequential bytes */
811 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
812 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
813 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
814 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
815 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
816 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
817 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
818 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
823 /*****************************************************************************/
825 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
830 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
831 return CO_E_CLASSSTRING;
834 ret = __CLSIDFromStringA(xid,id);
835 if(ret != S_OK) { /* It appears a ProgID is also valid */
836 ret = CLSIDFromProgID(idstr, id);
841 /* Converts a GUID into the respective string representation. */
842 HRESULT WINE_StringFromCLSID(
843 const CLSID *id, /* [in] GUID to be converted */
844 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
846 static const char *hex = "0123456789ABCDEF";
851 { ERR("called with id=Null\n");
856 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
857 id->Data1, id->Data2, id->Data3,
858 id->Data4[0], id->Data4[1]);
862 for (i = 2; i < 8; i++) {
863 *s++ = hex[id->Data4[i]>>4];
864 *s++ = hex[id->Data4[i] & 0xf];
870 TRACE("%p->%s\n", id, idstr);
876 /******************************************************************************
877 * StringFromCLSID [OLE32.@]
878 * StringFromIID [OLE32.@]
880 * Converts a GUID into the respective string representation.
881 * The target string is allocated using the OLE IMalloc.
884 * id [I] the GUID to be converted.
885 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
892 * StringFromGUID2, CLSIDFromString
894 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
900 if ((ret = CoGetMalloc(0,&mllc)))
903 ret=WINE_StringFromCLSID(id,buf);
905 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
906 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
907 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
912 /******************************************************************************
913 * StringFromGUID2 [OLE32.@]
914 * StringFromGUID2 [COMPOBJ.76]
916 * Modified version of StringFromCLSID that allows you to specify max
920 * id [I] GUID to convert to string.
921 * str [O] Buffer where the result will be stored.
922 * cmax [I] Size of the buffer in characters.
925 * Success: The length of the resulting string in characters.
928 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
932 if (WINE_StringFromCLSID(id,xguid))
934 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
937 /******************************************************************************
938 * ProgIDFromCLSID [OLE32.@]
940 * Converts a class id into the respective program ID.
943 * clsid [I] Class ID, as found in registry.
944 * lplpszProgID [O] Associated ProgID.
949 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
951 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
953 char strCLSID[50], *buf, *buf2;
959 WINE_StringFromCLSID(clsid, strCLSID);
961 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
962 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
963 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
964 ret = REGDB_E_CLASSNOTREG;
966 HeapFree(GetProcessHeap(), 0, buf);
970 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
972 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
973 ret = REGDB_E_CLASSNOTREG;
977 if (CoGetMalloc(0,&mllc))
981 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
982 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
983 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
986 HeapFree(GetProcessHeap(), 0, buf2);
993 HRESULT WINAPI CLSIDFromProgID16(
994 LPCOLESTR16 progid, /* [in] program id as found in registry */
995 LPCLSID riid /* [out] associated CLSID */
1002 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1003 sprintf(buf,"%s\\CLSID",progid);
1004 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1005 HeapFree(GetProcessHeap(),0,buf);
1006 return CO_E_CLASSSTRING;
1008 HeapFree(GetProcessHeap(),0,buf);
1009 buf2len = sizeof(buf2);
1010 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1012 return CO_E_CLASSSTRING;
1015 return __CLSIDFromStringA(buf2,riid);
1018 /******************************************************************************
1019 * CLSIDFromProgID [OLE32.@]
1020 * CLSIDFromProgID [COMPOBJ.61]
1022 * Converts a program id into the respective GUID.
1025 * progid [I] Unicode program ID, as found in registry.
1026 * riid [O] Associated CLSID.
1030 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1032 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1034 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1036 DWORD buf2len = sizeof(buf2);
1039 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1040 strcpyW( buf, progid );
1041 strcatW( buf, clsidW );
1042 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1044 HeapFree(GetProcessHeap(),0,buf);
1045 return CO_E_CLASSSTRING;
1047 HeapFree(GetProcessHeap(),0,buf);
1049 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1052 return CO_E_CLASSSTRING;
1055 return __CLSIDFromStringA(buf2,riid);
1060 /*****************************************************************************
1061 * CoGetPSClsid [OLE32.@]
1063 * This function returns the CLSID of the proxy/stub factory that
1064 * implements IPSFactoryBuffer for the specified interface.
1067 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1068 * pclsid [O] Where to store returned proxy/stub CLSID.
1073 * E_INVALIDARG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1077 * The standard marshaller activates the object with the CLSID
1078 * returned and uses the CreateProxy and CreateStub methods on its
1079 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1082 * CoGetPSClsid determines this CLSID by searching the
1083 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1084 * in the registry and any interface id registered by
1085 * CoRegisterPSClsid within the current process.
1089 * We only search the registry, not ids registered with
1090 * CoRegisterPSClsid.
1092 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1094 char *buf, buf2[40];
1098 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1100 /* Get the input iid as a string */
1101 WINE_StringFromCLSID(riid, buf2);
1102 /* Allocate memory for the registry key we will construct.
1103 (length of iid string plus constant length of static text */
1104 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1107 return (E_OUTOFMEMORY);
1110 /* Construct the registry key we want */
1111 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1113 /* Open the key.. */
1114 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1116 WARN("No PSFactoryBuffer object is registered for this IID\n");
1117 HeapFree(GetProcessHeap(),0,buf);
1118 return (E_INVALIDARG);
1120 HeapFree(GetProcessHeap(),0,buf);
1122 /* ... Once we have the key, query the registry to get the
1123 value of CLSID as a string, and convert it into a
1124 proper CLSID structure to be passed back to the app */
1125 buf2len = sizeof(buf2);
1126 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1129 return E_INVALIDARG;
1133 /* We have the CLSid we want back from the registry as a string, so
1134 lets convert it into a CLSID structure */
1135 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
1136 return E_INVALIDARG;
1139 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1145 /***********************************************************************
1146 * WriteClassStm (OLE32.@)
1148 * Writes a CLSID to a stream.
1151 * pStm [I] Stream to write to.
1152 * rclsid [I] CLSID to write.
1156 * Failure: HRESULT code.
1158 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1160 TRACE("(%p,%p)\n",pStm,rclsid);
1163 return E_INVALIDARG;
1165 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1168 /***********************************************************************
1169 * ReadClassStm (OLE32.@)
1171 * Reads a CLSID from a stream.
1174 * pStm [I] Stream to read from.
1175 * rclsid [O] CLSID to read.
1179 * Failure: HRESULT code.
1181 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1186 TRACE("(%p,%p)\n",pStm,pclsid);
1189 return E_INVALIDARG;
1191 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1196 if (nbByte != sizeof(CLSID))
1204 * COM_GetRegisteredClassObject
1206 * This internal method is used to scan the registered class list to
1207 * find a class object.
1210 * rclsid Class ID of the class to find.
1211 * dwClsContext Class context to match.
1212 * ppv [out] returns a pointer to the class object. Complying
1213 * to normal COM usage, this method will increase the
1214 * reference count on this object.
1216 static HRESULT COM_GetRegisteredClassObject(
1221 HRESULT hr = S_FALSE;
1222 RegisteredClass* curClass;
1224 EnterCriticalSection( &csRegisteredClassList );
1232 * Iterate through the whole list and try to match the class ID.
1234 curClass = firstRegisteredClass;
1236 while (curClass != 0)
1239 * Check if we have a match on the class ID.
1241 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1244 * Since we don't do out-of process or DCOM just right away, let's ignore the
1249 * We have a match, return the pointer to the class object.
1251 *ppUnk = curClass->classObject;
1253 IUnknown_AddRef(curClass->classObject);
1260 * Step to the next class in the list.
1262 curClass = curClass->nextClass;
1266 LeaveCriticalSection( &csRegisteredClassList );
1268 * If we get to here, we haven't found our class.
1273 /******************************************************************************
1274 * CoRegisterClassObject [OLE32.@]
1276 * Registers the class object for a given class ID. Servers housed in EXE
1277 * files use this method instead of exporting DllGetClassObject to allow
1278 * other code to connect to their objects.
1281 * rclsid [I] CLSID of the object to register.
1282 * pUnk [I] IUnknown of the object.
1283 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1284 * flags [I] REGCLS flags indicating how connections are made.
1285 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1289 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1290 * CO_E_OBJISREG if the object is already registered. We should not return this.
1293 * CoRevokeClassObject, CoGetClassObject
1296 * MSDN claims that multiple interface registrations are legal, but we
1297 * can't do that with our current implementation.
1299 HRESULT WINAPI CoRegisterClassObject(
1304 LPDWORD lpdwRegister)
1306 RegisteredClass* newClass;
1307 LPUNKNOWN foundObject;
1310 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1311 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1313 if ( (lpdwRegister==0) || (pUnk==0) )
1314 return E_INVALIDARG;
1316 if (!COM_CurrentApt())
1318 ERR("COM was not initialized\n");
1319 return CO_E_NOTINITIALIZED;
1325 * First, check if the class is already registered.
1326 * If it is, this should cause an error.
1328 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1330 IUnknown_Release(foundObject);
1331 return CO_E_OBJISREG;
1334 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1335 if ( newClass == NULL )
1336 return E_OUTOFMEMORY;
1338 EnterCriticalSection( &csRegisteredClassList );
1340 newClass->classIdentifier = *rclsid;
1341 newClass->runContext = dwClsContext;
1342 newClass->connectFlags = flags;
1344 * Use the address of the chain node as the cookie since we are sure it's
1345 * unique. FIXME: not on 64-bit platforms.
1347 newClass->dwCookie = (DWORD)newClass;
1348 newClass->nextClass = firstRegisteredClass;
1351 * Since we're making a copy of the object pointer, we have to increase its
1354 newClass->classObject = pUnk;
1355 IUnknown_AddRef(newClass->classObject);
1357 firstRegisteredClass = newClass;
1358 LeaveCriticalSection( &csRegisteredClassList );
1360 *lpdwRegister = newClass->dwCookie;
1362 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1363 IClassFactory *classfac;
1365 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1366 (LPVOID*)&classfac);
1369 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1371 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1372 IUnknown_Release(classfac);
1375 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1376 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1377 MSHLFLAGS_TABLESTRONG);
1379 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1380 IUnknown_Release(classfac);
1384 IUnknown_Release(classfac);
1386 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1391 /***********************************************************************
1392 * CoRevokeClassObject [OLE32.@]
1394 * Removes a class object from the class registry.
1397 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1401 * Failure: HRESULT code.
1404 * CoRegisterClassObject
1406 HRESULT WINAPI CoRevokeClassObject(
1409 HRESULT hr = E_INVALIDARG;
1410 RegisteredClass** prevClassLink;
1411 RegisteredClass* curClass;
1413 TRACE("(%08lx)\n",dwRegister);
1415 EnterCriticalSection( &csRegisteredClassList );
1418 * Iterate through the whole list and try to match the cookie.
1420 curClass = firstRegisteredClass;
1421 prevClassLink = &firstRegisteredClass;
1423 while (curClass != 0)
1426 * Check if we have a match on the cookie.
1428 if (curClass->dwCookie == dwRegister)
1431 * Remove the class from the chain.
1433 *prevClassLink = curClass->nextClass;
1436 * Release the reference to the class object.
1438 IUnknown_Release(curClass->classObject);
1440 if (curClass->pMarshaledData)
1443 memset(&zero, 0, sizeof(zero));
1444 /* FIXME: stop local server thread */
1445 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1446 CoReleaseMarshalData(curClass->pMarshaledData);
1450 * Free the memory used by the chain node.
1452 HeapFree(GetProcessHeap(), 0, curClass);
1459 * Step to the next class in the list.
1461 prevClassLink = &(curClass->nextClass);
1462 curClass = curClass->nextClass;
1466 LeaveCriticalSection( &csRegisteredClassList );
1468 * If we get to here, we haven't found our class.
1473 /***********************************************************************
1474 * compobj_RegReadPath [internal]
1476 * Reads a registry value and expands it when necessary
1478 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1484 DWORD dwLength = dstlen;
1486 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1487 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1488 if (keytype == REG_EXPAND_SZ) {
1489 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1491 lstrcpynA(dst, src, dstlen);
1499 /***********************************************************************
1500 * CoGetClassObject [COMPOBJ.7]
1501 * CoGetClassObject [OLE32.@]
1503 * FIXME. If request allows of several options and there is a failure
1504 * with one (other than not being registered) do we try the
1505 * others or return failure? (E.g. inprocess is registered but
1506 * the DLL is not found but the server version works)
1508 HRESULT WINAPI CoGetClassObject(
1509 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1510 REFIID iid, LPVOID *ppv
1512 LPUNKNOWN regClassObject;
1513 HRESULT hres = E_UNEXPECTED;
1516 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1517 DllGetClassObjectFunc DllGetClassObject;
1519 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1521 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1524 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1525 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1529 * First, try and see if we can't match the class ID with one of the
1530 * registered classes.
1532 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1535 * Get the required interface from the retrieved pointer.
1537 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1540 * Since QI got another reference on the pointer, we want to release the
1541 * one we already have. If QI was unsuccessful, this will release the object. This
1542 * is good since we are not returning it in the "out" parameter.
1544 IUnknown_Release(regClassObject);
1549 /* first try: in-process */
1550 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1551 char keyname[MAX_PATH];
1552 char dllpath[MAX_PATH+1];
1554 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1556 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1557 /* failure: CLSID is not found in registry */
1558 WARN("class %s not registered inproc\n", xclsid);
1559 hres = REGDB_E_CLASSNOTREG;
1561 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1562 /* failure: DLL could not be loaded */
1563 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1564 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1565 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1566 /* failure: the dll did not export DllGetClassObject */
1567 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1568 FreeLibrary( hLibrary );
1569 hres = CO_E_DLLNOTFOUND;
1571 /* OK: get the ClassObject */
1572 COMPOBJ_DLLList_Add( hLibrary );
1573 return DllGetClassObject(rclsid, iid, ppv);
1578 /* Next try out of process */
1579 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1581 return create_marshalled_proxy(rclsid,iid,ppv);
1584 /* Finally try remote: this requires networked DCOM (a lot of work) */
1585 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1587 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1588 hres = E_NOINTERFACE;
1593 /***********************************************************************
1594 * CoResumeClassObjects (OLE32.@)
1596 * Resumes all class objects registered with REGCLS_SUSPENDED.
1600 * Failure: HRESULT code.
1602 HRESULT WINAPI CoResumeClassObjects(void)
1608 /***********************************************************************
1609 * GetClassFile (OLE32.@)
1611 * This function supplies the CLSID associated with the given filename.
1613 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1617 int nbElm, length, i;
1619 LPOLESTR *pathDec=0,absFile=0,progId=0;
1621 static const WCHAR bkslashW[] = {'\\',0};
1622 static const WCHAR dotW[] = {'.',0};
1624 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1626 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1627 if((StgIsStorageFile(filePathName))==S_OK){
1629 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1632 res=ReadClassStg(pstg,pclsid);
1634 IStorage_Release(pstg);
1638 /* if the file is not a storage object then attemps to match various bits in the file against a
1639 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1642 for(i=0;i<nFileTypes;i++)
1644 for(i=0;j<nPatternsForType;j++){
1649 pat=ReadPatternFromRegistry(i,j);
1650 hFile=CreateFileW(filePathName,,,,,,hFile);
1651 SetFilePosition(hFile,pat.offset);
1652 ReadFile(hFile,buf,pat.size,&r,NULL);
1653 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1655 *pclsid=ReadCLSIDFromRegistry(i);
1661 /* if the above strategies fail then search for the extension key in the registry */
1663 /* get the last element (absolute file) in the path name */
1664 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1665 absFile=pathDec[nbElm-1];
1667 /* failed if the path represente a directory and not an absolute file name*/
1668 if (!lstrcmpW(absFile, bkslashW))
1669 return MK_E_INVALIDEXTENSION;
1671 /* get the extension of the file */
1673 length=lstrlenW(absFile);
1674 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1677 if (!extension || !lstrcmpW(extension, dotW))
1678 return MK_E_INVALIDEXTENSION;
1680 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1682 /* get the progId associated to the extension */
1683 progId = CoTaskMemAlloc(sizeProgId);
1684 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1686 if (res==ERROR_SUCCESS)
1687 /* return the clsid associated to the progId */
1688 res= CLSIDFromProgID(progId,pclsid);
1690 for(i=0; pathDec[i]!=NULL;i++)
1691 CoTaskMemFree(pathDec[i]);
1692 CoTaskMemFree(pathDec);
1694 CoTaskMemFree(progId);
1696 if (res==ERROR_SUCCESS)
1699 return MK_E_INVALIDEXTENSION;
1701 /***********************************************************************
1702 * CoCreateInstance [COMPOBJ.13]
1703 * CoCreateInstance [OLE32.@]
1705 HRESULT WINAPI CoCreateInstance(
1707 LPUNKNOWN pUnkOuter,
1713 LPCLASSFACTORY lpclf = 0;
1715 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1724 * Initialize the "out" parameter
1729 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1730 * Rather than create a class factory, we can just check for it here
1732 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1733 if (StdGlobalInterfaceTableInstance == NULL)
1734 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1735 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1736 if (hres) return hres;
1738 TRACE("Retrieved GIT (%p)\n", *ppv);
1743 * Get a class factory to construct the object we want.
1745 hres = CoGetClassObject(rclsid,
1752 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1753 debugstr_guid(rclsid),hres);
1758 * Create the object and don't forget to release the factory
1760 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1761 IClassFactory_Release(lpclf);
1763 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1764 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1769 /***********************************************************************
1770 * CoCreateInstanceEx [OLE32.@]
1772 HRESULT WINAPI CoCreateInstanceEx(
1774 LPUNKNOWN pUnkOuter,
1776 COSERVERINFO* pServerInfo,
1780 IUnknown* pUnk = NULL;
1783 ULONG successCount = 0;
1788 if ( (cmq==0) || (pResults==NULL))
1789 return E_INVALIDARG;
1791 if (pServerInfo!=NULL)
1792 FIXME("() non-NULL pServerInfo not supported!\n");
1795 * Initialize all the "out" parameters.
1797 for (index = 0; index < cmq; index++)
1799 pResults[index].pItf = NULL;
1800 pResults[index].hr = E_NOINTERFACE;
1804 * Get the object and get its IUnknown pointer.
1806 hr = CoCreateInstance(rclsid,
1816 * Then, query for all the interfaces requested.
1818 for (index = 0; index < cmq; index++)
1820 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1821 pResults[index].pIID,
1822 (VOID**)&(pResults[index].pItf));
1824 if (pResults[index].hr == S_OK)
1829 * Release our temporary unknown pointer.
1831 IUnknown_Release(pUnk);
1833 if (successCount == 0)
1834 return E_NOINTERFACE;
1836 if (successCount!=cmq)
1837 return CO_S_NOTALLINTERFACES;
1842 /***********************************************************************
1843 * CoLoadLibrary (OLE32.@)
1848 * lpszLibName [I] Path to library.
1849 * bAutoFree [I] Whether the library should automatically be freed.
1852 * Success: Handle to loaded library.
1856 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1858 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1860 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1862 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1865 /***********************************************************************
1866 * CoFreeLibrary [OLE32.@]
1868 * Unloads a library from memory.
1871 * hLibrary [I] Handle to library to unload.
1877 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1879 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1881 FreeLibrary(hLibrary);
1885 /***********************************************************************
1886 * CoFreeAllLibraries [OLE32.@]
1888 * Function for backwards compatibility only. Does nothing.
1894 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1896 void WINAPI CoFreeAllLibraries(void)
1902 /***********************************************************************
1903 * CoFreeUnusedLibraries [OLE32.@]
1904 * CoFreeUnusedLibraries [COMPOBJ.17]
1906 * Frees any unused libraries. Unused are identified as those that return
1907 * S_OK from their DllCanUnloadNow function.
1913 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1915 void WINAPI CoFreeUnusedLibraries(void)
1917 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1918 * through the main apartment's thread to call DllCanUnloadNow */
1919 COMPOBJ_DllList_FreeUnused(0);
1922 /***********************************************************************
1923 * CoFileTimeNow [OLE32.@]
1924 * CoFileTimeNow [COMPOBJ.82]
1926 * Retrieves the current time in FILETIME format.
1929 * lpFileTime [O] The current time.
1934 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1936 GetSystemTimeAsFileTime( lpFileTime );
1940 static void COM_RevokeAllClasses()
1942 EnterCriticalSection( &csRegisteredClassList );
1944 while (firstRegisteredClass!=0)
1946 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1949 LeaveCriticalSection( &csRegisteredClassList );
1952 /****************************************************************************
1953 * COM External Lock methods implementation
1955 * This api provides a linked list to managed external references to
1958 * The public interface consists of three calls:
1959 * COM_ExternalLockAddRef
1960 * COM_ExternalLockRelease
1961 * COM_ExternalLockFreeList
1964 #define EL_END_OF_LIST 0
1965 #define EL_NOT_FOUND 0
1968 * Declaration of the static structure that manage the
1969 * external lock to COM objects.
1971 typedef struct COM_ExternalLock COM_ExternalLock;
1972 typedef struct COM_ExternalLockList COM_ExternalLockList;
1974 struct COM_ExternalLock
1976 IUnknown *pUnk; /* IUnknown referenced */
1977 ULONG uRefCount; /* external lock counter to IUnknown object*/
1978 COM_ExternalLock *next; /* Pointer to next element in list */
1981 struct COM_ExternalLockList
1983 COM_ExternalLock *head; /* head of list */
1987 * Declaration and initialization of the static structure that manages
1988 * the external lock to COM objects.
1990 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1993 * Private methods used to managed the linked list
1997 static COM_ExternalLock* COM_ExternalLockLocate(
1998 COM_ExternalLock *element,
2001 /****************************************************************************
2002 * Internal - Insert a new IUnknown* to the linked list
2004 static BOOL COM_ExternalLockInsert(
2007 COM_ExternalLock *newLock = NULL;
2008 COM_ExternalLock *previousHead = NULL;
2011 * Allocate space for the new storage object
2013 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
2015 if (newLock!=NULL) {
2016 if ( elList.head == EL_END_OF_LIST ) {
2017 elList.head = newLock; /* The list is empty */
2019 /* insert does it at the head */
2020 previousHead = elList.head;
2021 elList.head = newLock;
2024 /* Set new list item data member */
2025 newLock->pUnk = pUnk;
2026 newLock->uRefCount = 1;
2027 newLock->next = previousHead;
2034 /****************************************************************************
2035 * Internal - Method that removes an item from the linked list.
2037 static void COM_ExternalLockDelete(
2038 COM_ExternalLock *itemList)
2040 COM_ExternalLock *current = elList.head;
2042 if ( current == itemList ) {
2043 /* this section handles the deletion of the first node */
2044 elList.head = itemList->next;
2045 HeapFree( GetProcessHeap(), 0, itemList);
2048 if ( current->next == itemList ){ /* We found the item to free */
2049 current->next = itemList->next; /* readjust the list pointers */
2050 HeapFree( GetProcessHeap(), 0, itemList);
2054 /* Skip to the next item */
2055 current = current->next;
2057 } while ( current != EL_END_OF_LIST );
2061 /****************************************************************************
2062 * Internal - Recursivity agent for IUnknownExternalLockList_Find
2064 * NOTES: how long can the list be ?? (recursive!!!)
2066 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
2068 if ( element == EL_END_OF_LIST )
2069 return EL_NOT_FOUND;
2070 else if ( element->pUnk == pUnk ) /* We found it */
2072 else /* Not the right guy, keep on looking */
2073 return COM_ExternalLockLocate( element->next, pUnk);
2076 /****************************************************************************
2077 * Public - Method that increments the count for a IUnknown* in the linked
2078 * list. The item is inserted if not already in the list.
2080 static void COM_ExternalLockAddRef(IUnknown *pUnk)
2082 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2085 * Add an external lock to the object. If it was already externally
2086 * locked, just increase the reference count. If it was not.
2087 * add the item to the list.
2089 if ( externalLock == EL_NOT_FOUND )
2090 COM_ExternalLockInsert(pUnk);
2092 externalLock->uRefCount++;
2095 * Add an internal lock to the object
2097 IUnknown_AddRef(pUnk);
2100 /****************************************************************************
2101 * Public - Method that decrements the count for a IUnknown* in the linked
2102 * list. The item is removed from the list if its count end up at zero or if
2105 static void COM_ExternalLockRelease(
2109 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2111 if ( externalLock != EL_NOT_FOUND ) {
2113 externalLock->uRefCount--; /* release external locks */
2114 IUnknown_Release(pUnk); /* release local locks as well */
2116 if ( bRelAll == FALSE ) break; /* perform single release */
2118 } while ( externalLock->uRefCount > 0 );
2120 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
2121 COM_ExternalLockDelete(externalLock);
2124 /****************************************************************************
2125 * Public - Method that frees the content of the list.
2127 static void COM_ExternalLockFreeList()
2129 COM_ExternalLock *head;
2131 head = elList.head; /* grab it by the head */
2132 while ( head != EL_END_OF_LIST ) {
2133 COM_ExternalLockDelete(head); /* get rid of the head stuff */
2134 head = elList.head; /* get the new head... */
2138 /****************************************************************************
2139 * Public - Method that dump the content of the list.
2141 void COM_ExternalLockDump()
2143 COM_ExternalLock *current = elList.head;
2145 DPRINTF("\nExternal lock list contains:\n");
2147 while ( current != EL_END_OF_LIST ) {
2148 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
2150 /* Skip to the next item */
2151 current = current->next;
2155 /******************************************************************************
2156 * CoLockObjectExternal [OLE32.@]
2158 * Increments or decrements the external reference count of a stub object.
2161 * pUnk [I] Stub object.
2162 * fLock [I] If TRUE then increments the external ref-count,
2163 * otherwise decrements.
2164 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2165 * calling CoDisconnectObject.
2169 * Failure: HRESULT code.
2171 HRESULT WINAPI CoLockObjectExternal(
2172 LPUNKNOWN pUnk, /* */
2173 BOOL fLock, /* [in] do lock */
2174 BOOL fLastUnlockReleases) /* [in] unlock all */
2176 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2177 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2181 * Increment the external lock coutner, COM_ExternalLockAddRef also
2182 * increment the object's internal lock counter.
2184 COM_ExternalLockAddRef( pUnk);
2187 * Decrement the external lock coutner, COM_ExternalLockRelease also
2188 * decrement the object's internal lock counter.
2190 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
2196 /***********************************************************************
2197 * CoInitializeWOW (OLE32.@)
2199 * WOW equivalent of CoInitialize?
2208 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2210 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2214 /***********************************************************************
2215 * CoGetState [OLE32.@]
2217 * Retrieves the thread state object previously stored by CoSetState().
2220 * ppv [I] Address where pointer to object will be stored.
2224 * Failure: E_OUTOFMEMORY.
2227 * Crashes on all invalid ppv addresses, including NULL.
2228 * If the function returns a non-NULL object then the caller must release its
2229 * reference on the object when the object is no longer required.
2234 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2236 struct oletls *info = COM_CurrentInfo();
2237 if (!info) return E_OUTOFMEMORY;
2243 IUnknown_AddRef(info->state);
2245 TRACE("apt->state=%p\n", info->state);
2251 /***********************************************************************
2252 * CoSetState [OLE32.@]
2254 * Sets the thread state object.
2257 * pv [I] Pointer to state object to be stored.
2260 * The system keeps a reference on the object while the object stored.
2264 * Failure: E_OUTOFMEMORY.
2266 HRESULT WINAPI CoSetState(IUnknown * pv)
2268 struct oletls *info = COM_CurrentInfo();
2269 if (!info) return E_OUTOFMEMORY;
2271 if (pv) IUnknown_AddRef(pv);
2275 TRACE("-- release %p now\n", info->state);
2276 IUnknown_Release(info->state);
2285 /******************************************************************************
2286 * OleGetAutoConvert [OLE32.@]
2288 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2296 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2297 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2299 res = REGDB_E_CLASSNOTREG;
2303 /* we can just query for the default value of AutoConvertTo key like that,
2304 without opening the AutoConvertTo key and querying for NULL (default) */
2305 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2307 res = REGDB_E_KEYMISSING;
2310 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2311 CLSIDFromString(wbuf,pClsidNew);
2313 if (hkey) RegCloseKey(hkey);
2317 /******************************************************************************
2318 * CoTreatAsClass [OLE32.@]
2320 * Sets the TreatAs value of a class.
2323 * clsidOld [I] Class to set TreatAs value on.
2324 * clsidNew [I] The class the clsidOld should be treated as.
2328 * Failure: HRESULT code.
2333 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2337 char szClsidNew[39];
2339 char auto_treat_as[39];
2340 LONG auto_treat_as_size = sizeof(auto_treat_as);
2343 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2344 WINE_StringFromCLSID(clsidNew, szClsidNew);
2345 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2347 res = REGDB_E_CLASSNOTREG;
2350 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2352 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2353 !__CLSIDFromStringA(auto_treat_as, &id))
2355 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2357 res = REGDB_E_WRITEREGDB;
2363 RegDeleteKeyA(hkey, "TreatAs");
2367 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2369 res = REGDB_E_WRITEREGDB;
2374 if (hkey) RegCloseKey(hkey);
2378 /******************************************************************************
2379 * CoGetTreatAsClass [OLE32.@]
2381 * Gets the TreatAs value of a class.
2384 * clsidOld [I] Class to get the TreatAs value of.
2385 * clsidNew [I] The class the clsidOld should be treated as.
2389 * Failure: HRESULT code.
2394 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2397 char buf[200], szClsidNew[200];
2399 LONG len = sizeof(szClsidNew);
2401 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2402 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2403 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2405 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2407 res = REGDB_E_CLASSNOTREG;
2410 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2415 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2417 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2419 if (hkey) RegCloseKey(hkey);
2424 /******************************************************************************
2425 * CoGetCurrentProcess [OLE32.@]
2426 * CoGetCurrentProcess [COMPOBJ.34]
2428 * Gets the current process ID.
2431 * The current process ID.
2434 * Is DWORD really the correct return type for this function?
2436 DWORD WINAPI CoGetCurrentProcess(void)
2438 return GetCurrentProcessId();
2441 /******************************************************************************
2442 * CoRegisterMessageFilter [OLE32.@]
2444 * Registers a message filter.
2447 * lpMessageFilter [I] Pointer to interface.
2448 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2452 * Failure: HRESULT code.
2454 HRESULT WINAPI CoRegisterMessageFilter(
2455 LPMESSAGEFILTER lpMessageFilter,
2456 LPMESSAGEFILTER *lplpMessageFilter)
2459 if (lplpMessageFilter) {
2460 *lplpMessageFilter = NULL;
2465 /***********************************************************************
2466 * CoIsOle1Class [OLE32.@]
2468 * Determines whether the specified class an OLE v1 class.
2471 * clsid [I] Class to test.
2474 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2476 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2478 FIXME("%s\n", debugstr_guid(clsid));
2482 /***********************************************************************
2483 * IsEqualGUID [OLE32.@]
2485 * Compares two Unique Identifiers.
2488 * rguid1 [I] The first GUID to compare.
2489 * rguid2 [I] The other GUID to compare.
2495 BOOL WINAPI IsEqualGUID(
2499 return !memcmp(rguid1,rguid2,sizeof(GUID));
2502 /***********************************************************************
2503 * CoInitializeSecurity [OLE32.@]
2505 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2506 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2507 void* pReserved1, DWORD dwAuthnLevel,
2508 DWORD dwImpLevel, void* pReserved2,
2509 DWORD dwCapabilities, void* pReserved3)
2511 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2512 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2513 dwCapabilities, pReserved3);
2517 /***********************************************************************
2518 * CoSuspendClassObjects [OLE32.@]
2520 * Suspends all registered class objects to prevent further requests coming in
2521 * for those objects.
2525 * Failure: HRESULT code.
2527 HRESULT WINAPI CoSuspendClassObjects(void)
2533 /***********************************************************************
2534 * CoAddRefServerProcess [OLE32.@]
2536 * Helper function for incrementing the reference count of a local-server
2540 * New reference count.
2542 ULONG WINAPI CoAddRefServerProcess(void)
2548 /***********************************************************************
2549 * CoReleaseServerProcess [OLE32.@]
2551 * Helper function for decrementing the reference count of a local-server
2555 * New reference count.
2557 ULONG WINAPI CoReleaseServerProcess(void)
2563 /***********************************************************************
2564 * CoQueryProxyBlanket [OLE32.@]
2566 * Retrieves the security settings being used by a proxy.
2569 * pProxy [I] Pointer to the proxy object.
2570 * pAuthnSvc [O] The type of authentication service.
2571 * pAuthzSvc [O] The type of authorization service.
2572 * ppServerPrincName [O] Optional. The server prinicple name.
2573 * pAuthnLevel [O] The authentication level.
2574 * pImpLevel [O] The impersonation level.
2575 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2576 * pCapabilities [O] Flags affecting the security behaviour.
2580 * Failure: HRESULT code.
2583 * CoCopyProxy, CoSetProxyBlanket.
2585 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2586 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2587 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2589 IClientSecurity *pCliSec;
2592 TRACE("%p\n", pProxy);
2594 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2596 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2597 pAuthzSvc, ppServerPrincName,
2598 pAuthnLevel, pImpLevel, ppAuthInfo,
2601 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2605 /***********************************************************************
2606 * CoSetProxyBlanket [OLE32.@]
2608 * Sets the security settings for a proxy.
2611 * pProxy [I] Pointer to the proxy object.
2612 * AuthnSvc [I] The type of authentication service.
2613 * AuthzSvc [I] The type of authorization service.
2614 * pServerPrincName [I] The server prinicple name.
2615 * AuthnLevel [I] The authentication level.
2616 * ImpLevel [I] The impersonation level.
2617 * pAuthInfo [I] Information specific to the authorization/authentication service.
2618 * Capabilities [I] Flags affecting the security behaviour.
2622 * Failure: HRESULT code.
2625 * CoQueryProxyBlanket, CoCopyProxy.
2627 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2628 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2629 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2631 IClientSecurity *pCliSec;
2634 TRACE("%p\n", pProxy);
2636 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2638 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2639 AuthzSvc, pServerPrincName,
2640 AuthnLevel, ImpLevel, pAuthInfo,
2643 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2647 /***********************************************************************
2648 * CoCopyProxy [OLE32.@]
2653 * pProxy [I] Pointer to the proxy object.
2654 * ppCopy [O] Copy of the proxy.
2658 * Failure: HRESULT code.
2661 * CoQueryProxyBlanket, CoSetProxyBlanket.
2663 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2665 IClientSecurity *pCliSec;
2668 TRACE("%p\n", pProxy);
2670 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2672 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2674 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);