4

コントロールを使用Microsoft's DSOFramerして、ダイアログにExcelファイルを埋め込んで、ユーザーがシートを選択してからセルの範囲を選択できるようにしています。ダイアログのインポートボタンで使用されます。

問題は、DSOFramer's OPEN関数を呼び出すときに、Excelを別のウィンドウで開いていると、Excelドキュメントが閉じてしまうことです(ただし、Excelは実行されたままになります)。閉じようとしているドキュメントに未保存のデータがある場合、別のウィンドウにExcelドキュメントを閉じるダイアログボックスが表示されます。ファイルに保存されていないデータがある場合dsoframer、メッセージボックスで開くことができません:Attempt to access invalid address

ソースを作成してステップスルーし、そのCDsoDocObject::CreateFromFile関数で呼び出しBindToObjectを行って、クラスIMonikerのオブジェクトを呼び出しました。HRです0x8001010a The message filter indicated that the application is busy。_ その失敗で、それはMicrosoftExcelワークシートを使用しようとします...これはので失敗InstantiateDocObjectServerします。は、最初に、を呼び出し、次に(失敗した場合は)を呼び出します。classidCLSIDHRESULT0x80040154 Class not registeredInstantiateDocObjectServerCoCreateInstanceclassidCLSCTX_LOCAL_SERVERCLSCTX_INPROC_SERVER

DSOFramerさまざまなダイアログやフォームにOfficeアプリを埋め込むための人気のあるサンプルプロジェクトです。他の誰かがこの問題を抱えていて、私がこれをどのように解決できるかについての洞察を持っているかもしれないことを願っています。開いている他のExcelドキュメントを閉じたくないし、データが保存されていないためにドキュメントを閉じることができない場合にエラーアウトしたくない。

classid更新1:渡されたものを変更しようとしましたがExcel.Application(クラスが解決されることはわかっています)、それは機能しませんでした。でCDsoDocObject、キーを開こうとしますHKEY_CLASSES_ROOT\CLSID\{00024500-0000-0000-C000-000000000046}\DocObjectが、失敗します。キーがレジストリに存在しないことを視覚的に確認しました。ガイドにはキーがありますが、DocObjectサブキーはありません。次に、エラーメッセージボックスが生成されますThe associated COM server does not support ActiveX document embedding。を使用しようとすると、同様の(もちろん異なるキー)結果が得られますExcel.Workbook programid

更新2:問題のあるExcelインスタンスではなく、自動化が(最後に呼び出された)Excelにバインドされることを期待して、Excelの2番目のインスタンスを起動しようとしましたが、そうはならなかったようです。結果は同じでした。私の問題は、要約すると次のようになります。BindToObjectクラスのオブジェクトでを呼び出し、IMonikerを受信して​​い0x8001010A (RPC_E_SERVERCALL_RETRYLATER) The message filter indicated that the application is busyます。BindToObject(を介して)に渡されたフラグで遊んでみましたSetBindOptionsが、何も違いがないようです。

更新3:最初にIMonikerクラスを使用してバインドを試みます。それが失敗した場合は、メソッドCoCreateInstanceとしてを呼び出します。これは他のMSOfficeオブジェクトでも機能する可能性がありますが、Excelの場合、クラスはワークシート用です。サンプルをに変更してから、ワークブックを取得し、ターゲットファイルに対してを呼び出しました。これにより、ワークシートオブジェクトが返されます。次に、そのポインターを返し、元のサンプルコードパスにマージして戻しました。すべてが現在機能しています。clsidfallbackCoCreateInstance _ApplicationWorkbooks::Open

4

3 に答える 3

0

@Jinjin:Excel :: _ Applicationを使用しているcppファイルにインポートステートメント(#import "XL5EN32.olb")を入れましたか?そうでない場合は、それを実行してください...プロジェクトに追加することはできません。すでにそれを行っている場合は、これらのマッピングを使用しているcppファイルにこのステートメントを追加してみてください。#import "Debug\XL5EN32.tlh"。tlhファイルは、#importを実行して生成されるヘッダーです。デバッグディレクトリにあります(デバッグビルドを実行していることを前提としています)。

_Applicationの名前をApplication(およびその他)に変更するのは正しい方法ではありません。_Application構造は、マッピングを持つ構造です。そのため、app->get_Workbooksが見つかりません。

_ApplicationではなくApplicationを検索しているファイルを探していますか?

于 2008-11-18T17:43:05.200 に答える
0

DSOFRAMER プロジェクトを使用していると仮定すると、このコードを dsofdocobj.cpp の CreateFromFile 関数の 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 で次の新しいメンバー関数を定義します。

////////////////////////////////////////////////////////////////////////
// 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;
}
于 2008-11-14T21:22:28.283 に答える
0

@ジンジン

  1. #import ディレクティブを使用して、Excel の OLB ファイルをインポートできます。これが生成されます (_Application の構造 (および必要な残りの部分) を含む Excel .tlh ファイルが自動的に含まれます)。理想的には、サポートしたい最も古いバージョンの Excel に一致する OLB ファイルを見つける必要があります。ローカル システム上のファイルは、おそらく c:\Program Files\Microsoft Office\Office12 にあります (Office 2007 がインストールされていることを前提としています)。Excel.olb、または XL5EN32.OLB という名前になる場合があります (米国英語版の Excel をインストールしていない場合は、明らかに異なります。.olb
    ファイルをプロジェクトのソース ディレクトリにコピーし、ソース ファイルの先頭に、 #import "XL5EN32.olb" の行を追加します。

  2. はい、古いバージョンを開きます。これが当てはまることを保証する最善の方法は、サポートする最も古いバージョンの Excel のインストールからの OLB ファイル (上記の項目 1 で説明) を見つけることです。Office 2000 の Excel9.olb を使用しています。Office 2007 から最新版まで、Excel バージョンのテストで問題なく動作します。

  3. はい、これらの変更を行った後は、通常どおり dsoframer を使用する必要があります。

  4. 残念ながら、雇用主の制限により、おそらくそれはできません。ただし、「ストック」の dsoframer プロジェクトを使用して、この記事のパート 1 で説明した変更と、以前の記事で説明した変更を行うと、私が持っているものをほぼ正確に再現できます。

于 2008-11-17T17:28:07.477 に答える