【问题标题】:OPC DA client ItemMgt Incorrect function errorOPC DA 客户端 ItemMgt 不正确的功能错误
【发布时间】:2021-05-05 08:41:03
【问题描述】:

我为 Qt5 中的 C++ COM API 创建了一个简单的 OPC DA 客户端。 客户端连接到远程服务器,获取 OPCServer 指针,使用 ItemMgt 接口创建一个新的 OPC 组,当我尝试向组中添加项目时失败。

错误信息是:函数不正确。 据我所知,IUnknown::QueryInterface 适用于此 pItemMgt,但 ValidateItems、CreateEnumerator 和 AddItems 调用会导致相同的 Incorrect function 错误。 OPC 服务器是 QMS220Simulator (Quadera)。 知道可能是什么问题吗? 这是我第一次尝试编写 DCOM 客户端,这段代码可能有很多很多问题。 qms220.h 文件包含 QMS220Simulator 的 CLSID。 重现问题的最短代码是这样的:

#include "opcda.h"
#include "qms220.h"

#include <QApplication>
#include <QDebug>
#include <comdef.h>

static void showStatus(const QString &message,HRESULT code);

IOPCServer *pOPCServer = nullptr;
IOPCItemMgt *pItemMgt = nullptr;
OPCHANDLE serverGroupHandle;

bool initializeCOM()

{
    HRESULT hr = CoInitializeEx(nullptr,COINIT_APARTMENTTHREADED);
    if (FAILED(hr)) {
        showStatus("COM initialization failed!",hr);
        return false;
    }

    hr = CoInitializeSecurity(
                NULL, //security descriptor
                -1, //COM authentication
                NULL, //authentication services
                NULL, //reserved
                RPC_C_AUTHN_LEVEL_DEFAULT, //default authentication
                RPC_C_IMP_LEVEL_IMPERSONATE, //default impersonation
                NULL, //authentication info
                EOAC_NONE, //additional capabilities
                NULL //reserved
                );

    if (hr == RPC_E_TOO_LATE) {
        showStatus("RPC initalization is too late, ignoring...",hr);
    } else {
        if (FAILED(hr)) {
            showStatus("CoInitializeSecurity",hr);
            return false;
        }
    }

    return true;
}


void deinitializeCOM()
{
    CoUninitialize();
}


static const int INTERFACE_COUNT = 1;


bool connectToServer(const QString &address)
{
    _bstr_t serverName = address.toStdString().c_str();
    COSERVERINFO cs;
    memset(&cs,0,sizeof(cs));
    cs.pwszName = serverName;
    MULTI_QI qi[INTERFACE_COUNT];
    memset(qi,0,sizeof(qi));

    qi[0].pIID = &IID_IOPCServer;

    HRESULT hr = CoCreateInstanceEx(
                CLSID_QMG220SIMDA,
                NULL,
                CLSCTX_SERVER,
                &cs,
                INTERFACE_COUNT,
                qi
                );

    if (FAILED(hr)) {
        showStatus("CoCreateInstanceEx",hr);
        return false;
    }

    pOPCServer = (IOPCServer*)(qi[0].pItf);

    return true;
}

void disconnectFromServer()
{
    if (pOPCServer != nullptr) {
        pOPCServer->Release();
        pOPCServer = nullptr;
    }
}
void showOPCStatus(const QString &message,HRESULT hr)
{
    if (pOPCServer != nullptr) {
        LPWSTR buffer = nullptr;
        HRESULT hr2 = pOPCServer->GetErrorString(hr,LOCALE_SYSTEM_DEFAULT,&buffer);
        if (hr2 != S_OK) {
            qDebug() << message << QString(": HRESULT: 0x%1").arg(hr,8,16,QChar('0'));
        } else {
            qDebug() << message << QString(": ") << QString::fromWCharArray(buffer);
            CoTaskMemFree(buffer);
        }
    } else {
       qDebug() << message << QString(": HRESULT: 0x%1").arg(hr,8,16,QChar('0'));
    }
}

static const LPCWSTR MIDGROUPNAME = L"mid";

