windows-nt/Source/XPSP1/NT/com/ole32/dcomss/olescm/scmif.cxx
2020-09-26 16:20:57 +08:00

1125 lines
30 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: scmif.cxx
//
// Contents: Entry points for scm interface.
//
// Functions: StartObjectService
// SvcActivateObject
// SvcCreateActivateObject
// ObjectServerStarted
// StopServer
//
// History: 01-May-93 Ricksa Created
// 31-Dec-93 ErikGav Chicago port
//
//--------------------------------------------------------------------------
#include "act.hxx"
//+-------------------------------------------------------------------------
//
// Function: Dummy1
//
// Synopsis: Needed for IDL hack. Never called.
//
// Arguments: [hRpc] - RPC handle
// [orpcthis] - ORPC handle
// [localthis] - ORPC call data
// [orpcthat] - ORPC reply data
//
// Returns: HRESULT
//
// History: 14 Apr 95 AlexMit Created
//
//--------------------------------------------------------------------------
extern "C" HRESULT DummyQueryInterfaceIOSCM(
handle_t hRpc,
ORPCTHIS *orpcthis,
LOCALTHIS *localthis,
ORPCTHAT *orpcthat,
DWORD dummy )
{
CairoleDebugOut((DEB_ERROR, "SCM Dummy function should never be called!\n" ));
orpcthat->flags = 0;
orpcthat->extensions = NULL;
return E_FAIL;
}
//+-------------------------------------------------------------------------
//
// Function: Dummy2
//
// Synopsis: Needed for IDL hack. Never called.
//
// Arguments: [hRpc] - RPC handle
// [orpcthis] - ORPC handle
// [localthis] - ORPC call data
// [orpcthat] - ORPC reply data
//
// Returns: HRESULT
//
// History: 14 Apr 95 AlexMit Created
//
//--------------------------------------------------------------------------
extern "C" HRESULT DummyAddRefIOSCM(
handle_t hRpc,
ORPCTHIS *orpcthis,
LOCALTHIS *localthis,
ORPCTHAT *orpcthat,
DWORD dummy )
{
CairoleDebugOut((DEB_ERROR, "SCM Dummy function should never be called!\n" ));
orpcthat->flags = 0;
orpcthat->extensions = NULL;
return E_FAIL;
}
//+-------------------------------------------------------------------------
//
// Function: Dummy3
//
// Synopsis: Needed for IDL hack. Never called.
//
// Arguments: [hRpc] - RPC handle
// [orpcthis] - ORPC handle
// [localthis] - ORPC call data
// [orpcthat] - ORPC reply data
//
// Returns: HRESULT
//
// History: 14 Apr 95 AlexMit Created
//
//--------------------------------------------------------------------------
extern "C" HRESULT DummyReleaseIOSCM(
handle_t hRpc,
ORPCTHIS *orpcthis,
LOCALTHIS *localthis,
ORPCTHAT *orpcthat,
DWORD dummy )
{
CairoleDebugOut((DEB_ERROR, "SCM Dummy function should never be called!\n" ));
orpcthat->flags = 0;
orpcthat->extensions = NULL;
return E_FAIL;
}
//+-------------------------------------------------------------------------
//
// Function: ServerRegisterClsid
//
// Synopsis: Notifies SCM that server is started for a class
//
// Arguments: [hRpc] - RPC handle
// [phProcess] - context handle
// [lpDeskTop] - caller's desktop
// [pregin] - array of registration entries
// [ppregout] - array of registration cookies to return
// [rpcstat] - status code
//
// Returns: HRESULT
//
// History: 01-May-93 Ricksa Created
//
//--------------------------------------------------------------------------
extern "C" HRESULT ServerRegisterClsid(
handle_t hRpc,
PHPROCESS phProcess,
RegInput *pregin,
RegOutput **ppregout,
error_status_t *rpcstat)
{
CProcess * pProcess;
RegOutput * pregout;
CServerTableEntry * pClassTableEntry;
CClsidData * pClsidData = NULL;
DWORD Size, Entries, i;
UCHAR ServerState;
LONG Status;
HRESULT hr;
HANDLE* phRegisterEvents = NULL;
CheckLocalCall( hRpc );
// Parameter validation
if (!pregin || !ppregout || !rpcstat)
return E_INVALIDARG;
*rpcstat = 0;
*ppregout = 0;
pProcess = ReferenceProcess( phProcess, TRUE );
if ( ! pProcess )
return E_ACCESSDENIED;
// Allocate an array of handles to hold the register events.
phRegisterEvents = (HANDLE*)alloca(sizeof(HANDLE) * pregin->dwSize);
memset(phRegisterEvents, 0, sizeof(HANDLE) * pregin->dwSize);
Size = sizeof(RegOutput) + (pregin->dwSize - 1) * sizeof(DWORD);
*ppregout = (RegOutput *) PrivMemAlloc(Size);
if ( ! *ppregout )
{
ReleaseProcess( pProcess );
return E_OUTOFMEMORY;
}
pregout = *ppregout;
memset( pregout, 0, Size );
pregout->dwSize = pregin->dwSize;
Entries = pregin->dwSize;
//
// First loop, we add all of the registrations.
//
for ( i = 0; i < Entries; i++ )
{
pClsidData = 0;
#ifndef _CHICAGO_
// This path taken by non-COM+ servers, ergo
// no IComClassinfo
(void) LookupClsidData(
pregin->rginent[i].clsid,
NULL,
pProcess->GetToken(),
LOAD_APPID,
&pClsidData );
//
// Check that the caller is allowed to register this CLSID.
//
if ( pClsidData && ! pClsidData->CertifyServer( pProcess ) )
{
delete pClsidData;
hr = CO_E_WRONG_SERVER_IDENTITY;
break;
}
#endif
//
// Get the register event for this clsid, to be signalled later on
// in the second loop below. If we couldn't find a pClsidData for
// this clsid, that's fine it just means it was a registration for
// an unknown clsid (which is legal).
//
if (pClsidData)
{
phRegisterEvents[i] = pClsidData->ServerRegisterEvent();
if (!phRegisterEvents[i])
{
delete pClsidData;
hr = E_OUTOFMEMORY;
break;
}
}
ServerState = SERVERSTATE_SUSPENDED;
// Note: REGCLS_SINGLEUSE is *not* a bitflag, it's zero!
// Therefore, it is incompatible with all other flags
if ( pregin->rginent[i].dwFlags == REGCLS_SINGLEUSE )
ServerState |= SERVERSTATE_SINGLEUSE;
if ( pregin->rginent[i].dwFlags & REGCLS_SURROGATE )
ServerState |= SERVERSTATE_SURROGATE;
#if 0 // #ifdef _CHICAGO_
//
// On Win9x, we use a notification window to do lazy registers from a
// single threaded apartment. We don't use the notification window if
// this register is coming in from a resumed suspended registration.
// This is when the overloaded REGCLS_SUSPENDED flag is set.
//
if ( ! (pregin->rginent[i].dwFlags | REGCLS_SUSPENDED) && IsSTAThread() )
ServerState |= SERVERSTATE_USENOTIFYWIN;
#endif
pClassTableEntry = gpClassTable->GetOrCreate( pregin->rginent[i].clsid );
if ( ! pClassTableEntry )
hr = E_OUTOFMEMORY;
if ( pClassTableEntry )
{
hr = pClassTableEntry->RegisterServer(
pProcess,
pregin->rginent[i].ipid,
pClsidData,
NULL,
ServerState,
&pregout->RegKeys[i] );
pClassTableEntry->Release();
}
if ( pClsidData )
{
delete pClsidData;
pClsidData = NULL;
}
if ( hr != S_OK )
break;
}
//
// If we encountered any errors then we remove any entries which were
// successfully added.
//
// On success, we now signal all of the class table events.
//
// This loop restarts itself in removal mode if it encounters an errors
// while trying to signal the register events.
//
for ( i = 0; i < Entries; i++ )
{
HANDLE hRegisterEvent;
pClassTableEntry = gpClassTable->Lookup( pregin->rginent[i].clsid );
if ( S_OK == hr )
{
ASSERT( pClassTableEntry );
pClassTableEntry->UnsuspendServer( pregout->RegKeys[i] );
//
// Signal to waiting client (if any) that this clsid is registered
//
if (phRegisterEvents[i])
{
SetEvent(phRegisterEvents[i]);
CloseHandle(phRegisterEvents[i]);
phRegisterEvents[i] = 0;
}
}
if ( (hr != S_OK) && pregout->RegKeys[i] )
{
if ( pClassTableEntry )
pClassTableEntry->RevokeServer( pProcess, pregout->RegKeys[i] );
}
if ( pClassTableEntry )
pClassTableEntry->Release();
}
if ( hr != S_OK )
memset( pregout->RegKeys, 0, pregout->dwSize * sizeof(DWORD) );
//
// Release all of the registration event handles
//
for (i = 0; i < Entries; i++)
{
if (phRegisterEvents[i])
CloseHandle(phRegisterEvents[i]);
}
ReleaseProcess( pProcess );
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: StopServer
//
// Synopsis: Get notification that class server is stopping
//
// Arguments: [hRpc] - RPC handle
// [prevcls] - list of classes/registrations to stop
//
// History: 01-May-93 Ricksa Created
//
//--------------------------------------------------------------------------
extern "C" void ServerRevokeClsid(
handle_t hRpc,
PHPROCESS phProcess,
RevokeClasses *prevcls,
error_status_t *rpcstat)
{
CServerTableEntry* pClassTableEntry;
RevokeEntry* prevent;
DWORD Entries;
CProcess* pProcess;
CheckLocalCall( hRpc );
// Parameter validation
if (!prevcls || !rpcstat)
return;
pProcess = ReferenceProcess(phProcess);
if (!pProcess)
return;
*rpcstat = 0;
Entries = prevcls->dwSize;
prevent = prevcls->revent;
for ( ; Entries--; prevent++ )
{
pClassTableEntry = gpClassTable->Lookup( prevent->clsid );
if ( pClassTableEntry )
{
pClassTableEntry->RevokeServer( pProcess, prevent->dwReg );
pClassTableEntry->Release();
}
}
}
void GetThreadID(
handle_t hRpc,
DWORD * pThreadID,
error_status_t *prpcstat)
{
CheckLocalCall( hRpc );
// Parameter validation
if (!pThreadID || !prpcstat)
return;
*prpcstat = 0;
*pThreadID = InterlockedExchangeAdd((long *)&gNextThreadID,1);
}
//+-------------------------------------------------------------------------
//
// Function: UpdateActivationSettings
//
// Synopsis: Re-read default activation settings.
//
// Arguments: [hRpc] - RPC handle
// [prpcstat] - communication status
//
//--------------------------------------------------------------------------
#ifdef _CHICAGO_
extern HRESULT ReadRegistry();
#else
extern void ComputeSecurity();
#endif _CHICAGO_
extern "C" void UpdateActivationSettings(
handle_t hRpc,
error_status_t *prpcstat)
{
CheckLocalCall( hRpc );
// Parameter validation
if (!prpcstat)
return;
*prpcstat = 0;
ReadRemoteActivationKeys();
ComputeSecurity();
}
//+-------------------------------------------------------------------------
//
// Function: VerifyCallerIsAdministrator
//
// Synopsis: Verifies that the specified user is an administrator
//
// Returns: S_OK -- success, *pbAdmin is valid
// other -- error occurred
//
// Arguments: [pToken] - token of the user
// [pbAdmin] - out param denoting admin status
//
//--------------------------------------------------------------------------
HRESULT VerifyCallerIsAdministrator(CToken* pToken, BOOL* pbAdmin)
{
BOOL fSuccess;
PSID psidAdmin;
SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
// Allocate sid for Administrators
fSuccess = AllocateAndInitializeSid(&SystemSidAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &psidAdmin);
if (!fSuccess)
return HRESULT_FROM_WIN32(GetLastError());
// Check that caller is an admin
fSuccess = CheckTokenMembership(pToken->GetToken(), psidAdmin, pbAdmin);
FreeSid(psidAdmin);
if (!fSuccess)
return HRESULT_FROM_WIN32(GetLastError());
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Function: EnableDisableDynamicIPTracking
//
// Synopsis: Writes a "Y" or "N" to the HKLM\Software\MS\Ole\
// EnableSystemDynamicIPTracking string value, and sets the
// global variable gbDynamicIPChangesEnabled accordingly.
//
// Arguments: [hRpc] - RPC handle
// [phProcess] - context handle
// [fEnable] - whether to enable or disable
// [prpcstat] - communication status
//
//--------------------------------------------------------------------------
extern "C"
HRESULT EnableDisableDynamicIPTracking(
handle_t hRpc,
PHPROCESS phProcess,
BOOL fEnable,
error_status_t* prpcstat)
{
HRESULT hr = S_OK;
BOOL bAdmin;
ORSTATUS status;
CheckLocalCall( hRpc ); // raises exception if not
// Parameter validation
if (!prpcstat)
return E_INVALIDARG;
*prpcstat = 0; // we got here so we are OK
// Make sure we know who's calling
CProcess* pProcess = ReferenceProcess(phProcess);
if (!pProcess)
return E_ACCESSDENIED;
// Get token for the caller
CToken* pToken;
status = LookupOrCreateToken(hRpc, TRUE, &pToken);
if (status != ERROR_SUCCESS)
return E_ACCESSDENIED;
hr = VerifyCallerIsAdministrator(pToken, &bAdmin);
pToken->Release();
if (FAILED(hr))
return hr;
if (!bAdmin)
return E_ACCESSDENIED;
SCMVDATEHEAP();
hr = gAddrExclusionMgr.EnableDisableDynamicTracking(fEnable);
SCMVDATEHEAP();
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: GetCurrentIPExclusionList
//
// Synopsis: Passes the contents of the current address exclusion list
// back to the caller
//
// Arguments: [hRpc] - RPC handle
// [phProcess] - context handle
// [pdwNumStrings] - size of the pppszStrings array
// [pppszStrings] - array of pointers to NULL-term'd strings
// [prpcstat] - communication status
//
//--------------------------------------------------------------------------
extern "C"
HRESULT GetCurrentAddrExclusionList(
handle_t hRpc,
PHPROCESS phProcess,
DWORD* pdwNumStrings,
LPWSTR** pppszStrings,
error_status_t* prpcstat)
{
HRESULT hr = S_OK;
BOOL bAdmin;
ORSTATUS status;
CheckLocalCall( hRpc ); // raises exception if not
// Parameter validation
if (!pdwNumStrings || !pppszStrings || !prpcstat)
return E_INVALIDARG;
*prpcstat = 0; // we got here so we are OK
// Make sure we know who's calling
CProcess* pProcess = ReferenceProcess(phProcess);
if (!pProcess)
return E_ACCESSDENIED;
// Get token for the caller
CToken* pToken;
status = LookupOrCreateToken(hRpc, TRUE, &pToken);
if (status != ERROR_SUCCESS)
return E_ACCESSDENIED;
hr = VerifyCallerIsAdministrator(pToken, &bAdmin);
pToken->Release();
if (FAILED(hr))
return hr;
if (!bAdmin)
return E_ACCESSDENIED;
SCMVDATEHEAP();
hr = gAddrExclusionMgr.GetExclusionList(
pdwNumStrings,
pppszStrings);
SCMVDATEHEAP();
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: SetAddrExclusionList
//
// Synopsis: Re-sets the contents of the address exclusion list, and updates
// all currently running processes with the new bindings.
//
// Arguments: [hRpc] - RPC handle
// [phProcess] - context handle
// [dwNumStrings] - size of the ppszStrings array
// [ppszStrings] - array of pointers to NULL-term'd strings
// [prpcstat] - communication status
//
//--------------------------------------------------------------------------
extern "C"
HRESULT SetAddrExclusionList(
handle_t hRpc,
PHPROCESS phProcess,
DWORD dwNumStrings,
LPWSTR* ppszStrings,
error_status_t* prpcstat)
{
HRESULT hr = S_OK;
BOOL bAdmin;
ORSTATUS status;
CheckLocalCall( hRpc ); // raises exception if not
// Parameter validation
if (!ppszStrings || !prpcstat)
return E_INVALIDARG;
*prpcstat = 0; // we got here so we are OK
// Make sure we know who's calling
CProcess* pProcess = ReferenceProcess(phProcess);
if (!pProcess)
return E_ACCESSDENIED;
// Get token for the caller
CToken* pToken;
status = LookupOrCreateToken(hRpc, TRUE, &pToken);
if (status != ERROR_SUCCESS)
return E_ACCESSDENIED;
hr = VerifyCallerIsAdministrator(pToken, &bAdmin);
pToken->Release();
if (FAILED(hr))
return hr;
if (!bAdmin)
return E_ACCESSDENIED;
SCMVDATEHEAP();
hr = gAddrExclusionMgr.SetExclusionList(
dwNumStrings,
ppszStrings);
SCMVDATEHEAP();
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: FlushSCMBindings
//
// Synopsis: Remove the specified machine bindings from our remote binding
// handle cache
//
// Arguments: [hRpc] - RPC handle
// [prpcstat] - communication status
//
//--------------------------------------------------------------------------
extern "C"
HRESULT FlushSCMBindings(
handle_t hRpc,
PHPROCESS phProcess,
WCHAR* pszMachineName,
error_status_t* prpcstat)
{
HRESULT hr;
BOOL bAdmin;
ORSTATUS status;
CheckLocalCall( hRpc ); // raises exception if not
// Parameter validation
if (!pszMachineName || !prpcstat)
return E_INVALIDARG;
*prpcstat = 0; // we got here so we are OK
// Make sure we know who's calling
CProcess* pProcess = ReferenceProcess(phProcess);
if (!pProcess)
return E_ACCESSDENIED;
// Get token for the caller
CToken* pToken;
status = LookupOrCreateToken(hRpc, TRUE, &pToken);
if (status != ERROR_SUCCESS)
return E_ACCESSDENIED;
hr = VerifyCallerIsAdministrator(pToken, &bAdmin);
pToken->Release();
if (FAILED(hr))
return hr;
if (!bAdmin)
return E_ACCESSDENIED;
SCMVDATEHEAP();
hr = gpRemoteMachineList->FlushSpecificBindings(pszMachineName);
SCMVDATEHEAP();
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: RetireServer
//
// Synopsis: Marks the specified server as being no longer eligible for
// component activations of any type. Currently only used
// to support COM+'s process recycling feature.
//
// Arguments: [hRpc] - RPC handle
// [pguidProcessIdentifier] - guid which identifies the server
// [prpcstat] - communication status
//
//--------------------------------------------------------------------------
extern "C"
HRESULT RetireServer(
handle_t hRpc,
PHPROCESS phProcess,
GUID* pguidProcessIdentifier,
error_status_t* prpcstat)
{
CheckLocalCall( hRpc ); // raises exception if not
// Parameter validation
if (!pguidProcessIdentifier || !prpcstat)
return E_INVALIDARG;
*prpcstat = 0; // we got here so we are OK
if (!pguidProcessIdentifier)
return E_INVALIDARG;
// Make sure we know who's calling
CProcess* pProcess = ReferenceProcess(phProcess);
if (!pProcess)
return E_ACCESSDENIED;
// Get token for the caller
CToken* pToken;
ORSTATUS status;
status = LookupOrCreateToken(hRpc, TRUE, &pToken);
if (status != ERROR_SUCCESS)
return E_ACCESSDENIED;
// Make sure they're an administrator
HRESULT hr;
BOOL bAdmin;
hr = VerifyCallerIsAdministrator(pToken, &bAdmin);
pToken->Release();
if (FAILED(hr))
return hr;
if (!bAdmin)
return E_ACCESSDENIED;
// Okay, see if we know which process they're talking about
gpProcessListLock->LockShared();
hr = E_INVALIDARG; // review for better code when we don't find the process
CBListIterator all_procs(gpProcessList);
CProcess* pprocess;
while (pprocess = (CProcess*)all_procs.Next())
{
if (*pprocess->GetGuidProcessIdentifier() == *pguidProcessIdentifier)
{
// Found it. Mark it as retired
pprocess->Retire();
hr = S_OK;
break;
}
}
gpProcessListLock->UnlockShared();
return hr;
}
CWIPTable gWIPTbl; // global instance of the class
CWIPTable * gpWIPTbl = &gWIPTbl;
//+-------------------------------------------------------------------------
//
// Function: CopyDualStringArray
//
// Synopsis: makes a copy of the given string array
//
// History: 22-Jan-96 Rickhi Created
//
//--------------------------------------------------------------------------
HRESULT CopyDualStringArray(DUALSTRINGARRAY *psa, DUALSTRINGARRAY **ppsaNew)
{
ULONG ulSize = sizeof(DUALSTRINGARRAY) + (psa->wNumEntries * sizeof(WCHAR));
*ppsaNew = (DUALSTRINGARRAY *) PrivMemAlloc(ulSize);
if (*ppsaNew == NULL)
{
return E_OUTOFMEMORY;
}
memcpy(*ppsaNew, psa, ulSize);
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Member: CWIPTable::AddEntry, public
//
// Synopsis: Adds a WIPEntry to the table.
//
// Arguments: [hWnd] - window handle
// [pStd] - standard marshaled interface STDOBJREF
// [pOxidInfo] - info needed to resolve the OXID
// [pdwCookie] - cookie to return (to be placed on the window)
//
// History: 22-Jan-96 Rickhi Created
//
//--------------------------------------------------------------------------
HRESULT CWIPTable::AddEntry(
DWORD_PTR hWnd,
STDOBJREF *pStd,
OXID_INFO *pOxidInfo,
DWORD_PTR *pdwCookie
)
{
// make a copy of the string array in the OxidInfo since MIDL will
// delete it on the way back out of the call.
DUALSTRINGARRAY *psaNew;
HRESULT hr;
if (m_fCsInitialized == FALSE)
{
ASSERT(FALSE);
return E_OUTOFMEMORY;
}
psaNew = (DUALSTRINGARRAY *) PrivMemAlloc(sizeof(DUALSTRINGARRAY) + (pOxidInfo->psa->wNumEntries * sizeof(WCHAR)));
if (psaNew == NULL)
{
return E_OUTOFMEMORY;
}
memcpy(psaNew, pOxidInfo->psa, sizeof(DUALSTRINGARRAY) + (pOxidInfo->psa->wNumEntries * sizeof(WCHAR)));
#if 0 // #ifdef _CHICAGO_
CLockSmMutex lck(gWIPmxs);
#else
CLock2 lck(s_mxs);
#endif
// find a free slot in the table
DWORD_PTR dwpIndex = s_iNextFree;
if (dwpIndex == (DWORD_PTR)-1)
{
// grow the table
dwpIndex = Grow();
}
if (dwpIndex != (DWORD_PTR)-1)
{
// get the pointer to the entry,
WIPEntry *pEntry = s_pTbl + dwpIndex;
// update the next free index.
s_iNextFree = pEntry->hWnd;
// copy in the data
memcpy(&pEntry->std, pStd, sizeof(STDOBJREF));
memcpy(&pEntry->oxidInfo, pOxidInfo, sizeof(OXID_INFO));
pEntry->oxidInfo.psa = psaNew;
pEntry->hWnd = hWnd;
pEntry->dwFlags = WIPF_OCCUPIED;
// set the cookie to return
*pdwCookie = dwpIndex+5000;
// return success
hr = S_OK;
}
else
{
// free the allocated string array
PrivMemFree(psaNew);
hr = E_OUTOFMEMORY;
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CWIPTable::GetEntry, public
//
// Synopsis: Retrieves and optionally delets a WIPEntry from the table.
//
// Arguments: [hWnd] - window handle
// [dwCookie] - cookie from the window
// [pStd] - place to return STDOBJREF data
// [pOxidInfo] - place to return info needed to resolve the OXID
//
// History: 22-Jan-96 Rickhi Created
//
//--------------------------------------------------------------------------
HRESULT CWIPTable::GetEntry(
DWORD_PTR hWnd,
DWORD_PTR dwCookie,
BOOL fRevoke,
STDOBJREF *pStd,
OXID_INFO *pOxidInfo)
{
HRESULT hr = E_INVALIDARG;
// validate the cookie
DWORD_PTR dwpIndex = dwCookie - 5000;
if (dwpIndex >= s_cEntries)
{
return hr;
}
if (m_fCsInitialized == FALSE)
{
ASSERT(FALSE);
return E_OUTOFMEMORY;
}
#if 0 // #ifdef _CHICAGO_
CLockSmMutex lck(gWIPmxs);
#else
CLock2 lck(s_mxs);
#endif
// get the pointer to the entry,
WIPEntry *pEntry = s_pTbl + dwpIndex;
// make sure the entry is occupied
if (pEntry->dwFlags & WIPF_OCCUPIED)
{
DUALSTRINGARRAY *psaNew;
psaNew = (DUALSTRINGARRAY *) PrivMemAlloc(sizeof(DUALSTRINGARRAY) + (pEntry->oxidInfo.psa->wNumEntries * sizeof(WCHAR)));
if (psaNew == NULL)
{
return E_OUTOFMEMORY;
}
memcpy(psaNew, pEntry->oxidInfo.psa, sizeof(DUALSTRINGARRAY) + (pEntry->oxidInfo.psa->wNumEntries * sizeof(WCHAR)));
// copy out the data to return
memcpy(pStd, &pEntry->std, sizeof(STDOBJREF));
memcpy(pOxidInfo, &pEntry->oxidInfo, sizeof(OXID_INFO));
pOxidInfo->psa = psaNew;
if (fRevoke)
{
// free the entry by updating the flags and the next free index
PrivMemFree(pEntry->oxidInfo.psa);
pEntry->dwFlags = WIPF_VACANT;
pEntry->hWnd = s_iNextFree;
s_iNextFree = dwpIndex;
}
// return success
hr = S_OK;
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CWIPTable::Grow, private
//
// Synopsis: grows the WIPTable size.
//
// History: 22-Jan-96 Rickhi Created
//
//--------------------------------------------------------------------------
DWORD_PTR CWIPTable::Grow()
{
// compute the size and allocate a new table
DWORD_PTR dwSize = (s_cEntries + WIPTBL_GROW_SIZE) * sizeof(WIPEntry);
WIPEntry *pNewTbl = (WIPEntry *) PrivMemAlloc((size_t)dwSize);
if (pNewTbl != NULL)
{
// copy the old table in
memcpy(pNewTbl, s_pTbl, (size_t)(s_cEntries * sizeof(WIPEntry)));
// free the old table
if (s_pTbl)
{
PrivMemFree(s_pTbl);
}
// replace the old table ptr
s_pTbl = pNewTbl;
// update the free list and mark the new entries as vacant
s_iNextFree = s_cEntries;
WIPEntry *pNext = s_pTbl + s_cEntries;
for (ULONG i=0; i< WIPTBL_GROW_SIZE; i++)
{
pNext->hWnd = ++s_cEntries;
pNext->dwFlags = WIPF_VACANT;
pNext++;
}
(pNext-1)->hWnd = (DWORD_PTR)-1; // last entry has END_OF_LIST marker
}
return s_iNextFree;
}
//+-------------------------------------------------------------------------
//
// Function: RegisterWindowPropInterface
//
// Synopsis: Associate a window property with a (standard) marshaled
// interface.
//
// Arguments: [hRpc] - RPC handle
// [hWnd] - window handle
// [pStd] - standard marshaled interface STDOBJREF
// [pOxidInfo] - info needed to resolve the OXID
// [pdwCookie] - cookie to return (to be placed on the window)
// [prpcstat] - communication status
//
// History: 22-Jan-96 Rickhi Created
//
//--------------------------------------------------------------------------
extern "C" HRESULT RegisterWindowPropInterface(
handle_t hRpc,
DWORD_PTR hWnd,
STDOBJREF *pStd,
OXID_INFO *pOxidInfo,
DWORD_PTR *pdwCookie,
error_status_t *prpcstat)
{
CheckLocalCall( hRpc );
// Parameter validation
if (!pStd || !pOxidInfo || !pOxidInfo->psa || !pdwCookie || !prpcstat)
return E_INVALIDARG;
*prpcstat = 0;
CairoleDebugOut((DEB_SCM,
"_IN RegisterWindowPropInterface hWnd:%x pStd:%x pOxidInfo:%x\n",
hWnd, pStd, pOxidInfo));
VDATEHEAP();
HRESULT hr = gpWIPTbl->AddEntry(hWnd, pStd, pOxidInfo, pdwCookie);
CairoleDebugOut((DEB_SCM, "_OUT RegisterWindowPropInterface dwCookie:%x\n",
*pdwCookie));
VDATEHEAP();
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: GetWindowPropInterface
//
// Synopsis: Get the marshaled interface associated with a window property.
//
// Arguments: [hRpc] - RPC handle
// [hWnd] - window handle
// [dwCookie] - cookie from the window
// [fRevoke] - whether to revoke entry or not
// [pStd] - standard marshaled interface STDOBJREF to return
// [pOxidInfo] - info needed to resolve the OXID
// [prpcstat] - communication status
//
// History: 22-Jan-96 Rickhi Created
//
//--------------------------------------------------------------------------
extern "C" HRESULT GetWindowPropInterface(
handle_t hRpc,
DWORD_PTR hWnd,
DWORD_PTR dwCookie,
BOOL fRevoke,
STDOBJREF *pStd,
OXID_INFO *pOxidInfo,
error_status_t *prpcstat)
{
CheckLocalCall( hRpc );
// Parameter validation
if (!pStd || !pOxidInfo || !prpcstat)
return E_INVALIDARG;
*prpcstat = 0;
CairoleDebugOut((DEB_SCM,
"_IN GetWindowPropInterface hWnd:%x dwCookie:%x fRevoke:%x\n",
hWnd, dwCookie, fRevoke));
VDATEHEAP();
HRESULT hr = gpWIPTbl->GetEntry(hWnd, dwCookie, fRevoke, pStd, pOxidInfo);
CairoleDebugOut((DEB_SCM,
"_OUT GetWindowPropInterface pStd:%x pOxidInfo:%x\n", pStd, pOxidInfo));
VDATEHEAP();
return hr;
}