2010-11-20 16 views
3

次のコードは、 'app'パラメータで指定されたドキュメントを開き、特定のドキュメントが閉じられるまで待機します。これは、Excelブックを開いて別のExcelワークブックを開いている場合を除いて、すべてのドキュメントタイプで正常に機能します。コードは、文書が実際に開いているときに閉じていると考えます。どうすればこの問題を解決できますか?ExcelワークブックがDelphiで終了したときの判断

procedure RunAppAndWAit(a: TApplication; app, par, verb: string); 
var 
    seinfo: tshellexecuteinfo; 
    exitcode: dword; 
begin 
    fillchar(seinfo, sizeof(seinfo), 0); 
    seinfo.cbsize := sizeof(tshellexecuteinfo); 

    with seinfo do 
    begin 
    fmask := see_mask_nocloseprocess; 
    wnd := a.Handle; 
    lpfile := pchar(app); 
    lpDirectory := pchar(ExtractFileDir(app)); 
    lpParameters := pchar(par); 
    lpVerb := pchar(verb); 

    nshow := sw_shownormal; 
    end; 

    if ShellExecuteEx(@seinfo) then 
    begin 
    repeat 
     a.ProcessMessages; 
     GetExitCodeProcess(seinfo.hprocess, exitcode); 
    until (exitcode <> still_active) or a.terminated; 
    end 
    else 
    sshowmessage('Unable to open ' + app); 
end; 

答えて

4

この試行は、ドキュメントを起動するのと同じプロセスでドキュメントを開くアプリケーションでのみ機能します。

多くのアプリケーションがこれ以上動作しません。ドキュメントを起動するプロセスは、ドキュメントを表示/編集する別のプロセスにドキュメントを渡し、起動プロセスは終了します。

イベントコールバック(この場合Excel、おそらくExcelが公開するCOM API)をサポートするAPIを見つける必要があります。このAPIを使用すると、Excelが実際にドキュメントで行うことをより詳しく見ることができます。

このAPIを使用してドキュメントを開き、ドキュメントが閉じられたときに呼び出されるイベントを登録し、イベントを待ってから閉じます。

+0

私は最終的にファイルを開くことを試みた。例外が発生した場合、まだクローズしていません。それは動作しますが、私は今少し汚い感じ... –

1

これはきれいではなく、あなたが望むほど信頼できないかもしれませんが、あなたはExcelと同じタイトルバーを探してWindows EnumWindows関数を呼び出すことができますこのファイルに表示する

たとえば、「Excel」という単語が含まれるタイトルバーと、Excelがタイトルバーに表示するファイル名を調べます。

このアプローチでは脆弱になる可能性があります。実際、私はソリューションが特に堅牢だとは思わないので、これを投稿するのはちょっと躊躇しています。しかし、あなたの問題を解決する他の方法がない場合、これは動作するかもしれません...

Google "EnumWindows Delphi"のサンプルコードです。

...さらに考えて、以下は別の方法です。 Jeroenが述べたように、ExcelにAPIを使用することができます。あなたがこれらの呼び出しをたくさんしている場合、関数の外にCreateOLEObjectとunAssignedの代入を置くことで、より重いものにすることができます。 (そして、Excelがもはや走っていない場合にはブロックを除いていくつか試してみる必要があります。)この解決法もまた、Excel特有で不器用なIMOです。 Excelで開いているファイルやダイアログボックスのような状況があり、これが誤った結果を返すかどうかはわかりません。

基本的には、Excelに固有の2つの比較的弱いアプローチがあり、必ずしも機能しないということです。 (このように言うと、私はこの投稿全体を削除するだけです...しかし、多分、あなたがどのように進めたいかについてのいくつかのアイデアを与えるでしょう)。

このコードはテストされていませんが、同じコードが過去に私のために働いていた:

uses ComObj; 

    function FindWorkbook(Workbookname: String):boolean; 
    var 
    ExcelOLE: Variant; 
    WorkbookNumber: Integer; 
    begin 
    Result := FALSE; 
    ExcelOLE := CreateOLEObject('Excel.Application'); 
    try 
     for WorkbookNumber := 1 to ExcelOLE.Workbooks.Count do 
     if UpperCase(WorkbookName) = UpperCase(ExcelOLE.Workbooks[WorkbookNumber].Name) then 
      Result := TRUE; 
    finally 
     ExcelOLE := unAssigned; 
    end; 
    end; 
関連する問題