Excel通过IDispatch接口(oaidl)获取Range对象的外部地址

问题描述 投票:0回答:1

以下代码返回单元相关地址的列表;但是我需要依赖地址采用外部格式(包括工作簿名称和工作表) 我试图在调用该方法时将可选参数“External”设置为 True,但返回的地址仍然仅显示 rowcol。Range.address 有 5 个可选参数,第三个是“External”,我试图将其设置为 True。知道我在这里缺少什么吗?

if (vtDependencies.vt == VT_DISPATCH) {
    // CONVERT TO ENUMERATOR OBJECT
    hr = CComDispatchDriver(vtDependencies.pdispVal).GetPropertyByName(L"_NewEnum", &vtPropertyEnum);
    IFFAILED_RETURN(hr);
    CComPtr<IEnumVARIANT> pEnum;
    hr = vtPropertyEnum.pdispVal->QueryInterface(IID_IEnumVARIANT, (void**)&pEnum);
    ULONG lFetch;
    hr = pEnum->Next(1, &vtPropertyEnum, &lFetch);
    name = L"Address";
    vtPropertyEnum.pdispVal->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispID);
    IFFAILED_RETURN(hr);
    // ITERATE OVER THE DEPENDENCIES AND ADD THEM TO THE LIST
    while (hr == S_OK && lFetch == 1) {
        DISPPARAMS p = { NULL, NULL, 0, 0 };
        const int argNum = 5;
        param.cArgs = argNum;
        VARIANT pArr[argNum];
        p.rgvarg = pArr;
        p.rgvarg[0].vt = VT_BOOL;
        p.rgvarg[0].boolVal = false;
        p.rgvarg[1].vt = VT_BOOL;
        p.rgvarg[1].boolVal = false;
        p.rgvarg[2].vt = VT_BOOL;
        p.rgvarg[2].boolVal = false;
        p.rgvarg[3].vt = VT_BOOL;
        p.rgvarg[3].boolVal = true;
        p.rgvarg[4].vt = VT_BOOL;
        p.rgvarg[4].boolVal = false;
        // INVOKE ADDRESS METHOD
        hr = vtPropertyEnum.pdispVal->Invoke(
            dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &p, &vtAddress, NULL, NULL);
        IFFAILED_RETURN(hr);
        dependencies.push_back(vtAddress.bstrVal);
        hr = pEnum->Next(1, &vtPropertyEnum, &lFetch);
    }
}

c++ idispatch
1个回答
0
投票

您似乎正在尝试使用 IDispatch 接口检索 Excel 中范围对象的地址,并且您希望该地址在格式中包含工作簿名称和工作表名称。这需要在调用范围的 Address 属性时将可选参数External 设置为 true。但是,从您的代码来看,为 Range.Address 方法正确设置可选参数可能存在一些偏差。

使用 Invoke 时反转参数的顺序。 确保 ReferenceStyle 的类型 (VT_I4) 正确并使用适当的值(xlA1 或 xlR1C1)。 将External 设置为true 并仔细检查参数顺序。 这些更改应帮助您正确检索范围的外部地址格式,包括工作簿和工作表名称。

Range.Address 属性具有以下可选参数:

RowAbsolute(可选)- true 将引用的行部分作为绝对引用返回。 ColumnAbsolute(可选)- true 将引用的列部分作为绝对引用返回。 ReferenceStyle(可选)- XlReferenceStyle,指定引用样式(A1 或 R1C1)。 外部(可选)- true 则返回外部引用,其中包括工作簿和工作表名称。 relativeTo(可选)-范围对象,仅当 RowAbsolute 和 ColumnAbsolute 均为 false 时才适用。 您正确地尝试将 p.rgvarg[3] 设置为 true 以获取外部地址。但是,我发现一些潜在问题可能导致外部参数被忽略或设置不正确:

潜在问题和修复: 参数顺序:DISPPARAMS 的参数顺序必须与 Range.Address 方法签名中定义的顺序相匹配。在 COM 中,使用 Invoke 方法时应以相反的顺序提供参数,因为参数被压入堆栈。 在您的代码中,您按正向顺序推送参数,但它们需要反向。具体来说,如果签名是:

Range.Address([RowAbsolute], [ColumnAbsolute], [ReferenceStyle], [External], [RelativeTo])

DISPARAMS 中的顺序应该是:

相对于 外部的 参考样式 列绝对值 行绝对

将您的代码更新为:

    p.rgvarg[4].vt = VT_BOOL;    // RowAbsolute
p.rgvarg[4].boolVal = false;

p.rgvarg[3].vt = VT_BOOL;    // ColumnAbsolute
p.rgvarg[3].boolVal = false;

p.rgvarg[2].vt = VT_I4;      // ReferenceStyle (you may need to use an appropriate value for xlA1 or xlR1C1)
p.rgvarg[2].lVal = 1;        // xlA1

p.rgvarg[1].vt = VT_BOOL;    // External
p.rgvarg[1].boolVal = true;

p.rgvarg[0].vt = VT_DISPATCH; // RelativeTo (optional, can be NULL if not used)
p.rgvarg[0].pdispVal = NULL;  // Assuming you don't need it

设置正确的ReferenceStyle:确保为ReferenceStyle 参数指定正确的值。可能的值为: 1 个 xlA1 -4150 对于 xlR1C1 此参数对于 Excel 正确确定所需地址的格式可能至关重要。 正确初始化 DISPPARAMS:确保正确初始化 DISPPARAMS。您的代码应将 cArgs 设置为参数数量 (argNum),并将 rgvarg 设置为正确的参数数组。 检查输出变体 (vtAddress):确保 vtAddress 得到正确处理并且它包含有效的 BSTR 结果。如果参数“外部”设置正确,但仍然没有返回预期值,请检查 vtAddress 以确定是否存在任何错误或是否被以意外方式修改。 这是相关部分的更新版本:

// Correct order of parameters in DISPPARAMS (reverse order of the function signature)
const int argNum = 5;
param.cArgs = argNum;
VARIANT pArr[argNum];
param.rgvarg = pArr;

// Set parameters in reverse order
p.rgvarg[4].vt = VT_BOOL;    // RowAbsolute
p.rgvarg[4].boolVal = false;

p.rgvarg[3].vt = VT_BOOL;    // ColumnAbsolute
p.rgvarg[3].boolVal = false;

p.rgvarg[2].vt = VT_I4;      // ReferenceStyle (e.g., xlA1)
p.rgvarg[2].lVal = 1;        // xlA1

p.rgvarg[1].vt = VT_BOOL;    // External
p.rgvarg[1].boolVal = true;

p.rgvarg[0].vt = VT_DISPATCH; // RelativeTo (optional, can be NULL if not used)
p.rgvarg[0].pdispVal = NULL;  // Assuming you don't need it

// INVOKE ADDRESS METHOD
hr = vtPropertyEnum.pdispVal->Invoke(
    dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &p, &vtAddress, NULL, NULL);
IFFAILED_RETURN(hr);

// Push the resulting address into the dependencies list
dependencies.push_back(vtAddress.bstrVal);
hr = pEnum->Next(1, &vtPropertyEnum, &lFetch);
© www.soinside.com 2019 - 2024. All rights reserved.