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 * - Implement IRemUnknown and marshalling for it, then use that for
48 * reffing/unreffing the stub manager from a proxy instead of our
49 * current hack of simply reaching into local process memory to do it,
50 * which obviously doesn't work inter-process.
52 * - Make our custom marshalling use NDR to be wire compatible with
67 #define NONAMELESSUNION
68 #define NONAMELESSSTRUCT
80 #include "wine/unicode.h"
82 #include "ole32_main.h"
83 #include "compobj_private.h"
85 #include "wine/debug.h"
87 WINE_DEFAULT_DEBUG_CHANNEL(ole);
89 typedef LPCSTR LPCOLESTR16;
91 /****************************************************************************
92 * This section defines variables internal to the COM module.
94 * TODO: Most of these things will have to be made thread-safe.
97 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
98 static void COM_RevokeAllClasses(void);
99 static void COM_ExternalLockFreeList(void);
101 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
103 APARTMENT *MTA; /* protected by csApartment */
104 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
106 static CRITICAL_SECTION csApartment;
107 static CRITICAL_SECTION_DEBUG critsect_debug =
110 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
111 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
113 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
116 * This lock count counts the number of times CoInitialize is called. It is
117 * decreased every time CoUninitialize is called. When it hits 0, the COM
118 * libraries are freed
120 static LONG s_COMLockCount = 0;
123 * This linked list contains the list of registered class objects. These
124 * are mostly used to register the factories for out-of-proc servers of OLE
127 * TODO: Make this data structure aware of inter-process communication. This
128 * means that parts of this will be exported to the Wine Server.
130 typedef struct tagRegisteredClass
132 CLSID classIdentifier;
133 LPUNKNOWN classObject;
137 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
138 struct tagRegisteredClass* nextClass;
141 static RegisteredClass* firstRegisteredClass = NULL;
143 static CRITICAL_SECTION csRegisteredClassList;
144 static CRITICAL_SECTION_DEBUG class_cs_debug =
146 0, 0, &csRegisteredClassList,
147 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
148 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
150 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
152 /*****************************************************************************
153 * This section contains OpenDllList definitions
155 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
156 * other functions that do LoadLibrary _without_ giving back a HMODULE.
157 * Without this list these handles would never be freed.
159 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
160 * next unload-call but not before 600 sec.
163 typedef struct tagOpenDll {
165 struct tagOpenDll *next;
168 static OpenDll *openDllList = NULL; /* linked list of open dlls */
170 static CRITICAL_SECTION csOpenDllList;
171 static CRITICAL_SECTION_DEBUG dll_cs_debug =
173 0, 0, &csOpenDllList,
174 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
175 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
177 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
179 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
180 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
182 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
183 static void COMPOBJ_DllList_FreeUnused(int Timeout);
185 void COMPOBJ_InitProcess( void )
189 /* Dispatching to the correct thread in an apartment is done through
190 * window messages rather than RPC transports. When an interface is
191 * marshalled into another apartment in the same process, a window of the
192 * following class is created. The *caller* of CoMarshalInterface (ie the
193 * application) is responsible for pumping the message loop in that thread.
194 * The WM_USER messages which point to the RPCs are then dispatched to
195 * COM_AptWndProc by the user's code from the apartment in which the interface
198 memset(&wclass, 0, sizeof(wclass));
199 wclass.lpfnWndProc = &COM_AptWndProc;
200 wclass.hInstance = OLE32_hInstance;
201 wclass.lpszClassName = aptWinClass;
202 RegisterClassA(&wclass);
205 void COMPOBJ_UninitProcess( void )
207 UnregisterClassA(aptWinClass, OLE32_hInstance);
210 /******************************************************************************
214 /* creates an apartment structure which stores OLE apartment-local
216 APARTMENT* COM_CreateApartment(DWORD model)
218 APARTMENT *apt = COM_CurrentApt();
222 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
223 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
226 EnterCriticalSection(&csApartment);
227 if (!(model & COINIT_APARTMENTTHREADED) && MTA) /* See note 1 above */
229 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
231 COM_ApartmentAddRef(apt);
233 LeaveCriticalSection(&csApartment);
235 COM_CurrentInfo()->apt = apt;
239 TRACE("creating new apartment, model=%ld\n", model);
241 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
242 apt->tid = GetCurrentThreadId();
243 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
244 GetCurrentProcess(), &apt->thread,
245 THREAD_ALL_ACCESS, FALSE, 0);
247 list_init(&apt->proxies);
248 list_init(&apt->stubmgrs);
251 apt->remunk_exported = FALSE;
253 InitializeCriticalSection(&apt->cs);
257 if (model & COINIT_APARTMENTTHREADED)
259 /* FIXME: should be randomly generated by in an RPC call to rpcss */
260 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
261 apt->win = CreateWindowA(aptWinClass, NULL, 0,
263 0, 0, OLE32_hInstance, NULL);
267 /* FIXME: should be randomly generated by in an RPC call to rpcss */
268 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
272 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
274 list_add_head(&apts, &apt->entry);
275 LeaveCriticalSection(&csApartment);
277 COM_CurrentInfo()->apt = apt;
283 DWORD COM_ApartmentAddRef(struct apartment *apt)
285 return InterlockedIncrement(&apt->refs);
288 DWORD COM_ApartmentRelease(struct apartment *apt)
292 EnterCriticalSection(&csApartment);
294 ret = InterlockedDecrement(&apt->refs);
295 /* destruction stuff that needs to happen under csApartment CS */
298 if (apt == MTA) MTA = NULL;
299 list_remove(&apt->entry);
302 LeaveCriticalSection(&csApartment);
306 struct list *cursor, *cursor2;
308 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
310 MARSHAL_Disconnect_Proxies(apt);
312 if (apt->win) DestroyWindow(apt->win);
314 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
316 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
317 /* release the implicit reference given by the fact that the
318 * stub has external references (it must do since it is in the
319 * stub manager list in the apartment and all non-apartment users
320 * must have a ref on the apartment and so it cannot be destroyed).
322 stub_manager_int_release(stubmgr);
325 /* if this assert fires, then another thread took a reference to a
326 * stub manager without taking a reference to the containing
327 * apartment, which it must do. */
328 assert(list_empty(&apt->stubmgrs));
330 if (apt->filter) IUnknown_Release(apt->filter);
332 DeleteCriticalSection(&apt->cs);
333 CloseHandle(apt->thread);
334 HeapFree(GetProcessHeap(), 0, apt);
340 /* The given OXID must be local to this process: you cannot use
341 * apartment windows to send RPCs to other processes. This all needs
344 * The ref parameter is here mostly to ensure people remember that
345 * they get one, you should normally take a ref for thread safety.
347 APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
349 APARTMENT *result = NULL;
352 EnterCriticalSection(&csApartment);
353 LIST_FOR_EACH( cursor, &apts )
355 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
356 if (apt->oxid == oxid)
359 if (ref) COM_ApartmentAddRef(result);
363 LeaveCriticalSection(&csApartment);
368 /* gets the apartment which has a given creator thread ID. The caller must
369 * release the reference from the apartment as soon as the apartment pointer
370 * is no longer required. */
371 APARTMENT *COM_ApartmentFromTID(DWORD tid)
373 APARTMENT *result = NULL;
376 EnterCriticalSection(&csApartment);
377 LIST_FOR_EACH( cursor, &apts )
379 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
383 COM_ApartmentAddRef(result);
387 LeaveCriticalSection(&csApartment);
392 HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
396 apt = COM_ApartmentFromOXID(oxid, ref);
397 if (!apt) return NULL;
402 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
403 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
405 return DefWindowProcA(hWnd, msg, wParam, lParam);
408 /*****************************************************************************
409 * This section contains OpenDllList implemantation
412 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
419 EnterCriticalSection( &csOpenDllList );
421 if (openDllList == NULL) {
422 /* empty list -- add first node */
423 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
424 openDllList->hLibrary=hLibrary;
425 openDllList->next = NULL;
427 /* search for this dll */
429 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
430 if (ptr->hLibrary == hLibrary) {
436 /* dll not found, add it */
438 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
439 openDllList->hLibrary = hLibrary;
440 openDllList->next = tmp;
444 LeaveCriticalSection( &csOpenDllList );
447 static void COMPOBJ_DllList_FreeUnused(int Timeout)
449 OpenDll *curr, *next, *prev = NULL;
450 typedef HRESULT(*DllCanUnloadNowFunc)(void);
451 DllCanUnloadNowFunc DllCanUnloadNow;
455 EnterCriticalSection( &csOpenDllList );
457 for (curr = openDllList; curr != NULL; ) {
458 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
460 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
463 TRACE("freeing %p\n", curr->hLibrary);
464 FreeLibrary(curr->hLibrary);
466 HeapFree(GetProcessHeap(), 0, curr);
467 if (curr == openDllList) {
480 LeaveCriticalSection( &csOpenDllList );
483 /******************************************************************************
484 * CoBuildVersion [OLE32.@]
485 * CoBuildVersion [COMPOBJ.1]
487 * Gets the build version of the DLL.
492 * Current build version, hiword is majornumber, loword is minornumber
494 DWORD WINAPI CoBuildVersion(void)
496 TRACE("Returning version %d, build %d.\n", rmm, rup);
497 return (rmm<<16)+rup;
500 /******************************************************************************
501 * CoInitialize [OLE32.@]
503 * Initializes the COM libraries by calling CoInitializeEx with
504 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
507 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
510 * Success: S_OK if not already initialized, S_FALSE otherwise.
511 * Failure: HRESULT code.
516 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
519 * Just delegate to the newer method.
521 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
524 /******************************************************************************
525 * CoInitializeEx [OLE32.@]
527 * Initializes the COM libraries.
530 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
531 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
534 * S_OK if successful,
535 * S_FALSE if this function was called already.
536 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
541 * The behavior used to set the IMalloc used for memory management is
543 * The dwCoInit parameter must specify of of the following apartment
545 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
546 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
547 * The parameter may also specify zero or more of the following flags:
548 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
549 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
554 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
559 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
561 if (lpReserved!=NULL)
563 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
567 * Check the lock count. If this is the first time going through the initialize
568 * process, we have to initialize the libraries.
570 * And crank-up that lock count.
572 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
575 * Initialize the various COM libraries and data structures.
577 TRACE("() - Initializing the COM libraries\n");
579 /* we may need to defer this until after apartment initialisation */
580 RunningObjectTableImpl_Initialize();
583 if (!(apt = COM_CurrentInfo()->apt))
585 apt = COM_CreateApartment(dwCoInit);
586 if (!apt) return E_OUTOFMEMORY;
588 else if (dwCoInit != apt->model)
590 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
591 code then we are probably using the wrong threading model to implement that API. */
592 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
593 COM_ApartmentRelease(apt);
594 return RPC_E_CHANGED_MODE;
599 COM_CurrentInfo()->inits++;
604 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
605 pending RPCs are ignored. Non-COM messages are discarded at this point.
607 void COM_FlushMessageQueue(void)
610 APARTMENT *apt = COM_CurrentApt();
612 if (!apt || !apt->win) return;
614 TRACE("Flushing STA message queue\n");
616 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
618 if (message.hwnd != apt->win)
620 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
624 TranslateMessage(&message);
625 DispatchMessageA(&message);
629 /***********************************************************************
630 * CoUninitialize [OLE32.@]
632 * This method will decrement the refcount on the current apartment, freeing
633 * the resources associated with it if it is the last thread in the apartment.
634 * If the last apartment is freed, the function will additionally release
635 * any COM resources associated with the process.
645 void WINAPI CoUninitialize(void)
647 struct oletls * info = COM_CurrentInfo();
652 /* will only happen on OOM */
658 ERR("Mismatched CoUninitialize\n");
664 COM_ApartmentRelease(info->apt);
669 * Decrease the reference count.
670 * If we are back to 0 locks on the COM library, make sure we free
671 * all the associated data structures.
673 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
676 TRACE("() - Releasing the COM libraries\n");
678 RunningObjectTableImpl_UnInitialize();
680 /* Release the references to the registered class objects */
681 COM_RevokeAllClasses();
683 /* This will free the loaded COM Dlls */
684 CoFreeAllLibraries();
686 /* This will free list of external references to COM objects */
687 COM_ExternalLockFreeList();
689 /* This ensures we deal with any pending RPCs */
690 COM_FlushMessageQueue();
692 else if (lCOMRefCnt<1) {
693 ERR( "CoUninitialize() - not CoInitialized.\n" );
694 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
698 /******************************************************************************
699 * CoDisconnectObject [OLE32.@]
700 * CoDisconnectObject [COMPOBJ.15]
702 * Disconnects all connections to this object from remote processes. Dispatches
703 * pending RPCs while blocking new RPCs from occurring, and then calls
704 * IMarshal::DisconnectObject on the given object.
706 * Typically called when the object server is forced to shut down, for instance by
710 * lpUnk [I] The object whose stub should be disconnected.
711 * reserved [I] Reserved. Should be set to 0.
715 * Failure: HRESULT code.
718 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
720 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
722 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
726 /******************************************************************************
727 * CoCreateGuid [OLE32.@]
729 * Simply forwards to UuidCreate in RPCRT4.
732 * pguid [O] Points to the GUID to initialize.
736 * Failure: HRESULT code.
741 HRESULT WINAPI CoCreateGuid(GUID *pguid)
743 return UuidCreate(pguid);
746 /******************************************************************************
747 * CLSIDFromString [OLE32.@]
748 * IIDFromString [OLE32.@]
750 * Converts a unique identifier from its string representation into
754 * idstr [I] The string representation of the GUID.
755 * id [O] GUID converted from the string.
759 * CO_E_CLASSSTRING if idstr is not a valid CLSID
763 * In Windows, if idstr is not a valid CLSID string then it gets
764 * treated as a ProgID. Wine currently doesn't do this. If idstr is
765 * NULL it's treated as an all-zero GUID.
770 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
772 const BYTE *s = (const BYTE *) idstr;
777 s = "{00000000-0000-0000-0000-000000000000}";
778 else { /* validate the CLSID string */
781 return CO_E_CLASSSTRING;
783 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
784 return CO_E_CLASSSTRING;
786 for (i=1; i<37; i++) {
787 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
788 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
789 ((s[i] >= 'a') && (s[i] <= 'f')) ||
790 ((s[i] >= 'A') && (s[i] <= 'F'))))
791 return CO_E_CLASSSTRING;
795 TRACE("%s -> %p\n", s, id);
797 /* quick lookup table */
798 memset(table, 0, 256);
800 for (i = 0; i < 10; i++) {
803 for (i = 0; i < 6; i++) {
804 table['A' + i] = i+10;
805 table['a' + i] = i+10;
808 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
810 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
811 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
812 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
813 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
815 /* these are just sequential bytes */
816 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
817 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
818 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
819 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
820 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
821 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
822 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
823 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
828 /*****************************************************************************/
830 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
835 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
836 return CO_E_CLASSSTRING;
839 ret = __CLSIDFromStringA(xid,id);
840 if(ret != S_OK) { /* It appears a ProgID is also valid */
841 ret = CLSIDFromProgID(idstr, id);
846 /* Converts a GUID into the respective string representation. */
847 HRESULT WINE_StringFromCLSID(
848 const CLSID *id, /* [in] GUID to be converted */
849 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
851 static const char *hex = "0123456789ABCDEF";
856 { ERR("called with id=Null\n");
861 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
862 id->Data1, id->Data2, id->Data3,
863 id->Data4[0], id->Data4[1]);
867 for (i = 2; i < 8; i++) {
868 *s++ = hex[id->Data4[i]>>4];
869 *s++ = hex[id->Data4[i] & 0xf];
875 TRACE("%p->%s\n", id, idstr);
881 /******************************************************************************
882 * StringFromCLSID [OLE32.@]
883 * StringFromIID [OLE32.@]
885 * Converts a GUID into the respective string representation.
886 * The target string is allocated using the OLE IMalloc.
889 * id [I] the GUID to be converted.
890 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
897 * StringFromGUID2, CLSIDFromString
899 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
905 if ((ret = CoGetMalloc(0,&mllc)))
908 ret=WINE_StringFromCLSID(id,buf);
910 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
911 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
912 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
917 /******************************************************************************
918 * StringFromGUID2 [OLE32.@]
919 * StringFromGUID2 [COMPOBJ.76]
921 * Modified version of StringFromCLSID that allows you to specify max
925 * id [I] GUID to convert to string.
926 * str [O] Buffer where the result will be stored.
927 * cmax [I] Size of the buffer in characters.
930 * Success: The length of the resulting string in characters.
933 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
937 if (WINE_StringFromCLSID(id,xguid))
939 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
942 /******************************************************************************
943 * ProgIDFromCLSID [OLE32.@]
945 * Converts a class id into the respective program ID.
948 * clsid [I] Class ID, as found in registry.
949 * lplpszProgID [O] Associated ProgID.
954 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
956 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
958 char strCLSID[50], *buf, *buf2;
964 WINE_StringFromCLSID(clsid, strCLSID);
966 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
967 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
968 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
969 ret = REGDB_E_CLASSNOTREG;
971 HeapFree(GetProcessHeap(), 0, buf);
975 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
977 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
978 ret = REGDB_E_CLASSNOTREG;
982 if (CoGetMalloc(0,&mllc))
986 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
987 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
988 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
991 HeapFree(GetProcessHeap(), 0, buf2);
998 HRESULT WINAPI CLSIDFromProgID16(
999 LPCOLESTR16 progid, /* [in] program id as found in registry */
1000 LPCLSID riid /* [out] associated CLSID */
1007 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1008 sprintf(buf,"%s\\CLSID",progid);
1009 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1010 HeapFree(GetProcessHeap(),0,buf);
1011 return CO_E_CLASSSTRING;
1013 HeapFree(GetProcessHeap(),0,buf);
1014 buf2len = sizeof(buf2);
1015 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1017 return CO_E_CLASSSTRING;
1020 return __CLSIDFromStringA(buf2,riid);
1023 /******************************************************************************
1024 * CLSIDFromProgID [OLE32.@]
1025 * CLSIDFromProgID [COMPOBJ.61]
1027 * Converts a program id into the respective GUID.
1030 * progid [I] Unicode program ID, as found in registry.
1031 * riid [O] Associated CLSID.
1035 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1037 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1039 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1041 DWORD buf2len = sizeof(buf2);
1044 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1045 strcpyW( buf, progid );
1046 strcatW( buf, clsidW );
1047 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1049 HeapFree(GetProcessHeap(),0,buf);
1050 return CO_E_CLASSSTRING;
1052 HeapFree(GetProcessHeap(),0,buf);
1054 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1057 return CO_E_CLASSSTRING;
1060 return __CLSIDFromStringA(buf2,riid);
1065 /*****************************************************************************
1066 * CoGetPSClsid [OLE32.@]
1068 * This function returns the CLSID of the proxy/stub factory that
1069 * implements IPSFactoryBuffer for the specified interface.
1072 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1073 * pclsid [O] Where to store returned proxy/stub CLSID.
1078 * E_INVALIDARG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1082 * The standard marshaller activates the object with the CLSID
1083 * returned and uses the CreateProxy and CreateStub methods on its
1084 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1087 * CoGetPSClsid determines this CLSID by searching the
1088 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1089 * in the registry and any interface id registered by
1090 * CoRegisterPSClsid within the current process.
1094 * We only search the registry, not ids registered with
1095 * CoRegisterPSClsid.
1097 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1099 char *buf, buf2[40];
1103 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1105 /* Get the input iid as a string */
1106 WINE_StringFromCLSID(riid, buf2);
1107 /* Allocate memory for the registry key we will construct.
1108 (length of iid string plus constant length of static text */
1109 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1112 return (E_OUTOFMEMORY);
1115 /* Construct the registry key we want */
1116 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1118 /* Open the key.. */
1119 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1121 WARN("No PSFactoryBuffer object is registered for this IID\n");
1122 HeapFree(GetProcessHeap(),0,buf);
1123 return (E_INVALIDARG);
1125 HeapFree(GetProcessHeap(),0,buf);
1127 /* ... Once we have the key, query the registry to get the
1128 value of CLSID as a string, and convert it into a
1129 proper CLSID structure to be passed back to the app */
1130 buf2len = sizeof(buf2);
1131 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1134 return E_INVALIDARG;
1138 /* We have the CLSid we want back from the registry as a string, so
1139 lets convert it into a CLSID structure */
1140 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
1141 return E_INVALIDARG;
1144 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1150 /***********************************************************************
1151 * WriteClassStm (OLE32.@)
1153 * Writes a CLSID to a stream.
1156 * pStm [I] Stream to write to.
1157 * rclsid [I] CLSID to write.
1161 * Failure: HRESULT code.
1163 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1165 TRACE("(%p,%p)\n",pStm,rclsid);
1168 return E_INVALIDARG;
1170 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1173 /***********************************************************************
1174 * ReadClassStm (OLE32.@)
1176 * Reads a CLSID from a stream.
1179 * pStm [I] Stream to read from.
1180 * rclsid [O] CLSID to read.
1184 * Failure: HRESULT code.
1186 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1191 TRACE("(%p,%p)\n",pStm,pclsid);
1194 return E_INVALIDARG;
1196 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1201 if (nbByte != sizeof(CLSID))
1209 * COM_GetRegisteredClassObject
1211 * This internal method is used to scan the registered class list to
1212 * find a class object.
1215 * rclsid Class ID of the class to find.
1216 * dwClsContext Class context to match.
1217 * ppv [out] returns a pointer to the class object. Complying
1218 * to normal COM usage, this method will increase the
1219 * reference count on this object.
1221 static HRESULT COM_GetRegisteredClassObject(
1226 HRESULT hr = S_FALSE;
1227 RegisteredClass* curClass;
1229 EnterCriticalSection( &csRegisteredClassList );
1237 * Iterate through the whole list and try to match the class ID.
1239 curClass = firstRegisteredClass;
1241 while (curClass != 0)
1244 * Check if we have a match on the class ID.
1246 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1249 * Since we don't do out-of process or DCOM just right away, let's ignore the
1254 * We have a match, return the pointer to the class object.
1256 *ppUnk = curClass->classObject;
1258 IUnknown_AddRef(curClass->classObject);
1265 * Step to the next class in the list.
1267 curClass = curClass->nextClass;
1271 LeaveCriticalSection( &csRegisteredClassList );
1273 * If we get to here, we haven't found our class.
1278 /******************************************************************************
1279 * CoRegisterClassObject [OLE32.@]
1281 * Registers the class object for a given class ID. Servers housed in EXE
1282 * files use this method instead of exporting DllGetClassObject to allow
1283 * other code to connect to their objects.
1286 * rclsid [I] CLSID of the object to register.
1287 * pUnk [I] IUnknown of the object.
1288 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1289 * flags [I] REGCLS flags indicating how connections are made.
1290 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1294 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1295 * CO_E_OBJISREG if the object is already registered. We should not return this.
1298 * CoRevokeClassObject, CoGetClassObject
1301 * MSDN claims that multiple interface registrations are legal, but we
1302 * can't do that with our current implementation.
1304 HRESULT WINAPI CoRegisterClassObject(
1309 LPDWORD lpdwRegister)
1311 RegisteredClass* newClass;
1312 LPUNKNOWN foundObject;
1315 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1316 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1318 if ( (lpdwRegister==0) || (pUnk==0) )
1319 return E_INVALIDARG;
1321 if (!COM_CurrentApt())
1323 ERR("COM was not initialized\n");
1324 return CO_E_NOTINITIALIZED;
1330 * First, check if the class is already registered.
1331 * If it is, this should cause an error.
1333 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1335 IUnknown_Release(foundObject);
1336 return CO_E_OBJISREG;
1339 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1340 if ( newClass == NULL )
1341 return E_OUTOFMEMORY;
1343 EnterCriticalSection( &csRegisteredClassList );
1345 newClass->classIdentifier = *rclsid;
1346 newClass->runContext = dwClsContext;
1347 newClass->connectFlags = flags;
1349 * Use the address of the chain node as the cookie since we are sure it's
1350 * unique. FIXME: not on 64-bit platforms.
1352 newClass->dwCookie = (DWORD)newClass;
1353 newClass->nextClass = firstRegisteredClass;
1356 * Since we're making a copy of the object pointer, we have to increase its
1359 newClass->classObject = pUnk;
1360 IUnknown_AddRef(newClass->classObject);
1362 firstRegisteredClass = newClass;
1363 LeaveCriticalSection( &csRegisteredClassList );
1365 *lpdwRegister = newClass->dwCookie;
1367 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1368 IClassFactory *classfac;
1370 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1371 (LPVOID*)&classfac);
1374 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1376 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1377 IUnknown_Release(classfac);
1380 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1381 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1382 MSHLFLAGS_TABLESTRONG);
1384 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1385 IUnknown_Release(classfac);
1389 IUnknown_Release(classfac);
1391 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1396 /***********************************************************************
1397 * CoRevokeClassObject [OLE32.@]
1399 * Removes a class object from the class registry.
1402 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1406 * Failure: HRESULT code.
1409 * CoRegisterClassObject
1411 HRESULT WINAPI CoRevokeClassObject(
1414 HRESULT hr = E_INVALIDARG;
1415 RegisteredClass** prevClassLink;
1416 RegisteredClass* curClass;
1418 TRACE("(%08lx)\n",dwRegister);
1420 EnterCriticalSection( &csRegisteredClassList );
1423 * Iterate through the whole list and try to match the cookie.
1425 curClass = firstRegisteredClass;
1426 prevClassLink = &firstRegisteredClass;
1428 while (curClass != 0)
1431 * Check if we have a match on the cookie.
1433 if (curClass->dwCookie == dwRegister)
1436 * Remove the class from the chain.
1438 *prevClassLink = curClass->nextClass;
1441 * Release the reference to the class object.
1443 IUnknown_Release(curClass->classObject);
1445 if (curClass->pMarshaledData)
1448 memset(&zero, 0, sizeof(zero));
1449 /* FIXME: stop local server thread */
1450 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1451 CoReleaseMarshalData(curClass->pMarshaledData);
1455 * Free the memory used by the chain node.
1457 HeapFree(GetProcessHeap(), 0, curClass);
1464 * Step to the next class in the list.
1466 prevClassLink = &(curClass->nextClass);
1467 curClass = curClass->nextClass;
1471 LeaveCriticalSection( &csRegisteredClassList );
1473 * If we get to here, we haven't found our class.
1478 /***********************************************************************
1479 * compobj_RegReadPath [internal]
1481 * Reads a registry value and expands it when necessary
1483 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1489 DWORD dwLength = dstlen;
1491 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1492 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1493 if (keytype == REG_EXPAND_SZ) {
1494 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1496 lstrcpynA(dst, src, dstlen);
1504 /***********************************************************************
1505 * CoGetClassObject [COMPOBJ.7]
1506 * CoGetClassObject [OLE32.@]
1508 * FIXME. If request allows of several options and there is a failure
1509 * with one (other than not being registered) do we try the
1510 * others or return failure? (E.g. inprocess is registered but
1511 * the DLL is not found but the server version works)
1513 HRESULT WINAPI CoGetClassObject(
1514 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1515 REFIID iid, LPVOID *ppv
1517 LPUNKNOWN regClassObject;
1518 HRESULT hres = E_UNEXPECTED;
1521 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1522 DllGetClassObjectFunc DllGetClassObject;
1524 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1526 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1529 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1530 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1534 * First, try and see if we can't match the class ID with one of the
1535 * registered classes.
1537 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1540 * Get the required interface from the retrieved pointer.
1542 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1545 * Since QI got another reference on the pointer, we want to release the
1546 * one we already have. If QI was unsuccessful, this will release the object. This
1547 * is good since we are not returning it in the "out" parameter.
1549 IUnknown_Release(regClassObject);
1554 /* first try: in-process */
1555 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1556 char keyname[MAX_PATH];
1557 char dllpath[MAX_PATH+1];
1559 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1561 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1562 /* failure: CLSID is not found in registry */
1563 WARN("class %s not registered inproc\n", xclsid);
1564 hres = REGDB_E_CLASSNOTREG;
1566 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1567 /* failure: DLL could not be loaded */
1568 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1569 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1570 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1571 /* failure: the dll did not export DllGetClassObject */
1572 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1573 FreeLibrary( hLibrary );
1574 hres = CO_E_DLLNOTFOUND;
1576 /* OK: get the ClassObject */
1577 COMPOBJ_DLLList_Add( hLibrary );
1578 return DllGetClassObject(rclsid, iid, ppv);
1583 /* Next try out of process */
1584 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1586 return create_marshalled_proxy(rclsid,iid,ppv);
1589 /* Finally try remote: this requires networked DCOM (a lot of work) */
1590 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1592 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1593 hres = E_NOINTERFACE;
1598 /***********************************************************************
1599 * CoResumeClassObjects (OLE32.@)
1601 * Resumes all class objects registered with REGCLS_SUSPENDED.
1605 * Failure: HRESULT code.
1607 HRESULT WINAPI CoResumeClassObjects(void)
1613 /***********************************************************************
1614 * GetClassFile (OLE32.@)
1616 * This function supplies the CLSID associated with the given filename.
1618 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1622 int nbElm, length, i;
1624 LPOLESTR *pathDec=0,absFile=0,progId=0;
1626 static const WCHAR bkslashW[] = {'\\',0};
1627 static const WCHAR dotW[] = {'.',0};
1629 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1631 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1632 if((StgIsStorageFile(filePathName))==S_OK){
1634 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1637 res=ReadClassStg(pstg,pclsid);
1639 IStorage_Release(pstg);
1643 /* if the file is not a storage object then attemps to match various bits in the file against a
1644 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1647 for(i=0;i<nFileTypes;i++)
1649 for(i=0;j<nPatternsForType;j++){
1654 pat=ReadPatternFromRegistry(i,j);
1655 hFile=CreateFileW(filePathName,,,,,,hFile);
1656 SetFilePosition(hFile,pat.offset);
1657 ReadFile(hFile,buf,pat.size,&r,NULL);
1658 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1660 *pclsid=ReadCLSIDFromRegistry(i);
1666 /* if the above strategies fail then search for the extension key in the registry */
1668 /* get the last element (absolute file) in the path name */
1669 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1670 absFile=pathDec[nbElm-1];
1672 /* failed if the path represente a directory and not an absolute file name*/
1673 if (!lstrcmpW(absFile, bkslashW))
1674 return MK_E_INVALIDEXTENSION;
1676 /* get the extension of the file */
1678 length=lstrlenW(absFile);
1679 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1682 if (!extension || !lstrcmpW(extension, dotW))
1683 return MK_E_INVALIDEXTENSION;
1685 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1687 /* get the progId associated to the extension */
1688 progId = CoTaskMemAlloc(sizeProgId);
1689 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1691 if (res==ERROR_SUCCESS)
1692 /* return the clsid associated to the progId */
1693 res= CLSIDFromProgID(progId,pclsid);
1695 for(i=0; pathDec[i]!=NULL;i++)
1696 CoTaskMemFree(pathDec[i]);
1697 CoTaskMemFree(pathDec);
1699 CoTaskMemFree(progId);
1701 if (res==ERROR_SUCCESS)
1704 return MK_E_INVALIDEXTENSION;
1706 /***********************************************************************
1707 * CoCreateInstance [COMPOBJ.13]
1708 * CoCreateInstance [OLE32.@]
1710 HRESULT WINAPI CoCreateInstance(
1712 LPUNKNOWN pUnkOuter,
1718 LPCLASSFACTORY lpclf = 0;
1720 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1729 * Initialize the "out" parameter
1734 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1735 * Rather than create a class factory, we can just check for it here
1737 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1738 if (StdGlobalInterfaceTableInstance == NULL)
1739 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1740 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1741 if (hres) return hres;
1743 TRACE("Retrieved GIT (%p)\n", *ppv);
1748 * Get a class factory to construct the object we want.
1750 hres = CoGetClassObject(rclsid,
1757 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1758 debugstr_guid(rclsid),hres);
1763 * Create the object and don't forget to release the factory
1765 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1766 IClassFactory_Release(lpclf);
1768 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1769 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1774 /***********************************************************************
1775 * CoCreateInstanceEx [OLE32.@]
1777 HRESULT WINAPI CoCreateInstanceEx(
1779 LPUNKNOWN pUnkOuter,
1781 COSERVERINFO* pServerInfo,
1785 IUnknown* pUnk = NULL;
1788 ULONG successCount = 0;
1793 if ( (cmq==0) || (pResults==NULL))
1794 return E_INVALIDARG;
1796 if (pServerInfo!=NULL)
1797 FIXME("() non-NULL pServerInfo not supported!\n");
1800 * Initialize all the "out" parameters.
1802 for (index = 0; index < cmq; index++)
1804 pResults[index].pItf = NULL;
1805 pResults[index].hr = E_NOINTERFACE;
1809 * Get the object and get its IUnknown pointer.
1811 hr = CoCreateInstance(rclsid,
1821 * Then, query for all the interfaces requested.
1823 for (index = 0; index < cmq; index++)
1825 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1826 pResults[index].pIID,
1827 (VOID**)&(pResults[index].pItf));
1829 if (pResults[index].hr == S_OK)
1834 * Release our temporary unknown pointer.
1836 IUnknown_Release(pUnk);
1838 if (successCount == 0)
1839 return E_NOINTERFACE;
1841 if (successCount!=cmq)
1842 return CO_S_NOTALLINTERFACES;
1847 /***********************************************************************
1848 * CoLoadLibrary (OLE32.@)
1853 * lpszLibName [I] Path to library.
1854 * bAutoFree [I] Whether the library should automatically be freed.
1857 * Success: Handle to loaded library.
1861 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1863 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1865 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1867 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1870 /***********************************************************************
1871 * CoFreeLibrary [OLE32.@]
1873 * Unloads a library from memory.
1876 * hLibrary [I] Handle to library to unload.
1882 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1884 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1886 FreeLibrary(hLibrary);
1890 /***********************************************************************
1891 * CoFreeAllLibraries [OLE32.@]
1893 * Function for backwards compatibility only. Does nothing.
1899 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1901 void WINAPI CoFreeAllLibraries(void)
1907 /***********************************************************************
1908 * CoFreeUnusedLibraries [OLE32.@]
1909 * CoFreeUnusedLibraries [COMPOBJ.17]
1911 * Frees any unused libraries. Unused are identified as those that return
1912 * S_OK from their DllCanUnloadNow function.
1918 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1920 void WINAPI CoFreeUnusedLibraries(void)
1922 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1923 * through the main apartment's thread to call DllCanUnloadNow */
1924 COMPOBJ_DllList_FreeUnused(0);
1927 /***********************************************************************
1928 * CoFileTimeNow [OLE32.@]
1929 * CoFileTimeNow [COMPOBJ.82]
1931 * Retrieves the current time in FILETIME format.
1934 * lpFileTime [O] The current time.
1939 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1941 GetSystemTimeAsFileTime( lpFileTime );
1945 static void COM_RevokeAllClasses()
1947 EnterCriticalSection( &csRegisteredClassList );
1949 while (firstRegisteredClass!=0)
1951 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1954 LeaveCriticalSection( &csRegisteredClassList );
1957 /****************************************************************************
1958 * COM External Lock methods implementation
1960 * This api provides a linked list to managed external references to
1963 * The public interface consists of three calls:
1964 * COM_ExternalLockAddRef
1965 * COM_ExternalLockRelease
1966 * COM_ExternalLockFreeList
1969 #define EL_END_OF_LIST 0
1970 #define EL_NOT_FOUND 0
1973 * Declaration of the static structure that manage the
1974 * external lock to COM objects.
1976 typedef struct COM_ExternalLock COM_ExternalLock;
1977 typedef struct COM_ExternalLockList COM_ExternalLockList;
1979 struct COM_ExternalLock
1981 IUnknown *pUnk; /* IUnknown referenced */
1982 ULONG uRefCount; /* external lock counter to IUnknown object*/
1983 COM_ExternalLock *next; /* Pointer to next element in list */
1986 struct COM_ExternalLockList
1988 COM_ExternalLock *head; /* head of list */
1992 * Declaration and initialization of the static structure that manages
1993 * the external lock to COM objects.
1995 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1998 * Private methods used to managed the linked list
2002 static COM_ExternalLock* COM_ExternalLockLocate(
2003 COM_ExternalLock *element,
2006 /****************************************************************************
2007 * Internal - Insert a new IUnknown* to the linked list
2009 static BOOL COM_ExternalLockInsert(
2012 COM_ExternalLock *newLock = NULL;
2013 COM_ExternalLock *previousHead = NULL;
2016 * Allocate space for the new storage object
2018 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
2020 if (newLock!=NULL) {
2021 if ( elList.head == EL_END_OF_LIST ) {
2022 elList.head = newLock; /* The list is empty */
2024 /* insert does it at the head */
2025 previousHead = elList.head;
2026 elList.head = newLock;
2029 /* Set new list item data member */
2030 newLock->pUnk = pUnk;
2031 newLock->uRefCount = 1;
2032 newLock->next = previousHead;
2039 /****************************************************************************
2040 * Internal - Method that removes an item from the linked list.
2042 static void COM_ExternalLockDelete(
2043 COM_ExternalLock *itemList)
2045 COM_ExternalLock *current = elList.head;
2047 if ( current == itemList ) {
2048 /* this section handles the deletion of the first node */
2049 elList.head = itemList->next;
2050 HeapFree( GetProcessHeap(), 0, itemList);
2053 if ( current->next == itemList ){ /* We found the item to free */
2054 current->next = itemList->next; /* readjust the list pointers */
2055 HeapFree( GetProcessHeap(), 0, itemList);
2059 /* Skip to the next item */
2060 current = current->next;
2062 } while ( current != EL_END_OF_LIST );
2066 /****************************************************************************
2067 * Internal - Recursivity agent for IUnknownExternalLockList_Find
2069 * NOTES: how long can the list be ?? (recursive!!!)
2071 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
2073 if ( element == EL_END_OF_LIST )
2074 return EL_NOT_FOUND;
2075 else if ( element->pUnk == pUnk ) /* We found it */
2077 else /* Not the right guy, keep on looking */
2078 return COM_ExternalLockLocate( element->next, pUnk);
2081 /****************************************************************************
2082 * Public - Method that increments the count for a IUnknown* in the linked
2083 * list. The item is inserted if not already in the list.
2085 static void COM_ExternalLockAddRef(IUnknown *pUnk)
2087 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2090 * Add an external lock to the object. If it was already externally
2091 * locked, just increase the reference count. If it was not.
2092 * add the item to the list.
2094 if ( externalLock == EL_NOT_FOUND )
2095 COM_ExternalLockInsert(pUnk);
2097 externalLock->uRefCount++;
2100 * Add an internal lock to the object
2102 IUnknown_AddRef(pUnk);
2105 /****************************************************************************
2106 * Public - Method that decrements the count for a IUnknown* in the linked
2107 * list. The item is removed from the list if its count end up at zero or if
2110 static void COM_ExternalLockRelease(
2114 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2116 if ( externalLock != EL_NOT_FOUND ) {
2118 externalLock->uRefCount--; /* release external locks */
2119 IUnknown_Release(pUnk); /* release local locks as well */
2121 if ( bRelAll == FALSE ) break; /* perform single release */
2123 } while ( externalLock->uRefCount > 0 );
2125 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
2126 COM_ExternalLockDelete(externalLock);
2129 /****************************************************************************
2130 * Public - Method that frees the content of the list.
2132 static void COM_ExternalLockFreeList()
2134 COM_ExternalLock *head;
2136 head = elList.head; /* grab it by the head */
2137 while ( head != EL_END_OF_LIST ) {
2138 COM_ExternalLockDelete(head); /* get rid of the head stuff */
2139 head = elList.head; /* get the new head... */
2143 /****************************************************************************
2144 * Public - Method that dump the content of the list.
2146 void COM_ExternalLockDump()
2148 COM_ExternalLock *current = elList.head;
2150 DPRINTF("\nExternal lock list contains:\n");
2152 while ( current != EL_END_OF_LIST ) {
2153 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
2155 /* Skip to the next item */
2156 current = current->next;
2160 /******************************************************************************
2161 * CoLockObjectExternal [OLE32.@]
2163 * Increments or decrements the external reference count of a stub object.
2166 * pUnk [I] Stub object.
2167 * fLock [I] If TRUE then increments the external ref-count,
2168 * otherwise decrements.
2169 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2170 * calling CoDisconnectObject.
2174 * Failure: HRESULT code.
2176 HRESULT WINAPI CoLockObjectExternal(
2177 LPUNKNOWN pUnk, /* */
2178 BOOL fLock, /* [in] do lock */
2179 BOOL fLastUnlockReleases) /* [in] unlock all */
2181 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2182 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2186 * Increment the external lock coutner, COM_ExternalLockAddRef also
2187 * increment the object's internal lock counter.
2189 COM_ExternalLockAddRef( pUnk);
2192 * Decrement the external lock coutner, COM_ExternalLockRelease also
2193 * decrement the object's internal lock counter.
2195 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
2201 /***********************************************************************
2202 * CoInitializeWOW (OLE32.@)
2204 * WOW equivalent of CoInitialize?
2213 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2215 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2219 /***********************************************************************
2220 * CoGetState [OLE32.@]
2222 * Retrieves the thread state object previously stored by CoSetState().
2225 * ppv [I] Address where pointer to object will be stored.
2229 * Failure: E_OUTOFMEMORY.
2232 * Crashes on all invalid ppv addresses, including NULL.
2233 * If the function returns a non-NULL object then the caller must release its
2234 * reference on the object when the object is no longer required.
2239 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2241 struct oletls *info = COM_CurrentInfo();
2242 if (!info) return E_OUTOFMEMORY;
2248 IUnknown_AddRef(info->state);
2250 TRACE("apt->state=%p\n", info->state);
2256 /***********************************************************************
2257 * CoSetState [OLE32.@]
2259 * Sets the thread state object.
2262 * pv [I] Pointer to state object to be stored.
2265 * The system keeps a reference on the object while the object stored.
2269 * Failure: E_OUTOFMEMORY.
2271 HRESULT WINAPI CoSetState(IUnknown * pv)
2273 struct oletls *info = COM_CurrentInfo();
2274 if (!info) return E_OUTOFMEMORY;
2276 if (pv) IUnknown_AddRef(pv);
2280 TRACE("-- release %p now\n", info->state);
2281 IUnknown_Release(info->state);
2290 /******************************************************************************
2291 * OleGetAutoConvert [OLE32.@]
2293 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2301 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2302 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2304 res = REGDB_E_CLASSNOTREG;
2308 /* we can just query for the default value of AutoConvertTo key like that,
2309 without opening the AutoConvertTo key and querying for NULL (default) */
2310 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2312 res = REGDB_E_KEYMISSING;
2315 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2316 CLSIDFromString(wbuf,pClsidNew);
2318 if (hkey) RegCloseKey(hkey);
2322 /******************************************************************************
2323 * CoTreatAsClass [OLE32.@]
2325 * Sets the TreatAs value of a class.
2328 * clsidOld [I] Class to set TreatAs value on.
2329 * clsidNew [I] The class the clsidOld should be treated as.
2333 * Failure: HRESULT code.
2338 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2342 char szClsidNew[39];
2344 char auto_treat_as[39];
2345 LONG auto_treat_as_size = sizeof(auto_treat_as);
2348 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2349 WINE_StringFromCLSID(clsidNew, szClsidNew);
2350 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2352 res = REGDB_E_CLASSNOTREG;
2355 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2357 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2358 !__CLSIDFromStringA(auto_treat_as, &id))
2360 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2362 res = REGDB_E_WRITEREGDB;
2368 RegDeleteKeyA(hkey, "TreatAs");
2372 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2374 res = REGDB_E_WRITEREGDB;
2379 if (hkey) RegCloseKey(hkey);
2383 /******************************************************************************
2384 * CoGetTreatAsClass [OLE32.@]
2386 * Gets the TreatAs value of a class.
2389 * clsidOld [I] Class to get the TreatAs value of.
2390 * clsidNew [I] The class the clsidOld should be treated as.
2394 * Failure: HRESULT code.
2399 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2402 char buf[200], szClsidNew[200];
2404 LONG len = sizeof(szClsidNew);
2406 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2407 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2408 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2410 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2412 res = REGDB_E_CLASSNOTREG;
2415 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2420 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2422 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2424 if (hkey) RegCloseKey(hkey);
2429 /******************************************************************************
2430 * CoGetCurrentProcess [OLE32.@]
2431 * CoGetCurrentProcess [COMPOBJ.34]
2433 * Gets the current process ID.
2436 * The current process ID.
2439 * Is DWORD really the correct return type for this function?
2441 DWORD WINAPI CoGetCurrentProcess(void)
2443 return GetCurrentProcessId();
2446 /******************************************************************************
2447 * CoRegisterMessageFilter [OLE32.@]
2449 * Registers a message filter.
2452 * lpMessageFilter [I] Pointer to interface.
2453 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2457 * Failure: HRESULT code.
2459 HRESULT WINAPI CoRegisterMessageFilter(
2460 LPMESSAGEFILTER lpMessageFilter,
2461 LPMESSAGEFILTER *lplpMessageFilter)
2464 if (lplpMessageFilter) {
2465 *lplpMessageFilter = NULL;
2470 /***********************************************************************
2471 * CoIsOle1Class [OLE32.@]
2473 * Determines whether the specified class an OLE v1 class.
2476 * clsid [I] Class to test.
2479 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2481 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2483 FIXME("%s\n", debugstr_guid(clsid));
2487 /***********************************************************************
2488 * IsEqualGUID [OLE32.@]
2490 * Compares two Unique Identifiers.
2493 * rguid1 [I] The first GUID to compare.
2494 * rguid2 [I] The other GUID to compare.
2500 BOOL WINAPI IsEqualGUID(
2504 return !memcmp(rguid1,rguid2,sizeof(GUID));
2507 /***********************************************************************
2508 * CoInitializeSecurity [OLE32.@]
2510 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2511 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2512 void* pReserved1, DWORD dwAuthnLevel,
2513 DWORD dwImpLevel, void* pReserved2,
2514 DWORD dwCapabilities, void* pReserved3)
2516 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2517 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2518 dwCapabilities, pReserved3);
2522 /***********************************************************************
2523 * CoSuspendClassObjects [OLE32.@]
2525 * Suspends all registered class objects to prevent further requests coming in
2526 * for those objects.
2530 * Failure: HRESULT code.
2532 HRESULT WINAPI CoSuspendClassObjects(void)
2538 /***********************************************************************
2539 * CoAddRefServerProcess [OLE32.@]
2541 * Helper function for incrementing the reference count of a local-server
2545 * New reference count.
2547 ULONG WINAPI CoAddRefServerProcess(void)
2553 /***********************************************************************
2554 * CoReleaseServerProcess [OLE32.@]
2556 * Helper function for decrementing the reference count of a local-server
2560 * New reference count.
2562 ULONG WINAPI CoReleaseServerProcess(void)