1. 生成应用程序框架
这里不再对OPC的概念和开发OPC DA server的必要掌握的COM技术做介绍,相信关于这方面的书籍和资料在网上都可以找得到。我们言归正传,看看如何建立一个OPC DA Server的基本框架。
1)生成MDI应用程序框架
我们将基于MDI应用程序开发我们的OPC DA Server,这样可以充分利用MFC的一些类库来更好的管理OPCDA Server,也能简化我们的开发。如果大家有用过Rockwell 的RSLinx,就知道这个软件也是基于MFC 的 MDI应用程序框架的。
打开VS2005,创建一个新的project,选择Visual C++,MDI应用程序。把project的名字改为OPCTestServer。
2)添加ATL支持
开发OPCDA Server要用到ATL,使用ATL开发COM应用程序,可以大大简化工作量。上面我们建立了一个支持MFC的应用程序,为了使用ATL,我们需要加入ATL支持。 选择“Project->Add Class … ”,在弹出的添加类的对话框里选择“Add ATL Support to MFC”, 确定。VC会自动添加一个继承于“CAtlMfcModule”的新类“COPCTestServerModule”。
2. 实现COPCServer类框架
COPCServer类继承IOPCServer接口,实现IOPCServer的所有接口。 1) OPC DA头文件
在开发opc server的过程中,我们要包含的头文件主要有:
opcda.h: 定义IOPCServer, IOPCItemMgt, IOPCAsyncIO等OPC DA接
口;
opcda_i.c : Classs ID 定义; opcError.h: OPC Error 类型定义;
opccommon.h: 定义IOPCCommon,IOPCServerList等接口 opccommon_i.c: Class ID 定义
这些头文件都可以直接从OPC 网站上面的分发包里面安装获得。为了方便大家使用,我把这些文件上传这里了。
http://files.cnblogs.com/opc521/OPCDAInclude.zip
NOTE:如果机器上以前没有注册过opcproxy.dll,一定要先注册这个dll,这是实现OPC DA接口定义及代理/存根的dll. 至于什么是代理/存根,大家请参阅其他的关于COM 和DCOM的书籍。
2)添加COPCServer类定义
Project->Add Class -> C++ Class
VS 提示IOPCServer没有找到,是否继续,按“Yes”继续。我们将在后面添加“IOPCServer”的定义。
NOTE:这里,为了方便统一管理生成COPCServer对象,我们没有从ATL 中的CComCoClass类派生。
将需要包含的头文件(opcda.h, opcda_i.c)拷到include目录下(solution 下面的新建的一个子文件夹),在“OPCServer.h”文件中添加:
#include \"opcda.h\"
编译一下,确保没有错误。
3)实现IUnknown接口
IOPCServer继承IUnknown接口,所以COPCServer首先要实现IUnkonw接口。
a. 添加引用计数变量
private:
ULONG m_lRefCount;
b. 添加接口定义到OPCServer.h: // the IUnknown Functions
STDMETHODIMP QueryInterface(REFIIDiid, LPVOID* ppInterface); STDMETHODIMP_(ULONG) AddRef( void); STDMETHODIMP_(ULONG) Release( void);
c. 添加接口函数实现:
1 //////////////////////////////////////////////////////////////////////////////////// 2 STDMETHODIMP_(ULONG) COPCServer::AddRef( void) 3 {
4 return ++m_lRefCount; 5 } 6
7 //////////////////////////////////////////////////////////////////////////////////// 8 STDMETHODIMP_(ULONG) COPCServer::Release( void) 9 {
10 ULONG currentCount = --m_lRefCount; 11
12 // If no references left for this server 13 if ( currentCount == 0) 14 {
15 // Then delete this server. 16 delete this; 17 }
18 return currentCount;
19 } 20
21 ////////////////////////////////////////////////////////////////////////////////////
22 STDMETHODIMP COPCServer::QueryInterface( REFIID iid, LPVOID* ppInterface) 23 {
24 // check valid pointer 25 if ( ppInterface == NULL) 26 return E_INVALIDARG; 27
28 // default return is NULL in case of error 29 *ppInterface = NULL; 30
31 if ( iid == IID_IUnknown ) 32 {
33 *ppInterface = (IUnknown*) this; 34 } 35
36 else if ( iid == IID_IOPCServer) 37 {
38 *ppInterface = (IOPCServer*) this; 39 } 40
41 if ( *ppInterface == NULL) 42 return E_NOINTERFACE; 43
44 AddRef(); 45 return S_OK; 46 } 47
4. 添加IOPCServer接口函数
a. 在\"opcserver.h\"中添加函数定义
1 // the IOPCServer Functions
2 STDMETHODIMP GetStatus( 3 OPCSERVERSTATUS** ppServerStatus); 4 STDMETHODIMP GetErrorString( 5 HRESULT hr, 6 LCID locale, 7 LPWSTR *ppstring);
8 STDMETHODIMP AddGroup(
9 LPCWSTR szName, 10 BOOL bActive,
11 DWORD dwRequestedUpdateRate, 12 OPCHANDLE hClientGroup, 13 LONG *pTimeBias, 14 FLOAT *pPercentDeadband, 15 DWORD dwLCID,
16 OPCHANDLE *phServerGroup, 17 DWORD *pRevisedUpdateRate, 18 REFIID riid,
19 LPUNKNOWN *ppUnk 20 );
21 STDMETHODIMP GetGroupByName( 22 LPCWSTR szGroupName,
23 REFIID riid, LPUNKNOWN *ppUnk); 24 STDMETHODIMP RemoveGroup( 25 OPCHANDLE groupHandleID, 26 BOOL bForce); 27
28 STDMETHODIMP CreateGroupEnumerator( 29 OPCENUMSCOPE dwScope, 30 REFIID riid,
31 LPUNKNOWN *ppUnk 32 );
b. 在\"OPCServer.cpp\"中添加函数实现
////////////////////////////////////////////////////////////////////////////////// // the IOPCServer Functions
STDMETHODIMP COPCServer::GetStatus( OPCSERVERSTATUS** ppServerStatus) {
return S_OK; }
//////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP COPCServer::GetErrorString( HRESULT hr, LCID locale, LPWSTR *ppstring) {
return S_OK; }
//////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP COPCServer::AddGroup( LPCWSTR szName, BOOL bActive,
DWORD dwRequestedUpdateRate, OPCHANDLE hClientGroup, LONG *pTimeBias, FLOAT *pPercentDeadband, DWORD dwLCID,
OPCHANDLE *phServerGroup, DWORD *pRevisedUpdateRate, REFIID riid,
LPUNKNOWN *ppUnk ) {
return S_OK; }
////////////////////////////////////////////////////////////////////////////////// STDMETHODIMP COPCServer::GetGroupByName( LPCWSTR szGroupName,
REFIID riid, LPUNKNOWN *ppUnk) {
return S_OK; }
//////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP COPCServer::RemoveGroup( OPCHANDLE groupHandleID, BOOL bForce) {
return S_OK; }
////////////////////////////////////////////////////////////////////////////////// STDMETHODIMP COPCServer::CreateGroupEnumerator( OPCENUMSCOPE dwScope, REFIID riid,
LPUNKNOWN *ppUnk ) {
return S_OK; }
这些接口函数现在都是空函数,我们会在以后的章节中逐步实现这些函数。
3. 实现OPC 类工厂
这节我们将介绍com类工厂的实现。 1) 准备工作:
在OPC Server运行过程中,对应每一个OPC client,都会生成一个COPCServer对象,为了管理所有的OPC server对象,我们先创建一个OPC server的管理类CServerMgr. \"Project->Add Class.. ->C++ class\" CServerMgr头文件如下:
1 #pragma once 2
3 #include \"OPCServer.h\" 4
5 class CServerMgr 6 { 7 public:
8 CServerMgr(void); 9 ~CServerMgr(void); 10
11 //methods
12 void AddServerToList(COPCServer* pServer); 13 void RemoveServerFromList(COPCServer* pServer); 14
15 //members 16 public:
17 CTypedPtrList AddServerToList()实现: 1 void CServerMgr::AddServerToList(COPCServer* pServer) 2 { 3 if (pServer) 4 m_serverList.AddTail(pServer); 5 } RomoveServerFromList() 实现: 1 void CServerMgr::RemoveServerFromList(COPCServer* pServer) 2 { 3 if (pServer) 4 { 5 if (m_serverList.GetCount() > 0) 6 { 7 POSITION pos = m_serverList.Find(pServer); 8 if (pos) 9 m_serverList.RemoveAt(pos); 10 } 11 } 12 } 在ServerMgr.cpp文件中定义CServerMgr全局变量: CServerMgr g_ServerMgr; 2) 实现OPC 类工厂 这里实现的类工厂继承IClassFactory。 类工厂定义如下: 1 #pragma once 2 #include \"ocidl.h\" 3 4 class COPCClassFactory : 5 public IClassFactory 6 { 7 public: 8 COPCClassFactory(void); 9 ~COPCClassFactory(void); 10 11 //IUnknown interfaces 12 STDMETHODIMP QueryInterface( REFIID iid, LPVOID* ppInterface); 13 STDMETHODIMP_(ULONG) AddRef( void); 14 STDMETHODIMP_(ULONG) Release( void); 15 16 //IClassFactory interfaces 17 STDMETHODIMP CreateInstance( LPUNKNOWN pUnkOuter, REFIID riid, LPVOID* ppvObject); 18 STDMETHODIMP LockServer( BOOL fLock); 19 20 private: 21 ULONG m_lRefCount; 22 }; 现在我们来看看如何具体实现类工厂: a. 初始化引用计数 m_lRefCount = 0; b. QueryInterface() 1 // QueryInterface() 2 // Implementation of the standard IUnknown QueryInterface() function for the sample OPC class factory. 3 4 STDMETHODIMP COPCClassFactory::QueryInterface( REFIID iid, LPVOID* ppInterface) 5 { 6 if ( ppInterface == NULL) 7 return E_INVALIDARG; 8 9 if ( iid == IID_IUnknown || iid == IID_IClassFactory) 10 { 11 *ppInterface = this; 12 } 13 else 14 *ppInterface = NULL; 15 16 if( *ppInterface ) 17 { 18 AddRef(); 19 return S_OK; 20 } 21 22 return E_NOINTERFACE; 23 } c. AddRef() 1 // AddRef() 2 // Implementaion of the standard IUnknown AddRef() function for the sample OPC class factory. 3 4 STDMETHODIMP_(ULONG) COPCClassFactory::AddRef( void) 5 { 6 return ++m_lRefCount; 7 } d. Release() 1 // Release() 2 // Implementation of the standard IUnknown Release() function for the sample OPC class factory. 3 4 STDMETHODIMP_(ULONG) COPCClassFactory::Release( void) 5 { 6 ULONG currentCount = --m_lRefCount; 7 if ( currentCount == 0) 8 delete this; 9 return currentCount; 10 } e. CreateInstance() 在\"OPCClassFactory.cpp\"定义: #include \"ServerMgr.h\" extern CServerMgrg_ServerMgr; 1 // CreateInstance() 2 // This function creates an instance of the OPC sample server. 3 STDMETHODIMP COPCClassFactory::CreateInstance( LPUNKNOWN pUnkOuter, REFIID riid, LPVOID* ppvObject) 4 { 5 COPCServer* pServer = new COPCServer; 6 if ( pServer == NULL) 7 { 8 TRACE( \"OPCClassFactory::CreateInstance() - Not enough memory to create OPC Server object, returning E_OUTOFMEMORY\\n\" ); 9 return E_OUTOFMEMORY; 10 } 11 //get requested interface 12 HRESULT hr = pServer->QueryInterface( riid, ppvObject); 13 if ( FAILED( hr)) 14 { 15 delete pServer; 16 } 17 else 18 { 19 g_ServerMgr.AddServerToList(pServer); 20 } 21 return hr; 22 } 23 f. LockServer() 1 // LockServer() 2 // This is a standard implementation of the IClassFactory::LockServer() function that either 3 // adds or removes a lock on the server. 4 // This is very useful if our server is an inproc process. 5 // The count determines whether the dll can be unloaded or not. 6 STDMETHODIMP COPCClassFactory::LockServer( BOOL fLock) 7 { 8 if ( fLock) 9 g_dwLockCount++; 10 else 11 g_dwLockCount--; 12 13 return S_OK; 14 } 3) 注册类厂 因为我们的server是进程外server,所以要调用CoRegisterClassObject注册类厂对象。 a. 在\"COPCTestServerApp\"类中添加变量: IClassFactory* m_pFactory; DWORD m_dwRegisterID; 并在构造函数初始化: m_pFactory = NULL; m_dwRegisterID = 0; b. 定义OPC server GUID 在\"OPCTestServer.cpp\"中添加: //Server GUID // {2BBA92EA-809B-4717-B3F9-750422C937B2} DEFINE_GUID(CLSID_OPCTestServer, 0x2bba92ea, 0x809b, 0x4717, 0xb3, 0xf9, 0x75, 0x4, 0x22, 0xc9, 0x37, 0xb2); c. 在InitInstance()中添加: 1 //Register class object 2 if (m_pFactory == NULL) 3 { 4 m_pFactory = new COPCClassFactory(); 5 m_pFactory->AddRef(); 6 7 if (FAILED( CoRegisterClassObject( CLSID_OPCTestServer, 8 m_pFactory, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_dwRegisterID))) 9 { 10 TRACE(\"CoRegisterClassObject Failed.\"); 11 return FALSE; 12 } 13 } 并注释掉前面在添加ATL支持时VC自动加入的code: //#if !defined(_WIN32_WCE) || defined(_CE_DCOM) // Register class factories via CoRegisterClassObject(). //if (FAILED(_AtlModule.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE))) // return FALSE; //#endif // !defined(_WIN32_WCE) || defined(_CE_DCOM) d. 在Exitinstance()中添加 1 //#if !defined(_WIN32_WCE) || defined(_CE_DCOM) 2 // _AtlModule.RevokeClassObjects(); 3 //#endif 4 5 //Revoke class object 6 if (m_pFactory) 7 { 8 ::CoRevokeClassObject(m_dwRegisterID); 9 m_pFactory->Release(); 10 } 一定要注释掉:_AtlModule.RevokeClassObjects(); 5. IOPCServer接口函数实现 本节将详细介绍IOPCServer接口相关函数的实现。 1)准备工作 a. 添加CGlobalLock类 该类包装CRITICAL_SECTION,实现多线程程序中对共享数据成员的保护。这里我们用来实现对opc group list和opc item list的操作的保护。 将下面的code加到stdafx.h里面: 1 extern CRITICAL_SECTION g_globalLock; 2 class CGlobalLock 3 { 4 public: 5 CGlobalLock( ) 6 { 7 m_pCriticalSection = &g_globalLock; 8 EnterCriticalSection( m_pCriticalSection ); 9 } 10 11 CGlobalLock( CRITICAL_SECTION *cs ) 12 { 13 m_pCriticalSection = cs; 14 EnterCriticalSection( m_pCriticalSection ); 15 } 16 17 ~CGlobalLock() 18 { 19 LeaveCriticalSection( m_pCriticalSection ); 20 } 21 22 CRITICAL_SECTION* m_pCriticalSection; 23 }; 在\"OPCTestserver.cpp\"里面添加全局变量: CRITICAL_SECTION g_globalLock; 在COPCTestServerApp::InitInstance()中加入: InitializeCriticalSection(&g_globalLock); 在 COPCTestServerApp::ExitInstance(void)中加入: DeleteCriticalSection(&g_globalLock); b.添加COPCGroup类框架 因为在实现IOPCServer::AddGroup函数时要生成COPCGroup对象,所以在这里先生成该类的一个框架,具体实现将在后面章节介绍。 添加C++类,命名COPCGroup,继承IOPCItemMgt接口。 1 #pragma once 2 #include \"opcda.h\" 3 4 class COPCServer; 5 6 class COPCGroup : 7 public IOPCItemMgt 8 { 9 public: 10 COPCGroup(void); 11 ~COPCGroup(void); 12 13 //IUnknown interfaces 14 STDMETHODIMP QueryInterface( REFIID iid, LPVOID* ppInterface); 15 STDMETHODIMP_(ULONG) AddRef( void); 16 STDMETHODIMP_(ULONG) Release( void); 17 18 //IOPCItemMgt Functions 19 STDMETHODIMP AddItems( 20 DWORD dwNumItems, 21 OPCITEMDEF * pItemArray, 22 OPCITEMRESULT ** ppAddResults, 23 HRESULT ** ppErrors 24 ); 25 26 STDMETHODIMP ValidateItems( 27 DWORD dwNumItems, 28 OPCITEMDEF * pItemArray, 29 BOOL bBlobUpdate, 30 OPCITEMRESULT ** ppValidationResults, 31 HRESULT ** ppErrors 32 ); 33 34 STDMETHODIMP RemoveItems( 35 DWORD dwNumItems, 36 OPCHANDLE * phServer, 37 HRESULT ** ppErrors 38 ); 39 40 STDMETHODIMP SetActiveState( 41 DWORD dwNumItems, 42 OPCHANDLE * phServer, 43 BOOL bActive, 44 HRESULT ** ppErrors 45 ); 46 47 STDMETHODIMP SetClientHandles( 48 DWORD dwNumItems, 49 OPCHANDLE * phServer, 50 OPCHANDLE * phClient, 51 HRESULT ** ppErrors 52 ); 53 STDMETHODIMP SetDatatypes( 55 DWORD dwNumItems, 56 OPCHANDLE * phServer, 57 VARTYPE * pRequestedDatatypes, 58 HRESULT ** ppErrors 59 ); 60 61 STDMETHODIMP CreateEnumerator( 62 REFIID riid, 63 LPUNKNOWN * ppUnk ); 65 66 //public members 67 public: 68 LPWSTR m_szName; 69 BOOL m_bActive; 70 DWORD m_dwUpdateRate; 71 OPCHANDLE m_hClientGroup; 72 LONG m_timeBias; 73 FLOAT m_percentDeadband; 74 DWORD m_dwLCID; 75 time_t m_generationTime; 76 COPCServer* m_pServer; 77 78 //private members 79 private: 80 ULONG m_lRefCount; 81 BOOL m_bIsDeleted; 82 }; 83 OPCGroup.cpp: 1 #include \"StdAfx.h\" 2 #include \"OPCGroup.h\" 3 4 COPCGroup::COPCGroup(void) 5 :m_lRefCount(0) 6 { 7 m_szName = NULL; 8 m_timeBias = 300; // Supposedly gotten from TIME_ZONE_INFORMATION. 9 m_dwUpdateRate = 0; 10 m_bActive = TRUE; 11 m_hClientGroup = NULL; 12 m_bIsDeleted = FALSE; 13 m_percentDeadband = (float) 0.0; 14 15 m_pServer = NULL; 16 } 17 18 COPCGroup::~COPCGroup(void) 19 { 20 if( m_szName ) 21 free( m_szName ); 22 } 23 24 // IUnknown::QueryInterface() 25 // This function is the implementation of the standard IUnknown QueryInterface() for the OPC 26 // Sample group class. 27 STDMETHODIMP COPCGroup::QueryInterface( REFIID iid, LPVOID* ppInterface) 28 { 29 if ( ppInterface == NULL) 30 return E_INVALIDARG; 31 32 if( m_bIsDeleted ) 33 return E_FAIL; 34 35 if ( iid == IID_IOPCItemMgt) 36 *ppInterface = (IOPCItemMgt*) this; 37 else 38 *ppInterface = NULL; 39 40 if ( *ppInterface == NULL) 41 return E_NOINTERFACE; 42 43 AddRef(); 44 45 return S_OK; 46 } 47 48 // IUnknown::AddRef() 49 // Standard IUnknown implementation 50 51 STDMETHODIMP_(ULONG) COPCGroup::AddRef( void) 52 { 53 if( m_bIsDeleted ) return E_FAIL; 55 56 return ++m_lRefCount; 57 } 58 59 // IUnknown::Release() 60 // Standard IUnknown implementation 61 62 STDMETHODIMP_(ULONG) COPCGroup::Release( void) 63 { ULONG currentCount = --m_lRefCount; 65 if ( currentCount == 0 ) 66 { 67 delete this; 68 } 69 return currentCount; 70 } 71 72 ///////////////////////////////////////////////////////////////////////////////////////// 73 // the IOPCItemMgt Functions 74 STDMETHODIMP COPCGroup::AddItems( 75 DWORD dwNumItems, 76 OPCITEMDEF * pItemArray, 77 OPCITEMRESULT ** ppAddResults, 78 HRESULT ** ppErrors 79 ) 80 { 81 return S_OK; 82 } 83 84 STDMETHODIMP COPCGroup::ValidateItems( 85 DWORD dwNumItems, 86 OPCITEMDEF * pItemArray, 87 BOOL bBlobUpdate, 88 OPCITEMRESULT ** ppValidationResults, HRESULT ** ppErrors 90 ) 91 { 92 return S_OK; 93 } 94 95 96 STDMETHODIMP COPCGroup::RemoveItems( 97 DWORD dwNumItems, 98 OPCHANDLE * phServer, 99 HRESULT ** ppErrors 100 ) 101 { 102 return S_OK; 103 } 104 105 106 STDMETHODIMP COPCGroup::SetActiveState( 107 DWORD dwNumItems, 108 OPCHANDLE * phServer, 109 BOOL bActive, 110 HRESULT ** ppErrors 111 ) 112 { 113 return S_OK; 114 } 115 116 117 STDMETHODIMP COPCGroup::SetClientHandles( 118 DWORD dwNumItems, 119 OPCHANDLE * phServer, 120 OPCHANDLE * phClient, 121 HRESULT ** ppErrors 122 ) 123 { 124 return S_OK; 125 } 126 127 128 STDMETHODIMP COPCGroup::SetDatatypes( 129 DWORD dwNumItems, 130 OPCHANDLE * phServer, 131 VARTYPE * pRequestedDatatypes, 132 HRESULT ** ppErrors 133 ) 134 { 135 return S_OK; 136 } 137 138 139 STDMETHODIMP COPCGroup::CreateEnumerator( 140 REFIID riid, 141 LPUNKNOWN * ppUnk 142 ) 143 { 144 return S_OK; 145 } 146 2) 实现IOPCServer::AddGroup 1 STDMETHODIMP COPCServer::AddGroup( 2 LPCWSTR szName, 3 BOOL bActive, 4 DWORD dwRequestedUpdateRate, 5 OPCHANDLE hClientGroup, 6 LONG *pTimeBias, 7 FLOAT *pPercentDeadband, 8 DWORD dwLCID, 9 OPCHANDLE *phServerGroup, 10 DWORD *pRevisedUpdateRate, 11 REFIID riid, 12 LPUNKNOWN *ppUnk 13 ) 14 { 15 if( phServerGroup == NULL || ppUnk == NULL ) 16 return E_INVALIDARG; 17 18 if( pPercentDeadband ) 19 { 20 if( *pPercentDeadband < (float) 0.0 || *pPercentDeadband > (float) 100.0 ) 21 return E_INVALIDARG; 22 } 23 24 //group name 25 CString groupName( szName ); 26 27 //default return parameters 28 *phServerGroup = NULL; 29 *ppUnk = NULL; 30 31 HRESULT hr = S_OK; 32 POSITION pos; 33 COPCGroup* pGroup; 34 LPWSTR pGroupName; 35 36 //lock 37 CGlobalLock globalLock(); 38 39 if( szName == NULL || *szName == (WCHAR) NULL ) 40 { 41 // User did not specify a group name, create one for him. 42 pGroupName = (LPWSTR) malloc( 40 ); 43 if( pGroupName == NULL ) 44 { 45 TRACE( \"IOPCServer::AddGroup() - Out of memory, returning E_OUTOFMEMORY\\n\" ); 46 return E_OUTOFMEMORY; 47 } 48 memset( pGroupName, 0, 40 ); 49 CString tempStr; 50 tempStr.Format( \"_Group%d\", m_dwNextGroupNumber++ ); 51 mbstowcs( pGroupName, tempStr, tempStr.GetLength() ); 52 } 53 else { 55 pGroupName = (LPWSTR) malloc( sizeof(WCHAR) * (wcslen(szName) + 1) ); 56 if( pGroupName == NULL ) 57 { 58 TRACE( \"IOPCServer::AddGroup() - Out of memory, returning E_OUTOFMEMORY\\n\" ); 59 return E_OUTOFMEMORY; 60 } 61 wcscpy( pGroupName, szName ); 62 } 63 pos = m_groupList.GetHeadPosition(); 65 while( pos ) 66 { 67 pGroup = (COPCGroup *) m_groupList.GetNext( pos ); 68 if( wcscmp( pGroupName, pGroup->m_szName ) == 0 ) 69 { 70 if( szName == NULL || *szName == (WCHAR) NULL ) 71 { 72 // User didn't specify a group name, but our generated one already exists, so 73 // generate another name. 74 CString tempStr; 75 tempStr.Format( \"_Group%d\", m_dwNextGroupNumber++ ); 76 mbstowcs( pGroupName, tempStr, tempStr.GetLength() + 1 ); 77 pos = m_groupList.GetHeadPosition(); 78 } 79 else 80 { 81 free( pGroupName ); 82 TRACE( \"IOPCServer::AddGroup() - Duplicate Group Name, returning OPC_E_DUPLICATENAME\\n\" ); 83 return OPC_E_DUPLICATENAME; 84 } 85 } 86 } 87 88 pGroup = new COPCGroup; if (pGroup == NULL) 90 { 91 free( pGroupName ); 92 TRACE( \"IOPCServer::AddGroup() - Out of memory, returning E_OUTOFMEMORY\\n\" ); 93 return E_OUTOFMEMORY; 94 } 95 96 pGroup->m_szName = (LPWSTR) malloc( sizeof(WCHAR) * (wcslen(pGroupName) + 1) ); 97 if( !pGroup->m_szName ) 98 { 99 free( pGroupName ); 100 delete pGroup; 101 TRACE( \"IOPCServer::AddGroup() - Out of memory, returning E_OUTOFMEMORY\\n\" ); 102 return E_OUTOFMEMORY; 103 } 104 105 wcscpy( pGroup->m_szName, pGroupName ); 106 free( pGroupName ); 107 108 pGroup->m_bActive = bActive; 109 pGroup->m_hClientGroup = hClientGroup; 110 time(&pGroup->m_generationTime); 111 112 if( dwRequestedUpdateRate == 0 || dwRequestedUpdateRate == 1 ) 113 pGroup->m_dwUpdateRate = MIN_GROUP_UPDATERATE; 114 else if( dwRequestedUpdateRate % MIN_GROUP_INTERVAL == 0 ) 115 pGroup->m_dwUpdateRate = dwRequestedUpdateRate; 116 else 117 pGroup->m_dwUpdateRate = (((int) (dwRequestedUpdateRate / MIN_GROUP_INTERVAL)) + 1) * MIN_GROUP_INTERVAL; 118 119 if( pRevisedUpdateRate ) 120 *pRevisedUpdateRate = pGroup->m_dwUpdateRate; 121 122 *phServerGroup = (OPCHANDLE) pGroup; 123 124 if( pTimeBias ) 125 { 126 pGroup->m_timeBias = *pTimeBias; 127 } 128 else 129 { 130 TIME_ZONE_INFORMATION timeZoneInfo; 131 132 if( GetTimeZoneInformation( &timeZoneInfo ) != TIME_ZONE_ID_INVALID ) 133 { 134 pGroup->m_timeBias = timeZoneInfo.Bias; 135 } 136 } 137 138 if( pPercentDeadband ) 139 { 140 pGroup->m_percentDeadband = *pPercentDeadband; 141 } 142 143 pGroup->m_dwLCID = dwLCID; 144 pGroup->m_pServer = this; 145 146 // Get the interface that the client has asked for. 147 if ( FAILED( hr = pGroup->QueryInterface( riid, (void**)ppUnk))) 148 { 149 delete pGroup; 150 TRACE1( \"IOPCServer::AddGroup() - Unknown Interface for Group Object, returning %#8.8x\\n\", hr ); 151 return hr; 152 } 153 1 if( dwRequestedUpdateRate != pGroup->m_dwUpdateRate ) 155 hr = OPC_S_UNSUPPORTEDRATE; 156 157 m_groupList.AddTail( (CObject*) pGroup ); 158 159 return hr; 160 } 其中: //define #define MIN_GROUP_INTERVAL 10 #define MIN_GROUP_UPDATERATE 1 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- yrrf.cn 版权所有 赣ICP备2024042794号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务