i created a plugin for ms office,it's works fine on office 2019 Excel & wps office 2019 ET,but it has problems on ms office 2013.
here is the describe:
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);
the get_Rows
works fine and returns S_OK,but Range::QueryInterface returns E_NOINTERFACE
,that's strange! I can not understand, is there anything i missed?
there are many positions called the QueryInterface
method, but only the Range
type query the IRange
type will fail.
Office 2019 & WPS 2010 works fine,already reinstalled office 2013, but still no work. Maybe a Microsoft bug?
as @Joseph Willcoxson
says, the Range
type did not implement the IRange
interface but it implemented the features, we can use IDispatch
interface Invoke
method to do the same thing. and I'd like to share my utility code.
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,
¶ms,
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,
¶ms,
&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;
}
we can use it in this way
CComVariant top5Row; {
CComVariant args[] = {cellLoc};
top5Row = DispGetProperty(sheet, WorksheetDispID::Range, args, ArrayLen(args));
}