|
|
/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation **/ /**********************************************************************/
/*
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"
#include "iastrace.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
IASTraceString("CoCreateInstance SdoServer");
CHECK_HR(hr = CoCreateInstance( CLSID_SdoMachine, NULL, CLSCTX_INPROC_SERVER, IID_ISdoMachine, (void**)ppServer));
IASTracePrintf(" hr = %8x\r\n", hr); ASSERT(*ppServer);
IASTracePrintf("SdoServer::Attach(%s, %s, %s);", machine, user, passwd); CHECK_HR(hr = (*ppServer)->Attach(machine)); IASTracePrintf(" 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* pException) { pException->Delete(); hr = E_OUTOFMEMORY; } } cs.Unlock(); } else { IASTraceString("ERROR: 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
IASTraceString("CoCreateInstance SdoServer");
hr = CoCreateInstance( CLSID_SdoMachine, NULL, CLSCTX_INPROC_SERVER, IID_ISdoMachine, (void**)&spServer);
IASTracePrintf(" 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);
IASTracePrintf("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); IASTracePrintf(" 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()); };
|