--- trunk/reactos/lib/ole32/compobj.c 2005-02-13 17:25:52 UTC (rev 13531)
+++ trunk/reactos/lib/ole32/compobj.c 2005-02-13 20:52:16 UTC (rev 13532)
@@ -28,37 +28,19 @@
*
* TODO list: (items bunched together depend on each other)
*
- * - Switch wine_marshal_id to use IPIDs not IIDs
- * - Once that's done, replace wine_marshal_id with STDOBJREF
- *
- * - Rewrite the CoLockObjectExternal code, it does totally the wrong
- * thing currently (should be controlling the stub manager)
- *
- * - Make the MTA dynamically allocated and refcounted
- * - Free the ReservedForOle data in DllMain(THREAD_DETACH)
- *
* - Implement the service control manager (in rpcss) to keep track
* of registered class objects: ISCM::ServerRegisterClsid et al
* - Implement the OXID resolver so we don't need magic pipe names for
* clients and servers to meet up
* - Flip our marshalling on top of the RPC runtime transport API,
* so we no longer use named pipes to communicate
- * - Rework threading so re-entrant calls don't need to be sent on
- * the incoming pipe
* - Implement RPC thread affinity (should fix InstallShield painting
* problems)
*
- * - Implement IRemUnknown and marshalling for it, then use that for
- * reffing/unreffing the stub manager from a proxy instead of our
- * current hack of simply reffing the stub manager once when it's
- * registered.
- * - Implement table marshalling, then use it to let us do the final
- * rework of the threading
+ * - Make all ole interface marshaling use NDR to be wire compatible with
+ * native DCOM
+ * - Use & interpret ORPCTHIS & ORPCTHAT.
*
- * - Make our custom marshalling use NDR to be wire compatible with
- * native DCOM
- *
- *
*/
#include "config.h"
@@ -102,12 +84,11 @@
static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
static void COM_RevokeAllClasses(void);
-static void COM_ExternalLockFreeList(void);
const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
-APARTMENT MTA;
-static struct list apts = LIST_INIT( apts );
+APARTMENT *MTA; /* protected by csApartment */
+static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
static CRITICAL_SECTION csApartment;
static CRITICAL_SECTION_DEBUG critsect_debug =
@@ -213,89 +194,108 @@
UnregisterClassA(aptWinClass, OLE32_hInstance);
}
+void COM_TlsDestroy()
+{
+ struct oletls *info = NtCurrentTeb()->ReservedForOle;
+ if (info)
+ {
+ if (info->apt) COM_ApartmentRelease(info->apt);
+ if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
+ if (info->state) IUnknown_Release(info->state);
+ HeapFree(GetProcessHeap(), 0, info);
+ NtCurrentTeb()->ReservedForOle = NULL;
+ }
+}
+
/******************************************************************************
* Manage apartments.
*/
-
-/* The multi-threaded apartment (MTA) contains zero or more threads interacting
- with free threaded (ie thread safe) COM objects. There is only ever one MTA
- in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
- */
-static void COM_InitMTA(void)
+/* allocates memory and fills in the necessary fields for a new apartment
+ * object */
+static APARTMENT *apartment_construct(DWORD model)
{
- /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
- within a network. That is, two different MTAs on different machines will have
- different OXIDs.
+ APARTMENT *apt;
- This method of generating an OXID is therefore wrong as it doesn't work across
- a network, but for local RPC only it's OK. We can distinguish between MTAs and
- STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
+ TRACE("creating new apartment, model=%ld\n", model);
- The algorithm Microsoft use is currently unknown.
- */
- MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
- InitializeCriticalSection(&MTA.cs);
-}
+ apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
+ apt->tid = GetCurrentThreadId();
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &apt->thread,
+ THREAD_ALL_ACCESS, FALSE, 0);
-static void COM_UninitMTA(void)
-{
- DeleteCriticalSection(&MTA.cs);
- MTA.oxid = 0;
+ list_init(&apt->proxies);
+ list_init(&apt->stubmgrs);
+ apt->ipidc = 0;
+ apt->refs = 1;
+ apt->remunk_exported = FALSE;
+ apt->oidc = 1;
+ InitializeCriticalSection(&apt->cs);
+
+ apt->model = model;
+
+ if (model & COINIT_APARTMENTTHREADED)
+ {
+ /* FIXME: should be randomly generated by in an RPC call to rpcss */
+ apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
+ apt->win = CreateWindowA(aptWinClass, NULL, 0,
+ 0, 0, 0, 0,
+ 0, 0, OLE32_hInstance, NULL);
+ }
+ else
+ {
+ /* FIXME: should be randomly generated by in an RPC call to rpcss */
+ apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
+ }
+
+ apt->shutdown_event = CreateEventW(NULL, TRUE, FALSE, NULL);
+
+ TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
+
+ /* the locking here is not currently needed for the MTA case, but it
+ * doesn't hurt and makes the code simpler */
+ EnterCriticalSection(&csApartment);
+ list_add_head(&apts, &apt->entry);
+ LeaveCriticalSection(&csApartment);
+
+ return apt;
}
-
-/* creates an apartment structure which stores OLE thread-local
- * information. Call with COINIT_UNINITIALIZED to create an apartment
- * that will be initialized with a model later. Note: do not call
- * with COINIT_UNINITIALIZED if the apartment has already been initialized
- * with a different COINIT value */
-APARTMENT* COM_CreateApartment(DWORD model)
+/* gets and existing apartment if one exists or otherwise creates an apartment
+ * structure which stores OLE apartment-local information and stores a pointer
+ * to it in the thread-local storage */
+static APARTMENT *get_or_create_apartment(DWORD model)
{
APARTMENT *apt = COM_CurrentApt();
if (!apt)
{
- if (!(model & COINIT_APARTMENTTHREADED)) /* See note 1 above */
+ if (model & COINIT_APARTMENTTHREADED)
{
- TRACE("thread 0x%lx is entering the multithreaded apartment\n", GetCurrentThreadId());
- COM_CurrentInfo()->apt = &MTA;
- return COM_CurrentInfo()->apt;
+ apt = apartment_construct(model);
+ COM_CurrentInfo()->apt = apt;
}
+ else
+ {
+ EnterCriticalSection(&csApartment);
- TRACE("creating new apartment, model=%ld\n", model);
+ /* The multi-threaded apartment (MTA) contains zero or more threads interacting
+ * with free threaded (ie thread safe) COM objects. There is only ever one MTA
+ * in a process */
+ if (MTA)
+ {
+ TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
+ COM_ApartmentAddRef(MTA);
+ }
+ else
+ MTA = apartment_construct(model);
- apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
- apt->tid = GetCurrentThreadId();
- DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
- GetCurrentProcess(), &apt->thread,
- THREAD_ALL_ACCESS, FALSE, 0);
+ apt = MTA;
+ COM_CurrentInfo()->apt = apt;
- list_init(&apt->proxies);
- list_init(&apt->stubmgrs);
- apt->oidc = 1;
- apt->refs = 1;
- InitializeCriticalSection(&apt->cs);
-
- apt->model = model;
-
- /* we don't ref the apartment as CoInitializeEx will do it for us */
-
- if (model & COINIT_APARTMENTTHREADED)
- {
- /* FIXME: how does windoze create OXIDs? */
- apt->oxid = MTA.oxid | GetCurrentThreadId();
- TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
- apt->win = CreateWindowA(aptWinClass, NULL, 0,
- 0, 0, 0, 0,
- 0, 0, OLE32_hInstance, NULL);
+ LeaveCriticalSection(&csApartment);
}
-
- EnterCriticalSection(&csApartment);
- list_add_head(&apts, &apt->entry);
- LeaveCriticalSection(&csApartment);
-
- COM_CurrentInfo()->apt = apt;
}
return apt;
@@ -303,39 +303,61 @@
DWORD COM_ApartmentAddRef(struct apartment *apt)
{
- return InterlockedIncrement(&apt->refs);
+ DWORD refs = InterlockedIncrement(&apt->refs);
+ TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
+ return refs;
}
DWORD COM_ApartmentRelease(struct apartment *apt)
{
DWORD ret;
+ EnterCriticalSection(&csApartment);
+
ret = InterlockedDecrement(&apt->refs);
+ TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
+ /* destruction stuff that needs to happen under csApartment CS */
if (ret == 0)
{
+ if (apt == MTA) MTA = NULL;
+ list_remove(&apt->entry);
+ }
+
+ LeaveCriticalSection(&csApartment);
+
+ if (ret == 0)
+ {
+ struct list *cursor, *cursor2;
+
TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
- EnterCriticalSection(&csApartment);
- list_remove(&apt->entry);
- LeaveCriticalSection(&csApartment);
-
MARSHAL_Disconnect_Proxies(apt);
if (apt->win) DestroyWindow(apt->win);
- if (!list_empty(&apt->stubmgrs))
+ LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
{
- FIXME("Destroy outstanding stubs\n");
+ struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
+ /* release the implicit reference given by the fact that the
+ * stub has external references (it must do since it is in the
+ * stub manager list in the apartment and all non-apartment users
+ * must have a ref on the apartment and so it cannot be destroyed).
+ */
+ stub_manager_int_release(stubmgr);
}
+ /* if this assert fires, then another thread took a reference to a
+ * stub manager without taking a reference to the containing
+ * apartment, which it must do. */
+ assert(list_empty(&apt->stubmgrs));
+
if (apt->filter) IUnknown_Release(apt->filter);
-
DeleteCriticalSection(&apt->cs);
+ SetEvent(apt->shutdown_event);
+ CloseHandle(apt->shutdown_event);
CloseHandle(apt->thread);
HeapFree(GetProcessHeap(), 0, apt);
-
- apt = NULL;
}
return ret;
@@ -369,6 +391,30 @@
return result;
}
+/* gets the apartment which has a given creator thread ID. The caller must
+ * release the reference from the apartment as soon as the apartment pointer
+ * is no longer required. */
+APARTMENT *COM_ApartmentFromTID(DWORD tid)
+{
+ APARTMENT *result = NULL;
+ struct list *cursor;
+
+ EnterCriticalSection(&csApartment);
+ LIST_FOR_EACH( cursor, &apts )
+ {
+ struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
+ if (apt->tid == tid)
+ {
+ result = apt;
+ COM_ApartmentAddRef(result);
+ break;
+ }
+ }
+ LeaveCriticalSection(&csApartment);
+
+ return result;
+}
+
HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
{
APARTMENT *apt;
@@ -461,9 +507,13 @@
}
/******************************************************************************
+ * CoBuildVersion [OLE32.@]
* CoBuildVersion [COMPOBJ.1]
- * CoBuildVersion [OLE32.@]
*
+ * Gets the build version of the DLL.
+ *
+ * PARAMS
+ *
* RETURNS
* Current build version, hiword is majornumber, loword is minornumber
*/
@@ -479,13 +529,17 @@
* Initializes the COM libraries by calling CoInitializeEx with
* COINIT_APARTMENTTHREADED, ie it enters a STA thread.
*
+ * PARAMS
+ * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
+ *
+ * RETURNS
+ * Success: S_OK if not already initialized, S_FALSE otherwise.
+ * Failure: HRESULT code.
+ *
* SEE ALSO
* CoInitializeEx
*/
-HRESULT WINAPI CoInitialize(
- LPVOID lpReserved /* [in] pointer to win32 malloc interface
- (obsolete, should be NULL) */
-)
+HRESULT WINAPI CoInitialize(LPVOID lpReserved)
{
/*
* Just delegate to the newer method.
@@ -496,13 +550,11 @@
/******************************************************************************
* CoInitializeEx [OLE32.@]
*
- * Initializes the COM libraries. The behavior used to set the win32
- * IMalloc used for memory management is obsolete. If
- * COINIT_APARTMENTTHREADED is specified this thread enters a new STA
- * (single threaded apartment), otherwise COINIT_MULTITHREADED should
- * be specified which indicates that the thread will enter the MTA.
+ * Initializes the COM libraries.
*
- * Currently STA threading is only partly implemented.
+ * PARAMS
+ * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
+ * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
*
* RETURNS
* S_OK if successful,
@@ -510,13 +562,22 @@
* RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
* threading model.
*
+ * NOTES
+ *
+ * The behavior used to set the IMalloc used for memory management is
+ * obsolete.
+ * The dwCoInit parameter must specify of of the following apartment
+ * threading models:
+ *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
+ *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
+ * The parameter may also specify zero or more of the following flags:
+ *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
+ *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
+ *
* SEE ALSO
* CoUninitialize
*/
-HRESULT WINAPI CoInitializeEx(
- LPVOID lpReserved, /* [in] pointer to win32 malloc interface (obsolete, should be NULL) */
- DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
-)
+HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
{
HRESULT hr = S_OK;
APARTMENT *apt;
@@ -541,15 +602,13 @@
*/
TRACE("() - Initializing the COM libraries\n");
- COM_InitMTA();
-
/* we may need to defer this until after apartment initialisation */
RunningObjectTableImpl_Initialize();
}
if (!(apt = COM_CurrentInfo()->apt))
{
- apt = COM_CreateApartment(dwCoInit);
+ apt = get_or_create_apartment(dwCoInit);
if (!apt) return E_OUTOFMEMORY;
}
else if (dwCoInit != apt->model)
@@ -557,9 +616,10 @@
/* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
code then we are probably using the wrong threading model to implement that API. */
ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
- COM_ApartmentRelease(apt);
return RPC_E_CHANGED_MODE;
}
+ else
+ hr = S_FALSE;
COM_CurrentInfo()->inits++;
@@ -594,16 +654,16 @@
/***********************************************************************
* CoUninitialize [OLE32.@]
*
- * This method will decrement the refcount on the COM libraries,
- * potentially unloading them. The current thread leaves the apartment
- * it's currently in. If not in an apartment, the routine does
- * nothing.
+ * This method will decrement the refcount on the current apartment, freeing
+ * the resources associated with it if it is the last thread in the apartment.
+ * If the last apartment is freed, the function will additionally release
+ * any COM resources associated with the process.
*
- * If COM is to be shut down, any outstanding proxies are
- * disconnected, all registered class objects are unregistered and the
- * message queue for the thread is flushed (if native does
- * this or not is unknown).
+ * PARAMS
*
+ * RETURNS
+ * Nothing.
+ *
* SEE ALSO
* CoInitializeEx
*/
@@ -648,13 +708,8 @@
/* This will free the loaded COM Dlls */
CoFreeAllLibraries();
- /* This will free list of external references to COM objects */
- COM_ExternalLockFreeList();
-
/* This ensures we deal with any pending RPCs */
COM_FlushMessageQueue();
-
- COM_UninitMTA();
}
else if (lCOMRefCnt<1) {
ERR( "CoUninitialize() - not CoInitialized.\n" );
@@ -663,8 +718,8 @@
}
/******************************************************************************
+ * CoDisconnectObject [OLE32.@]
* CoDisconnectObject [COMPOBJ.15]
- * CoDisconnectObject [OLE32.@]
*
* Disconnects all connections to this object from remote processes. Dispatches
* pending RPCs while blocking new RPCs from occurring, and then calls
@@ -672,25 +727,65 @@
*
* Typically called when the object server is forced to shut down, for instance by
* the user.
+ *
+ * PARAMS
+ * lpUnk [I] The object whose stub should be disconnected.
+ * reserved [I] Reserved. Should be set to 0.
+ *
+ * RETURNS
+ * Success: S_OK.
+ * Failure: HRESULT code.
+ *
+ * SEE ALSO
+ * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
*/
HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
{
- FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
+ HRESULT hr;
+ IMarshal *marshal;
+ APARTMENT *apt;
+
+ TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
+
+ hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
+ if (hr == S_OK)
+ {
+ hr = IMarshal_DisconnectObject(marshal, reserved);
+ IMarshal_Release(marshal);
+ return hr;
+ }
+
+ apt = COM_CurrentApt();
+ if (!apt)
+ return CO_E_NOTINITIALIZED;
+
+ apartment_disconnect_object(apt, lpUnk);
+
+ /* Note: native is pretty broken here because it just silently
+ * fails, without returning an appropriate error code if the object was
+ * not found, making apps think that the object was disconnected, when
+ * it actually wasn't */
+
return S_OK;
}
/******************************************************************************
- * CoCreateGuid[OLE32.@]
+ * CoCreateGuid [OLE32.@]
*
* Simply forwards to UuidCreate in RPCRT4.
*
+ * PARAMS
+ * pguid [O] Points to the GUID to initialize.
+ *
+ * RETURNS
+ * Success: S_OK.
+ * Failure: HRESULT code.
+ *
* SEE ALSO
* UuidCreate
- *
*/
-HRESULT WINAPI CoCreateGuid(
- GUID *pguid /* [out] points to the GUID to initialize */
-) {
+HRESULT WINAPI CoCreateGuid(GUID *pguid)
+{
return UuidCreate(pguid);
}
@@ -701,17 +796,24 @@
* Converts a unique identifier from its string representation into
* the GUID struct.
*
+ * PARAMS
+ * idstr [I] The string representation of the GUID.
+ * id [O] GUID converted from the string.
+ *
+ * RETURNS
+ * S_OK on success
+ * CO_E_CLASSSTRING if idstr is not a valid CLSID
+ *
+ * BUGS
+ *
* In Windows, if idstr is not a valid CLSID string then it gets
* treated as a ProgID. Wine currently doesn't do this. If idstr is
* NULL it's treated as an all-zero GUID.
*
- * RETURNS
- * S_OK on success
- * CO_E_CLASSSTRING if idstr is not a valid CLSID
+ * SEE ALSO
+ * StringFromCLSID
*/
-HRESULT WINAPI __CLSIDFromStringA(
- LPCSTR idstr, /* [in] string representation of guid */
- CLSID *id) /* [out] GUID converted from string */
+HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
{
const BYTE *s = (const BYTE *) idstr;
int i;
@@ -771,9 +873,7 @@
/*****************************************************************************/
-HRESULT WINAPI CLSIDFromString(
- LPOLESTR idstr, /* [in] string representation of GUID */
- CLSID *id ) /* [out] GUID represented by above string */
+HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
{
char xid[40];
HRESULT ret;
@@ -831,14 +931,19 @@
* Converts a GUID into the respective string representation.
* The target string is allocated using the OLE IMalloc.
*
+ * PARAMS
+ * id [I] the GUID to be converted.
+ * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
+ *
* RETURNS
* S_OK
* E_FAIL
+ *
+ * SEE ALSO
+ * StringFromGUID2, CLSIDFromString
*/
-HRESULT WINAPI StringFromCLSID(
- REFCLSID id, /* [in] the GUID to be converted */
- LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
-) {
+HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
+{
char buf[80];
HRESULT ret;
LPMALLOC mllc;
@@ -856,19 +961,22 @@
}
/******************************************************************************
+ * StringFromGUID2 [OLE32.@]
* StringFromGUID2 [COMPOBJ.76]
- * StringFromGUID2 [OLE32.@]
*
* Modified version of StringFromCLSID that allows you to specify max
* buffer size.
*
+ * PARAMS
+ * id [I] GUID to convert to string.
+ * str [O] Buffer where the result will be stored.
+ * cmax [I] Size of the buffer in characters.
+ *
* RETURNS
- * The length of the resulting string, 0 if there was any problem.
+ * Success: The length of the resulting string in characters.
+ * Failure: 0.
*/
-INT WINAPI StringFromGUID2(
- REFGUID id, /* [in] GUID to convert to string */
- LPOLESTR str, /* [out] Unicode buffer to hold result */
- INT cmax)
+INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
{
char xguid[80];
@@ -880,18 +988,18 @@
/******************************************************************************
* ProgIDFromCLSID [OLE32.@]
*
- * Converts a class id into the respective Program ID. (By using a
- * registry lookup)
+ * Converts a class id into the respective program ID.
*
+ * PARAMS
+ * clsid [I] Class ID, as found in registry.
+ * lplpszProgID [O] Associated ProgID.
+ *
* RETURNS
* S_OK
* E_OUTOFMEMORY
* REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
*/
-HRESULT WINAPI ProgIDFromCLSID(
- REFCLSID clsid, /* [in] class id as found in registry */
- LPOLESTR *lplpszProgID/* [out] associated Prog ID */
-)
+HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
{
char strCLSID[50], *buf, *buf2;
DWORD buf2len;
@@ -959,18 +1067,20 @@
}
/******************************************************************************
+ * CLSIDFromProgID [OLE32.@]
* CLSIDFromProgID [COMPOBJ.61]
*
- * Converts a program id into the respective GUID. (By using a
- * registry lookup)
+ * Converts a program id into the respective GUID.
*
+ * PARAMS
+ * progid [I] Unicode program ID, as found in registry.
+ * riid [O] Associated CLSID.
+ *
* RETURNS
- * S_OK
- * CO_E_CLASSSTRING if the given ProgID cannot be found
+ * Success: S_OK
+ * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
*/
-HRESULT WINAPI CLSIDFromProgID(
- LPCOLESTR progid, /* [in] Unicode program id as found in registry */
- LPCLSID riid ) /* [out] associated CLSID */
+HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
{
static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
char buf2[80];
@@ -1001,9 +1111,20 @@
/*****************************************************************************
* CoGetPSClsid [OLE32.@]
*
- * This function returns the CLSID of the proxy/stub factory that
- * implements IPSFactoryBuffer for the specified interface.
+ * Retrieves the CLSID of the proxy/stub factory that implements
+ * IPSFactoryBuffer for the specified interface.
*
+ * PARAMS
+ * riid [I] Interface whose proxy/stub CLSID is to be returned.
+ * pclsid [O] Where to store returned proxy/stub CLSID.
+ *
+ * RETURNS
+ * S_OK
+ * E_OUTOFMEMORY
+ * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
+ *
+ * NOTES
+ *
* The standard marshaller activates the object with the CLSID
* returned and uses the CreateProxy and CreateStub methods on its
* IPSFactoryBuffer interface to construct the proxies and stubs for a
@@ -1014,17 +1135,15 @@
* in the registry and any interface id registered by
* CoRegisterPSClsid within the current process.
*
- * FIXME: We only search the registry, not ids registered with
+ * BUGS
+ *
+ * We only search the registry, not ids registered with
* CoRegisterPSClsid.
- *
- * RETURNS
- * S_OK
- * E_OUTOFMEMORY
- * E_INVALIDARG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
+ * Also, native returns S_OK for interfaces with an key in HKCR\Interface, but
+ * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
+ * considered a bug in native unless an application depends on this (unlikely).
*/
-HRESULT WINAPI CoGetPSClsid(
- REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
- CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
+HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
{
char *buf, buf2[40];
DWORD buf2len;
@@ -1038,9 +1157,7 @@
(length of iid string plus constant length of static text */
buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
if (buf == NULL)
- {
- return (E_OUTOFMEMORY);
- }
+ return E_OUTOFMEMORY;
/* Construct the registry key we want */
sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
@@ -1048,9 +1165,9 @@
/* Open the key.. */
if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
{
- WARN("No PSFactoryBuffer object is registered for this IID\n");
- HeapFree(GetProcessHeap(),0,buf);
- return (E_INVALIDARG);
+ WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
+ HeapFree(GetProcessHeap(),0,buf);
+ return REGDB_E_IIDNOTREG;
}
HeapFree(GetProcessHeap(),0,buf);
@@ -1060,19 +1177,18 @@
buf2len = sizeof(buf2);
if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
{
- RegCloseKey(xhkey);
- return E_INVALIDARG;
+ RegCloseKey(xhkey);
+ return REGDB_E_IIDNOTREG;
}
RegCloseKey(xhkey);
/* We have the CLSid we want back from the registry as a string, so
lets convert it into a CLSID structure */
- if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
- return E_INVALIDARG;
- }
+ if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR)
+ return REGDB_E_IIDNOTREG;
TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
- return (S_OK);
+ return S_OK;
}
@@ -1080,7 +1196,15 @@
/***********************************************************************
* WriteClassStm (OLE32.@)
*
- * This function write a CLSID on stream
+ * Writes a CLSID to a stream.
+ *
+ * PARAMS
+ * pStm [I] Stream to write to.
+ * rclsid [I] CLSID to write.
+ *
+ * RETURNS
+ * Success: S_OK.
+ * Failure: HRESULT code.
*/
HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
{
@@ -1095,7 +1219,15 @@
/***********************************************************************
* ReadClassStm (OLE32.@)
*
- * This function read a CLSID from a stream
+ * Reads a CLSID from a stream.
+ *
+ * PARAMS
+ * pStm [I] Stream to read from.
+ * rclsid [O] CLSID to read.
+ *
+ * RETURNS
+ * Success: S_OK.
+ * Failure: HRESULT code.
*/
HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
{
@@ -1196,6 +1328,13 @@
* files use this method instead of exporting DllGetClassObject to allow
* other code to connect to their objects.
*
+ * PARAMS
+ * rclsid [I] CLSID of the object to register.
+ * pUnk [I] IUnknown of the object.
+ * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
+ * flags [I] REGCLS flags indicating how connections are made.
+ * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
+ *
* RETURNS
* S_OK on success,
* E_INVALIDARG if lpdwRegister or pUnk are NULL,
@@ -1209,11 +1348,11 @@
* can't do that with our current implementation.
*/
HRESULT WINAPI CoRegisterClassObject(
- REFCLSID rclsid, /* [in] CLSID of the object to register */
- LPUNKNOWN pUnk, /* [in] IUnknown of the object */
- DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
- DWORD flags, /* [in] REGCLS flags indicating how connections are made */
- LPDWORD lpdwRegister) /* [out] A unique cookie that can be passed to CoRevokeClassObject */
+ REFCLSID rclsid,
+ LPUNKNOWN pUnk,
+ DWORD dwClsContext,
+ DWORD flags,
+ LPDWORD lpdwRegister)
{
RegisteredClass* newClass;
LPUNKNOWN foundObject;
[truncated at 1000 lines; 5300 more skipped]