1. 程式人生 > >OPC工作記錄整理——第四篇(OPC客戶端開發之OPC伺服器的列舉和連線)

OPC工作記錄整理——第四篇(OPC客戶端開發之OPC伺服器的列舉和連線)

    OPC客戶端的開發相對來說,只要掌握了OPC基類的幾個介面,並知道它們是如何運作的,那麼開發起來還是相對容易的。好了,廢話不多說了,我們開始吧。

    首先是對標頭檔案的引用:

#include "stdafx.h"
#include <afxcoll.h>
#include <iostream>
#include "opccomn.h"
#include "opcda.h"

#include "opcerror.h"
#include "OPCEnum.h"

#include "opccomn_i.c"
#include "opcda_i.c"
#include "OPCEnum_i.c"
using namespace std;
//#include "COPCDataCallback.h" //這裡是我在OPC中以資料訂閱讀取資料而加以引用的,後面會提到

    然後是初始化變數:

HRESULT hr;
COSERVERINFO si;
ZeroMemory(&si, sizeof(si)); //記憶體1 存放伺服器資訊
MULTI_QI mqi[1];
ZeroMemory(&mqi, sizeof(mqi)); //記憶體2 存放MULTI_QI用以獲取OPC伺服器列表
CATID catID[2];
ZeroMemory(&catID, 2 * sizeof(CATID));  //記憶體3 存放OPC標準介面1.0和2.0
CLSID clsid[20];
ZeroMemory(&clsid, 20 * sizeof(CLSID)); //記憶體4 存放枚舉出的OPC伺服器的CLSID

/*Initialize DCOM*/
CString strError;
CString strNode = _T("192.168.x.xx"); //The IP Address of the OPC SERVER
CString strProgID = _T("xxxxxx");  //The ProgID of the OPC SERVER	

/*初始化指標*/
IOPCServerList *pIServerList = NULL;  //第一個介面指標,指向OPC伺服器列表
IEnumGUID *pIEnumGUID = NULL; //第二個介面指標,指向OPC伺服器列表列舉
IUnknown *pIUnknown = NULL; //第三個指標,伺服器介面指標
IOPCServer *pIServer = NULL; //第四個指標,指向OPC伺服器的介面指標
//IOPCItemMgt *pIOPCItemMgt = NULL; //第五個指標,指向標籤的指標
//OPCITEMDEF *itemArray = NULL; //第六個指標,指向標籤內容陣列
//OPCITEMRESULT *pItemResult = NULL;  //第七個指標,指向新增項的結果
//HRESULT *pErrors = NULL; //第八個指標,指向新增項錯誤
//OPCHANDLE *hOPCServer2 = NULL; //第九個指標,指向第二個OPCServer控制代碼
//IOPCAsyncIO2 *pIOPCAsyncIO2 = NULL; /*第十一個指標,指向非同步讀取*/
//IOPCGroupStateMgt *pIOPCGroupStateMgt = NULL; //第十個指標,指向組狀態更新</span><pre name="code" class="cpp">//IConnectionPointContainer *pIConnectPointContainer = NULL;
//IConnectionPoint *pIConnectionPoint = NULL;
    緊接著進行元件註冊,因為OPC是使用COM元件開發的,所以部分過程與元件開發類似:
/*COM元件註冊及登陸*/
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); //註冊DCOM元件,獲取結果
HRESULT hr_sec = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
ASSERT(hr_sec == S_OK || RPC_E_TOO_LATE == hr_sec);</span><pre name="code" class="cpp">
if (FAILED(hr)) {
	cout << "未開啟COM元件註冊..." << endl;
	return 1;
}
else if (SUCCEEDED(hr)) {		
	cout << "已開啟COM元件註冊..." << endl;
	cout << "已登陸COM元件..." << endl;
}
    然後獲取伺服器列表,用到了OPCEnum.exe:
si.pwszName = (LPWSTR)(strNode.GetString()); //Covert CString to LPWSTR 把伺服器名轉為寬位元組字串	

mqi[0].hr = S_OK;
mqi[0].pIID = &IID_IOPCServerList;
mqi[0].pItf = NULL;

hr = CoCreateInstanceEx(CLSID_OpcServerList, NULL, CLSCTX_ALL, &si, 1, mqi); //Connect to the target OPC SERVER & Get the target SERVER's OPC SERVER List

