QT中的OpcDa 客户端 实现

时间:2023-02-02 21:13:32

前段时间开发Windows下的设备端软件接触到了OPC DA,虽然现在有了更强大的OPC UA,但是为了兼容一些老的设备,不得不硬着头皮去啃这个老掉牙的已经过时了的技术。本来只是想粗略了解一下,简单写一个应付了事,谁知道过程一波三折。

由于OPCDA采用COM技术,而我又不想再去学COM编程以及VC、AFX、MFC,我采取调用 WTClient 的懒人方法,并且只花了几个小时就整了一个出来,简单测试通过,结果经同事验证,Float、long等类型通通无法读取无法写入,并且每隔半小时左右便与Kepsrever断开连接。然后到处找解决方案,最后在官方网站得到答案:免费版本有30分钟时间限制,数据类型估计也顺手给限了,只有BOOL和WORD少数几个类型可以使用,这期间又是浪费好多时间。

经过这番教训,决定用QT从头开始写一个自己的库,于是有了以下内容,提供给需要的人,稍候会传到github(早已传上去了,但是忘记修改本文,需要的去拿吧:https://github.com/cncap/qt-opcda)。

参考:OPCDA服务器与客户程序开发指南修订版

#ifndef OPCCLIENT_H
#define OPCCLIENT_H
#include <iostream>
#include "opcerror.h"
#include "opccomn.h"
#include "OpcEnum.h"
#include "Opcda.h"
#include "copctransaction.h"
#include "wldef.h"
#include <QObject>
#include <QDebug>
#include "windows.h"
/**
* Copyright 2016 Chn.Captain (chn.captain@gmail.com)
*/
class COPCDataCallback;
class ItemDef
{
public:
QString name;
DWORD accessRights;
VARIANT value;
WORD quality;
OPCHANDLE hServerHandle;
OPCHANDLE hClientHandle;
FILETIME time;
VARTYPE type;
ItemDef()
{
type = VT_EMPTY;
quality = ;
hServerHandle = ;
hClientHandle = ; //ZeroMemory(&time, sizeof(time));
}
ItemDef( const ItemDef& it )
{
name = it.name;
value = it.value;
quality = it.quality;
hServerHandle = it.hServerHandle;
hClientHandle = it.hClientHandle;
time = it.time;
type = it.type;
}
}; class OPCClient:public QObject
{
Q_OBJECT
public:
explicit OPCClient();
OPCClient(QString s);
~OPCClient();
COPCTransaction *m_COPCTransaction; bool isWriteAble; bool isConnected();
HRESULT Connect(QString s);
void DisConnect();
HRESULT AddGroup(QString n, DWORD update_rate , int async=);
QStringList AddItems(QStringList names);
bool ReadItem(ItemDef *item); bool WriteValue(QString &name, QString &value );
bool WriteValue( DWORD cHandle, FILETIME &time, VARIANT &value, WORD Quality );
HRESULT WriteValue_Async(ItemDef * item);
HRESULT WriteValue_Sync (ItemDef * item); HRESULT RemoveItems(QStringList inames);
HRESULT RemoveAllItems(); void dataCallback();
QList<ItemDef*> *items; QString VariantString(VARIANT &pValue);
QString QualityString(UINT qnr);
QString ValueTypeString(const VARTYPE& v);
void StringVariant(ItemDef* item, QString v);
QString AccessTypeString(qint16 accessIdent);
QString TimeString(FILETIME t); HRESULT hResult;
HRESULT *pErrors; WString m_ServerName;
WString m_GroupName;
DWORD m_UpdateRate;
CLSID m_clsid;
DWORD m_Cookie;
bool m_Async; IConnectionPointContainer* _pIConnectionPointContainer;
IConnectionPoint* _pIConnectionPoint;
IOPCServer *_pIOPCServer;
IOPCBrowseServerAddressSpace *_pIOpcNamespace;
IOPCItemProperties *_pIOpcProperties;
IOPCGroupStateMgt *_pIOPCGroupStateMgt;
IOPCItemMgt *_pIOPCItemMgt;
IOPCSyncIO * _pIOPCSyncIO;
IOPCAsyncIO2 * _pIOPCAsyncIO2;
IOPCDataCallback * _pIOPCDataCallback;
COPCDataCallback *m_OPCDataCallback; OPCHANDLE m_GroupHandle;
OPCHANDLE m_ServerHandle;
void ClearOPCITEMDEF( OPCITEMDEF *idef, int count = );
ItemDef* getItemByName(QString s);
ItemDef* getItemByHandle(DWORD h);
WString qstr2Wstr(QString s); }; #endif //OPCCLIENT_H
#include "OPCClient.h"
#include "copcdatacallback.h"
#include <QDateTime>
#include <QMessageBox>
/**
* Copyright 2016 Chn.Captain (chn.captain@gmail.com)
*/
OPCClient::OPCClient(QString s):
m_ServerName(qstr2Wstr(s))
{
}
OPCClient::OPCClient()
{
_pIConnectionPointContainer = NULL;
_pIConnectionPoint = NULL;
_pIOPCServer = NULL;
_pIOPCDataCallback = NULL;
_pIOpcNamespace = NULL;
_pIOpcProperties = NULL;
_pIOPCGroupStateMgt = NULL;
_pIOPCItemMgt = NULL;
_pIOPCSyncIO = NULL;
_pIOPCAsyncIO2 = NULL;
m_GroupHandle = ;
m_ServerHandle = ;
m_OPCDataCallback = NULL;
m_COPCTransaction = NULL;
m_Cookie = ;
pErrors = NULL;
//state
isWriteAble = NULL; items = new QList<ItemDef*>();
}
/**
* 建立OPC连接
* @brief OPCClient::Connect
* @param s
* @return
*/
HRESULT OPCClient::Connect(QString s)
{
this->m_ServerName = qstr2Wstr(s);
hResult = CoInitialize();
if (FAILED(hResult))
{
if (hResult == S_FALSE)
{
qDebug()<<"Error CoInitialize():COM Library already initialized";
}
else
{
qDebug()<< "Error CoInitialize():Initialisation of COM Library failed. Error Code= " << hResult;
_pIOPCServer = ;
CoUninitialize();
return hResult;
}
} hResult = CLSIDFromProgID(this->m_ServerName, &this->m_clsid);
if (FAILED(hResult))
{
qDebug()<< "Error CLSIDFromProgID():Retrival of CLSID failed";
CoUninitialize();
return hResult;
} hResult = CoCreateInstance (this->m_clsid, NULL, CLSCTX_LOCAL_SERVER ,IID_IOPCServer, (void**)&_pIOPCServer);
if (FAILED(hResult))
{
qDebug()<< "Error CoCreateInstance():Creation of IOPCServer-Object failed";
_pIOPCServer = ;
CoTaskMemFree(&this->m_clsid);
CoUninitialize();
return hResult;
}
hResult = _pIOPCServer->QueryInterface(IID_IOPCBrowseServerAddressSpace, (void**)&_pIOpcNamespace);
if (FAILED(hResult))
{ qDebug()<< "Error CoCreateInstance():Creation of IID_IOPCBrowseServerAddressSpace-Object failed";
CoUninitialize();
return hResult;
}
hResult = _pIOPCServer->QueryInterface(IID_IOPCItemProperties, (void**)&_pIOpcProperties);
if (FAILED(hResult))
{
qDebug()<< "Error CoCreateInstance():Creation of IID_IOPCItemProperties-Object failed";
CoUninitialize();
return hResult;
}
return hResult;
} /**
* 添加分组
* @brief OPCClient::AddGroup
* @param n
* @param update_rate
* @return
*/
HRESULT OPCClient::AddGroup(QString n, DWORD update_rate, int async)
{
m_Async = async;
m_GroupName = qstr2Wstr(n);
m_ServerHandle = ;
m_UpdateRate = ;
long TimeBias;
DWORD LanguageCode = 0x416, RevisedUpdateRate;
float DeadBand; //刷新间隔
hResult=_pIOPCServer->AddGroup(m_GroupName, // [in] group name
TRUE, // [in] active
update_rate, // [in] request this Update Rate from Server
m_ServerHandle, // [in] Client handle
&TimeBias, // [in] no time interval to system UTC time
&DeadBand, // [in] no deadband, so all data changes are reported
LanguageCode, // [in] Server uses English language for text values
&m_GroupHandle, // [out] Server handle to identify this group in later calls
&RevisedUpdateRate, // [out] the answer form the Server to the requested update rate
IID_IOPCGroupStateMgt, // [in] requested interface type of the group object
(LPUNKNOWN*)&this->_pIOPCGroupStateMgt); // [out] pointer to the requested interface if( hResult ==OPC_E_DUPLICATENAME ) {
qDebug()<< "1001:分组名称已存在.";
}
if( hResult ==E_NOINTERFACE ) {
qDebug()<< "1002:IOPCServer::AddGroup returned E_NOINTERFACE (IID_IOPCGroupStateMgt)";
}
if( update_rate != m_UpdateRate ){
qDebug()<< "1003: OPC server rejected data refresh interval. Setting it to %1 ms." << update_rate;
}
if (hResult == OPC_S_UNSUPPORTEDRATE)
{
qDebug()<< "1004:请求的刷新速率与实际的刷新速率不一致";
}
if( FAILED(hResult) || _pIOPCGroupStateMgt == NULL) {
qDebug()<< "1005: 创建分组失败";
DisConnect();
} hResult = _pIOPCGroupStateMgt->QueryInterface(IID_IOPCItemMgt,(void**)&this->_pIOPCItemMgt);
if (FAILED(hResult)) {
qDebug()<<"1006: 项目操作指针(_pIOPCItemMgt)创建失败";
DisConnect();
}
//查询 group 对象的同步接口 if(m_Async){
hResult = _pIOPCItemMgt->QueryInterface(IID_IOPCAsyncIO2, (void**)&this->_pIOPCAsyncIO2);
if (FAILED(hResult)) {
qDebug()<<"1008: IOPCAsyncIO2 没有发现,错误的查询!";
DisConnect();
} m_COPCTransaction = new COPCTransaction;
hResult = _pIOPCItemMgt->QueryInterface(IID_IConnectionPointContainer, (void**)&this->_pIConnectionPointContainer); //hResult = _pIOPCItemMgt->QueryInterface(&_pIConnectionPointContainer);
if (FAILED(hResult)) {
qDebug()<<"1009: IConnectionPointContainer 创建失败!";
DisConnect();
}
hResult = _pIConnectionPointContainer->FindConnectionPoint( IID_IOPCDataCallback, &_pIConnectionPoint );
if( FAILED(hResult) || _pIConnectionPoint == NULL) {
qDebug()<< "1010: A group of OPC with no IOPCDataCallback. OPC server appears to not conform to the OPC DA 2.0 standard (%s).";
DisConnect();
}
if( m_OPCDataCallback == NULL ) { if(!m_COPCTransaction){
m_COPCTransaction = new COPCTransaction;
}
m_OPCDataCallback = new COPCDataCallback(m_COPCTransaction);
m_OPCDataCallback->AddRef();
// m_OPCDataCallback->receiver = m_DataReceiver;
}
hResult = _pIConnectionPoint->Advise(m_OPCDataCallback, &m_Cookie);
qDebug()<< hResult;
if(FAILED(hResult)) {
qDebug()<< "1011: OPCDataCallback set faild." << m_Cookie;
_pIConnectionPointContainer->Release();
DisConnect();
}
isWriteAble = true;
}else{
hResult = _pIOPCItemMgt->QueryInterface(IID_IOPCSyncIO, (void**)&this->_pIOPCSyncIO);
if (FAILED(hResult)) {
qDebug()<<"1007: IOPCSyncIO 没有发现,错误的查询!";
DisConnect();
}
isWriteAble = true;
} return hResult;
} /**
* 添加监视项
* @brief OPCClient::AddItems
* @param inames
* @return
*/
QStringList OPCClient::AddItems(QStringList inames)
{
QStringList r_inames; if(!_pIOPCItemMgt) return r_inames; pErrors = NULL;
DWORD iCount=items->count();
OPCITEMRESULT * pResults;
qDebug()<<"1--- begin add item -----------";
for(int i=;i<inames.count();i++) {
QString iname = inames[i];
if(getItemByName(iname)){
qDebug() << " already exsits."<< iname;
continue;
}
r_inames.append(iname);
}
int nCount=r_inames.count();
if(nCount>){
OPCITEMDEF idef[nCount];
for(int i=;i<nCount;i++) {
QString iname = r_inames[i];
qDebug()<< " build item def"<< iname;
idef[i].szAccessPath= SysAllocString(L""); // path SysAllocString(qstr2Wstr(name))
idef[i].szItemID = SysAllocString(qstr2Wstr(iname)); // name
idef[i].bActive = TRUE;
idef[i].hClient = iCount+i;
idef[i].dwBlobSize = ;
idef[i].pBlob = NULL;
idef[i].vtRequestedDataType = ;
}
qDebug()<<"2--- end of add item-----------"; hResult = _pIOPCItemMgt->AddItems(nCount, // [in] add items
idef, // [in] see above
&pResults, // [out] array with additional information about the item
&pErrors); // [out] tells which of the items was successfully added. if(hResult==S_OK && hResult!=S_FALSE){
for(int i=;i < nCount; i++) {
QString iname = r_inames[i];
DWORD cItemHandle = iCount+i;
ItemDef *item = new ItemDef;
item->name = iname;
item->accessRights = pResults[i].dwAccessRights;
item->hClientHandle = cItemHandle;
item->type = pResults[i].vtCanonicalDataType;
item->hServerHandle = pResults[i].hServer;
items->append(item);
// 检测 Item 的可读写性
// if (pResults[i].dwAccessRights != (OPC_READABLE + OPC_WRITEABLE)) {
// qDebug()<<"Item 不可读,也不可写,请检查服务器配置";
// }
}
} if(pResults) CoTaskMemFree( pResults );
if(pErrors) CoTaskMemFree( pErrors );
ClearOPCITEMDEF(idef, nCount);
}
return r_inames;
}
/**
* 同步读取指定项
* @brief OPCClient::ReadItem
* @param item
* @return
*/
bool OPCClient::ReadItem(ItemDef *item)
{
bool result = false;
OPCITEMSTATE *pItemValue;
hResult = _pIOPCSyncIO->Read(OPC_DS_DEVICE, , &item->hServerHandle, &pItemValue, &pErrors); if(SUCCEEDED(hResult)){
item->value = pItemValue[].vDataValue;
item->quality = pItemValue[].wQuality;
item->time = pItemValue[].ftTimeStamp;
item->hClientHandle = pItemValue[].hClient;
result = true;
VariantClear(&pItemValue->vDataValue);
}else{
qDebug()<< "同步读取项目失败" << hResult;
} CoTaskMemFree(pErrors);
CoTaskMemFree(pItemValue); return result;
}
/**
* 写入值
* @brief OPCClient::WriteValue
* @param cHandle
* @param time
* @param value
* @param Quality
* @return
*/
bool OPCClient::WriteValue( DWORD cHandle, FILETIME &time, VARIANT &value, WORD Quality )
{
ItemDef * item = getItemByHandle( cHandle );
if( !item )
return false; item->quality = Quality;
item->value = value;
item->time = time; if( m_Async )
return SUCCEEDED( WriteValue_Async(item) );
else
return SUCCEEDED( WriteValue_Sync( item ) );
}
bool OPCClient::WriteValue(QString &n, QString &v )
{
ItemDef * item = getItemByName(n);
if(!item )
return false;
StringVariant(item, v);
if( m_Async )
return SUCCEEDED( WriteValue_Async(item) );
else
return SUCCEEDED( WriteValue_Sync( item ) );
}
HRESULT OPCClient::WriteValue_Async(ItemDef * item)
{
QString str;
pErrors = NULL;
if( m_COPCTransaction == NULL ) return E_FAIL;
if( !isConnected() ) return E_FAIL; // m_Group->QueryInterface( &AsyncIO );
if( _pIOPCAsyncIO2 == NULL ) {
qDebug()<< "Failed to get interface IOPCAsyncIO2";
return E_FAIL;
}
DWORD cancelID = ; hResult = _pIOPCAsyncIO2->Write( , &item->hServerHandle, &item->value, rand(), &cancelID, &pErrors);
if( FAILED(hResult) /*|| FAILED(pErrors[0])*/) {
qDebug()<< "Parameter [%s] is not passed" << item->name;
hResult = E_FAIL; }
if( pErrors )
{
switch( pErrors[] ) {
case OPC_S_CLAMP:
qDebug()<< "AsyncIO->Write(%s) -> [OPC_S_CLAMP] The value was accepted but was clamped."<<item->name;
break;
case OPC_E_RANGE: qDebug()<< "AsyncIO->Write(%s) -> [OPC_E_RANGE] The value was out of range."<<item->name;
break;
case OPC_E_BADTYPE:
str=QString("AsyncIO->Write(%1) -> [OPC_E_BADTYPE] The passed data type (%2) cannot be accepted for this item.").arg(item->name, item->value.vt);
qDebug()<< str;
break;
case OPC_E_BADRIGHTS:
qDebug()<< "AsyncIO->Write(%s) -> [OPC_E_BADRIGHTS] The item is not writeable."<<item->name;
break;
case OPC_E_INVALIDHANDLE:
qDebug()<< "AsyncIO->Write(%s) -> [OPC_E_INVALIDHANDLE] The passed item handle was invalid."<<item->name;
break;
case OPC_E_UNKNOWNITEMID:
qDebug()<< "AsyncIO->Write(%s) -> [OPC_E_UNKNOWNITEMID] The item is no longer available in the server address space."<<item->name;
break;
} }
if( pErrors )CoTaskMemFree( pErrors );
return hResult; } HRESULT OPCClient::WriteValue_Sync( ItemDef * item )
{
pErrors = NULL;
if( m_COPCTransaction == NULL ) return E_FAIL;
if( !isConnected() ) return E_FAIL; qDebug() << "Sync Write start (hdl="<< item->hServerHandle << ") value=" << VariantString(item->value); hResult = _pIOPCSyncIO->Write( , &item->hServerHandle, &item->value, &pErrors); qDebug() << "Sync Write finished. hr = " << hResult; if( FAILED(hResult) /*|| FAILED(pErrors[0])*/) {
qDebug() << "Parameter [%s] is not passed"<<item->name;
hResult = E_FAIL; if( pErrors != NULL)
{
switch( pErrors[] ) {
case OPC_S_CLAMP:
qDebug() << "SyncIO->Write(%s) -> [OPC_S_CLAMP] The value was accepted but was clamped." << item->name ;
break;
case OPC_E_RANGE:
qDebug() << "SyncIO->Write(%s) -> [OPC_E_RANGE] The value was out of range."<<item->name ;
break;
case OPC_E_BADTYPE:
qDebug() << "SyncIO->Write(%s) -> [OPC_E_BADTYPE] The passed data type cannot be accepted for this item."<<item->name ;
break;
case OPC_E_BADRIGHTS:
qDebug() << "SyncIO->Write(%s) -> [OPC_E_BADRIGHTS] The item is not writeable."<<item->name ;
break;
case OPC_E_INVALIDHANDLE:
qDebug() << "SyncIO->Write(%s) -> [OPC_E_INVALIDHANDLE] The passed item handle was invalid."<<item->name ;
break;
case OPC_E_UNKNOWNITEMID:
qDebug() << "SyncIO->Write(%s) -> [OPC_E_UNKNOWNITEMID] The item is no longer available in the server address space."<<item->name ;
break;
}
}
} if( pErrors )
CoTaskMemFree( pErrors ); return hResult;
} /**
* 移除所有项目
* @brief OPCClient::RemoveItems
* @param _items
* @return
*/
HRESULT OPCClient::RemoveItems(QStringList inames)
{
int _iCount = inames.count();
if( _iCount==) return -;
OPCHANDLE _hpSvr[_iCount];
for(int i=;i<_iCount ;i++){
if(getItemByName(inames.value(i))){
_hpSvr[i] = getItemByName(inames.at(i))->hServerHandle;
} } hResult = _pIOPCItemMgt->RemoveItems(_iCount, _hpSvr, &pErrors);
if(SUCCEEDED(hResult)){
for(int i=;i<_iCount ;i++){
items->removeAll(getItemByName(inames.at(i)));;
}
} return hResult;
}
/**
* @brief OPCClient::RemoveAllItems
* @return
*/
HRESULT OPCClient::RemoveAllItems()
{
int _iCount = items->count();
OPCHANDLE _hpSvr[_iCount];
qDebug()<<"3---begin delete-----------";
for(int i=;i<_iCount ;i++){
qDebug() <<" next one->"<< items->at(i)->hServerHandle << items->at(i)->name;
_hpSvr[i] = items->at(i)->hServerHandle;
} hResult = _pIOPCItemMgt->RemoveItems(_iCount, _hpSvr, &pErrors);
qDebug() <<"4---end delete-----------" << hResult;
if(SUCCEEDED(hResult)){
while(items->count()!=){
items->removeAt();
}
}
return hResult;
}
/**
* 断开连接
* @brief OPCClient::DisConnect
*/
void OPCClient::DisConnect()
{
if(_pIOPCSyncIO){
_pIOPCSyncIO->Release();
_pIOPCSyncIO=;
}
if (_pIConnectionPoint)
{
_pIConnectionPoint->Unadvise(m_Cookie);
_pIConnectionPoint->Release();
_pIConnectionPoint = ;
}
if(_pIOPCItemMgt){
_pIOPCItemMgt->Release();
_pIOPCItemMgt = ;
}
if(_pIOPCGroupStateMgt){
_pIOPCGroupStateMgt->Release();
_pIOPCGroupStateMgt = ;
}
if(_pIOPCServer){
_pIOPCServer->RemoveGroup(m_GroupHandle, TRUE);
_pIOPCServer->Release();
_pIOPCServer=;
}
if(m_OPCDataCallback){
m_OPCDataCallback->Release();
m_OPCDataCallback = ;
}
if(m_COPCTransaction){
m_COPCTransaction->deleteLater();
m_COPCTransaction = ;
} m_GroupHandle = ;
m_ServerHandle = ;
CoUninitialize();
delete items;
} void OPCClient::dataCallback()
{ // // 建立异步回调
// CComObject<COPCDataCallback>* pCOPCDataCallback;
// // 回调对象的指针
// // 通过 ATL 模板创建回调对象的实例
// CComObject<COPCDataCallback>::CreateInstance(&pCOPCD ataCallback);
// // 查询 IUnknown 接口
// LPUNKNOWN pCbUnk;
// pCbUnk = pCOPCDataCallback->GetUnknown();
// // 建立一个服务器的连接点与客户程序接收器之间的连接
// HRESULT hRes = AtlAdvise( m_IOPCGroupStateMgt, // [in] //连接点的 IUnknown 接口
// pCbUnk, // [in] 回调对象的 IUnknown 接口
// IID_IOPCDataCallback,// [in] 连接点 ID
// &m_dwAdvise // [out] 唯一的标识符
// );
// if (hRes != S_OK) {
// AfxMessageBox("Advise 失败!");
// }
} /**
* 连接状态
* @brief OPCClient::isConnected
* @return
*/
bool OPCClient::isConnected()
{
return ( _pIOPCServer && _pIOPCGroupStateMgt );
} void OPCClient::ClearOPCITEMDEF( OPCITEMDEF *idef, int count )
{
if( idef )
for(int i=;i<count;i++)
{
if( idef[i].szItemID != NULL )
SysFreeString( idef[i].szItemID );
if( idef[i].szAccessPath != NULL )
SysFreeString( idef[i].szAccessPath );
}
}
/**
* 获取ItemDef by name
* @brief OPCClient::getItemByName
* @param s
* @return
*/
ItemDef* OPCClient::getItemByName(QString s)
{
int c = items->count(); for(int i=; i<c; i++) {
if(items->at(i)->name == s){
return items->at(i);
}
}
return ;
}
/**
* 获取ItemDef by Handle
* @brief OPCClient::getItemByHandle
* @param s
* @return
*/
ItemDef* OPCClient::getItemByHandle(DWORD h)
{
int c = items->count(); for(int i=; i<c; i++) {
if(items->at(i)->hClientHandle == h){
return items->at(i);
}
}
return ;
}
/**
* 析构函数
* @brief OPCClient::~OPCClient
*/
OPCClient::~OPCClient()
{
DisConnect();
}
////////////////////////////////////////////////// /**
* QString 转换为 const wchar*
* @brief OPCClient::qstr2Wstr
* @param s
* @return
*/
WString OPCClient::qstr2Wstr(QString s)
{
return reinterpret_cast<const wchar_t*>(s.utf16());
//wchar_t* tempWide = const_cast< wchar_t* >( tempConstWide );
}
/**
* 输出项目值字符串
* @brief OPCClient::VariantString
* @param pValue
* @return
*/
QString OPCClient::VariantString(VARIANT &pValue)
{
QString valueString;
//qDebug()<< QString(" Format type:%1 ").arg(pValue.vt);
switch(pValue.vt)
{
case VT_I1:
case VT_UI1: // BYTE
{
int i = pValue.iVal;
valueString= QString::number(i);
break;
}
case VT_I2: // SHORT
valueString= QString::number(pValue.iVal);
break;
case VT_UI2: // UNSIGNED SHORT
valueString= QString::number(pValue.uiVal); break;
case VT_I4: // LONG
valueString= QString::number(pValue.lVal);
break;
case VT_UI4: // UNSIGNED LONG
valueString= QString::number(pValue.ulVal);
break;
case VT_INT: // INTEGER
valueString= QString::number(pValue.intVal);
break;
case VT_UINT: // UNSIGNED INTEGER
valueString= QString::number(pValue.uintVal); break;
case VT_R4: // FLOAT
//sprintf (buf, "%5.2f ", pValue.fltVal );
valueString= QString::number(pValue.fltVal);
break;
case VT_R8: // DOUBLE
//sprintf (buf, "%9.4f ", pValue.dblVal );
valueString= QString::number(pValue.dblVal);
break;
case VT_BSTR: //BSTR
{
//sprintf (buf, "%ls ", pValue.bstrVal );
BSTR bstr_str = pValue.bstrVal;
QString q_str((QChar*)bstr_str, wcslen(bstr_str));
valueString = q_str; break;
}
case VT_BOOL:
{
if (pValue.boolVal)
valueString = "TRUE";
else
valueString = "FALSE";
break;
}
case VT_DATE:
{
QDateTime dt;
//qDebug()<< pValue.date;
dt.fromMSecsSinceEpoch(pValue.date);
valueString = dt.toString("yyyy-MM-dd hh:mm:ss");
break;
}
default:
valueString = QString(" unknown type:%1 ").arg(pValue.vt);
break;
}
return valueString;
}
/**
* 输出项目值质量字符串
* @brief OPCClient::VariantString
* @param pValue
* @return
*/
QString OPCClient::QualityString(UINT qnr)
{
QString result;
switch(qnr) {
case OPC_QUALITY_BAD:
result = "BAD";
break;
case OPC_QUALITY_UNCERTAIN:
result= "UNCERTAIN";
break;
case OPC_QUALITY_GOOD:
result = "GOOD";
break;
case OPC_QUALITY_NOT_CONNECTED:
result = "NOT_CONNECTED";
break;
case OPC_QUALITY_DEVICE_FAILURE:
result = "DEVICE_FAILURE";
break;
case OPC_QUALITY_SENSOR_FAILURE:
result = "SENSOR_FAILURE";
break;
case OPC_QUALITY_LAST_KNOWN:
result = "LAST_KNOWN";
break;
case OPC_QUALITY_COMM_FAILURE:
result = "COMM_FAILURE";
break;
case OPC_QUALITY_OUT_OF_SERVICE:
result = "OUT_OF_SERVICE";
break;
case OPC_QUALITY_LAST_USABLE:
result = "LAST_USABLE";
break;
case OPC_QUALITY_SENSOR_CAL:
result = "SENSOR_CAL";
break;
case OPC_QUALITY_EGU_EXCEEDED:
result = "EGU_EXCEEDED";
break; case OPC_QUALITY_SUB_NORMAL:
result = "SUB_NORMAL";
break;
case OPC_QUALITY_LOCAL_OVERRIDE:
result = "LOCAL_OVERRIDE";
break;
default:
result = "UNKNOWN ERROR";
}
return result;
}
/**
* 输出值类型字符串
* @brief OPCClient::ValueTypeString
* @param v
* @return
*/
QString OPCClient::ValueTypeString(const VARTYPE& v)
{
QString str; switch(v) {
case VT_BSTR:
str = QString("VT_BSTR");
break;
case VT_I1:
str = QString("VT_I1");
break;
case VT_I2:
str = QString("VT_I2");
break;
case VT_I4:
str = QString("VT_I4");
break;
case VT_I8:
str = QString("VT_I8");
break;
case VT_R4:
str = QString("VT_R4");
break;
case VT_R8:
str = QString("VT_R8");
break;
case VT_UI1:
str = QString("VT_UI1");
break;
case VT_UI2:
str = QString("VT_UI2");
break;
case VT_UI4:
str = QString("VT_UI4");
break;
case VT_UI8:
str = QString("VT_UI8");
break;
case VT_INT:
str = QString("VT_INT");
break;
case VT_UINT:
str = QString("VT_UINT");
break;
case VT_BOOL:
str = QString("VT_BOOL");
break;
case VT_DATE:
str = QString("VT_DATE");
break;
default:
str = QString("unknown");
break;
};
return str;
}
/**
* 赋值
* @brief OPCClient::StringVariant
* @param item
* @param v
* @return
*/
void OPCClient::StringVariant(ItemDef* item, QString v)
{
switch (item->value.vt)
{
case VT_UI1:
case VT_I1:
//cbRead = sizeof(BYTE);
break;
case VT_I2:
case VT_UI2:
case VT_BOOL:
item->value.iVal = v.toShort();
break;
case VT_I4:
case VT_UI4:
case VT_INT:
case VT_UINT:
case VT_ERROR:
item->value.lVal = v.toLong();
break;
case VT_R4:
item->value.fltVal = v.toFloat();
break;
case VT_I8:
case VT_UI8:
item->value.llVal = v.toLongLong();
break;
case VT_R8:
case VT_CY:
case VT_DATE:
item->value.dblVal = v.toDouble();
break;
case VT_BSTR:
{
//Value.bstrVal = SysAllocString(v.utf16());
//Value.bstrVal = qstringToBstr(v);
wchar_t *pW = new wchar_t[v.size()+];
v.toWCharArray(pW);
//dialog.m_valueValue.bstrVal = SysAllocString(dialog.m_value.toStdWString().c_str());
break;
}
default:
break;
} return;
}
/**
* 输出权限字符串
* @brief OPCClient::AccessTypeString
* @param accessIdent
* @return
*/
QString OPCClient::AccessTypeString(qint16 accessIdent)
{
QString s;
switch(accessIdent){
case OPC_READABLE:
s = "Read";
break;
case OPC_WRITEABLE:
s = "Write";
break;
default:
s = "Read/Write";
}
return s;
}
QString OPCClient::TimeString(FILETIME t)
{
return QString::number(t.dwLowDateTime);
}