【问题标题】:Excel OpenText methodExcel OpenText 方法
【发布时间】:2010-12-02 07:50:24
【问题描述】:

我不断收到 0x800A03EC 的模棱两可的错误代码。

 我一直在寻找是否可以找到错误的具体原因,但不幸的是,该代码似乎涵盖了许多可能的错误。我将复制并粘贴似乎给我带来问题的代码,希望有人能够就我如何解决问题向我提供一些反馈。我正在使用我在这篇 kb21686 文章中遇到的称为 AutoWrap 的方法。

我将在此处添加该方法:

HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...) {
    // 开始变量参数列表...
    va_list 标记;
    va_start(标记,cArgs);

    如果(!pDisp){
        //MessageBox(NULL, "NULL IDispatch 传递给 AutoWrap()", "Error", 0x10010);
        MessageBox(NULL,_T("IDispatch 错误"),_T("LError"),MB_OK | MB_ICONEXCLAMATION);
        _exit(0);
    }

    // 使用的变量...
    DISPARAMS dp = { NULL, NULL, 0, 0 };
    DISPID dispidNamed = DISPID_PROPERTYPUT;
    DISPID dispID;
    HRESULT 小时;
    字符缓冲区[200];
    字符 szName[200];


    // 向下转换为 ANSI
    WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);

    // 获取传递的名称的 DISPID...
    hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
    如果(失败(小时)){
        sprintf_s(buf, "IDispatch::GetIDsOfNames(\"%s\") 失败 w/err 0x%08lx", szName, hr);
        MessageBox(NULL, CString(buf), _T("AutoWrap()"), MB_OK | MB_ICONEXCLAMATION);
        _exit(0);
        返回小时;
    }

    // 为参数分配内存...
    变体 *pArgs = 新变体 [cArgs+1];
    // 提取参数...
    for(int i=0; iInvoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, autoType, &dp, pvResult, NULL, NULL);
    如果(失败(小时)){
        sprintf_s(buf, "IDispatch::Invoke(\"%s\"=%08lx) 失败 w/err 0x%08lx", szName, dispID, hr);
        MessageBox(NULL, CString(buf), _T("AutoWrap()"), MB_OK | MB_ICONEXCLAMATION);
        _exit(0);
        返回小时;
    }
    // 结束变量参数部分...
    va_end(标记);

    删除 [] pArgs;

    返回小时;
}

在我拨打这个电话之前一切正常:

AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"OpenText",18,param1,vtMissing,vtMissing,paramOpt,paramOpt,
                vtMissing,vtMissing,vtMissing,paramTrue,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing
                ,vtMissing,vtMissing);

传递给函数的参数初始化为:

 VARIANT param1,paramOpt,paramFalse,paramTrue;
        参数1.vt = VT_BSTR;
        参数选择.vt = VT_I2;
        参数选择.iVal = 1;
        paramFalse.vt = VT_BOOL;
        paramFalse.boolVal = 0;
        参数True.vt = VT_BOOL;
        参数True.boolVal = 1;
        //param1.bstrVal = ::SysAllocString(L"C:\\Documents and Settings\\donaldc\\My Documents\\DepositSlip.xls");
        param1.bstrVal = ::SysAllocString(L"C:\\logs\\TestOut.txt");

如果我取消注释掉注释掉的 param1 并调用 Open 并将它传递给 param1 的那个版本,一切都会很好。不幸的是,当在 OpenText 方法上调用 Invoke 时,我得到了 0x800A03EC 错误代码。我在搜索时发现的 90% 是在 C# 中使用互操作执行自动化,另外 10% 在 VB 中做同样的事情,虽然 C# 示例很有帮助,但它们无助于解释很好地使用 C++ 时传递的参数.我觉得这都是参数的问题,但我很难弄清楚它们到底是什么问题。

提前感谢您提供的任何帮助,如果我需要发布更多代码,请告诉我。

【问题讨论】:

  • 您对使用 ATL 有什么重要的看法吗?即使是这样,至少要测试基于 ATL 的等效代码的行为是否相似。
  • 这是应用程序中唯一不能正常工作的部分。我真的不想为了在 ATL 中测试而重写整个东西。

