C++ Office Excel插件范围查询界面“E_NOINTERFACE”问题

ppcbkaq5  于 2022-12-01  发布在  其他
关注(0)|答案(1)|浏览(99)

我创建了一个插件的微软办公室,它的工程罚款Office 2019 Excel & WPS Office 2019 ET,但它有问题的微软办公室2013.
这里是描述:

rst = disp->QueryInterface(__uuidof(Excel::_Worksheet), (void**)&sheet);
        disp->Release();
        Excel::Range* rawRange = nullptr;
        Excel::IRange* rows = nullptr;
        rst = sheet->get_Rows(&rawRange);
        rst = rawRange ->QueryInterface( __uuidof(Excel::IRange), (void**)&rows);

get_Rows运行正常,返回S_OK,但是Range::QueryInterface返回E_NOINTERFACE,这很奇怪!我不明白,我错过了什么吗?
有许多位置称为QueryInterface方法,但只有Range类型查询IRange类型会失败。
Office 2019 & WPS 2010工作正常,已经重新安装了Office 2013,但仍然没有工作。也许是微软的bug?

icnyk63a

icnyk63a1#

正如@Joseph Willcoxson所说,Range类型没有实现IRange接口,但它实现了特性,我们可以使用IDispatch接口Invoke方法来做同样的事情。我想分享我的实用程序代码。

template<class T, size_t N>
constexpr size_t ArrayLen(T(&ref)[N]) {
    return N;
}

enum class RangeDispID : DISPID {
    // Props
    NumberFormat    = 0x000000c1,
    Column          = 0x000000f0,
    Row             = 0x00000101,
    Rows            = 0x00000102,
    Columns         = 0x000000f1,
    Text            = 0x0000008a,
    Item            = 0x000000aa,
    Cells           = 0x000000ee,
    Count           = 0x00000076,
    Value2          = 0x0000056c,
    // Methods
    Select          = 0x000000eb,
    Find            = 0x0000018e,
    AutoFilter      = 0x00000319,
    Activate        = 0x00000130,
};

enum class WindowDispID : DISPID {
    FreezePanes     = 0x0000028a
};

enum class WorksheetDispID : DISPID {
    Rows            = 0x00000102,
    Range           = 0x000000c5,
    UsedRange       = 0x0000019c,
};

template<class T>
struct DispIDBridge {};

template<>
struct DispIDBridge<RangeDispID> {
    using DispIDType = RangeDispID;
    using UUIDType = Excel::IRange;
    DispIDBridge(DispIDType id) : id_(id){}
    operator DispIDType() const { return id_; }
    operator DISPID() const { return (DISPID)id_; }
private:
    DispIDType id_;
};

template<>
struct DispIDBridge<WindowDispID> {
    using DispIDType = WindowDispID;
    using UUIDType = Excel::IWindow;
    DispIDBridge(DispIDType id) : id_(id) {}
    operator DispIDType() const { return id_; }
    operator DISPID() const { return (DISPID)id_; }
private:
    DispIDType id_;
};

template<>
struct DispIDBridge<WorksheetDispID> {
    using DispIDType = WorksheetDispID;
    using UUIDType = Excel::_Worksheet;
    DispIDBridge(DispIDType id) : id_(id) {}
    operator DispIDType() const { return id_; }
    operator DISPID() const { return (DISPID)id_; }
private:
    DispIDType id_;
};

template<class T>
HRESULT DispSetProperty(IDispatch* obj, T id, CComVariant& val) {
    DISPID dispid = DISPID_PROPERTYPUT;
    DISPPARAMS params; {
        params.cNamedArgs = 1;
        params.rgdispidNamedArgs = &dispid;
        params.cArgs = 1;
        params.rgvarg = &val;
    }
    UINT errIn;
    auto rst = obj->Invoke(
        (DISPID)id,
        __uuidof(DispIDBridge<T>::UUIDType),
        chs_lcid,
        DISPATCH_PROPERTYPUT,
        &params,
        nullptr,
        nullptr,
        &errIn
    );
    return rst;
}

template<class T>
CComVariant DispGetProperty(IDispatch* obj, T id, CComVariant* args = nullptr, int argc = 0) {
    if (argc > 1) {
        std::reverse(args, args + argc);
    }
    CComVariant ret;
    DISPPARAMS params; {
        params.cNamedArgs = 0;
        params.rgdispidNamedArgs = nullptr;
        params.cArgs = argc;
        params.rgvarg = args;
    }
    UINT errIn;
    auto rst = obj->Invoke(
        (DISPID)id,
        __uuidof(DispIDBridge<T>::UUIDType),
        chs_lcid,
        DISPATCH_PROPERTYGET,
        &params,
        &ret,
        nullptr,
        &errIn
    );
    if (rst == S_OK) {
        return ret;
    }
    else {
        return CComVariant();
    }
}

template<class T>
HRESULT DispCallMethod(IDispatch* obj, T id, CComVariant* args, int argc) {
    if (argc > 1) {
        std::reverse(args, args + argc);
    }
    DISPPARAMS dispParams{};
    dispParams.cArgs = argc;
    dispParams.rgvarg = args;
    UINT errIn;
    auto rst = obj->Invoke(
        (DISPID)id,
        __uuidof(DispIDBridge<T>::UUIDType),
        chs_lcid,
        DISPATCH_METHOD,
        &dispParams,
        nullptr,
        nullptr,
        &errIn
    );
    return rst;
}

template<class T>
CComVariant DispCallMethodWithRet(IDispatch* obj, T id, CComVariant* args, int argc) {
    if (argc > 1) {
        std::reverse(args, args + argc);
    }
    DISPPARAMS dispParams{};
    dispParams.cArgs = argc;
    dispParams.rgvarg = args;
    UINT errIn;
    CComVariant ret;
    auto rst = obj->Invoke(
        (DISPID)id,
        __uuidof(DispIDBridge<T>::UUIDType),
        chs_lcid,
        DISPATCH_METHOD,
        &dispParams,
        &ret,
        nullptr,
        &errIn
    );
    assert(rst == S_OK);
    return ret;
}

我们可以这样使用它

CComVariant top5Row; {
            CComVariant args[] = {cellLoc};
            top5Row = DispGetProperty(sheet, WorksheetDispID::Range, args, ArrayLen(args));
        }

相关问题