?? opcdrvserver.cpp
字號:
// OPCDrvServer.cpp
//
// This file contains the implementation of the Server object.
//
// This implementation uses 'tear off' interfaces
// (I.e. the interfaces are separate from the object
// which supports only IUnknown)
//
//
// (c) COPYRIGHT 1996-1998, INTELLUTION INC.
// ALL RIGHTS RESERVED
//
//
// Functions defined in this module:
//
// COPCDrvServer::COPCDrvServer()
// COPCDrvServer::~COPCDrvServer()
// COPCDrvServer::AddRef()
// COPCDrvServer::Release()
// COPCDrvServer::QueryInterface()
// COPCDrvServer::Init()
// COPCDrvServer::GetNameList()
// COPCDrvServer::FreeNameList()
// COPCDrvServer::GetUnkList()
// COPCDrvServer::FreeUnkList()
// COPCDrvServer::UpdateDataCache()
// COPCDrvServer::GetDriverInfo()
// COPCDrvServer::IsDataTypeSupported()
// COPCDrvServer::SendMessageToDriver()
// COPCDrvServer::PollThread()
//
//
//
// Modification Log:
// Vers Date By Notes
// ---- -------- --- -----
// 1.0 08/26/97 jra Created
// 1.3 03/10/98 jra Modified to be wizard generated and driver specific.
//
//
#define WIN32_LEAN_AND_MEAN
#include "OpcStdAfx.h"
#include <AFXCONV.h>
#include <process.h>
#include "OPCDrv.h"
#include "OPCDrvThread.h"
#include "..\server\interfaces\InterfaceDef_i.c"
// added support for OSDKPS.dll
#include <OSDKDefs_i.c>
#include "NioFuncs.h"
extern BOOL ChangeDriverThreadPriority(DWORD dwPriority);
extern DWORD g_dwWaitPeriod;
extern DWORD g_dwServerThreadPriority;
extern TCHAR g_tszAcronym[];
extern FILETIME g_ftStartTime;
/////////////////////////////////////////////////////////////////////////////
// Constructor /Destructor functions
//
////////////////////////////////////////////////////////////////
// COPCDrvServer()
//
// Constructor for the main server object
//
////////////////////////////////////////////////////////////////
COPCDrvServer::COPCDrvServer(LPUNKNOWN pOuter,
void (*pfn)(void))
{
// Init reference count to 0
//
m_lRefCount = 0;
// Clear out 'tear-off' interface ptrs
// The interfaces will be created as needed in QueryInterface
//
m_pCImpIOPCServer = NULL;
m_pCImpIOPCBrowseServer = NULL;
m_pCImpIPersistFile = NULL;
m_dwBandwidth = 0;
m_ServerState = OPC_STATUS_NOCONFIG;
// Used to calculate bandwidth
//
m_dwNumGroupsProcessed = 0;
m_dwTotalPasses = 0;
m_bKeepRunning = TRUE;
m_dwLastTickCount = 0;
// Get current UTC Time and store it
//
CoFileTimeNow(&m_ftLastUpdate);
m_ftServerStartTime = g_ftStartTime;
m_pfnDestroy = pfn;
m_lTransactionID = 0;
m_Slot = 0;
m_dwPollThreadId = 0L;
// Management of the groups
//
m_dwNumGroups = 0;
// Initialize the Group hash table to a prime number
//
m_mapGroup.InitHashTable(31);
InitializeCriticalSection(&this->m_Lock);
// Hardware options stuff
//
m_nOptionsSize = 0;
m_nNumOptions = 0;
m_pszOptions = NULL;
m_pvtOptionValues = NULL;
// I/O Server interface stuff
//
m_pIDriver = NULL;
m_pIDriverMessage = NULL;
m_pIDriverMessageMarshalled = NULL;
m_pIOpcConnections = NULL;
m_pIDriverMessageStream = NULL;
}
////////////////////////////////////////////////////////////////
// ~COPCDrvServer()
//
// Destructor for the main server object
//
////////////////////////////////////////////////////////////////
COPCDrvServer::~COPCDrvServer(void)
{
// Shutdown the bandwidth thread
//
m_bKeepRunning = FALSE;
// First, turn off any background processing
//
ClearServerSlot(m_Slot);
// Wait for the threads to shutdown.
//
if (WaitForSingleObject(m_hPollThread,
THREAD_SHUTDOWN_TIME) == WAIT_TIMEOUT)
{
TerminateThread(m_hPollThread, 0);
}
// Lock out this server
//
Lock();
// If necessary free any memory associated with the Group map
//
FreeAllGroups();
// Then delete any tear off interfaces
//
if (m_pCImpIOPCServer)
{
delete m_pCImpIOPCServer;
}
if (m_pCImpIPersistFile)
{
delete m_pCImpIPersistFile;
}
if (m_pCImpIOPCBrowseServer)
{
delete m_pCImpIOPCBrowseServer;
}
// Delete the hardware options lists
//
if (m_pszOptions)
{
delete [] m_pszOptions;
}
if (m_pvtOptionValues)
{
delete [] m_pvtOptionValues;
}
// Inform NIO that we are unloading if this is the last one
//
if (0 == GetServerSlotCount())
{
IOSTAT IoStat;
memset(&IoStat, 0, sizeof(IOSTAT));
nio_CleanUp(&IoStat);
if (IoStat.iostatus != FE_OK)
{
HRESULT hr = (HRESULT)((IoStat.aux1 << 16) | IoStat.aux2);
CString szMsg;
szMsg.Format("nio_CleanUp() failed. Returned code = %lX", hr);
SendMessageToDriver(szMsg, MSG_DEBUG);
}
}
// Disconnect from the automation interface
//
if (m_pIDriverMessage)
{
m_pIDriverMessage->Release();
}
if (m_pIOpcConnections)
{
long lRef = 0L;
m_pIOpcConnections->GetOpcRef(&lRef);
m_pIOpcConnections->Release();
}
if (m_pIDriver)
{
m_pIDriver->Release();
}
UnLock();
DeleteCriticalSection(&this->m_Lock);
}
/////////////////////////////////////////////////////////////////////////////
// IUnknown functions
//
////////////////////////////////////////////////////////////////
// IUnknown::AddRef()
//
// Standard IUnknown implementation
//
////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) COPCDrvServer::AddRef(void)
{
return InterlockedIncrement(&m_lRefCount);
}
////////////////////////////////////////////////////////////////
// IUnknown::Release()
// Standard IUnknown implementation
//
////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) COPCDrvServer::Release(void)
{
ASSERT(0 != m_lRefCount);
ULONG currentCount = InterlockedDecrement(&m_lRefCount);
// If no references left for this server
if (currentCount == 0)
{
// Then delete this server.
//
if(m_pfnDestroy)
{
(*m_pfnDestroy)(); // DLL can unload if last one
}
delete this;
}
return currentCount;
}
////////////////////////////////////////////////////////////////
// IUnknown::QueryInterface()
//
// Standard IUnknown implementation using 'tear off' interfaces
//
////////////////////////////////////////////////////////////////
STDMETHODIMP COPCDrvServer::QueryInterface(REFIID iid,
LPVOID *ppInterface)
{
// Make sure we got a valid pointer
//
if (NULL == ppInterface)
{
return E_INVALIDARG;
}
// IUnknown
if (iid == IID_IUnknown)
{
*ppInterface = (IUnknown *)this;
}
// IOPCServer
else if (iid == IID_IOPCServer)
{
if(NULL == m_pCImpIOPCServer)
{
m_pCImpIOPCServer = new CImpIOPCServer(this);
}
if (NULL == m_pCImpIOPCServer)
{
return E_OUTOFMEMORY;
}
*ppInterface = m_pCImpIOPCServer;
}
// IOPCBrowseServerAddressSpace
else if (iid == IID_IOPCBrowseServerAddressSpace)
{
if(NULL == m_pCImpIOPCBrowseServer)
{
m_pCImpIOPCBrowseServer = new CImpIOPCBrowseServer(this);
}
if (NULL == m_pCImpIOPCBrowseServer)
{
return E_OUTOFMEMORY;
}
*ppInterface = m_pCImpIOPCBrowseServer;
}
// IPersistFile
else if ((iid == IID_IPersistFile) || (iid == IID_IPersist))
{
if(NULL == m_pCImpIPersistFile)
{
m_pCImpIPersistFile = new CImpIPersistFile(this);
}
if (NULL == m_pCImpIPersistFile)
{
return E_OUTOFMEMORY;
}
*ppInterface = m_pCImpIPersistFile;
}
// IEnumUnknown
else if (iid == IID_IEnumUnknown)
{
// Note enumerators are special in that they are independent objects
// They are not just interfaces on an existing object
//
HRESULT hr;
CImpIEnumUnknown *temp;
LPUNKNOWN *GroupList;
int nGroupCount;
// Get a snapshot of the group list
// (Note this does NOT do AddRefs to the groups - but see IXXXEnum below)
//
GetUnkList(OPC_ENUM_ALL_CONNECTIONS, &GroupList, &nGroupCount);
// Create the Enumerator using the snapshot (which might be empty)
// Note that the enumerator constructor will AddRef
// all of the groups.
//
temp = new CImpIEnumUnknown(this, nGroupCount, GroupList, pIMalloc);
delete [] GroupList;
if (NULL == temp)
{
return E_OUTOFMEMORY;
}
// Then QI for the interface ('temp') actually is the interface
// but QI is the 'proper' way to get it.
// Note QI will do an AddRef of the Enum which will also do
// an AddRef of the 'parent' - i.e. the 'this' pointer passed above.
//
hr = temp->QueryInterface(iid, ppInterface);
if (FAILED(hr))
{
delete temp;
return hr;
}
// If all OK - return here
// Unlike most interfaces this one does NOT directly addref the server
// (since we created a new and independent object)
//
return S_OK;
}
// No interface available
else
{
*ppInterface = NULL;
}
if (NULL == *ppInterface)
{
return E_NOINTERFACE;
}
// Record the reference to the new object.
//
((LPUNKNOWN)*ppInterface)->AddRef();
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// Private (non-OPC) Utility Functions
//
////////////////////////////////////////////////////////////////
// COPCDrvServer::Init()
//
// Initializes the object
//
// Returns:
// S_OK success
// E_FAIL failure
//
////////////////////////////////////////////////////////////////
HRESULT COPCDrvServer::Init(void)
{
// Connect to the driver's automation interface
//
if (FAILED(GetDriverInfo()))
{
m_pIDriver = NULL;
m_pIDriverMessage = NULL;
LogEventMessage(TEXT("CoCreateInstance() failed. Unable to connect to automation interface"),
g_tszAcronym,
3);
return E_FAIL;
}
// Fire off the main poll thread that does all of the work
//
unsigned int nAddress = 0;
m_hPollThread = (HANDLE)_beginthreadex(NULL,
0,
PollThread,
(LPVOID)this,
0,
&nAddress);
if (NULL == m_hPollThread)
{
LogEventMessage(TEXT("_beginthreadex failed. Unalbe to create polling thread"),
g_tszAcronym,
3);
return E_FAIL;
}
// Plug this server into the map for bandwidth calculations.
//
if (!FindServerSlot(&m_Slot, this))
{
LogEventMessage(TEXT("Unable to initialize server object"),
g_tszAcronym,
3);
}
return S_OK;
}
////////////////////////////////////////////////////////////////
// COPCDrvServer::GetNameList()
//
// Create a list of all the group names.
//
// Returns:
// void
//
////////////////////////////////////////////////////////////////
void COPCDrvServer::GetNameList(OPCENUMSCOPE OPCScope,
LPOLESTR **ppGroupList,
int *pnGroupCount)
{
int nNumGroups = 0,
i = 0;
LPOLESTR *mylist = NULL;
OPCHANDLE OPCHandle = 0;
COPCDrvGroup *pGroup = NULL;
POSITION posGroup;
// Initialize return parameters
*ppGroupList = NULL;
*pnGroupCount = 0;
// Lock the server object
//
this->Lock();
// Get the info about the group list
//
nNumGroups = this->GetNumGroupHandles();
posGroup = this->GetFirstGroupPosition();
// See if there is anything to enumerate
//
if (0 == nNumGroups)
{
this->UnLock();
return;
}
switch(OPCScope)
{
case OPC_ENUM_PRIVATE_CONNECTIONS:
case OPC_ENUM_PRIVATE:
case OPC_ENUM_ALL_CONNECTIONS:
case OPC_ENUM_ALL:
*ppGroupList = mylist = new LPOLESTR[nNumGroups]; // Caller must free this!
if (*mylist == NULL)
{
this->UnLock();
return;
}
for (i = 0; i < nNumGroups; i++)
{
this->GetNextGroup(posGroup, OPCHandle, pGroup);
// Note that the string is cloned to keep the enumerator 'stable'
//
mylist[*pnGroupCount] = WSTRClone(pGroup->m_szName, NULL);
(*pnGroupCount)++;
}
break;
case OPC_ENUM_PUBLIC:
case OPC_ENUM_PUBLIC_CONNECTIONS:
break;
default:
// Should never happen!!
TRACE("Invalid scope passed to GetNameList() (%d), File %s, Line %d\n",
OPCScope, __FILE__, __LINE__);
break;
}
// Unlock the server object
//
this->UnLock();
}
////////////////////////////////////////////////////////////////
// COPCDrvServer::FreeNameList()
//
// Free a list of group names.
//
// Returns:
// void
//
////////////////////////////////////////////////////////////////
void COPCDrvServer::FreeNameList(LPOLESTR *ppGroupList,
int nCount)
{
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -