上篇讲到了如何找到OPC服务器,具体执行是在enumServerList的函数中,获得执行IID_IOPCServerList2的实例。下面继续分析。
MULTI_QI MultiQI[2] = { NULL };
MultiQI[0].pIID = &IID_IOPCServerList;
MultiQI[0].pItf = NULL;
MultiQI[0].hr = S_OK;
MultiQI[1].pIID = &IID_IOPCServerList2;
MultiQI[1].pItf = NULL;
MultiQI[1].hr = S_OK;
if (FAILED(enumServerList(hostname, MultiQI, sizeof(MultiQI) / sizeof(MULTI_QI))))
{
_tprintf(_T("Failed in enumServerList\n"));
CoUninitialize();
exit(EXIT_FAILURE);
}
serverIdInfo serverIdList[10] = { NULL };
USHORT index = 0;
if (FAILED(listServers(serverIdList, sizeof(serverIdList) / sizeof(serverIdInfo), MultiQI, index)))
{
_tprintf(_T("Failed in listServers\n"));
CoUninitialize();
exit(EXIT_FAILURE);
}
这里出现了另一个函数,listServers,基于OpcEnum.exe返回的类实例,通过DA的三个CATID(CATID_OPCDAServer10/20/30)来获得枚举类指针,如下面的pEnum。有了它循环一下获得各个OPC服务器的类,进一步获得相对应的OPC服务器的程序名和GUID等。
HRESULT listServers(serverIdInfo serverIdList[], USHORT count, MULTI_QI MultiQI[], USHORT& index)
{
CLSID clsid, opcServerId;
opcServerId.Data1 = 0;
ULONG fetched;
HRESULT hr = S_OK;
LPOLESTR ppszProgID, ppszUserType, ppszVerIndProgID;
CATID arrcatid[3];
arrcatid[0] = CATID_OPCDAServer10;
arrcatid[1] = CATID_OPCDAServer20;
arrcatid[2] = CATID_OPCDAServer30;
IOPCServerList *m_spServerList = (IOPCServerList*)MultiQI[0].pItf;
IOPCServerList2 *m_spServerList2 = (IOPCServerList2*)MultiQI[1].pItf;
if (m_spServerList2)
{
IOPCEnumGUID * pEnum = NULL;
hr = m_spServerList2->EnumClassesOfCategories(sizeof(arrcatid), arrcatid, 0, NULL, &pEnum);
if (pEnum)
{
while ((hr = pEnum->Next(1, &clsid, &fetched)) == S_OK && fetched)
{
hr = m_spServerList2->GetClassDetails(clsid, &ppszProgID, &ppszUserType, &ppszVerIndProgID);
if (FAILED(hr)) {
LPOLESTR stringID = NULL;
StringFromCLSID(clsid, &stringID);
_com_error err(hr);
LPCTSTR errMsg = err.ErrorMessage();
if (ppszProgID)
CoTaskMemFree(ppszProgID);
if (ppszUserType)
CoTaskMemFree(ppszUserType);
if (ppszVerIndProgID)
CoTaskMemFree(ppszVerIndProgID);
_tprintf(_T("Failed in GetClassDetails: %s clsid=%S\n"), errMsg, stringID);
continue;
}
hr = m_spServerList2->CLSIDFromProgID(ppszProgID, &opcServerId);
if (FAILED(hr))
break;
wcscpy_s(serverIdList[index].ppszProgID, MAXCHAR, ppszProgID);
memcpy_s(&serverIdList[index].opcServerId, sizeof(GUID), &opcServerId, sizeof(GUID));
CoTaskMemFree(ppszProgID);
CoTaskMemFree(ppszUserType);
CoTaskMemFree(ppszVerIndProgID);
if (index + 1 < count)
index++;
else
break;
}
pEnum->Release();
}
}
else if (m_spServerList)
{
IEnumCLSID * pEnum = NULL;
hr = m_spServerList->EnumClassesOfCategories(sizeof(arrcatid), arrcatid, 0, NULL, &pEnum);
if (pEnum)
{
while ((hr = pEnum->Next(1, &clsid, &fetched)) == S_OK && fetched)
{
hr = m_spServerList->GetClassDetails(clsid, &ppszProgID, &ppszUserType);
if (FAILED(hr)) {
LPOLESTR stringID = NULL;
StringFromCLSID(clsid, &stringID);
_com_error err(hr);
LPCTSTR errMsg = err.ErrorMessage();
if (ppszProgID)
CoTaskMemFree(ppszProgID);
if (ppszUserType)
CoTaskMemFree(ppszUserType);
_tprintf(_T("Failed in GetClassDetails: %s clsid=%S\n"), errMsg, stringID);
continue;
}
hr = m_spServerList->CLSIDFromProgID(ppszProgID, &opcServerId);
if (FAILED(hr))
break;
wcscpy_s(serverIdList[index].ppszProgID, MAXCHAR, ppszProgID);
memcpy_s(&serverIdList[index].opcServerId, sizeof(GUID), &opcServerId, sizeof(GUID));
CoTaskMemFree(ppszProgID);
CoTaskMemFree(ppszUserType);
if (index + 1 < count)
index++;
else
break;
}
pEnum->Release();
}
}
if (m_spServerList2)
m_spServerList2->Release();
if (m_spServerList)
m_spServerList->Release();
return hr;
}
下篇再给点干货,看下读写操作的执行。