标签: c++ excel com


【解决方案1】:

来自您链接到的知识库文章:

一个警告是,如果你通过 多个参数,它们需要 倒序传递。

MSDN,到OpenText的参数是:

expression.OpenText(Filename, Origin, StartRow, DataType, 
TextQualifier, ConsecutiveDelimiter, Tab, Semicolon, Comma, 
Space, Other, OtherChar, FieldInfo, TextVisualLayout, DecimalSeparator, 
ThousandsSeparator, TrailingMinusNumbers, Local)

因此,如果 param1 包含您的文件名,那么您当前正尝试将其作为 Local 参数传递,并且您没有将任何内容传递给所需的 Filename 参数

【讨论】:

  • 太棒了!!!感谢您指出参数顺序。这样做并将缺少的 VARIANT 参数(paramOpt)正确初始化为; paramOpt.vt = VT_ERROR; paramOpt.scode = DISP_E_PARAMNOTFOUND;解决了这个问题。再次感谢。
【解决方案2】:

尽管这个问题是很久以前提出的,但我还是想回答一下。 我为此苦苦挣扎了一整天,但最终还是完成了。

代码 0x800a03ec 是模棱两可的,它本质上意味着,(没有冒犯的意思!),你这个笨蛋!你做了一些非常愚蠢的事情,试着自己找出来。接近旧的“语法错误”,无需进一步说明。

因此,代码 0x800a03ec 没有单一含义,通过谷歌搜索,您可以看到在范围内使用基于零的寻址以及许多其他问题时会发生这种情况。

在这种情况下,问题是您必须将参数传递给 DISPATCH_METHOD 调用 IN REVERSE。显然,使用单个参数不会导致麻烦,并且许多调度调用可以使用单个参数。

所以,当我想打开一个只有文件名的工作簿时,一切正常。

AutoWrap(DISPATCH_METHOD, &Result, pExcelWorkbooks, "Open", 1, fn);

但是例如以下代码不起作用:

_variant_t fn("MyExcelBook.xlsx"), updatelinks(0), readonly(true);
VARIANT Result;
hr = Autowrap(DISPATCH_METHOD, &Result, pExcelWorkbooks, "Open", 3, fn, updatelinks, readonly);

它产生 0x800a03ec 并且不会加载工作簿。

要在不重写所有调用的情况下对此进行修改,应将 AutoWrap 函数扩展如下:

// Allocate memory for arguments..
VARIANT * pArgs = new VARIANT[cArgs + 1];
// Extract arguments..
if (autoType & DISPATCH_METHOD)
{   // reverse (variable) DISPATCH parameters after cArgs
    for (int i = 1; i <= cArgs; i++)
        pArgs[cArgs-i] = va_arg(marker, VARIANT);
}
else
{
    for (int i = 0; i < cArgs; i++)
        pArgs[i] = va_arg(marker, VARIANT);
}

(仅显示相关部分,整个方法见之前的帖子)。

所以现在我调用 C++ 版本的 workbooks.open()

_variant_t fn("MyExcelBook.xlsx"), updatelinks(0), readonly(true), optional(DISP_E_PARAMNOTFOUND, VT_ERROR);
VARIANT Result; readonly,
hr = Autowrap(DISPATCH_METHOD, &Result, pExcelWorkbooks, "Open", 7, fn, updatelinks,
        optional, optional, optional, readonly);
//  copy the dispatch pointer to the workbook pointer
if (Result.vt == VT_DISPATCH)
{
    pExcelWorkbook = Result.pdispVal;
    //  save the workbook pointer to close it later if needed
    if (pExcelWorkbook)
        IDworkBooks.push_back(pExcelWorkbook);
}

如您所见,您不必填写无论如何都不会使用的尾部选项,就像在某些 VB 代码和 C# 中那样。

快乐的编码, 一月

PS,我看到之前提到过相反的事情(见上文).. 直到现在我才弄清楚我在哪里看到它......

【讨论】:

    猜你喜欢
    • 2016-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多