mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2959 lines
85 KiB
2959 lines
85 KiB
//+-------------------------------------------------------------------
|
|
//
|
|
// File: resolver.cxx
|
|
//
|
|
// Contents: class implementing interface to RPC OXID/PingServer
|
|
// resolver process. Only one instance per process.
|
|
//
|
|
// Classes: CRpcResolver
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
#include <ole2int.h>
|
|
#include <resolver.hxx> // CRpcResolver
|
|
#include <service.hxx> // GetStringBindings
|
|
#include <locks.hxx> // LOCK/UNLOCK etc
|
|
#include <security.hxx> // GetCallAuthnLevel
|
|
#include <marshal.hxx> // GetOXIDFromObjRef
|
|
#include <sobjact.hxx> // CObjServer
|
|
|
|
|
|
// global instance of OXID resolver
|
|
CRpcResolver gResolver;
|
|
|
|
// static members of CRpcResolver
|
|
|
|
handle_t CRpcResolver::_hRpc = NULL; // binding handle to resolver
|
|
PHPROCESS CRpcResolver::_ph = NULL; // context handle to resolver
|
|
HANDLE CRpcResolver::_hThrd = NULL; // worker thread handle
|
|
HANDLE CRpcResolver::_hEventOXID = NULL; // event for registering threads
|
|
DWORD CRpcResolver::_dwFlags = 0; // flags
|
|
DWORD CRpcResolver::_dwSleepPeriod = 0; // worker thread sleep period
|
|
ULONG CRpcResolver::_cReservedOidsAvail = 0;
|
|
ULONGLONG CRpcResolver::_OidNextReserved = 0;
|
|
ULONG CRpcResolver::_cOidsToAdd = 0; // # OIDs to add next call
|
|
ULONG CRpcResolver::_cOidsToRemove = 0; // # OIDs to remove next call
|
|
ULONG CRpcResolver::_cPreRegOidsAvail = 0; // # Pre-Regist'd OIDs available
|
|
OID CRpcResolver::_arPreRegOids[MAX_PREREGISTERED_OIDS];
|
|
|
|
IDSCM * CRpcResolver::_pSCMSTA = NULL; // single-threaded scm proxy
|
|
IDSCM * CRpcResolver::_pSCMMTA = NULL; // multi-threaded scm proxy
|
|
LPWSTR CRpcResolver::_pwszWinstaDesktop = NULL;
|
|
|
|
DWORD CRpcResolver::_dwProcessSignature = 0;
|
|
BOOL CRpcResolver::_bDynamicSecurity = FALSE;
|
|
|
|
// List of OIDs to register/ping/revoke with the resolver used
|
|
// for lazy/batch client-side OID processing.
|
|
|
|
SOIDRegistration CRpcResolver::_ClientOIDRegList = {{{NULL, NULL},},
|
|
0, 0, NULL,
|
|
&_ClientOIDRegList,
|
|
&_ClientOIDRegList};
|
|
// MID (machine ID) of local machine
|
|
MID gLocalMid;
|
|
|
|
// Ping period in milliseconds.
|
|
DWORD giPingPeriod;
|
|
|
|
// string binding to the resolver
|
|
const WCHAR *pwszResolverBindString = L"ncalrpc:[epmapper,Security=Impersonation Dynamic False]";
|
|
|
|
// String arrays for the SCM process. These are used to tell the interface
|
|
// marshaling code the protocol and endpoint of the SCM process.
|
|
|
|
#ifdef _CHICAGO_
|
|
typedef struct tagSCMSA
|
|
{
|
|
unsigned short wNumEntries; // Number of entries in array.
|
|
unsigned short wSecurityOffset; // Offset of security info.
|
|
WCHAR awszStringArray[26];
|
|
} SCMSA;
|
|
|
|
SCMSA saSCM = {26, 25, L"mswmsg:[endpoint mapper]\0" };
|
|
|
|
#else
|
|
|
|
typedef struct tagSCMSA
|
|
{
|
|
unsigned short wNumEntries; // Number of entries in array.
|
|
unsigned short wSecurityOffset; // Offset of security info.
|
|
WCHAR awszStringArray[60];
|
|
} SCMSA;
|
|
|
|
// The last 4 characters in the string define the security bindings.
|
|
// \0xA is RPC_C_AUTHN_WINNT
|
|
// \0xFFFF is COM_C_AUTHZ_NONE
|
|
// \0 is an empty principle name
|
|
SCMSA saSCM = {57, 56, L"ncalrpc:[epmapper,Security=Impersonation Dynamic False]\0\xA\xFFFF\0"};
|
|
#endif
|
|
|
|
DWORD GetThreadWinstaDesktop( WCHAR ** ppwszWinstaDesktop );
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::Cleanup, public
|
|
//
|
|
// Synopsis: cleanup the resolver state. Called by ProcessUninitialze.
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CRpcResolver::Cleanup()
|
|
{
|
|
ASSERT_LOCK_HELD
|
|
|
|
// release our context handle
|
|
if (_ph != NULL)
|
|
{
|
|
RpcSmDestroyClientContext(&_ph);
|
|
_ph = NULL;
|
|
}
|
|
|
|
// release regular handle
|
|
if (_hRpc)
|
|
{
|
|
RpcBindingFree(&_hRpc);
|
|
_hRpc = NULL;
|
|
}
|
|
|
|
// Release the string bindings for the local object exporter.
|
|
if (gpsaLocalResolver)
|
|
{
|
|
MIDL_user_free(gpsaLocalResolver);
|
|
gpsaLocalResolver = NULL;
|
|
}
|
|
|
|
// empty the OIDRegList. Any SOIDRegistration records have already
|
|
// been deleted by the gClientRegisteredOIDs list cleanup code.
|
|
|
|
_ClientOIDRegList.pPrevList = &_ClientOIDRegList;
|
|
_ClientOIDRegList.pNextList = &_ClientOIDRegList;
|
|
_cOidsToAdd = 0;
|
|
_cOidsToRemove = 0;
|
|
|
|
// zero the count of pre-registered oids since all pre-registered
|
|
// Oids are for our old OXID value.
|
|
|
|
_cPreRegOidsAvail = 0;
|
|
|
|
// close the event handle (if any)
|
|
if (_hEventOXID)
|
|
{
|
|
CloseHandle(_hEventOXID);
|
|
_hEventOXID = NULL;
|
|
}
|
|
|
|
if (_pwszWinstaDesktop != NULL)
|
|
{
|
|
PrivMemFree(_pwszWinstaDesktop);
|
|
_pwszWinstaDesktop = NULL;
|
|
}
|
|
|
|
_bDynamicSecurity = FALSE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ReleaseSCMProxy, public
|
|
//
|
|
// Synopsis: cleanup the resolver state. Called by ProcessUninitialze.
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CRpcResolver::ReleaseSCMProxy()
|
|
{
|
|
if (_pSCMSTA != NULL)
|
|
{
|
|
_pSCMSTA->Release();
|
|
_pSCMSTA = NULL;
|
|
}
|
|
|
|
if (_pSCMMTA != NULL)
|
|
{
|
|
_pSCMMTA->Release();
|
|
_pSCMMTA = NULL;
|
|
}
|
|
|
|
if (gpMTAObjServer != NULL)
|
|
{
|
|
delete gpMTAObjServer;
|
|
gpMTAObjServer = NULL;
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::RetryRPC, private
|
|
//
|
|
// Synopsis: determine if we need to retry the RPC call due to
|
|
// the resolver being too busy.
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
BOOL CRpcResolver::RetryRPC(RPC_STATUS sc)
|
|
{
|
|
if (sc != RPC_S_SERVER_TOO_BUSY)
|
|
return FALSE;
|
|
|
|
// give the resolver time to run, then try again.
|
|
Sleep(100);
|
|
|
|
// CODEWORK: this is currently an infinite loop. Should we limit it?
|
|
return TRUE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::CheckStatus, private
|
|
//
|
|
// Synopsis: Checks the status code of an Rpc call, prints a debug
|
|
// ERROR message if failed, and maps the failed status code
|
|
// into an HRESULT.
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::CheckStatus(RPC_STATUS sc)
|
|
{
|
|
if (sc != RPC_S_OK)
|
|
{
|
|
ComDebOut((DEB_ERROR, "OXID Resolver Failure sc:%x\n", sc));
|
|
sc = HRESULT_FROM_WIN32(sc);
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::GetConnection, public
|
|
//
|
|
// Synopsis: connects to the resolver process
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::GetConnection()
|
|
{
|
|
ComDebOut((DEB_OXID,"CRpcResolver::GetConnection\n"));
|
|
|
|
HRESULT hr;
|
|
COleTls tls(hr);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
RPC_STATUS sc = RPC_S_OK;
|
|
|
|
LOCK
|
|
|
|
if (_ph == NULL)
|
|
{
|
|
sc = RpcBindingFromStringBinding((LPWSTR)pwszResolverBindString, &_hRpc);
|
|
ComDebErr(sc != RPC_S_OK, "Resolver Binding Failed.\n");
|
|
|
|
if (sc == RPC_S_OK)
|
|
{
|
|
OID oidBase;
|
|
DWORD fConnectFlags;
|
|
|
|
do
|
|
{
|
|
// call the resolver to get a context handle
|
|
sc = Connect(_hRpc,
|
|
&_ph,
|
|
&giPingPeriod,
|
|
&gpsaLocalResolver,
|
|
&gLocalMid,
|
|
MAX_RESERVED_OIDS,
|
|
&oidBase,
|
|
&fConnectFlags,
|
|
(WCHAR **) &gLegacySecurity,
|
|
&gAuthnLevel,
|
|
&gImpLevel,
|
|
&gServerSvcListLen,
|
|
&gServerSvcList,
|
|
&gClientSvcListLen,
|
|
&gClientSvcList,
|
|
&(tls->dwApartmentID),
|
|
&gdwScmProcessID,
|
|
&_dwProcessSignature);
|
|
} while (RetryRPC(sc));
|
|
|
|
if (sc == RPC_S_OK)
|
|
{
|
|
gDisableDCOM = fConnectFlags & CONNECT_DISABLEDCOM;
|
|
if (fConnectFlags & CONNECT_MUTUALAUTH)
|
|
gCapabilities = EOAC_MUTUAL_AUTH;
|
|
else
|
|
gCapabilities = EOAC_NONE;
|
|
if (fConnectFlags & CONNECT_SECUREREF)
|
|
gCapabilities |= EOAC_SECURE_REFS;
|
|
|
|
// remember the reserved OID base.
|
|
_OidNextReserved = oidBase;
|
|
_cReservedOidsAvail = MAX_RESERVED_OIDS;
|
|
|
|
// Mark the security data as initialized.
|
|
gGotSecurityData = TRUE;
|
|
if (IsWOWProcess())
|
|
{
|
|
gDisableDCOM = TRUE;
|
|
}
|
|
|
|
// Convert the ping period from seconds to milliseconds.
|
|
giPingPeriod *= 1000;
|
|
Win4Assert(gpsaLocalResolver->wNumEntries != 0);
|
|
|
|
// compute the sleep period for the registration worker thread
|
|
// (which is 1/6th the ping period). The ping period may differ
|
|
// on debug and retail builds.
|
|
#if DBG==1
|
|
// shorter time period to enable testing
|
|
_dwSleepPeriod = 5000;
|
|
#else
|
|
_dwSleepPeriod = giPingPeriod / 6;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
ComDebOut((DEB_OXID, "Resolver Connect Failed sc:%x\n", sc));
|
|
RpcBindingFree(&_hRpc);
|
|
_hRpc = NULL;
|
|
Win4Assert(gpsaLocalResolver == NULL);
|
|
Win4Assert(_ph == NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( (sc == RPC_S_OK) && (_pwszWinstaDesktop == NULL))
|
|
sc = SetWinstaDesktop();
|
|
|
|
UNLOCK
|
|
|
|
hr = CheckStatus(sc);
|
|
ComDebErr(hr != S_OK, "GetConnection Failed.\n");
|
|
ComDebOut((DEB_OXID,"CRpcResolver::GetConnection hr:%x\n", hr));
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ServerGetReservedMOID, public
|
|
//
|
|
// Synopsis: Get an OID that does not need to be pinged.
|
|
//
|
|
// History: 06-Nov-95 Rickhi Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ServerGetReservedMOID(MOID *pmoid)
|
|
{
|
|
ComDebOut((DEB_OXID,"ServerGetReservedMOID\n"));
|
|
|
|
OID oid;
|
|
HRESULT hr = ServerGetReservedID(&oid);
|
|
|
|
MOIDFromOIDAndMID(oid, gLocalMid, pmoid);
|
|
|
|
ASSERT_LOCK_HELD
|
|
ComDebOut((DEB_OXID,"ServerGetReservedMOID hr:%x moid:%I\n", pmoid));
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ServerGetReservedID, public
|
|
//
|
|
// Synopsis: Get an ID that does not need to be pinged.
|
|
//
|
|
// History: 06-Nov-95 Rickhi Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ServerGetReservedID(OID *pid)
|
|
{
|
|
ComDebOut((DEB_OXID,"ServerGetReservedID\n"));
|
|
ASSERT_LOCK_HELD
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_cReservedOidsAvail == 0)
|
|
{
|
|
// go get more reserved OIDs from the ping server
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
OID OidBase;
|
|
|
|
do
|
|
{
|
|
hr = ::AllocateReservedIds(
|
|
_hRpc, // Rpc binding handle
|
|
MAX_RESERVED_OIDS, // count of OIDs requested
|
|
&OidBase); // place to hold base id
|
|
|
|
} while (RetryRPC(hr));
|
|
|
|
// map Rpc status if necessary
|
|
hr = CheckStatus(hr);
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// copy into global state. Dont have to worry about two threads
|
|
// getting more simultaneously, since these OIDs are expendable.
|
|
|
|
_cReservedOidsAvail = MAX_RESERVED_OIDS;
|
|
_OidNextReserved = OidBase;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pid = _OidNextReserved;
|
|
_OidNextReserved++;
|
|
_cReservedOidsAvail--;
|
|
}
|
|
|
|
ASSERT_LOCK_HELD
|
|
ComDebOut((DEB_OXID,"ServerGetReservedID hr:%x id:%08x %08x\n", *pid));
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ServerGetPreRegMOID, public
|
|
//
|
|
// Synopsis: Get an OID that has been pre-registered with the Ping
|
|
// Server.
|
|
//
|
|
// History: 06-Nov-95 Rickhi Created.
|
|
//
|
|
// Notes: careful. The oids are dispensed in reverse order [n]-->[0], so the
|
|
// unused ones are from [0]-->[cPreRegOidsAvail-1]. ServerCanRundownOID
|
|
// depends on this behavior.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ServerGetPreRegMOID(MOID *pmoid)
|
|
{
|
|
ComDebOut((DEB_OXID,"ServerGetPreRegMOID\n"));
|
|
ASSERT_LOCK_HELD
|
|
|
|
// Get the local OXID. This cant fail because the local
|
|
// entry was pre-created in ChannelThreadInitialize.
|
|
|
|
OXIDEntry *pOXIDEntry;
|
|
HRESULT hr = gOXIDTbl.GetLocalEntry(&pOXIDEntry);
|
|
Win4Assert(SUCCEEDED(hr));
|
|
|
|
COleTls tls;
|
|
if (!(tls->dwFlags & OLETLS_APARTMENTTHREADED))
|
|
{
|
|
// in MTA Apartment, use the global list and global count.
|
|
|
|
if (_cPreRegOidsAvail == 0)
|
|
{
|
|
hr = ServerAllocMoreOIDs(&_cPreRegOidsAvail, _arPreRegOids,
|
|
pOXIDEntry);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_cPreRegOidsAvail--;
|
|
MOIDFromOIDAndMID(_arPreRegOids[_cPreRegOidsAvail],
|
|
gLocalMid, pmoid);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// In STA Apartment, the pre-registered OIDs are kept per apartment
|
|
// in a list off of tls.
|
|
|
|
if (tls->cPreRegOidsAvail == 0)
|
|
{
|
|
if (tls->pPreRegOids == NULL)
|
|
{
|
|
// first time for this thread. Allocate a list to hold
|
|
// the pre-registered oids.
|
|
|
|
tls->pPreRegOids = (OID *)PrivMemAlloc(MAX_PREREGISTERED_OIDS *
|
|
sizeof(OID));
|
|
if (tls->pPreRegOids == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ServerAllocMoreOIDs(&tls->cPreRegOidsAvail,
|
|
tls->pPreRegOids, pOXIDEntry);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
tls->cPreRegOidsAvail--;
|
|
MOIDFromOIDAndMID(tls->pPreRegOids[tls->cPreRegOidsAvail],
|
|
gLocalMid, pmoid);
|
|
}
|
|
}
|
|
|
|
ASSERT_LOCK_HELD
|
|
ComDebOut((DEB_OXID,"ServerGetPreRegMOID hr:%x moid:%I\n", hr, pmoid));
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ServerCanRundownOID, public
|
|
//
|
|
// Synopsis: Determine if OK to rundown the specified OID.
|
|
//
|
|
// History: 06-Nov-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
BOOL CRpcResolver::ServerCanRundownOID(REFOID roid)
|
|
{
|
|
ComDebOut((DEB_OXID,"ServerCanRundownOID poid:%x\n", &roid));
|
|
ASSERT_LOCK_HELD
|
|
|
|
// look in the list of unused pre-registered OIDs to see if the
|
|
// OID is in there. If so, we dont want to run it down yet so
|
|
// return FALSE, otherwise return TRUE
|
|
|
|
BOOL fRundown = TRUE; // assume not found
|
|
|
|
ULONG cPreRegOidsAvail = _cPreRegOidsAvail;
|
|
OID *pPreRegOids = &_arPreRegOids[0];
|
|
|
|
COleTls tls;
|
|
|
|
if (tls->dwFlags & OLETLS_APARTMENTTHREADED)
|
|
{
|
|
cPreRegOidsAvail = tls->cPreRegOidsAvail;
|
|
pPreRegOids = tls->pPreRegOids;
|
|
}
|
|
|
|
// carefull. The oids are dispensed in reverse order (ie [n]-->[0])
|
|
// so when checking for unused ones check in forward order
|
|
// [0]-->[cPreRegOidsAvail-1]
|
|
|
|
for (ULONG i=0; i<cPreRegOidsAvail; i++, pPreRegOids++)
|
|
{
|
|
if (roid == *pPreRegOids)
|
|
{
|
|
// found the oid in the list of unused ones. Dont run it down.
|
|
fRundown = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT_LOCK_HELD
|
|
ComDebOut((DEB_OXID,"ServerCanRundownOID fRundown:%x\n", fRundown));
|
|
return fRundown;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::WaitForOXIDEntry, private
|
|
//
|
|
// Synopsis: waits until an OXIDEntry is not busy
|
|
//
|
|
// History: 06-Nov-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::WaitForOXIDEntry(OXIDEntry *pOXIDEntry)
|
|
{
|
|
ASSERT_LOCK_HELD
|
|
|
|
if (pOXIDEntry->dwFlags & OXIDF_REGISTERINGOIDS)
|
|
{
|
|
// some other thread is busy registering OIDs for this OXID
|
|
// so lets wait for it to finish. This should only happen in
|
|
// the MTA apartment.
|
|
Win4Assert(IsMTAThread());
|
|
|
|
if (_hEventOXID == NULL)
|
|
{
|
|
_hEventOXID = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (_hEventOXID == NULL)
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
// count one more waiter
|
|
pOXIDEntry->cWaiters++;
|
|
|
|
do
|
|
{
|
|
// release the lock before we block so the other thread can wake
|
|
// us up when it returns.
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
ComDebOut((DEB_WARN,"WaitForOXIDEntry wait on hEvent:%x\n", _hEventOXID));
|
|
DWORD rc = WaitForSingleObject(_hEventOXID, INFINITE);
|
|
Win4Assert(rc == WAIT_OBJECT_0);
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
} while (pOXIDEntry->dwFlags & OXIDF_REGISTERINGOIDS);
|
|
|
|
// one less waiter
|
|
pOXIDEntry->cWaiters--;
|
|
}
|
|
|
|
// mark the entry as busy by us
|
|
pOXIDEntry->dwFlags |= OXIDF_REGISTERINGOIDS;
|
|
|
|
ASSERT_LOCK_HELD
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::CheckForWaiters, private
|
|
//
|
|
// Synopsis: wakes up any threads waiting for this OXIDEntry
|
|
//
|
|
// History: 06-Nov-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CRpcResolver::CheckForWaiters(OXIDEntry *pOXIDEntry)
|
|
{
|
|
ASSERT_LOCK_HELD
|
|
|
|
if (pOXIDEntry->cWaiters > 0)
|
|
{
|
|
// some other thread is busy waiting for the current thread to
|
|
// finish registering so signal him that we are done.
|
|
|
|
Win4Assert(_hEventOXID != NULL);
|
|
ComDebOut((DEB_TRACE,"CheckForWaiters signalling hEvent:%x\n", _hEventOXID));
|
|
SetEvent(_hEventOXID);
|
|
}
|
|
|
|
// mark the entry as no longer busy by us
|
|
pOXIDEntry->dwFlags &= ~OXIDF_REGISTERINGOIDS;
|
|
|
|
ASSERT_LOCK_HELD
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ServerAllocMoreOIDs, private
|
|
//
|
|
// Synopsis: register Object ID with the local ping server
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ServerAllocMoreOIDs(ULONG *pcPreRegOidsAvail,
|
|
OID *parPreRegOids,
|
|
OXIDEntry *pOXIDEntry)
|
|
{
|
|
ComDebOut((DEB_OXID,"ServerAllocMoreOIDs\n"));
|
|
ASSERT_LOCK_HELD
|
|
Win4Assert(_ph != NULL);
|
|
|
|
// wait until no other threads are calling ServerAllocOIDs
|
|
HRESULT hr = WaitForOXIDEntry(pOXIDEntry);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (*pcPreRegOidsAvail == 0)
|
|
{
|
|
// need to really go get more
|
|
hr = ServerAllocOIDs(pOXIDEntry,
|
|
pcPreRegOidsAvail,
|
|
parPreRegOids);
|
|
}
|
|
|
|
// wakeup any waiters
|
|
CheckForWaiters(pOXIDEntry);
|
|
}
|
|
|
|
ComDebOut((DEB_OXID, "ServerAllocMoreOIDs hr:%x\n", hr));
|
|
ComDebErr(hr != S_OK, "ServerAllocMoreOIDs Failed.\n");
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ServerAllocOIDs, private
|
|
//
|
|
// Synopsis: allocate Object IDs from the local ping server
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ServerAllocOIDs(OXIDEntry *pOXIDEntry,
|
|
ULONG *pcPreRegOidsAvail,
|
|
OID *parPreRegOids)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// make up a list of pre-registered OIDs on our stack so multiple
|
|
// threads executing here simultaneously are not a problem.
|
|
|
|
ULONG cOidsToAllocate = MAX_PREREGISTERED_OIDS;
|
|
OID arNewOidList[MAX_PREREGISTERED_OIDS];
|
|
|
|
if (!(pOXIDEntry->dwFlags & OXIDF_REGISTERED))
|
|
{
|
|
// have not yet registered the OXID, so go do that at the same time
|
|
// we allocate OIDs.
|
|
|
|
hr = ServerRegisterOXID(pOXIDEntry, &cOidsToAllocate, arNewOidList);
|
|
}
|
|
else
|
|
{
|
|
// just need to allocate more OIDs.
|
|
|
|
OXID oxid;
|
|
OXIDFromMOXID(pOXIDEntry->moxid, &oxid);
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
do
|
|
{
|
|
hr = ::ServerAllocateOIDs(
|
|
_hRpc, // Rpc binding handle
|
|
_ph, // context handle
|
|
&oxid, // OXID of server
|
|
cOidsToAllocate, // count of OIDs requested
|
|
arNewOidList, // array of reserved oids
|
|
&cOidsToAllocate);// count actually allocated
|
|
|
|
} while (RetryRPC(hr));
|
|
|
|
// map Rpc status if necessary
|
|
hr = CheckStatus(hr);
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// copy the newly created OIDs into the list in whatever space
|
|
// is still available, since some other thread could have come
|
|
// along and pre-registered OIDs simultaneously (in MTA apartment
|
|
// only). The OIDs that are not copied will be lost and
|
|
// eventually the resolver will run them down. This should be
|
|
// relatively rare.
|
|
|
|
LONG cToCopy = min(cOidsToAllocate,
|
|
MAX_PREREGISTERED_OIDS - *pcPreRegOidsAvail);
|
|
|
|
memcpy(parPreRegOids + *pcPreRegOidsAvail,
|
|
arNewOidList,
|
|
sizeof(OID) * cToCopy);
|
|
|
|
*pcPreRegOidsAvail += cToCopy;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ServerRegisterOXID, public
|
|
//
|
|
// Synopsis: allocate an OXID and Object IDs with the local ping server
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ServerRegisterOXID(OXIDEntry *pOXIDEntry,
|
|
ULONG *pcOidsToAllocate,
|
|
OID arNewOidList[])
|
|
{
|
|
ComDebOut((DEB_OXID, "ServerRegisterOXID TID:%x\n", GetCurrentThreadId()));
|
|
ASSERT_LOCK_HELD
|
|
|
|
// OXID has not yet been registered with the resolver, do that
|
|
// now along with pre-registering a bunch of OIDs.
|
|
|
|
// make sure we have the local binding and security strings
|
|
HRESULT hr = StartListen();
|
|
ComDebErr(hr != S_OK, "StartListen Failed.\n");
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
OXID_INFO oxidInfo;
|
|
oxidInfo.dwTid = pOXIDEntry->dwTid;
|
|
oxidInfo.dwPid = pOXIDEntry->dwPid;
|
|
oxidInfo.ipidRemUnknown = pOXIDEntry->ipidRundown;
|
|
oxidInfo.dwAuthnHint = gAuthnLevel;
|
|
oxidInfo.psa = NULL;
|
|
|
|
|
|
DUALSTRINGARRAY *psaSB = gpsaCurrentProcess; // string bindings
|
|
DUALSTRINGARRAY *psaSC = gpsaSecurity; // security bindings
|
|
|
|
if (_dwFlags & ORF_STRINGSREGISTERED)
|
|
{
|
|
// already registered these once, dont need to do it again.
|
|
psaSB = NULL;
|
|
psaSC = NULL;
|
|
}
|
|
|
|
OXID oxid;
|
|
|
|
ComDebOut((DEB_OXID,"ServerRegisterOXID oxidInfo:%x psaSB:%x psaSC:%x\n",
|
|
&oxidInfo, psaSB, psaSC));
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
do
|
|
{
|
|
hr = ::ServerAllocateOXIDAndOIDs(
|
|
_hRpc, // Rpc binding handle
|
|
_ph, // context handle
|
|
&oxid, // OXID of server
|
|
IsSTAThread(), // fApartment Threaded
|
|
*pcOidsToAllocate, // count of OIDs requested
|
|
arNewOidList, // array of reserved oids
|
|
pcOidsToAllocate, // count actually allocated
|
|
&oxidInfo, // OXID_INFO to register
|
|
psaSB, // string bindings for process
|
|
psaSC); // security bindings for process
|
|
|
|
} while (RetryRPC(hr));
|
|
|
|
// map Rpc status if necessary
|
|
hr = CheckStatus(hr);
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
// mark the OXID as registered with the resolver, and replace
|
|
// the (temporarily zero) oxid with the real one the resolver
|
|
// returned to us.
|
|
|
|
pOXIDEntry->dwFlags |= OXIDF_REGISTERED;
|
|
MOXIDFromOXIDAndMID(oxid, gLocalMid, &pOXIDEntry->moxid);
|
|
}
|
|
}
|
|
|
|
ComDebOut((DEB_OXID, "ServerRegisterOXID hr:%x\n", hr));
|
|
ASSERT_LOCK_HELD
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ServerFreeOXID, public
|
|
//
|
|
// Synopsis: frees an OXID and associated OIDs that were pre-registered
|
|
// with the local ping server
|
|
//
|
|
// History: 20-Jan-96 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ServerFreeOXID(OXIDEntry *pOXIDEntry)
|
|
{
|
|
ComDebOut((DEB_OXID, "ServerFreeOXID TID:%x\n", GetCurrentThreadId()));
|
|
ASSERT_LOCK_HELD
|
|
|
|
if (!(pOXIDEntry->dwFlags & OXIDF_REGISTERED))
|
|
{
|
|
// OXID was never registered, just return
|
|
return S_OK;
|
|
}
|
|
|
|
// Free any pre-registered OIDs since these are registered for the
|
|
// current OXID. We get a new OXID if the thread is re-initialized.
|
|
// Set the ptr and count of Oids to de-register.
|
|
|
|
ULONG cOids;
|
|
OID *pOids;
|
|
|
|
COleTls tls;
|
|
if (!(tls->dwFlags & OLETLS_APARTMENTTHREADED))
|
|
{
|
|
pOids = _arPreRegOids;
|
|
cOids = _cPreRegOidsAvail;
|
|
_cPreRegOidsAvail = 0;
|
|
}
|
|
else
|
|
{
|
|
cOids = tls->cPreRegOidsAvail;
|
|
tls->cPreRegOidsAvail = 0;
|
|
|
|
pOids = tls->pPreRegOids;
|
|
tls->pPreRegOids = NULL;
|
|
}
|
|
|
|
// extract the OXID and mark the OXIDEntry as no longer registered
|
|
OXID oxid;
|
|
OXIDFromMOXID(pOXIDEntry->moxid, &oxid);
|
|
pOXIDEntry->dwFlags &= ~OXIDF_REGISTERED;
|
|
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
// call the resolver.
|
|
HRESULT hr;
|
|
|
|
do
|
|
{
|
|
Win4Assert(_ph != NULL);
|
|
|
|
hr = ::ServerFreeOXIDAndOIDs(
|
|
_hRpc, // Rpc binding handle
|
|
_ph, // context handle
|
|
oxid, // OXID of server
|
|
cOids, // count of OIDs to de-register
|
|
pOids); // ptr to OIDs to de-register
|
|
|
|
} while (RetryRPC(hr));
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
// map Rpc status if necessary
|
|
hr = CheckStatus(hr);
|
|
|
|
if (tls->dwFlags & OLETLS_APARTMENTTHREADED)
|
|
{
|
|
// delete the space allocated for the pre-registered OIDs
|
|
PrivMemFree(pOids);
|
|
}
|
|
|
|
ComDebOut((DEB_OXID, "ServerFreeOXID hr:%x\n", hr));
|
|
ASSERT_LOCK_HELD
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ClientResolveOXID, public
|
|
//
|
|
// Synopsis: Resolve client-side OXID and returns the OXIDEntry, AddRef'd.
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ClientResolveOXID(REFOXID roxid,
|
|
DUALSTRINGARRAY *psaResolver,
|
|
OXIDEntry **ppOXIDEntry)
|
|
{
|
|
ComDebOut((DEB_OXID,"ClientResolveOXID oxid:%08x %08x psa:%x\n",
|
|
roxid, psaResolver));
|
|
ASSERT_LOCK_HELD
|
|
RPC_STATUS sc = RPC_S_OK;
|
|
|
|
*ppOXIDEntry = NULL;
|
|
|
|
// Look for a MID entry for the resolver. if we cant find it
|
|
// then we know we dont have an OXIDEntry for the oxid.
|
|
|
|
DWORD dwHash;
|
|
MIDEntry *pMIDEntry = gMIDTbl.LookupMID(psaResolver, &dwHash);
|
|
if (pMIDEntry)
|
|
{
|
|
// found the MID, now look for the OXID
|
|
*ppOXIDEntry = gOXIDTbl.LookupOXID(roxid, pMIDEntry->mid);
|
|
}
|
|
|
|
if (*ppOXIDEntry == NULL)
|
|
{
|
|
// didn't find the OXIDEntry in the table so we need to resolve it.
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
MID mid;
|
|
OXID_INFO oxidInfo;
|
|
oxidInfo.psa = NULL;
|
|
|
|
do
|
|
{
|
|
Win4Assert(_ph != NULL);
|
|
|
|
sc = ::ClientResolveOXID(
|
|
_hRpc, // Rpc binding handle
|
|
_ph, // context handle
|
|
(OXID *)&roxid, // OXID of server
|
|
psaResolver, // resolver binging strings
|
|
IsSTAThread(), // fApartment threaded
|
|
// GetCallAuthnLevel(), CODEWORK: someday
|
|
&oxidInfo, // resolver info returned
|
|
&mid); // mid for the machine
|
|
|
|
} while (RetryRPC(sc));
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
// map Rpc status if necessary
|
|
sc = CheckStatus(sc);
|
|
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
// create an OXIDEntry.
|
|
sc = FindOrCreateOXIDEntry(roxid, oxidInfo, FOCOXID_REF,
|
|
psaResolver,
|
|
mid, pMIDEntry, ppOXIDEntry);
|
|
|
|
// free the returned string bindings
|
|
MIDL_user_free(oxidInfo.psa);
|
|
}
|
|
}
|
|
|
|
if (pMIDEntry)
|
|
{
|
|
DecMIDRefCnt(pMIDEntry);
|
|
}
|
|
|
|
ASSERT_LOCK_HELD
|
|
ComDebOut((DEB_OXID,"ClientResolveOXID hr:%x pOXIDEntry:%x\n",
|
|
sc, *ppOXIDEntry));
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: FillLocalOXIDInfo
|
|
//
|
|
// Synopsis: Fills in a OXID_INFO structure for the current apartment.
|
|
// Used by the Drag & Drop code to register with the resolver.
|
|
//
|
|
// History: 20-Feb-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT FillLocalOXIDInfo(OBJREF &objref, OXID_INFO &oxidInfo)
|
|
{
|
|
// extract the OXIDEntry from the objref
|
|
OXIDEntry *pOXIDEntry = GetOXIDFromObjRef(objref);
|
|
Win4Assert(pOXIDEntry);
|
|
|
|
// fill in the fields of the OXID_INFO structure.
|
|
oxidInfo.dwTid = pOXIDEntry->dwTid;
|
|
oxidInfo.dwPid = pOXIDEntry->dwPid;
|
|
oxidInfo.ipidRemUnknown = pOXIDEntry->ipidRundown;
|
|
oxidInfo.dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE;
|
|
|
|
HRESULT hr = GetStringBindings(&oxidInfo.psa);
|
|
ComDebErr(hr != S_OK, "GetStringBindings Failed.\n");
|
|
return (hr);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: AddToList / RemoveFromList
|
|
//
|
|
// Synopsis: adds or removes an SOIDRegistration entry to/from
|
|
// a doubly linked list.
|
|
//
|
|
// History: 30-Oct-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void AddToList(SOIDRegistration *pOIDReg, SOIDRegistration* pOIDListHead)
|
|
{
|
|
pOIDReg->pPrevList = pOIDListHead;
|
|
pOIDListHead->pNextList->pPrevList = pOIDReg;
|
|
pOIDReg->pNextList = pOIDListHead->pNextList;
|
|
pOIDListHead->pNextList = pOIDReg;
|
|
}
|
|
|
|
void RemoveFromList(SOIDRegistration *pOIDReg)
|
|
{
|
|
pOIDReg->pPrevList->pNextList = pOIDReg->pNextList;
|
|
pOIDReg->pNextList->pPrevList = pOIDReg->pPrevList;
|
|
pOIDReg->pPrevList = pOIDReg;
|
|
pOIDReg->pNextList = pOIDReg;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ClientRegisterOIDWithPingServer
|
|
//
|
|
// Synopsis: registers an OID with the Ping Server if it has
|
|
// not already been registered.
|
|
//
|
|
// History: 30-Oct-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ClientRegisterOIDWithPingServer(REFOID roid,
|
|
OXIDEntry *pOXIDEntry)
|
|
{
|
|
ComDebOut((DEB_OXID, "ClientRegisterOIDWithPingServer poid:%x\n", &roid));
|
|
ASSERT_LOCK_HELD
|
|
AssertValid();
|
|
HRESULT hr = S_OK;
|
|
|
|
// make a MOID from the OID
|
|
MOID moid;
|
|
MOIDFromOIDAndMID(roid, pOXIDEntry->pMIDEntry->mid, &moid);
|
|
|
|
|
|
// see if this OID already has a client-side registration
|
|
// record created by another apartment in this process.
|
|
|
|
DWORD iHash = gClientRegisteredOIDs.Hash(moid);
|
|
SOIDRegistration *pOIDReg = (SOIDRegistration *)
|
|
gClientRegisteredOIDs.Lookup(iHash, moid);
|
|
|
|
if (pOIDReg == NULL)
|
|
{
|
|
// not yet registered with resolver, create a new entry and
|
|
// add it to the hash table and to the List of items to register
|
|
// with the Resolver.
|
|
|
|
// make sure we have a worker thread ready to do the register
|
|
// at some point in the future.
|
|
hr = EnsureWorkerThread();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
pOIDReg = new SOIDRegistration;
|
|
|
|
if (pOIDReg)
|
|
{
|
|
pOIDReg->cRefs = 1;
|
|
pOIDReg->pPrevList = pOIDReg;
|
|
pOIDReg->pNextList = pOIDReg;
|
|
pOIDReg->pOXIDEntry = pOXIDEntry;
|
|
|
|
gClientRegisteredOIDs.Add(iHash, moid, (SUUIDHashNode *)pOIDReg);
|
|
|
|
pOIDReg->flags = ROIDF_REGISTER;
|
|
AddToList(pOIDReg, &_ClientOIDRegList);
|
|
_cOidsToAdd++;
|
|
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// already have a record for this OID, inc the refcnt
|
|
pOIDReg->cRefs++;
|
|
|
|
if (pOIDReg->cRefs == 1)
|
|
{
|
|
// re-using an entry that had a count of zero, so it must have
|
|
// been going to be deregistered or pinged.
|
|
Win4Assert((pOIDReg->flags == ROIDF_PING) ||
|
|
(pOIDReg->flags == ROIDF_DEREGISTER));
|
|
|
|
_cOidsToRemove--;
|
|
|
|
if (pOIDReg->flags & ROIDF_PING)
|
|
{
|
|
// was only going to be pinged, now must be added.
|
|
pOIDReg->flags |= ROIDF_REGISTER;
|
|
}
|
|
else
|
|
{
|
|
// was going to be unregistered, already registered so does
|
|
// not need to be on the registration list anymmore
|
|
|
|
Win4Assert(pOIDReg->flags & ROIDF_DEREGISTER);
|
|
pOIDReg->flags = 0;
|
|
RemoveFromList(pOIDReg);
|
|
}
|
|
}
|
|
}
|
|
|
|
AssertValid();
|
|
ASSERT_LOCK_HELD
|
|
ComDebOut((DEB_OXID,"ClientRegisterOIDWithPingServer pOIDReg:%x hr:%x\n",
|
|
pOIDReg, hr));
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ClientDeRegisterOIDWithPingServer
|
|
//
|
|
// Synopsis: de-registers an OID that has previously been registered
|
|
// with the Ping Server
|
|
//
|
|
// History: 30-Oct-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ClientDeRegisterOIDFromPingServer(REFMOID rmoid,
|
|
BOOL fMarshaled)
|
|
{
|
|
ComDebOut((DEB_OXID,"ClientDeRegisterOIDWithPingServer rmoid:%I\n", &rmoid));
|
|
ASSERT_LOCK_HELD
|
|
AssertValid();
|
|
|
|
// find the OID in the hash table. it better still be there!
|
|
|
|
DWORD iHash = gClientRegisteredOIDs.Hash(rmoid);
|
|
SOIDRegistration *pOIDReg = (SOIDRegistration *)
|
|
gClientRegisteredOIDs.Lookup(iHash, rmoid);
|
|
Win4Assert(pOIDReg != NULL);
|
|
Win4Assert((pOIDReg->flags == ROIDF_REGISTER) ||
|
|
(pOIDReg->flags == (ROIDF_REGISTER | ROIDF_PING)) ||
|
|
(pOIDReg->flags == 0));
|
|
|
|
if (-- pOIDReg->cRefs == 0)
|
|
{
|
|
// this was the last registration of the OID in this process.
|
|
|
|
if (pOIDReg->flags & ROIDF_REGISTER)
|
|
{
|
|
// still on the Register list, have not yet told the Ping Server
|
|
// about this OID so dont have to do anything unless it was
|
|
// client-side marshaled.
|
|
|
|
if (fMarshaled || pOIDReg->flags & ROIDF_PING)
|
|
{
|
|
// object was marshaled by the client. Still need to tell
|
|
// the Ping Server to ping the OID then forget about it.
|
|
|
|
pOIDReg->flags = ROIDF_PING;
|
|
_cOidsToRemove++;
|
|
|
|
// make sure we have a worker thread ready to do the deregister
|
|
// at some point in the future. Not much we can do about an
|
|
// error here. If transient, then a thread will most likely
|
|
// be created later.
|
|
EnsureWorkerThread();
|
|
}
|
|
else
|
|
{
|
|
// dont need this record any longer. remove from chain
|
|
// and delete the record.
|
|
|
|
RemoveFromList(pOIDReg);
|
|
_cOidsToAdd--;
|
|
gClientRegisteredOIDs.Remove((SHashChain *)pOIDReg);
|
|
delete pOIDReg;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// must already be registered with the resolver. now need to
|
|
// deregister it so put it on the Registration list for delete.
|
|
|
|
pOIDReg->flags = ROIDF_DEREGISTER;
|
|
AddToList(pOIDReg, &_ClientOIDRegList);
|
|
_cOidsToRemove++;
|
|
|
|
// make sure we have a worker thread ready to do the deregister
|
|
// at some point in the future. Not much we can do about an
|
|
// error here. If transient, then a thread will most likely
|
|
// be created later.
|
|
EnsureWorkerThread();
|
|
}
|
|
}
|
|
|
|
AssertValid();
|
|
ASSERT_LOCK_HELD
|
|
ComDebOut((DEB_OXID,"ClientDeRegisterOIDWithPingServer pOIDReg:%x hr:%x\n",
|
|
pOIDReg, S_OK));
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::ClientBulkUpdateOIDWithPingServer
|
|
//
|
|
// Synopsis: registers/deregisters/pings any OIDs waiting to be
|
|
// sent to the ping server.
|
|
//
|
|
// History: 30-Oct-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::ClientBulkUpdateOIDWithPingServer(void)
|
|
{
|
|
ComDebOut((DEB_OXID, "ClientBulkUpdateOIDWithPingServer\n"));
|
|
ASSERT_LOCK_HELD
|
|
AssertValid();
|
|
Win4Assert(_cOidsToAdd + _cOidsToRemove != 0);
|
|
|
|
// Copy the counters so we can reset them before we make the call.
|
|
// Allocate space for the Add, Status, and Remove lists to send to the
|
|
// ping server, and remember the start address so we can free the
|
|
// memory later. Compute the address of the other lists within the
|
|
// one allocated memory block.
|
|
|
|
ULONG cOidsToAdd = _cOidsToAdd;
|
|
ULONG cOidsToRemove = _cOidsToRemove;
|
|
ULONG cOxidsToRemove = gOXIDTbl.NumOxidsToRemove();
|
|
|
|
ULONG cBytesToAlloc = (cOidsToAdd * (sizeof(OXID_OID_PAIR)+sizeof(ULONG)))
|
|
+ (cOidsToRemove * sizeof(OID_MID_PAIR))
|
|
+ (cOxidsToRemove * sizeof(OXID_REF));
|
|
|
|
OXID_OID_PAIR *pOidsToAdd = (OXID_OID_PAIR *)PrivMemAlloc(cBytesToAlloc);
|
|
if (pOidsToAdd == NULL)
|
|
{
|
|
// cant allocate memory. Leave the registration lists alone for
|
|
// now, this may be a transient problem and we can handle the
|
|
// registration later (unless of course the problem persists and
|
|
// our object is run down!).
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
ComDebOut((DEB_ERROR, "ClientBulkUpdate OOM\n"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
OXID_OID_PAIR *pOidsToAddStart = pOidsToAdd;
|
|
LONG *pStatusOfAdds = (LONG *) (&pOidsToAdd[cOidsToAdd]);
|
|
OID_MID_PAIR *pOidsToRemove = (OID_MID_PAIR *)(&pStatusOfAdds[cOidsToAdd]);
|
|
OXID_REF *pOxidsToRemove = (OXID_REF *) (&pOidsToRemove[cOidsToRemove]);
|
|
|
|
|
|
// loop through each OID registration records in the list filling in
|
|
// the Add and Remove lists. Pinged OIDs are placed in both lists.
|
|
|
|
while (_ClientOIDRegList.pNextList != &_ClientOIDRegList)
|
|
{
|
|
// get the entry and remove it from the registration list
|
|
SOIDRegistration *pOIDReg = _ClientOIDRegList.pNextList;
|
|
RemoveFromList(pOIDReg);
|
|
|
|
// reset the state flags before we begin
|
|
DWORD dwFlags = pOIDReg->flags;
|
|
pOIDReg->flags = 0;
|
|
|
|
if (dwFlags & (ROIDF_REGISTER | ROIDF_PING))
|
|
{
|
|
// register the OID with the ping server
|
|
MIDFromMOXID (pOIDReg->pOXIDEntry->moxid, &pOidsToAdd->mid);
|
|
OXIDFromMOXID(pOIDReg->pOXIDEntry->moxid, &pOidsToAdd->oxid);
|
|
OIDFromMOID (pOIDReg->Node.key, &pOidsToAdd->oid);
|
|
|
|
pOidsToAdd++;
|
|
_cOidsToAdd--;
|
|
}
|
|
|
|
if (dwFlags == ROIDF_DEREGISTER || dwFlags == ROIDF_PING)
|
|
{
|
|
// deregister the OID with the ping server
|
|
// Node.key is the OID+MID so extract each part
|
|
MIDFromMOID(pOIDReg->Node.key, &pOidsToRemove->mid);
|
|
OIDFromMOID(pOIDReg->Node.key, &pOidsToRemove->oid);
|
|
|
|
pOidsToRemove++;
|
|
_cOidsToRemove--;
|
|
|
|
// dont need the entry any more since there are no more
|
|
// users of it. remove from hash table and delete it.
|
|
gClientRegisteredOIDs.Remove((SHashChain *)pOIDReg);
|
|
delete pOIDReg;
|
|
}
|
|
}
|
|
|
|
// Ask the OXID table to fill in the list of OXIDs to remove.
|
|
gOXIDTbl.GetOxidsToRemove( pOxidsToRemove, &cOxidsToRemove );
|
|
|
|
// make sure we got all the entries and that our counters work correctly.
|
|
Win4Assert(_cOidsToAdd == 0);
|
|
Win4Assert(_cOidsToRemove == 0);
|
|
AssertValid();
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
// reset the OidsToRemove list pointer since we mucked with it above.
|
|
pOidsToRemove = (OID_MID_PAIR *) (&pStatusOfAdds[cOidsToAdd]);
|
|
|
|
RPC_STATUS sc;
|
|
|
|
do
|
|
{
|
|
// call the Resolver.
|
|
sc = BulkUpdateOIDs(_hRpc, // Rpc binding handle
|
|
_ph, // context handle
|
|
cOidsToAdd, // #oids to add
|
|
pOidsToAddStart, // ptr to oids to add
|
|
pStatusOfAdds, // status of adds
|
|
cOidsToRemove, // #oids to remove
|
|
pOidsToRemove, // ptr to oids to remove
|
|
0, 0, // ptr to oids to free
|
|
cOxidsToRemove, // #oxids to remove
|
|
pOxidsToRemove); // ptr to oxids to remove
|
|
|
|
} while (RetryRPC(sc));
|
|
|
|
// map status if necessary
|
|
sc = CheckStatus(sc);
|
|
|
|
// CODEWORK: reset the status flags for any OIDs not successfully added
|
|
// to the resolver.
|
|
|
|
// release the memory allocated above
|
|
PrivMemFree(pOidsToAddStart);
|
|
|
|
#if DBG==1
|
|
LOCK
|
|
AssertValid();
|
|
UNLOCK
|
|
#endif
|
|
ASSERT_LOCK_RELEASED
|
|
ComDebOut((DEB_OXID, "ClientBulkUpdateOIDWithPingServer hr:%x\n", S_OK));
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::EnsureWorkerThread
|
|
//
|
|
// Synopsis: Make sure there is a worker thread. Create one if
|
|
// necessary.
|
|
//
|
|
// History: 06-Nov-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRpcResolver::EnsureWorkerThread(void)
|
|
{
|
|
ASSERT_LOCK_HELD
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_hThrd == NULL)
|
|
{
|
|
// no worker thread currently exists, try to create one. First, make
|
|
// sure that we have a connection to the resolver.
|
|
|
|
hr = GetConnection();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD dwThrdId;
|
|
_hThrd = CreateThread(NULL, 0,
|
|
WorkerThreadLoop,
|
|
0, 0, &dwThrdId);
|
|
if (_hThrd)
|
|
{
|
|
// although the handle is closed, it is NOT nulled until
|
|
// the worker thread exits. That is the signal that there
|
|
// is no more worker thread and we may need to allocate
|
|
// another one.
|
|
|
|
CloseHandle(_hThrd);
|
|
}
|
|
else
|
|
{
|
|
// unable to create worker thread
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
ComDebOut((DEB_ERROR,"Create Resolver worker thread hr:%x\n",hr));
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT_LOCK_HELD
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::WorkerThreadLoop
|
|
//
|
|
// Synopsis: Worker thread for doing lazy/bulk OID registration
|
|
// with the ping server.
|
|
//
|
|
// History: 06-Nov-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
DWORD _stdcall CRpcResolver::WorkerThreadLoop(void *param)
|
|
{
|
|
// First thing we need to do is LoadLibrary ourselves in order to
|
|
// prevent our code from going away while this worker thread exists.
|
|
// The library will be freed when this thread exits.
|
|
|
|
HINSTANCE hInst = LoadLibrary(L"OLE32.DLL");
|
|
|
|
while (TRUE)
|
|
{
|
|
// sleep for a while to let the OIDs batch up in the registration list
|
|
Sleep(_dwSleepPeriod);
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
if (_cOidsToAdd == 0 && _cOidsToRemove == 0)
|
|
{
|
|
// There is no work to do. Exit this thread. If we need to
|
|
// register more oids later we will spin up another thread.
|
|
|
|
_hThrd = NULL;
|
|
UNLOCK
|
|
break;
|
|
}
|
|
|
|
ASSERT_LOCK_HELD
|
|
ClientBulkUpdateOIDWithPingServer();
|
|
ASSERT_LOCK_RELEASED
|
|
}
|
|
|
|
// Simultaneously free our Dll and exit our thread. This allows us to
|
|
// keep our Dll around incase a remote call was is progress and the
|
|
// worker thread is still blocked on the call, and allows us to cleanup
|
|
// properly when all threads are done with the code.
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
FreeLibraryAndExitThread(hInst, 0);
|
|
|
|
// compiler wants a return value
|
|
return 0;
|
|
}
|
|
|
|
#if DBG==1
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::AssertValid
|
|
//
|
|
// Synopsis: validates the state of this object
|
|
//
|
|
// History: 30-Oct-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CRpcResolver::AssertValid(void)
|
|
{
|
|
ASSERT_LOCK_HELD
|
|
|
|
Win4Assert((_cOidsToAdd & 0xf0000000) == 0x00000000);
|
|
Win4Assert((_cOidsToRemove & 0xf0000000) == 0x00000000);
|
|
|
|
if (_cOidsToAdd == 0 && _cOidsToRemove == 0)
|
|
{
|
|
// make sure the Reg list is empty.
|
|
Win4Assert(_ClientOIDRegList.pPrevList == &_ClientOIDRegList);
|
|
Win4Assert(_ClientOIDRegList.pNextList == &_ClientOIDRegList);
|
|
}
|
|
else
|
|
{
|
|
// make sure we have a worker thread. we cant assert because
|
|
// we could be OOM trying to create the thread.
|
|
if (_hThrd == NULL)
|
|
{
|
|
ComDebOut((DEB_WARN, "No Resolver Worked Thread\n"));
|
|
}
|
|
|
|
// make sure the Reg list is consistent with the counters
|
|
ULONG cAdd = 0;
|
|
ULONG cRemove = 0;
|
|
|
|
SOIDRegistration *pOIDReg = _ClientOIDRegList.pNextList;
|
|
while (pOIDReg != &_ClientOIDRegList)
|
|
{
|
|
// make sure the flags are valid
|
|
Win4Assert(pOIDReg->flags == ROIDF_REGISTER ||
|
|
pOIDReg->flags == ROIDF_DEREGISTER ||
|
|
pOIDReg->flags == ROIDF_PING ||
|
|
pOIDReg->flags == (ROIDF_PING | ROIDF_REGISTER));
|
|
|
|
if (pOIDReg->flags & (ROIDF_REGISTER | ROIDF_PING))
|
|
{
|
|
// OID is to be registered
|
|
cAdd++;
|
|
}
|
|
|
|
if (pOIDReg->flags == ROIDF_DEREGISTER ||
|
|
pOIDReg->flags == ROIDF_PING)
|
|
{
|
|
// OID is to be deregistered
|
|
cRemove++;
|
|
}
|
|
|
|
pOIDReg = pOIDReg->pNextList;
|
|
}
|
|
|
|
Win4Assert(cAdd == _cOidsToAdd);
|
|
Win4Assert(cRemove == _cOidsToRemove);
|
|
}
|
|
|
|
ASSERT_LOCK_HELD
|
|
}
|
|
#endif
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: MakeSCMProxy, public
|
|
//
|
|
// Synopsis: Creates an OXIDEntry and a proxy for the SCM Activation
|
|
// Interface.
|
|
//
|
|
// History: 14 Apr 95 AlexMit Created
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
INTERNAL MakeSCMProxy(DUALSTRINGARRAY *psaSCM, REFIID riid, void **ppSCM)
|
|
{
|
|
ComDebOut((DEB_OXID, "MakeSCMProxy psaSCM:%x ppSCM:%x\n", psaSCM, ppSCM));
|
|
Win4Assert(gdwScmProcessID != 0);
|
|
|
|
// Init out parameter
|
|
*ppSCM = NULL;
|
|
|
|
// Make a fake OXIDEntry for the SCM.
|
|
OXID_INFO oxidInfo;
|
|
oxidInfo.dwTid = 0;
|
|
oxidInfo.dwPid = gdwScmProcessID;
|
|
oxidInfo.ipidRemUnknown = GUID_NULL;
|
|
oxidInfo.psa = psaSCM;
|
|
oxidInfo.dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE;
|
|
|
|
LOCK
|
|
|
|
OXIDEntry *pOXIDEntry;
|
|
MIDEntry *pMIDEntry;
|
|
|
|
HRESULT hr = GetLocalMIDEntry(&pMIDEntry); // not AddRef'd
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Make a fake OXID for the SCM. We can use any ID that the resolver
|
|
// hands out as the OXID for the SCM.
|
|
|
|
OXID oxid;
|
|
hr = gResolver.ServerGetReservedID(&oxid);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = gOXIDTbl.AddEntry(oxid, &oxidInfo, pMIDEntry, &pOXIDEntry);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Make an object reference for the SCM. The oid and ipid dont
|
|
// matter, except the OID must be machine-unique.
|
|
|
|
IPID ipidTmp;
|
|
UuidCreate(&ipidTmp); // fake the IPID
|
|
|
|
OBJREF objref;
|
|
hr = MakeFakeObjRef(objref, pOXIDEntry, ipidTmp, riid);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// now unmarshal the objref to create a proxy to the SCM.
|
|
// use the internal form to reduce initialization time.
|
|
UNLOCK
|
|
hr = UnmarshalInternalObjRef(objref, ppSCM);
|
|
|
|
if (SUCCEEDED(hr) && gImpLevel != RPC_C_IMP_LEVEL_IMPERSONATE)
|
|
{
|
|
// Make sure SCM can impersonate us.
|
|
hr = CoSetProxyBlanket( (IUnknown *) *ppSCM,
|
|
RPC_C_AUTHN_WINNT,
|
|
RPC_C_AUTHZ_NONE, NULL,
|
|
RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL, EOAC_NONE );
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
((IUnknown *) (*ppSCM))->Release();
|
|
*ppSCM = NULL;
|
|
}
|
|
}
|
|
|
|
LOCK
|
|
}
|
|
|
|
// release the reference to the OXIDEntry from AddEntry, since
|
|
// UnmarshalInternalObjRef added another one if it was successful.
|
|
DecOXIDRefCnt(pOXIDEntry);
|
|
}
|
|
}
|
|
|
|
UNLOCK
|
|
ComDebOut((DEB_OXID, "MakeSCMProxy hr:%x *ppSCM:%x\n", hr, *ppSCM));
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::BindToSCMProxy
|
|
//
|
|
// Synopsis: Get a proxy to the SCM Activation interface.
|
|
//
|
|
// History: 19-May-95 Rickhi Created
|
|
//
|
|
// Notes: The SCM activation interface is an ORPC interface so that
|
|
// apartment model apps can receive callbacks and do cancels
|
|
// while activating object servers.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::BindToSCMProxy()
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::BindToSCMProxy"));
|
|
|
|
// since we are calling out on this thread, we have to ensure that the
|
|
// call control is set up for this thread.
|
|
|
|
HRESULT hr = InitChannelIfNecessary();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
COleStaticLock lck(gmxsOleMisc);
|
|
|
|
if (IsSTAThread())
|
|
{
|
|
if (_pSCMSTA == NULL)
|
|
{
|
|
// Make a proxy to the SCM
|
|
hr = MakeSCMProxy((DUALSTRINGARRAY *)&saSCM, IID_IDSCM, (void **) &_pSCMSTA);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_pSCMMTA == NULL)
|
|
{
|
|
// Make a proxy to the SCM
|
|
hr = MakeSCMProxy((DUALSTRINGARRAY *)&saSCM, IID_IDSCM, (void **) &_pSCMMTA);
|
|
}
|
|
}
|
|
|
|
ComDebOut((SUCCEEDED(hr) ? DEB_SCM : DEB_ERROR,
|
|
"CCoScm::BindToSCMProxy for IDSCM returns %x.\n", hr));
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::NotifyStarted
|
|
//
|
|
// Synopsis: Notify the SCM that a class has been started
|
|
//
|
|
// Arguments: [rclsid] - class started
|
|
// [dwFlags] - whether class is multiple use or not.
|
|
//
|
|
// History: 19-May-92 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::NotifyStarted(
|
|
RegInput *pRegIn,
|
|
RegOutput **ppRegOut)
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::NotifyStarted"));
|
|
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat;
|
|
WCHAR * pwszWinstaDesktop;
|
|
|
|
hr = GetWinstaDesktop( &pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
do
|
|
{
|
|
hr = ServerRegisterClsid(
|
|
_hRpc,
|
|
_ph,
|
|
pwszWinstaDesktop,
|
|
pRegIn,
|
|
ppRegOut,
|
|
&rpcstat );
|
|
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
if ( pwszWinstaDesktop != _pwszWinstaDesktop )
|
|
PrivMemFree( pwszWinstaDesktop );
|
|
|
|
ComDebOut(( (hr == S_OK) ? DEB_SCM : DEB_ERROR,
|
|
"Class Registration returned %x", hr));
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(rpcstat);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::NotifyStopped
|
|
//
|
|
// Synopsis: Notify the SCM that the server is stopped.
|
|
//
|
|
// History: 19-May-92 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CRpcResolver::NotifyStopped(
|
|
REFCLSID rclsid,
|
|
DWORD dwReg)
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::NotifyStopped"));
|
|
|
|
error_status_t rpcstat;
|
|
|
|
RevokeClasses revcls;
|
|
revcls.dwSize = 1;
|
|
revcls.revent[0].clsid = rclsid;
|
|
revcls.revent[0].dwReg = dwReg;
|
|
|
|
do
|
|
{
|
|
ServerRevokeClsid(_hRpc, _ph, &revcls, &rpcstat);
|
|
|
|
} while (RetryRPC(rpcstat));
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::GetClassObject
|
|
//
|
|
// Synopsis: Send a get object request to the SCM
|
|
//
|
|
// Arguments: [rclsid] - class id for class object
|
|
// [dwCtrl] - type of server required
|
|
// [ppIFDClassObj] - marshaled buffer for class object
|
|
// [ppwszDllToLoad] - DLL name to use for server
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 20-May-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::GetClassObject(
|
|
REFCLSID rclsid,
|
|
DWORD dwContext,
|
|
IID *pIID,
|
|
COSERVERINFO *pServerInfo,
|
|
MInterfacePointer **ppIFDClassObj,
|
|
DWORD *pdwDllServerType,
|
|
WCHAR **ppwszDllToLoad)
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::GetClassObject"));
|
|
|
|
HRESULT hr;
|
|
ACTIVATION_INFO ActivationInfo;
|
|
OXID OxidServer;
|
|
DUALSTRINGARRAY * pssaServerObjectResolverBindings;
|
|
OXID_INFO OxidInfo;
|
|
MID LocalMidOfRemote;
|
|
OXIDEntry * pOxidEntry;
|
|
LPWSTR pwszWinstaDesktop;
|
|
|
|
hr = BindToSCMProxy();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = GetWinstaDesktop( &pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
ActivationInfo.Clsid = &rclsid;
|
|
ActivationInfo.pServerInfo = pServerInfo;
|
|
ActivationInfo.pwszWinstaDesktop = pwszWinstaDesktop;
|
|
ActivationInfo.ClsContext = dwContext;
|
|
ActivationInfo.ProcessSignature = _dwProcessSignature;
|
|
ActivationInfo.bDynamicSecurity = _bDynamicSecurity;
|
|
|
|
pssaServerObjectResolverBindings = 0;
|
|
OxidInfo.psa = 0;
|
|
pOxidEntry = 0;
|
|
|
|
hr = GetSCM()->SCMGetClassObject(
|
|
&ActivationInfo,
|
|
pIID,
|
|
IsSTAThread(),
|
|
&OxidServer,
|
|
&pssaServerObjectResolverBindings,
|
|
&OxidInfo,
|
|
&LocalMidOfRemote,
|
|
ppIFDClassObj );
|
|
|
|
if ( pwszWinstaDesktop != _pwszWinstaDesktop )
|
|
PrivMemFree( pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) || (OxidServer == 0) )
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::GetClassObject hr:%x", hr));
|
|
return hr;
|
|
}
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
hr = FindOrCreateOXIDEntry(
|
|
OxidServer,
|
|
OxidInfo,
|
|
FOCOXID_REF,
|
|
pssaServerObjectResolverBindings,
|
|
LocalMidOfRemote,
|
|
NULL,
|
|
&pOxidEntry );
|
|
|
|
CoTaskMemFree(OxidInfo.psa);
|
|
CoTaskMemFree(pssaServerObjectResolverBindings);
|
|
|
|
//
|
|
// CODEWORK CODEWORK CODEWORK
|
|
//
|
|
// These comments also apply to CreateInstance and GetPersistentInstance
|
|
// methods.
|
|
//
|
|
// Releasing the OXID and reacquiring it makes me a little
|
|
// nervous. The Expired list is fairly short, so if multiple guys are doing
|
|
// this simultaneously, the entries could get lost. I guess this is not
|
|
// too bad since it should be rare and the local resolver will have it
|
|
// anyway, but I think there is a window where the local resolver could
|
|
// lose it too, forcing a complete roundtrip back to the server.
|
|
//
|
|
// A better mechanism may be to pass the iid and ppunk into this method
|
|
// and do the unmarshal inside it. We could improve performance by calling
|
|
// UnmarshalObjRef instead of putting a stream wrapper around the
|
|
// MInterfacePointer and then calling CoUnmarshalInterface. It would avoid
|
|
// looking up the OXIDEntry twice, and would avoid the race where we could
|
|
// lose the OXIDEntry off the expired list. It would require a small
|
|
// change in UnmarshalObjRef to deal with the custom marshal case.
|
|
//
|
|
|
|
//
|
|
// Decrement our ref. The interface unmarshall will do a LookupOXID
|
|
// which will increment the count and move the OXIDEntry back to the
|
|
// InUse list.
|
|
//
|
|
if ( pOxidEntry )
|
|
DecOXIDRefCnt(pOxidEntry);
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::GetClassObject hr:%x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::CreateInstance
|
|
//
|
|
// Synopsis: Send a create instance request to the SCM
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 20-May-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::CreateInstance(
|
|
COSERVERINFO *pServerInfo,
|
|
CLSID *pClsid,
|
|
DWORD dwClsCtx,
|
|
DWORD dwCount,
|
|
IID *pIIDs,
|
|
MInterfacePointer **pRetdItfs,
|
|
HRESULT *pRetdHrs,
|
|
DWORD *pdwDllServerType,
|
|
OLECHAR **ppwszDllToLoad )
|
|
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::CreateInstance"));
|
|
|
|
HRESULT hr;
|
|
ACTIVATION_INFO ActivationInfo;
|
|
OXID OxidServer;
|
|
DUALSTRINGARRAY * pssaServerObjectResolverBindings;
|
|
OXID_INFO OxidInfo;
|
|
MID LocalMidOfRemote;
|
|
OXIDEntry * pOxidEntry;
|
|
LPWSTR pwszWinstaDesktop;
|
|
|
|
hr = BindToSCMProxy();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = GetWinstaDesktop( &pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
ActivationInfo.Clsid = pClsid;
|
|
ActivationInfo.pServerInfo = pServerInfo;
|
|
ActivationInfo.pwszWinstaDesktop = pwszWinstaDesktop;
|
|
ActivationInfo.ClsContext = dwClsCtx;
|
|
ActivationInfo.ProcessSignature = _dwProcessSignature;
|
|
ActivationInfo.bDynamicSecurity = _bDynamicSecurity;
|
|
|
|
pssaServerObjectResolverBindings = 0;
|
|
OxidInfo.psa = 0;
|
|
pOxidEntry = 0;
|
|
|
|
hr = GetSCM()->SCMCreateInstance(
|
|
&ActivationInfo,
|
|
dwCount,
|
|
pIIDs,
|
|
IsSTAThread(),
|
|
&OxidServer,
|
|
&pssaServerObjectResolverBindings,
|
|
&OxidInfo,
|
|
&LocalMidOfRemote,
|
|
pRetdItfs,
|
|
pRetdHrs );
|
|
|
|
if ( pwszWinstaDesktop != _pwszWinstaDesktop )
|
|
PrivMemFree( pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) || (OxidServer == 0) )
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::CreateInstance hr:%x", hr));
|
|
return hr;
|
|
}
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
hr = FindOrCreateOXIDEntry(
|
|
OxidServer,
|
|
OxidInfo,
|
|
FOCOXID_REF,
|
|
pssaServerObjectResolverBindings,
|
|
LocalMidOfRemote,
|
|
NULL,
|
|
&pOxidEntry );
|
|
|
|
CoTaskMemFree(OxidInfo.psa);
|
|
CoTaskMemFree(pssaServerObjectResolverBindings);
|
|
|
|
//
|
|
// Decrement our ref. The interface unmarshall will do a LookupOXID
|
|
// which will increment the count and move the OXIDEntry back to the
|
|
// InUse list.
|
|
//
|
|
if ( pOxidEntry )
|
|
DecOXIDRefCnt(pOxidEntry);
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::CreateInstance hr:%x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::GetPersistentInstance
|
|
//
|
|
// Synopsis: Send a get object request to the SCM
|
|
//
|
|
//GAJGAJ - fix this comment block
|
|
// Arguments: [rclsid] - class id for class object
|
|
// [dwCtrl] - type of server required
|
|
// [ppIFDClassObj] - marshaled buffer for class object
|
|
// [ppwszDllToLoad] - DLL name to use for server
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 20-May-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::GetPersistentInstance(
|
|
COSERVERINFO * pServerInfo,
|
|
CLSID *pClsid,
|
|
DWORD dwClsCtx,
|
|
DWORD grfMode,
|
|
BOOL bFileWasOpened,
|
|
OLECHAR *pwszName,
|
|
MInterfacePointer *pstg,
|
|
DWORD dwCount,
|
|
IID *pIIDs,
|
|
BOOL * FoundInROT,
|
|
MInterfacePointer **pRetdItfs,
|
|
HRESULT *pRetdHrs,
|
|
DWORD *pdwDllServerType,
|
|
OLECHAR **ppwszDllToLoad )
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::GetPersistentInstance"));
|
|
|
|
HRESULT hr;
|
|
ACTIVATION_INFO ActivationInfo;
|
|
OXID OxidServer;
|
|
DUALSTRINGARRAY * pssaServerObjectResolverBindings;
|
|
OXID_INFO OxidInfo;
|
|
MID LocalMidOfRemote;
|
|
OXIDEntry * pOxidEntry;
|
|
LPWSTR pwszWinstaDesktop;
|
|
|
|
hr = BindToSCMProxy();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = GetWinstaDesktop( &pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
ActivationInfo.Clsid = pClsid;
|
|
ActivationInfo.pServerInfo = pServerInfo;
|
|
ActivationInfo.pwszWinstaDesktop = pwszWinstaDesktop;
|
|
ActivationInfo.ClsContext = dwClsCtx;
|
|
ActivationInfo.ProcessSignature = _dwProcessSignature;
|
|
ActivationInfo.bDynamicSecurity = _bDynamicSecurity;
|
|
|
|
pssaServerObjectResolverBindings = 0;
|
|
OxidInfo.psa = 0;
|
|
pOxidEntry = 0;
|
|
|
|
hr = GetSCM()->SCMGetPersistentInstance(
|
|
&ActivationInfo,
|
|
pwszName,
|
|
pstg,
|
|
grfMode,
|
|
bFileWasOpened,
|
|
dwCount,
|
|
pIIDs,
|
|
IsSTAThread(),
|
|
&OxidServer,
|
|
&pssaServerObjectResolverBindings,
|
|
&OxidInfo,
|
|
&LocalMidOfRemote,
|
|
FoundInROT,
|
|
pRetdItfs,
|
|
pRetdHrs );
|
|
|
|
if ( pwszWinstaDesktop != _pwszWinstaDesktop )
|
|
PrivMemFree( pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) || (OxidServer == 0) )
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::GetPersistentInstance hr:%x",hr));
|
|
return hr;
|
|
}
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
hr = FindOrCreateOXIDEntry(
|
|
OxidServer,
|
|
OxidInfo,
|
|
FOCOXID_REF,
|
|
pssaServerObjectResolverBindings,
|
|
LocalMidOfRemote,
|
|
NULL,
|
|
&pOxidEntry );
|
|
|
|
CoTaskMemFree(OxidInfo.psa);
|
|
CoTaskMemFree(pssaServerObjectResolverBindings);
|
|
|
|
//
|
|
// Decrement our ref. The interface unmarshall will do a LookupOXID
|
|
// which will increment the count and move the OXIDEntry back to the
|
|
// InUse list.
|
|
//
|
|
if ( pOxidEntry )
|
|
DecOXIDRefCnt(pOxidEntry);
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::GetPersistentInstance hr:%x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::IrotRegister
|
|
//
|
|
// Synopsis: Register an object in the ROT
|
|
//
|
|
// Arguments: [pmkeqbuf] - moniker compare buffer
|
|
// [pifdObject] - marshaled interface for object
|
|
// [pifdObjectName] - marshaled moniker
|
|
// [pfiletime] - file time of last change
|
|
// [dwProcessID] -
|
|
// [psrkRegister] - output of registration
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 28-Jan-95 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::IrotRegister(
|
|
MNKEQBUF *pmkeqbuf,
|
|
InterfaceData *pifdObject,
|
|
InterfaceData *pifdObjectName,
|
|
FILETIME *pfiletime,
|
|
DWORD dwProcessID,
|
|
WCHAR *pwszServerExe,
|
|
SCMREGKEY *psrkRegister)
|
|
{
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat = RPC_S_OK;
|
|
WCHAR * pwszWinstaDesktop;
|
|
|
|
hr = GetWinstaDesktop( &pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
do
|
|
{
|
|
hr = ::IrotRegister(
|
|
_hRpc,
|
|
_ph,
|
|
pwszWinstaDesktop,
|
|
pmkeqbuf,
|
|
pifdObject,
|
|
pifdObjectName,
|
|
pfiletime,
|
|
dwProcessID,
|
|
pwszServerExe,
|
|
psrkRegister,
|
|
&rpcstat);
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
if ( pwszWinstaDesktop != _pwszWinstaDesktop )
|
|
PrivMemFree( pwszWinstaDesktop );
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
hr = CO_E_SCM_RPC_FAILURE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::IrotRevoke
|
|
//
|
|
// Synopsis: Call to SCM to revoke object from the ROT
|
|
//
|
|
// Arguments: [psrkRegister] - moniker compare buffer
|
|
// [fServerRevoke] - whether server for object is revoking
|
|
// [pifdObject] - where to put marshaled object
|
|
// [pifdName] - where to put marshaled moniker
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 28-Jan-95 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::IrotRevoke(
|
|
SCMREGKEY *psrkRegister,
|
|
BOOL fServerRevoke,
|
|
InterfaceData **ppifdObject,
|
|
InterfaceData **ppifdName)
|
|
{
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat = RPC_S_OK;
|
|
|
|
do
|
|
{
|
|
hr = ::IrotRevoke(
|
|
_hRpc,
|
|
psrkRegister,
|
|
fServerRevoke,
|
|
ppifdObject,
|
|
ppifdName,
|
|
&rpcstat);
|
|
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
hr = CO_E_SCM_RPC_FAILURE;
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::IrotIsRunning
|
|
//
|
|
// Synopsis: Call to SCM to determine if object is in the ROT
|
|
//
|
|
// Arguments: [pmkeqbuf] - moniker compare buffer
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 28-Jan-95 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::IrotIsRunning(MNKEQBUF *pmkeqbuf)
|
|
{
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat = RPC_S_OK;
|
|
WCHAR * pwszWinstaDesktop;
|
|
|
|
hr = GetWinstaDesktop( &pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
do
|
|
{
|
|
hr = ::IrotIsRunning(
|
|
_hRpc,
|
|
_ph,
|
|
pwszWinstaDesktop,
|
|
pmkeqbuf,
|
|
&rpcstat);
|
|
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
if ( pwszWinstaDesktop != _pwszWinstaDesktop )
|
|
PrivMemFree( pwszWinstaDesktop );
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
hr = CO_E_SCM_RPC_FAILURE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::IrotGetObject
|
|
//
|
|
// Synopsis: Call to SCM to determine if object is in the ROT
|
|
//
|
|
// Arguments: [dwProcessID] - process ID for object we want
|
|
// [pmkeqbuf] - moniker compare buffer
|
|
// [psrkRegister] - registration ID in SCM
|
|
// [pifdObject] - marshaled interface for the object
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 28-Jan-95 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::IrotGetObject(
|
|
DWORD dwProcessID,
|
|
MNKEQBUF *pmkeqbuf,
|
|
SCMREGKEY *psrkRegister,
|
|
InterfaceData **pifdObject)
|
|
{
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat = RPC_S_OK;
|
|
WCHAR * pwszWinstaDesktop;
|
|
|
|
hr = GetWinstaDesktop( &pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
do
|
|
{
|
|
hr = ::IrotGetObject(
|
|
_hRpc,
|
|
_ph,
|
|
pwszWinstaDesktop,
|
|
dwProcessID,
|
|
pmkeqbuf,
|
|
psrkRegister,
|
|
pifdObject,
|
|
&rpcstat);
|
|
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
if ( pwszWinstaDesktop != _pwszWinstaDesktop )
|
|
PrivMemFree( pwszWinstaDesktop );
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
hr = CO_E_SCM_RPC_FAILURE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::IrotNoteChangeTime
|
|
//
|
|
// Synopsis: Call to SCM to set time of change for object in the ROT
|
|
//
|
|
// Arguments: [psrkRegister] - SCM registration ID
|
|
// [pfiletime] - time of change
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 28-Jan-95 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::IrotNoteChangeTime(
|
|
SCMREGKEY *psrkRegister,
|
|
FILETIME *pfiletime)
|
|
{
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat = RPC_S_OK;
|
|
|
|
do
|
|
{
|
|
hr = ::IrotNoteChangeTime(
|
|
_hRpc,
|
|
psrkRegister,
|
|
pfiletime,
|
|
&rpcstat);
|
|
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
hr = CO_E_SCM_RPC_FAILURE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::IrotGetTimeOfLastChange
|
|
//
|
|
// Synopsis: Call to SCM to get time changed of object in the ROT
|
|
//
|
|
// Arguments: [pmkeqbuf] - moniker compare buffer
|
|
// [pfiletime] - where to put time of last change
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 28-Jan-95 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::IrotGetTimeOfLastChange(
|
|
MNKEQBUF *pmkeqbuf,
|
|
FILETIME *pfiletime)
|
|
{
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat = RPC_S_OK;
|
|
WCHAR * pwszWinstaDesktop;
|
|
|
|
hr = GetWinstaDesktop( &pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
do
|
|
{
|
|
hr = ::IrotGetTimeOfLastChange(
|
|
_hRpc,
|
|
_ph,
|
|
pwszWinstaDesktop,
|
|
pmkeqbuf,
|
|
pfiletime,
|
|
&rpcstat);
|
|
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
if ( pwszWinstaDesktop != _pwszWinstaDesktop )
|
|
PrivMemFree( pwszWinstaDesktop );
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
hr = CO_E_SCM_RPC_FAILURE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::IrotEnumRunning
|
|
//
|
|
// Synopsis: Call to SCM to enumerate running objects in the ROT
|
|
//
|
|
// Arguments: [ppMkIFList] - output pointer to array of marshaled monikers
|
|
//
|
|
// Returns: S_OK
|
|
//
|
|
// History: 28-Jan-95 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::IrotEnumRunning(MkInterfaceList **ppMkIFList)
|
|
{
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat = RPC_S_OK;
|
|
WCHAR * pwszWinstaDesktop;
|
|
|
|
hr = GetWinstaDesktop( &pwszWinstaDesktop );
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
do
|
|
{
|
|
hr = ::IrotEnumRunning(
|
|
_hRpc,
|
|
_ph,
|
|
pwszWinstaDesktop,
|
|
ppMkIFList,
|
|
&rpcstat);
|
|
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
if ( pwszWinstaDesktop != _pwszWinstaDesktop )
|
|
PrivMemFree( pwszWinstaDesktop );
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
hr = CO_E_SCM_RPC_FAILURE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::UpdateShrdTbls
|
|
//
|
|
// Synopsis: Ask the SCM to update the shared memory tables.
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// History: 11-July-94 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::UpdateShrdTbls(void)
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "CRpcResolver::UpdateShrdTbls"));
|
|
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat;
|
|
|
|
do
|
|
{
|
|
hr = ::UpdateShrdTbls(_hRpc, &rpcstat);
|
|
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
|
|
ComDebOut(( (hr == S_OK) ? DEB_SCM : DEB_ERROR,
|
|
"UpdateShrdTbls returned %x\n", hr));
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
return HRESULT_FROM_WIN32(rpcstat);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::GetThreadID
|
|
//
|
|
// Synopsis: Get unique thread id from SCM.
|
|
//
|
|
// Arguments: [pThreadID] - Pointer to returned thread ID.
|
|
//
|
|
// History: 22-Jan-96 Rickhi Created
|
|
//--------------------------------------------------------------------------
|
|
void CRpcResolver::GetThreadID( DWORD * pThreadID )
|
|
{
|
|
HRESULT hr;
|
|
|
|
*pThreadID = 0;
|
|
|
|
hr = GetConnection();
|
|
if ( FAILED(hr) )
|
|
return;
|
|
|
|
//
|
|
// If GetConnection does the initial connect to the SCM/OR then
|
|
// our apartment thread id, which is aliased by pThreadID, will be set.
|
|
//
|
|
if ( *pThreadID != 0 )
|
|
return;
|
|
|
|
error_status_t rpcstat;
|
|
|
|
do
|
|
{
|
|
::GetThreadID( _hRpc, pThreadID, &rpcstat );
|
|
} while (RetryRPC(rpcstat));
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::UpdateActivationSettings
|
|
//
|
|
// Synopsis: Tells rpcss to re-read default activation keys/values.
|
|
// Used by OLE test team.
|
|
//
|
|
// Arguments: none
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CRpcResolver::UpdateActivationSettings()
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = GetConnection();
|
|
if ( FAILED(hr) )
|
|
return;
|
|
|
|
error_status_t rpcstat;
|
|
|
|
do
|
|
{
|
|
::UpdateActivationSettings( _hRpc, &rpcstat );
|
|
} while (RetryRPC(rpcstat));
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::RegisterWindowPropInterface
|
|
//
|
|
// Synopsis: Register window property interface with the SCM
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 22-Jan-96 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::RegisterWindowPropInterface(HWND hWnd, STDOBJREF *pStd,
|
|
OXID_INFO *pOxidInfo,
|
|
DWORD *pdwCookie)
|
|
{
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat;
|
|
|
|
do
|
|
{
|
|
hr = ::RegisterWindowPropInterface(_hRpc, (DWORD) hWnd,
|
|
pStd, pOxidInfo, pdwCookie, &rpcstat);
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
ComDebOut(( (hr == S_OK) ? DEB_SCM : DEB_ERROR,
|
|
"RegisterWindowPropInterface returned %x\n", hr));
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
return HRESULT_FROM_WIN32(rpcstat);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::RegisterWindowPropInterface
|
|
//
|
|
// Synopsis: Get (and possibly Revoke) window property interface
|
|
// registration with the SCM.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 22-Jan-96 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::GetWindowPropInterface(HWND hWnd, DWORD dwCookie, BOOL fRevoke,
|
|
STDOBJREF *pStd, OXID_INFO *pOxidInfo)
|
|
{
|
|
// Bind to the SCM if that hasn't already happened
|
|
HRESULT hr = GetConnection();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
error_status_t rpcstat;
|
|
|
|
do
|
|
{
|
|
hr = ::GetWindowPropInterface(_hRpc, (DWORD) hWnd, dwCookie, fRevoke,
|
|
pStd, pOxidInfo, &rpcstat);
|
|
} while (RetryRPC(rpcstat));
|
|
|
|
ComDebOut(( (hr == S_OK) ? DEB_SCM : DEB_ERROR,
|
|
"GetWindowPropInterface returned %x\n", hr));
|
|
|
|
if (rpcstat != RPC_S_OK)
|
|
{
|
|
return HRESULT_FROM_WIN32(rpcstat);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::SetWinstaDesktop
|
|
//
|
|
// Purpose: Sets the default winsta\desktop string we'll use for this
|
|
// process.
|
|
//
|
|
// Returns: Success code.
|
|
//
|
|
// History: Nov 96 DKays Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD CRpcResolver::SetWinstaDesktop()
|
|
{
|
|
return GetThreadWinstaDesktop( &_pwszWinstaDesktop );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::GetWinstaDesktop
|
|
//
|
|
// Purpose: Gets the winsta\desktop string to use for an activation call.
|
|
//
|
|
// Returns: Success code.
|
|
//
|
|
// History: Nov 96 DKays Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CRpcResolver::GetWinstaDesktop( WCHAR ** ppwszWinstaDesktop )
|
|
{
|
|
DWORD Status;
|
|
|
|
*ppwszWinstaDesktop = 0;
|
|
|
|
if ( ! _bDynamicSecurity )
|
|
{
|
|
*ppwszWinstaDesktop = _pwszWinstaDesktop;
|
|
return S_OK;
|
|
}
|
|
|
|
Status = GetThreadWinstaDesktop( ppwszWinstaDesktop );
|
|
return HRESULT_FROM_WIN32( Status );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::GetDynamicSecurity
|
|
//
|
|
// Purpose: Get the dynamic security setting for the process.
|
|
//
|
|
// Returns: TRUE or FALSE
|
|
//
|
|
// History: Nov 96 DKays Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CRpcResolver::GetDynamicSecurity()
|
|
{
|
|
return _bDynamicSecurity;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRpcResolver::SetDynamicSecurity
|
|
//
|
|
// Purpose: Set the dynamic security setting for the process to TRUE.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// History: Nov 96 DKays Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CRpcResolver::SetDynamicSecurity()
|
|
{
|
|
_bDynamicSecurity = TRUE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: GetThreadWinstaDesktop
|
|
//
|
|
// Purpose: Get the winsta\desktop string for the calling thread.
|
|
//
|
|
// Returns: Success code.
|
|
//
|
|
// History: Nov-96 DKays Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD GetThreadWinstaDesktop( WCHAR ** ppwszWinstaDesktop )
|
|
{
|
|
HWINSTA hWinsta;
|
|
HDESK hDesk;
|
|
WCHAR wszWinsta[32];
|
|
WCHAR wszDesktop[32];
|
|
LPWSTR pwszWinsta;
|
|
LPWSTR pwszDesktop;
|
|
DWORD WinstaSize;
|
|
DWORD DesktopSize;
|
|
DWORD Length;
|
|
BOOL Status;
|
|
DWORD Result;
|
|
|
|
*ppwszWinstaDesktop = 0;
|
|
|
|
hWinsta = GetProcessWindowStation();
|
|
|
|
if ( ! hWinsta )
|
|
return GetLastError();
|
|
|
|
hDesk = GetThreadDesktop(GetCurrentThreadId());
|
|
|
|
if ( ! hDesk )
|
|
return GetLastError();
|
|
|
|
pwszWinsta = wszWinsta;
|
|
pwszDesktop = wszDesktop;
|
|
|
|
Length = sizeof(wszWinsta);
|
|
|
|
Status = GetUserObjectInformation(
|
|
hWinsta,
|
|
UOI_NAME,
|
|
pwszWinsta,
|
|
Length,
|
|
&Length );
|
|
|
|
if ( ! Status )
|
|
{
|
|
Result = GetLastError();
|
|
if ( Result != ERROR_INSUFFICIENT_BUFFER )
|
|
goto WinstaDesktopExit;
|
|
|
|
pwszWinsta = (LPWSTR)PrivMemAlloc( Length );
|
|
if ( ! pwszWinsta )
|
|
{
|
|
Result = ERROR_OUTOFMEMORY;
|
|
goto WinstaDesktopExit;
|
|
}
|
|
|
|
Status = GetUserObjectInformation(
|
|
hWinsta,
|
|
UOI_NAME,
|
|
pwszWinsta,
|
|
Length,
|
|
&Length );
|
|
|
|
if ( ! Status )
|
|
{
|
|
Result = GetLastError();
|
|
goto WinstaDesktopExit;
|
|
}
|
|
}
|
|
|
|
Length = sizeof(wszDesktop);
|
|
|
|
Status = GetUserObjectInformation(
|
|
hDesk,
|
|
UOI_NAME,
|
|
pwszDesktop,
|
|
Length,
|
|
&Length );
|
|
|
|
if ( ! Status )
|
|
{
|
|
Result = GetLastError();
|
|
if ( Result != ERROR_INSUFFICIENT_BUFFER )
|
|
goto WinstaDesktopExit;
|
|
|
|
pwszDesktop = (LPWSTR)PrivMemAlloc( Length );
|
|
if ( ! pwszDesktop )
|
|
{
|
|
Result = ERROR_OUTOFMEMORY;
|
|
goto WinstaDesktopExit;
|
|
}
|
|
|
|
Status = GetUserObjectInformation(
|
|
hDesk,
|
|
UOI_NAME,
|
|
pwszDesktop,
|
|
Length,
|
|
&Length );
|
|
|
|
if ( ! Status )
|
|
{
|
|
Result = GetLastError();
|
|
goto WinstaDesktopExit;
|
|
}
|
|
}
|
|
|
|
*ppwszWinstaDesktop = (WCHAR *)
|
|
PrivMemAlloc( (lstrlenW(pwszWinsta) + 1 + lstrlenW(pwszDesktop) + 1) * sizeof(WCHAR) );
|
|
|
|
if ( *ppwszWinstaDesktop )
|
|
{
|
|
lstrcpyW( *ppwszWinstaDesktop, pwszWinsta );
|
|
lstrcatW( *ppwszWinstaDesktop, L"\\" );
|
|
lstrcatW( *ppwszWinstaDesktop, pwszDesktop );
|
|
Result = S_OK;
|
|
}
|
|
else
|
|
{
|
|
Result = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
WinstaDesktopExit:
|
|
|
|
if ( pwszWinsta != wszWinsta )
|
|
PrivMemFree( pwszWinsta );
|
|
|
|
if ( pwszDesktop != wszDesktop )
|
|
PrivMemFree( pwszDesktop );
|
|
|
|
return Result;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: ScmGetThreadId
|
|
//
|
|
// Purpose: Stupid helper method so gResolver is not used in
|
|
// com\class subdir.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void ScmGetThreadId( DWORD * pThreadID )
|
|
{
|
|
gResolver.GetThreadID( pThreadID );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------
|
|
//
|
|
// Function: UpdateDCOMSettings
|
|
//
|
|
// Synopsis: Calls rpcss to re-read the default activation keys/values.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
STDAPI_(void) UpdateDCOMSettings(void)
|
|
{
|
|
gResolver.UpdateActivationSettings();
|
|
}
|
|
|