上篇给大家分析了如何在客户端进行服务器查询,今天再分析下在客户端的读和写的操作。下面这个函数囊括各路类型的读写操作,如异步或同步等等,实用性很强。
HRESULT synReadOrWrite(serverGroup* serverGroup, bool read, bool async) {
char *buffer = (char *)malloc(MAXBYTE);
OPCITEMRESULT *pResults = NULL;
OPCHANDLE *hServerItem = NULL;
HRESULT hResult = S_OK;
IOPCSyncIO *pIOPCSyncIO = NULL;
IOPCAsyncIO2 *pIOPCAsyncIO2 = NULL;
if (async) {
if (serverGroup->groupInfo->ipCPC == NULL) {
hResult = buildCallback(serverGroup);
if (FAILED(hResult)) {
_tprintf(_T("Failed in buildCallback.\n"));
return hResult;
}
}
hResult = serverGroup->groupInfo->ipMgt->QueryInterface(IID_IOPCAsyncIO2, (void**)&pIOPCAsyncIO2);
showConsole = false;
}
else
hResult = serverGroup->groupInfo->ipMgt->QueryInterface(IID_IOPCSyncIO, (void**)&pIOPCSyncIO);
HRESULT *pErrors = NULL;
if (FAILED(hResult))
{
_tprintf(_T("getting interface IID_IOPCSyncIO or IID_IOPCAsyncIO2 failed.\r\n"));
goto end;
}
if (read) {
_tprintf(_T("Enter tag names seperated by comma and press enter: "));
fgets(buffer, MAXBYTE, stdin);
size_t ln = strlen(buffer) - 1;
if (buffer[ln] == '\n')
buffer[ln] = '\0';
char **result = NULL;
size_t dwCount = 0;
OPCITEMSTATE *pValues = NULL;
if (strlen(buffer) == 0) {
_tprintf(_T("tag names should be in format like this - tagName1, tagName2, tagName3\n"));
hResult = E_INVALIDARG;
goto end;
}
tokenizeString(buffer, ',', (char***)&result, &dwCount);
pResults = (OPCITEMRESULT*)CoTaskMemAlloc(dwCount * sizeof(OPCITEMRESULT));
hServerItem = (OPCHANDLE *)CoTaskMemAlloc(dwCount * sizeof(OPCHANDLE));
pErrors = (HRESULT *)CoTaskMemAlloc(dwCount * sizeof(HRESULT));
hResult = addItems(serverGroup->groupInfo->ipMgt, result, &pResults, &pErrors, dwCount);
for (DWORD ii = 0; ii < dwCount; ii++) {
if (!pErrors[ii])
hServerItem[ii] = pResults[ii].hServer;
}
if (async) {
DWORD dwCancelID;
hResult = pIOPCAsyncIO2->Read(dwCount, hServerItem, *hServerItem, &dwCancelID, &pErrors); /* *hServerItem as transactionID*/
}
else
hResult = pIOPCSyncIO->Read(OPC_DS_DEVICE, dwCount, hServerItem, &pValues, &pErrors);
if (FAILED(hResult) || hResult == S_FALSE)
{
_com_error err(hResult);
LPCTSTR errMsg = err.ErrorMessage();
_tprintf(_T("Read failed: %s\r\n"), errMsg);
for (DWORD ii = 0; ii < dwCount; ii++) {
if (pErrors && pErrors[ii]) {
if (pErrors[ii] == OPC_E_INVALIDHANDLE) {
_tprintf(_T("element with index [%d] is invalid\n"), ii);
}
else
{
_com_error err(pErrors[ii]);
errMsg = err.ErrorMessage();
_tprintf(_T("Reading element with index [%d] failed: %s\n"), ii, errMsg);
}
}
else
{
if (!async) {
VARIANT vValue;
VariantInit(&vValue);
if (SUCCEEDED(VariantChangeType(&vValue, &pValues[ii].vDataValue, NULL, VT_BSTR))) {
clientNode* tmpNode = findNode(true, hServerItem[ii]);
_tprintf(_T("syncoReadWrite Read: %S %S\r\n"), tmpNode->clientName, vValue.bstrVal);
}
VariantClear(&vValue);
}
}
}
}
else if (!async)
{
for (DWORD ii = 0; ii < dwCount; ii++)
{
VARIANT vValue;
VariantInit(&vValue);
if (SUCCEEDED(VariantChangeType(&vValue, &pValues[ii].vDataValue, NULL, VT_BSTR))) {
clientNode* tmpNode = findNode(true, hServerItem[ii]);
_tprintf(_T("syncoReadWrite Read: %S %S\r\n"), tmpNode->clientName, vValue.bstrVal);
}
VariantClear(&vValue);
}
}
for (size_t i = 0; i < dwCount; i++) {
if (!async)
freeNode(hServerItem[i]);
free(*(result + i));
}
free(result);
if (!async)
hResult = serverGroup->groupInfo->ipMgt->RemoveItems(dwCount, hServerItem, &pErrors);
CoTaskMemFree(pValues);
}
else
{
_tprintf(_T("Enter tag name and value seperated by comma, and delimit them in semicolon: "));
fgets(buffer, MAXBYTE, stdin);
size_t ln = strlen(buffer) - 1;
if (buffer[ln] == '\n')
buffer[ln] = '\0';
char **result = NULL, **nameValuePair = NULL, **names = NULL, **values = NULL;
size_t dwCount = 0;
if (strlen(buffer) == 0) {
_tprintf(_T("tag name/value pair should be in format like this - tagName1, tagValue1; tagName2, tagValue2; tagName3, tagValue3\n"));
hResult = E_INVALIDARG;
goto end;
}
tokenizeString(buffer, ';', (char***)&result, &dwCount);
names = (char**)malloc(sizeof(void*)*dwCount);
values = (char**)malloc(sizeof(void*)*dwCount);
for (DWORD ii = 0; ii < dwCount; ii++) {
names[ii] = NULL;
values[ii] = NULL;
}
size_t count = 0;
for (DWORD ii = 0; ii < dwCount; ii++) {
tokenizeString(result[ii], ',', (char***)&nameValuePair, &count);
if (count == 2) {
names[ii] = nameValuePair[0];
values[ii] = nameValuePair[1];
}
else
{
_tprintf(_T("tag name and value should be paired. Check your input.\n"));
for (size_t i = 0; i < dwCount; i++) {
free(names[i]);
free(values[i]);
free(result[i]);
}
free(nameValuePair);
free(names);
free(values);
free(result);
goto end;
}
count = 0;
}
pResults = (OPCITEMRESULT*)CoTaskMemAlloc(dwCount * sizeof(OPCITEMRESULT));
hServerItem = (OPCHANDLE *)CoTaskMemAlloc(dwCount * sizeof(OPCHANDLE));
pErrors = (HRESULT *)CoTaskMemAlloc(dwCount * sizeof(HRESULT));
hResult = addItems(serverGroup->groupInfo->ipMgt, names, &pResults, &pErrors, dwCount);
for (DWORD ii = 0; ii < dwCount; ii++) {
if (!pErrors[ii])
hServerItem[ii] = pResults[ii].hServer;
}
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);
}
}
if (async) {
DWORD dwCancelID;
hResult = pIOPCAsyncIO2->Write(dwCount, hServerItem, varValue, *hServerItem, &dwCancelID, &pErrors); /* *hServerItem as transactionID */
}
else
hResult = pIOPCSyncIO->Write(dwCount, hServerItem, varValue, &pErrors);
if (FAILED(hResult) || hResult == S_FALSE)
{
_com_error err(hResult);
LPCTSTR errMsg = err.ErrorMessage();
_tprintf(_T("Write failed: %s\r\n"), errMsg);
for (DWORD ii = 0; ii < dwCount; ii++)
{
if (pErrors && pErrors[ii]) {
if (pErrors[ii] == OPC_E_INVALIDHANDLE)
_tprintf(_T("element with index [%d] is invalid\n"), ii);
else {
_com_error err(pErrors[ii]);
errMsg = err.ErrorMessage();
_tprintf(_T("Writing element with index [%d] failed: %s\n"), ii, errMsg);
}
}
}
}
else
{
_tprintf(_T("Writing is successful.\n"));
}
if (!async)
hResult = serverGroup->groupInfo->ipMgt->RemoveItems(dwCount, hServerItem, &pErrors);
CoTaskMemFree(varValue);
for (size_t i = 0; i < dwCount; i++) {
if (!async)
freeNode(hServerItem[i]);
free(names[i]);
free(values[i]);
free(*(result + i));
}
free(names);
free(values);
free(result);
}
end:
free(buffer);
CoTaskMemFree(pResults);
CoTaskMemFree(hServerItem);
CoTaskMemFree(pErrors);
if (pIOPCSyncIO)
pIOPCSyncIO->Release();
if (pIOPCAsyncIO2)
pIOPCAsyncIO2->Release();
return hResult;
}
程序比较长,大致的结构是这样的。根据传入的是否异步的值,从获得的OPC服务端的实例中取得执行IID_IOPCAsyncIO2(异步)或者IID_IOPCSyncIO(同步)的实例位置,如果是异步还需先告诉OPC服务器你的回调函数是什么,在这里是buildCallback(), 具体程序见下。根据传入的读写值来处理。先进行读的处理,根据异同步分别处理;然后是写的处理,也分异同步进行。当中也有一些辅助函数,我就不一一例举了,有需要的和我联系我再在这里贴出来。客户端打算告一段落,下篇讲讲服务端的安全问题。
HRESULT buildCallback(serverGroup *serverGroup) {
HRESULT hResult = S_OK;
hResult = serverGroup->groupInfo->ipMgt->QueryInterface(IID_IConnectionPointContainer, (void**)&serverGroup->groupInfo->ipCPC);
if (FAILED(hResult))
{
_tprintf(_T("QueryInterface for IConnectionPointContainer failed.\r\n"));
return hResult;
}
IConnectionPoint* ipCP = NULL;
hResult = serverGroup->groupInfo->ipCPC->FindConnectionPoint(IID_IOPCDataCallback, &ipCP);
if (FAILED(hResult))
{
_tprintf(_T("FindConnectionPoint failed.\r\n"));
return hResult;
}
// create the callback object.
Callback* ipCallback = new Callback();
DWORD dwAdvise;
hResult = ipCP->Advise(ipCallback, &dwAdvise);
if (FAILED(hResult))
{
_tprintf(_T("Advise failed.\r\n"));
return hResult;
}
return hResult;
}