bool createMIDGroup()
{
    if (pOPCServer == nullptr) return false;

    OPCHANDLE clientGroupHandle = 1;
    DWORD revisedUpdateRate;

    HRESULT hr = pOPCServer->AddGroup(
                MIDGROUPNAME,
                FALSE, //active
                0, // requestedUpdateRate
                clientGroupHandle,
                NULL, //timebias
                NULL, //percentDeadBand,
                LOCALE_SYSTEM_DEFAULT, //lcid
                &serverGroupHandle,
                &revisedUpdateRate,
                IID_IOPCItemMgt,
                (LPUNKNOWN *)(&pItemMgt)
                );
    showOPCStatus("OPCServer::AddGroup",hr);
    if (hr != S_OK) return false;

    qDebug() << "The server group handle is: " << QString("0x%1").arg(serverGroupHandle,4,16);
    qDebug() << "The revised update rate is: " << revisedUpdateRate;


    #define ITEM_ID L"Hardware.Modules.Analyser.SI220.SimulationMode"
    QString accessPath("");
    QString itemId("Hardware.Modules.Analyser.SI220.SimulationMode");
    wchar_t accessPathBuffer[1024];
    wchar_t itemIdBuffer[1024];
    accessPath.toWCharArray(accessPathBuffer);
    itemId.toWCharArray(itemIdBuffer);
    static const int ITEM_COUNT = 1;

    OPCITEMDEF ItemArray[ITEM_COUNT] =
        {{
        /*szAccessPath*/ accessPathBuffer,
        /*szItemID*/ itemIdBuffer,
        /*bActive*/ FALSE,
        /*hClient*/ 1,
        /*dwBlobSize*/ 0,
        /*pBlob*/ NULL,
        /*vtRequestedDataType*/ VT_UI1,
        /*wReserved*/0
        }};

    OPCITEMRESULT *itemResults = nullptr;
    HRESULT *errors = nullptr;

    hr = pItemMgt->AddItems(ITEM_COUNT,ItemArray,&itemResults,&errors);

    bool failed = false;
    if (hr != S_OK) {
        failed = true;
    }

    showOPCStatus("createMidGroup/AddItems ",hr);

    for(DWORD k=0;k<ITEM_COUNT;k++) {
        showOPCStatus(QString("createMidGroup/AddItems[%1]").arg(k),errors[k]);
        if (errors[k] != S_OK) {
            failed = true;
        }
        CoTaskMemFree(itemResults[k].pBlob);
    }

    CoTaskMemFree(itemResults);
    CoTaskMemFree(errors);

    return !failed;
}

void removeMIDGroup()
{
    if (pOPCServer != nullptr) {
        if (pItemMgt != nullptr) {
            pItemMgt->Release();
            pItemMgt = nullptr;
        }

        HRESULT hr = pOPCServer->RemoveGroup(serverGroupHandle,false);
        if (hr != S_OK) {
            showStatus("deleteMIDGroup",hr);
        }
    }
}


int main(int argc, char *argv[])
{
    Q_UNUSED(argc)
    Q_UNUSED(argv)

    if (!initializeCOM()) return -1;
    if (connectToServer(QString("192.168.12.106"))) {
        if (createMIDGroup()) {
            removeMIDGroup();
        }

        disconnectFromServer();
    }


    deinitializeCOM();

    return 0;
}

static void showStatus(const QString &message,HRESULT code)
{
    _com_error error(code);

    qDebug() << message + QString(": " ) +  QString::fromWCharArray(error.ErrorMessage());
}

【问题讨论】:

  • 这似乎 100% 特定于此 QMS api,而不是 COM 本身。
  • 唯一特定于 QMS 的是 Hardware.Modules.Analyser.SI220.SimulationMode。其他一切都只是使用 COM 的 OPC DA。程序输出为:code "OPCServer::AddGroup" ": " "操作成功完成。\r\n" 服务器组句柄为:"0x1059698" 修改后的更新率为:0 "createMidGroup/AddItems " " : " "Incorrect function.\r\n" "createMidGroup/AddItems[0]" ": " "Unspecified error\r\n" code 我不知道 Incorrect function 在这种情况下是什么意思。
  • 99% 的代码是特定于 QMS 的。您正在调用返回错误的 QMS 特定方法,这与 COM 无关。
  • 先生,您是对的!我已将 opc 服务器类 id 更改为 Softing Toolbox DA Demo 服务器,并将属性更改为 time.local.hour,现在相同的代码运行没有错误(只是将更新速率更改为 10)。 AddItems 函数应返回 S_OK、E_FAIL、E_OUTOFMEMORY、E_INVALIDARG 或 S_FALSE,但不返回 ERROR_INVALID_FUNCTION。谢谢你的回答。

标签: c++ qt com opc


【解决方案1】:

因此,根据 Qt 文档:https://doc.qt.io/qt-5/qstring.html#toWCharArray toWCharArray 创建一个 NOT NULL CHAR TERMINATED unicode 字符串。 所以更好的用法是: int size = itemId.toWCharArray(itemIdBuffer); itemIdBuffer[大小] = L'\0'; 和 accessPathBuffer 一样。 将未终止的组名发送到 OPC 服务器可能不是一个好主意。 好消息是,CreateGroupEnumerator 发送回与接收到的相同的未终止组名称。 所以问题与 COM 或 OPC 无关,只是没有阅读精美的文档。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-15
    • 2021-08-04
    • 2020-07-24
    • 2013-08-05
    • 1970-01-01
    相关资源
    最近更新 更多