DSOFramer在另一个窗口中关闭Excel文档。如果文件中未保存的数据,则dsoframer无法打开并显示“尝试访问无效地址”。 [英] DSOFramer closing Excel doc in another window. If unsaved data in file, dsoframer fails to open with "Attempt to access invalid address"

查看:235
本文介绍了DSOFramer在另一个窗口中关闭Excel文档。如果文件中未保存的数据,则dsoframer无法打开并显示“尝试访问无效地址”。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Microsoft的DSOFramer 控件允许我在对话框中嵌入Excel文件,以便用户可以选择其工作表,然后选择其单元格范围;

I'm using Microsoft's DSOFramer control to allow me to embed an Excel file in my dialog so the user can choose his sheet, then select his range of cells; it's used with an import button on my dialog.

问题是当我调用 DSOFramer的OPEN 函数时,如果我在另一个窗口中打开了Excel,它将关闭Excel文档(但使Excel运行)。如果它试图关闭的文档中有未保存的数据,则会显示一个对话框,在另一个窗口中关闭Excel文档。如果文件中未保存的数据, dsoframer 无法打开,并显示以下消息框:试图访问无效地址

The problem is that when I call the DSOFramer's OPEN function, if I have Excel open in another window, it closes the Excel document (but leaves Excel running). If the document it tries to close has unsaved data, I get a dialog boxclosing Excel doc in another window. If unsaved data in file, dsoframer fails to open with a messagebox: Attempt to access invalid address.

我构建了源代码,并逐步完成了工作,并在其 CDsoDocObject :: CreateFromFile 函数中进行了调用,在IMoniker类的对象上调用 BindToObject HR 0x8001010a 消息过滤器表明应用程序很忙。在失败时,它将尝试通过 CLSID classid InstantiateDocObjectServer > Microsoft Excel工作表...这失败,并且 HRESULT 0x80040154 未注册的类 InstantiateDocObjectServer 只是在 classid 上调用 CoCreateInstance CLSCTX_LOCAL_SERVER ,然后(如果失败)使用 CLSCTX_INPROC_SERVER

I built the source, and stepped through, and its making a call in its CDsoDocObject::CreateFromFile function, calling BindToObject on an object of class IMoniker. The HR is 0x8001010a The message filter indicated that the application is busy. On that failure, it tries to InstantiateDocObjectServer by classid of CLSID Microsoft Excel Worksheet... this fails with an HRESULT of 0x80040154 Class not registered. The InstantiateDocObjectServer just calls CoCreateInstance on the classid, first with CLSCTX_LOCAL_SERVER, then (if that fails) with CLSCTX_INPROC_SERVER.

我知道 DSOFramer 是一个流行的示例项目,用于将Office应用程序嵌入各种对话框和表单中。我希望其他人遇到这个问题,并且可能对我如何解决这个问题有一些了解。我真的不希望它关闭任何其他打开的Excel文档,如果由于未保存的数据而无法关闭文档,我真的不希望它出错。

I know DSOFramer is a popular sample project for embedding Office apps in various dialog and forms. I'm hoping someone else has had this problem and might have some insight on how I can solve this. I really don't want it to close any other open Excel documents, and I really don't want it to error-out if it can't close the document due to unsaved data.

更新1:我尝试更改传递给 Excel.Application classid (我知道该类将解决),但这没有用。在 CDsoDocObject 中,它尝试打开键 HKEY_CLASSES_ROOT\CLSID\ {00024500-0000-0000-C000-000000000046} \DocObject ,但失败。我已经从视觉上确认了注册表中不存在该密钥;该密钥已存在于指南中,但没有 DocObject 子项。然后,它会生成一个错误消息框:关联的COM服务器不支持ActiveX文档嵌入。当我尝试使用 Excel.Workbook程序ID 时,我得到类似的结果(当然是不同的键)。

Update 1: I've tried changing the classid that's passed in to Excel.Application (I know that class will resolve), but that didn't work. In CDsoDocObject, it tries to open key HKEY_CLASSES_ROOT\CLSID\{00024500-0000-0000-C000-000000000046}\DocObject, but fails. I've visually confirmed that the key is not present in my registry; The key is present for the guide, but there's no DocObject subkey. It then produces an error message box: The associated COM server does not support ActiveX document embedding. I get similar (different key, of course) results when I try to use the Excel.Workbook programid.

更新2:我尝试启动Excel的第二个实例,希望我的自动化程序可以绑定到它(是最近被调用的),而不是有问题的Excel实例,但是它似乎没有这样做。结果是一样的。我的问题似乎可以归结为:我在 IMoniker 类的对象上调用 BindToObject ,然后接收 0x8001010A(RPC_E_SERVERCALL_RETRYLATER) 消息过滤器指示应用程序很忙。我试过传递给 BindToObject 的标志(通过 SetBindOptions ),但是似乎没有任何作用