if (FAILED(hr)) {
	cout << "獲取目標伺服器端OPC伺服器列表失敗..." << endl;
}
else if (SUCCEEDED(hr)) {
	cout << "獲取目標伺服器端OPC伺服器列表成功..." << endl;
}
    進行具有OPC1.0和OPC2.0介面標準的OPC伺服器的列舉:
pIServerList = (IOPCServerList*)mqi[0].pItf; //得到第一個指標
ASSERT(pIServerList);
	
catID[0] = CATID_OPCDAServer10;
catID[1] = CATID_OPCDAServer20;
	
hr = pIServerList->EnumClassesOfCategories(2, catID, 2, catID, &pIEnumGUID); //Enum OPCDASERVER1.0 & OPCDASERVER2.0 得到第二個指標
ASSERT(pIEnumGUID);

if (FAILED(hr)) {
	cout << "未獲取到OPCDAServer1.0和OPCDAServer2.0介面" << endl;
	CoTaskMemFree(&catID); //第三個記憶體釋放
	CoTaskMemFree(&mqi); //第二個記憶體釋放
	CoTaskMemFree(&si); //第一個記憶體釋放
	if (pIEnumGUID) pIEnumGUID->Release(); //第二個指標釋放
	pIEnumGUID = NULL;
	if (pIServerList) pIServerList->Release(); //第一個指標釋放
	pIServerList = NULL;
	return 1;
}
else if (SUCCEEDED(hr)) {
	cout << "已獲取到OPCDAServer1.0和OPCDAServer2.0介面" << endl;
}

ULONG nCount;
	
HRESULT hr_1;
cout << "搜尋到的介面列表:" << endl;
do
{
	hr_1 = pIEnumGUID->Next(20, clsid, &nCount);
	for (ULONG i = 0; i < nCount; i++)
	{
		LPOLESTR szProID;
		LPOLESTR szUserType;
		HRESULT hr_2 = pIServerList->GetClassDetails(clsid[i], &szProID, &szUserType);
		ASSERT(hr_2 == S_OK);
		wcout << szProID << endl;
		CoTaskMemFree(szProID);
		CoTaskMemFree(szUserType);
	}
} while (hr_1 == S_OK);
cout << "列舉完畢..." << endl;
    然後進行OPC的連線:
CLSID clsid_citect;

hr = pIServerList->CLSIDFromProgID(strProgID, &clsid_citect); //獲取OPC伺服器的CLSID

if (FAILED(hr)) {
	cout << "未找到需要連線的OPC伺服器..." << endl;
	CoTaskMemFree(&clsid); //第四個記憶體釋放
	CoTaskMemFree(&catID); //第三個記憶體釋放
	CoTaskMemFree(&mqi); //第二個記憶體釋放
	CoTaskMemFree(&si); //第一個記憶體釋放
	if (pIEnumGUID) pIEnumGUID->Release(); //第二個指標釋放
	pIEnumGUID = NULL;
	if (pIServerList) pIServerList->Release(); //第一個指標釋放
	pIServerList = NULL;
	return 1;
}
else if (SUCCEEDED(hr)) {
	cout << "已找到需要連線的OPC伺服器..." << endl;
}

mqi[0].hr = S_OK;
mqi[0].pIID = &IID_IOPCServer;
mqi[0].pItf = NULL;

hr = CoCreateInstanceEx(clsid_citect, NULL, CLSCTX_ALL, &si, 1, mqi);

if (FAILED(hr)) {
	cout << "未連線上需要連線的OPC伺服器..." << endl;
	CoTaskMemFree(&clsid); //第四個記憶體釋放
	CoTaskMemFree(&catID); //第三個記憶體釋放
	CoTaskMemFree(&mqi); //第二個記憶體釋放
	CoTaskMemFree(&si); //第一個記憶體釋放
	if (pIEnumGUID) pIEnumGUID->Release(); //第二個指標釋放
	pIEnumGUID = NULL;
	if (pIServerList) pIServerList->Release(); //第一個指標釋放
	pIServerList = NULL;
	return 1;
}
else if (SUCCEEDED(hr)) {
	cout << "已連線上需要連線的OPC伺服器..." << endl;
}
    如此,OPC伺服器已連線上。