如何读写 opcserver 的数组item? 点击:2830 | 回复:5



abcdefjj

    
  • 精华:0帖
  • 求助:1帖
  • 帖子:1帖 | 10回
  • 年度积分:0
  • 历史总积分:84
  • 注册:2007年11月07日
发表于:2013-09-23 18:38:09
楼主

如何在VC环境下对opc server中的数据块(array)Item进行读写操作呢,比如address:DB1.DBW0[60]的一维数组?




tsgxcj

  • 精华:0帖
  • 求助:0帖
  • 帖子:1帖 | 3回
  • 年度积分:0
  • 历史总积分:35
  • 注册:2017年3月11日
发表于:2017-03-25 16:19:36
1楼

不知道你的这个问题解决了吗

当年醉花荫下

  • 精华:0帖
  • 求助:0帖
  • 帖子:1帖 | 2回
  • 年度积分:0
  • 历史总积分:90
  • 注册:2017年8月15日
发表于:2017-08-15 23:14:27
2楼


回复内容:

对: tsgxcj 不知道你的这个问题解决了吗 内容的回复!

没有啊,大神

OPC那点事

  • 精华:0帖
  • 求助:0帖
  • 帖子:11帖 | 41回
  • 年度积分:0
  • 历史总积分:52
  • 注册:2015年4月25日
发表于:2017-08-26 08:32:51
3楼

大致程序如下,纯手工原创,需要的话再电邮咨询 fuelone@gmail.com


IOPCItemMgt* ipMgt; // ipServer->AddGroup 时获得 ipMgt的实际指针

IOPCSyncIO *pIOPCSyncIO = NULL;

HRESULT hResult = ipMgt->QueryInterface(IID_IOPCSyncIO, (void**)&pIOPCSyncIO);


OPCITEMRESULT* pResults = (OPCITEMRESULT*)CoTaskMemAlloc(dwCount * sizeof(OPCITEMRESULT));


DWORD dwCount = 10; // 点数,多少个item你想读或写?


OPCHANDLE *  hServerItem = (OPCHANDLE *)CoTaskMemAlloc(dwCount * sizeof(OPCHANDLE));
HRESULT *  pErrors = (HRESULT *)CoTaskMemAlloc(dwCount * sizeof(HRESULT));

OPCITEMDEF*    pItems = (OPCITEMDEF*)CoTaskMemAlloc(dwCount * sizeof(OPCITEMDEF));
 memset(pItems, NULL, dwCount * sizeof(OPCITEMDEF));


 wchar_t wtext[MAXCHAR] = { 0 };
 size_t size, numOfCharConverted;


 for (size_t i = 0; i < dwCount; i++)
 {
  size = strlen(*(items + i)) + 1;
  pItems[i].szItemID = (LPWSTR)malloc(sizeof(wchar_t)*size);

  mbstowcs_s(&numOfCharConverted, pItems[i].szItemID, size, *(items + i), size);//Plus null
  pItems[i].szAccessPath = NULL;
  pItems[i].bActive = TRUE;
  pItems[i].hClient = (OPCHANDLE)pItems[i].szItemID;  // use unique point as client handle
  pItems[i].vtRequestedDataType = VT_EMPTY;
  pItems[i].dwBlobSize = 0;
  pItems[i].pBlob = NULL;
 }


hResult = ipMgt->AddItems(dwCount, pItems, pResults, pErrors);


// 这里需要对返回的值进行有效性检查,并释放一些刚分配以后不再用的内存参数


for (DWORD ii = 0; ii < dwCount; ii++) {
   if (!pErrors[ii])
    hServerItem[ii] = pResults[ii].hServer;
  }


 1. 如果要进行同步读


hResult = pIOPCSyncIO->Read(OPC_DS_DEVICE, dwCount, hServerItem, &pValues, &pErrors);


for (DWORD ii = 0; ii < dwCount; ii++)
   {
    VARIANT vValue;
    VariantInit(&vValue);

    if (SUCCEEDED(VariantChangeType(&vValue, &pValues[ii].vDataValue, NULL, VT_BSTR))) {

     //获得你的值vValue.bstrVal

   }

    VariantClear(&vValue);
   }


// 释放一些刚分配以后不再用的内存参数


2. 如果要进行同步写

char** values = NULL; //你需要建一个要写入的数组

VARIANT *varValue = (VARIANT *)CoTaskMemAlloc(dwCount * sizeof(VARIANT));


  for (DWORD ii = 0; ii < dwCount; ii++)
  {
   if (!pErrors[ii])
   {
    varValue[ii].vt = VT_R4;
    varValue[ii].fltVal = strtof(values[ii], NULL);
   }
  }


hResult = pIOPCSyncIO->Write(dwCount, hServerItem, varValue, &pErrors);


// 释放一些刚分配以后不再用的内存参数

守护蛋黄派

  • 精华:0帖
  • 求助:0帖
  • 帖子:0帖 | 7回
  • 年度积分:0
  • 历史总积分:102
  • 注册:2017年8月29日
发表于:2017-08-29 12:19:43
4楼

同求这个问题的解决方法啊~

OPC那点事

  • 精华:0帖
  • 求助:0帖
  • 帖子:11帖 | 41回
  • 年度积分:0
  • 历史总积分:52
  • 注册:2015年4月25日
发表于:2017-09-01 05:51:03
5楼

COM是programming against interface,面向接口编程,OPC客户端编程也不例外。根据接口的定义,需要什么数据类型就给什么类型,直接了当,要注意把不要的数据清理干净,尤其是通过客户端在服务端创建的内存占用,否则在服务端造成内存泄漏而不自知。需要有清楚的栈和堆的概念,知道内存是如何在它们上分配的,这是最基本的功力。读写问题涉及的接口及过程如下,


        1. 列出所有的OPC服务端,用到的实例接口是CLSID_OpcServerList,MultiQI含有二个子接口IID_IOPCServerList和IID_IOPCServerList2,

MULTI_QI MultiQI[2] = { NULL };

 MultiQI[0].pIID = &IID_IOPCServerList;
 MultiQI[1].pIID = &IID_IOPCServerList2;

 hr = CoCreateInstanceEx(CLSID_OpcServerList, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, &ServerInfo, count, MultiQI); 然后可以遍历获得的子接口中的任何一个,这里是用的支持IID_IOPCServerList2的实例m_spServerList2,

m_spServerList2->EnumClassesOfCategories(sizeof(arrcatid), arrcatid, 0, NULL, &pEnum);

        2. 根据你要的OPC服务器实例接口cClsid获得实例,hResult = CoCreateInstanceEx(
  cClsid,
  NULL,
  CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
  &cInfo,
  1,
  &cResults);

        3. 获取该服务器相应的管理接口,这里用到的接口是IID_IOPCItemMgt,hResult = ipServer->AddGroup(
  L"",
  TRUE,
  1000, 
  NULL,
  NULL,
  NULL,
  LOCALE_SYSTEM_DEFAULT,
  &hGroup,
  &dwRevisedUpdateRate,
  IID_IOPCItemMgt,
  (IUnknown**)&ipMgt
 );

        4. 从管理接口获得读写接口,这里用到的接口是IID_IOPCSyncIO,hResult = ipMgt->QueryInterface(IID_IOPCSyncIO, (void**)&pIOPCSyncIO);

       5. 从读写接口开始读,hResult = pIOPCSyncIO->Read(OPC_DS_DEVICE, dwCount, hServerItem, &pValues, &pErrors);

        6. 从读写接口开始写,hResult = pIOPCSyncIO->Write(dwCount, hServerItem, varValue, &pErrors);


热门招聘
相关主题

官方公众号

智造工程师