本节将详细介绍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
54 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
64 );
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 )
54 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 {
64 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,
89 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
54 {
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
64 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;
89 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
154 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
(未完待续)