Update 2: I tried starting a 2nd instance of Excel, hoping that my automation would bind to it (being the most recently invoked) instead of the problem Excel instance, but it didn't seem to do that. Results were the same. My problem seems to have boiled down to this: I'm calling the BindToObject on an object of class IMoniker, and receiving 0x8001010A (RPC_E_SERVERCALL_RETRYLATER) The message filter indicated that the application is busy. I've tried playing with the flags passed to the BindToObject (via the SetBindOptions), but nothing seems to make any difference.

更新3:它首先尝试使用IMoniker类进行绑定。如果失败,它将调用 clsid CoCreateInstance 作为 fallback 方法。这可能适用于其他MS Office对象,但是当使用Excel时,该类适用于工作表。我将示例修改为 CoCreateInstance _Application ,然后获得了工作簿,然后将目标文件称为 Workbooks :: Open ,它返回一个工作表对象。然后,我返回了该指针,并与原始示例代码路径合并在一起。现在一切正常。

Update 3: It first tries to bind using an IMoniker class. If that fails, it calls CoCreateInstance for the clsid as a fallback method. This may work for other MS Office objects, but when it's Excel, the class is for the Worksheet. I modified the sample to CoCreateInstance _Application, then got the workbooks, then called the Workbooks::Open for the target file, which returns a Worksheet object. I then returned that pointer and merged back with the original sample code path. All working now.

推荐答案

假设您正在使用DSOFRAMER项目,则需要将此代码添加到dsofdocobj。 cpp在348行附近:

Assuming you are using the DSOFRAMER project, you need to add this code to dsofdocobj.cpp in the CreateFromFile function, at around line 348:

CLSID clsidExcelWS;
hr = CLSIDFromProgID(OLESTR("Excel.Sheet"),clsidExcelWS);                   
if (FAILED(hr)) return hr;

if (clsid == clsidExcelWS)
{
    hr = InstantiateAndLoadExcel(pwszFile, &pole);
    if (FAILED(hr)) return hr;
}
else
{
    <the IMoniker::BindToObject call and it's failure handling from the "stock" sample goes here>
}

然后,在CDsoDocObject中定义以下新成员函数:

Then, define the following new member function in CDsoDocObject:

////////////////////////////////////////////////////////////////////////
// CDsoDocObject::InstantiateAndLoadExcel (protected)
//
//  Create an instance of Excel and load the target file into its worksheet
//
STDMETHODIMP CDsoDocObject::InstantiateAndLoadExcel(LPWSTR pwszFile, IOleObject **ppole)
{
    IUnknown *punkApp=NULL;
    Excel::_Application *app=NULL;
    Excel::Workbooks *wbList=NULL;
    Excel::_Workbook *wb;

    CLSID   clsidExcel;
    HRESULT hr = CLSIDFromProgID(OLESTR("Excel.Application"), &clsidExcel);
    if (FAILED(hr)) 
        return hr;

    hr = CoCreateInstance(clsidExcel, NULL, CLSCTX_LOCAL_SERVER,  IID_IUnknown, (void**)&punkApp);
    if (SUCCEEDED(hr)) 
    {
        hr = punkApp->QueryInterface(__uuidof(Excel::_Application),(LPVOID *)&app);
        if (SUCCEEDED(hr))
        {
            hr = app->get_Workbooks(&wbList);

            VARIANT vNoParam;
            VariantInit(&vNoParam);
            V_VT(&vNoParam) = VT_ERROR;
            V_ERROR(&vNoParam) = DISP_E_PARAMNOTFOUND;

            VARIANT vReadOnly;
            VariantInit(&vReadOnly);
            V_VT(&vReadOnly) = VT_BOOL;
            V_BOOL(&vReadOnly) = VARIANT_TRUE;

            BSTR bstrFilename = SysAllocString(pwszFile);

            hr = wbList->Open(bstrFilename, vNoParam,vNoParam,vNoParam,vNoParam,vReadOnly,vNoParam,vNoParam,vNoParam,vNoParam,vNoParam,vNoParam,vNoParam,0,&wb);
            if (SUCCEEDED(hr))
                hr = wb->QueryInterface(IID_IOleObject, (void**)ppole);

            VariantClear(&vReadOnly);
            VariantClear(&vNoParam);
            SysFreeString(bstrFilename);
        }
    }

    if (wb != NULL) wb->Release();
    if (wbList != NULL) wbList->Release();
    if (app != NULL) app->Release();
    if (punkApp != NULL) punkApp->Release();

    return hr;
}

这篇关于DSOFramer在另一个窗口中关闭Excel文档。如果文件中未保存的数据,则dsoframer无法打开并显示“尝试访问无效地址”。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