windows-nt/Source/XPSP1/NT/net/mmc/dialinusr/sharesdo.cpp
2020-09-26 16:20:57 +08:00

339 lines
8 KiB
C++

/**********************************************************************/
/** Microsoft Windows/NT **/
/** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
/**********************************************************************/
/*
sharesdo.cpp
implement classes for sharing SdoServer among property pages for different users and snapins
FILE HISTORY:
*/
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <rtutils.h>
#include "rasdial.h"
#include "sharesdo.h"
// the server pool pointer used to share SdoServer among pages and snapins
CSdoServerPool* g_pSdoServerPool;
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// DO SDO Attach -- real
HRESULT ConnectToSdoServer(BSTR machine, BSTR user, BSTR passwd,ISdoMachine** ppServer)
{
ASSERT(ppServer);
if(!ppServer) return E_INVALIDARG;
else
*ppServer = NULL;
HRESULT hr = S_OK;
// connect to the new one
TracePrintf(g_dwTraceHandle,_T("CoCreateInstance SdoServer"));
CHECK_HR(hr = CoCreateInstance( CLSID_SdoMachine,
NULL,
CLSCTX_INPROC_SERVER,
IID_ISdoMachine,
(void**)ppServer));
TracePrintf(g_dwTraceHandle,_T(" hr = %8x\r\n"), hr);
ASSERT(*ppServer);
TracePrintf(g_dwTraceHandle, _T("SdoServer::Attach(%s, %s, %s);"), machine, user, passwd);
CHECK_HR(hr = (*ppServer)->Attach(machine));
TracePrintf(g_dwTraceHandle,_T(" hr = %8x\r\n"), hr);
L_ERR:
if(FAILED(hr) && *ppServer)
{
(*ppServer)->Release();
*ppServer = NULL;
}
return hr;
}
// When using Single connection, get the marshaled interface from the stream
HRESULT GetSharedSdoServer(LPCTSTR machine, LPCTSTR user, LPCTSTR passwd, bool* pbConnect, CMarshalSdoServer* pServer)
{
static CCriticalSection cs;
HRESULT hr = S_OK;
if(cs.Lock()) // locked
{
if(NULL == g_pSdoServerPool)
{
try{
g_pSdoServerPool = new CSdoServerPool;
}catch(CMemoryException&)
{
hr = E_OUTOFMEMORY;
}
}
cs.Unlock();
}
else
{
TracePrintf(g_dwTraceHandle,_T(" GetSharedSdoServer, CS lock failed"));
return E_FAIL;
}
if(FAILED(hr))
return hr;
return g_pSdoServerPool->GetMarshalServer(machine, user, passwd, pbConnect, pServer);
}
//======================================================
// class CSharedSdoServerImp
// implementation class of shared server
CSharedSdoServerImp::CSharedSdoServerImp(LPCTSTR machine, LPCTSTR user, LPCTSTR passwd)
: strMachine(machine), strUser(user), strPasswd(passwd), bConnected(false)
{};
// to make this class element of collection, provide following member functions
bool CSharedSdoServerImp::IsFor(LPCTSTR machine, LPCTSTR user, LPCTSTR passwd) const
{
// Compare order, ServerName, UserName, Passwd, and RetriveType
CString strM(machine);
CString strU(user);
CString strP(passwd);
return (
strMachine.CompareNoCase(strM) == 0 &&
strUser.Compare(strU) == 0 &&
strPasswd.Compare(strP) == 0
);
};
// CoCreate SdoServer object
HRESULT CSharedSdoServerImp::CreateServer()
{
// cannot create twice!
ASSERT(!(ISdoMachine*)spServer);
if((ISdoMachine*)spServer) return S_OK;
HRESULT hr = S_OK;
// connect to the new one
TracePrintf(g_dwTraceHandle,_T("CoCreateInstance SdoServer"));
hr = CoCreateInstance( CLSID_SdoMachine,
NULL,
CLSCTX_INPROC_SERVER,
IID_ISdoMachine,
(void**)&spServer);
TracePrintf(g_dwTraceHandle,_T(" hr = %8x\r\n"), hr);
threadId = ::GetCurrentThreadId();
return hr;
};
// get marshal stream, can specify, if immediate connection is required.
HRESULT CSharedSdoServerImp::GetMarshalStream(LPSTREAM *ppStream, bool* pbConnect /* both input and output */)
{
ASSERT(ppStream);
DWORD tid = ::GetCurrentThreadId();
if (tid != threadId)
return E_FAIL; // make sure the interface should be marshaled from the same thread
HRESULT hr = S_OK;
cs.Lock();
if(pbConnect)
{
if(*pbConnect && !bConnected)
{
*pbConnect = false;
CHECK_HR(hr = Connect(NULL));
*pbConnect = true;
}
else
{
*pbConnect = bConnected;
}
}
// Marshal the interface
CHECK_HR(hr = CoMarshalInterThreadInterfaceInStream(IID_ISdoMachine, (ISdoMachine*)spServer, ppStream));
L_ERR:
cs.Unlock();
return hr;
};
// Connect the server to the a machine
HRESULT CSharedSdoServerImp::Connect(ISdoMachine* pServer)
// pServer, marshaled pointer, passed in from a different thread ( than the spServer in the object)
{
cs.Lock();
HRESULT hr = S_OK;
DWORD tid = ::GetCurrentThreadId();
USES_CONVERSION;
if(!bConnected)
{
ASSERT((ISdoMachine*)spServer);
BSTR bstrM = NULL;
BSTR bstrU = NULL;
BSTR bstrP = NULL;
if(!strMachine.IsEmpty())
bstrM = T2BSTR((LPTSTR)(LPCTSTR)strMachine);
if(!strUser.IsEmpty())
bstrM = T2BSTR((LPTSTR)(LPCTSTR)strUser);
if(!strPasswd.IsEmpty())
bstrP = T2BSTR((LPTSTR)(LPCTSTR)strPasswd);
TracePrintf(g_dwTraceHandle, _T("SdoServer::Connect(%s, %s, %s );"), bstrM, bstrU, bstrP);
if(!pServer)
{
// this function should be called within the same thread
// if the request if from a different thread, then this should NOT be NULL
ASSERT(tid == threadId);
pServer = (ISdoMachine*)spServer;
}
hr = pServer->Attach(bstrM);
TracePrintf(g_dwTraceHandle,_T(" hr = %8x\r\n"), hr);
bConnected = (hr == S_OK);
SysFreeString(bstrM);
SysFreeString(bstrU);
SysFreeString(bstrP);
}
cs.Unlock();
return hr;
};
HRESULT CSharedSdoServerImp::GetServerNReleaseStream(LPSTREAM pStream, ISdoMachine** ppServer)
{
#ifdef _DEBUG
DWORD __tid = ::GetCurrentThreadId();
#endif
return CoGetInterfaceAndReleaseStream(pStream, IID_ISdoMachine, (LPVOID*) ppServer);
};
// if connection is needed, should call the connec of CSharedSdoServer, rather than ISdoServer::Connect
HRESULT CMarshalSdoServer::GetServer(ISdoMachine** ppServer)
{
HRESULT hr = S_OK;
if(!(ISdoMachine*)spServer)
{
if((IStream*)spStm)
{
CHECK_HR(hr = CSharedSdoServerImp::GetServerNReleaseStream((IStream*)spStm, (ISdoMachine**)&spServer));
}
spStm.p = NULL; // need to manually clean this, since the above API already Release the COM interface
}
else
CHECK_HR(hr = E_FAIL);
if((ISdoMachine*)spServer)
{
*ppServer = (ISdoMachine*)spServer;
(*ppServer)->AddRef();
}
L_ERR:
return hr; // not valid to call at this point
};
// make SDO connect when / if NOT already done so. Note: multiple thread safe
HRESULT CMarshalSdoServer::Connect()
{
ASSERT(pImp); // should not happen
return pImp->Connect(spServer);
};
void CMarshalSdoServer::Release()
{
pImp = NULL;
spServer.Release();
spStm.Release();
};
CMarshalSdoServer::CMarshalSdoServer(): pImp(NULL)
{};
// estiblish an entry in the pool, if it's new
// get marshaServer object from the thread pool
HRESULT CSdoServerPool::GetMarshalServer(LPCTSTR machineName, LPCTSTR userName, LPCTSTR passwd, bool* pbConnect, CMarshalSdoServer* pServer)
{
ASSERT(pServer);
CSharedSdoServerImp* pImp = NULL;
HRESULT hr = S_OK;
std::list<CSharedSdoServerImp*>::iterator i;
// search if the server is already exist
cs.Lock();
for(i = listServers.begin(); i != listServers.end(); i++)
{
if((*i)->IsFor( machineName, userName, passwd))
{
pImp = (*i);
break;
}
}
// if not, then create one
if(!pImp)
{
try{
pImp = new CSharedSdoServerImp( machineName, userName, passwd);
}catch(...)
{
CHECK_HR(hr = E_OUTOFMEMORY);
}
ASSERT(pImp);
CHECK_HR(hr = pImp->CreateServer());
listServers.push_front(pImp);
}
// marshal it. bConnect will be filled
pServer->Release();
{
CComPtr<IStream> spStm;
CHECK_HR(hr = pImp->GetMarshalStream(&spStm, pbConnect));
// fill the information to the provided buffer
pServer->SetInfo((IStream*)spStm, pImp);
}
L_ERR:
cs.Unlock();
return hr;
};
// clean the POOL
CSdoServerPool::~CSdoServerPool()
{
#ifdef _DEBUG
DWORD __tid = ::GetCurrentThreadId();
#endif
std::list<CSharedSdoServerImp*>::iterator i;
for(i = listServers.begin(); i != listServers.end(); i++)
{
delete (*i);
}
listServers.erase(listServers.begin(), listServers.end());
};