3

この C# WinForms アプリケーションでは、PDF ファイルを生成し、クラスを介して Adob​​e Reader (または既定のシステム .pdf ハンドラー) を起動しますProcess。PDF ファイルは大きくなる可能性があるため (約 200K)、Exitedイベントを処理して、後で一時ファイルをクリーンアップします。

ファイルが開かれ、再び閉じられると、システムは必要に応じて機能します。ただし、2 番目のファイルが (Adobe Reader を閉じる前に) 開かれると、2 番目のプロセスはすぐに終了し (Reader が MDI 機能を使用しているため)、Exitedハンドラーで File.Delete 呼び出しが失敗するはずです。これは、結合された Adob​​e プロセスによってロックされているためです。ただし、Reader では代わりに次のようになります。

このドキュメントを開くときにエラーが発生しました。このファイルが見つかりません。

異常なのは、ファイルを削除する前にデバッガーのブレークポイントを設定し、削除を試みる (そして失敗する) ことを許可すると、システムが期待どおりに動作することです!

ファイルが存在することは確かであり、プロセスを開始する前にファイルへのすべてのハンドル/ファイル ストリームが閉じられていることはかなり肯定的です。

次のコードで起動しています。

// Open the file for viewing/printing (if the default program supports it) 
var pdfProcess = new Process();
pdfProcess.StartInfo.FileName = tempFileName;
if (pdfProcess.StartInfo.Verbs.Contains("open", StringComparer.InvariantCultureIgnoreCase))
{
    var verb = pdfProcess.StartInfo.Verbs.First(v => v.Equals("open", StringComparison.InvariantCultureIgnoreCase));
    pdfProcess.StartInfo.Verb = verb;
}
pdfProcess.StartInfo.Arguments = "/N"; // Specifies a new window will be used! (But not definitely...)
pdfProcess.SynchronizingObject = this;
pdfProcess.EnableRaisingEvents = true;
pdfProcess.Exited += new EventHandler(pdfProcess_Exited);

_pdfProcessDictionary.Add(pdfProcess, tempFileName);

pdfProcess.Start();

注: を使用し_pdfProcessDictionaryて Process オブジェクトへの参照を保存し、Exited イベントを正常に発生できるようにスコープ内にとどめます。

クリーンアップ/終了イベントは次のとおりです。

void pdfProcess_Exited(object sender, EventArgs e)
{
    Debug.Assert(!InvokeRequired);
    var p = sender as Process;
    try
    {
        if (_pdfProcessDictionary.ContainsKey(p))
        {
            var tempFileName = _pdfProcessDictionary[p];
            if (File.Exists(tempFileName)) // How else can I check if I can delete it!!??
            {
                // NOTE: Will fail if the Adobe Reader application instance has been re-used!
                File.Delete(tempFileName);
                _pdfProcessDictionary.Remove(p);
            }

            CleanOtherFiles(); // This function will clean up files for any other previously exited processes in our dictionary
        }
    }
    catch (IOException ex)
    {
        // Just swallow it up, we will deal with trying to delete it at another point
    }
}

可能な解決策:

  • ファイルがまだ別のプロセスで開かれていることを検出する
  • 2 番目のプロセスが実際には完全に終了しておらず、代わりに最初のプロセスでファイルが開かれていることを検出します。
4

2 に答える 2

3

私は数日前にこれに対処しました

開いているインスタンスがまだない場合、ドキュメントは新しいインスタンスで直接開きます。

すでに開いているインスタンスがある場合、そのインスタンスは、実際にはハンドルを取得していない新しいインスタンスを生成すると思います。何が起こるかというと、制御はすぐに関数に戻り、新しいインスタンスがファイルを読み取る前にファイルを削除します。したがって、ファイルは存在しないように見えます。

私はこれを「解決」しました。ファイルをすぐに削除するのではなく、リスト内のパスを追跡し、プログラムの終了時にすべてのパスを削除します(ファイルの場合は空のcatchブロックで各削除をtry /catchでラップします)その間に消えました)。

于 2010-12-21T05:14:23.117 に答える
1

次のアプローチをお勧めします。

  1. ユーザーの一時ディレクトリ(Path.GetTempPath)にファイルを作成します。その下にサブフォルダを作成できます。
  2. プロセスの最後のインスタンスが終了したときにのみファイルを削除しようとします(つまり、起動したプロセスの数をカウントする必要があります。終了時にカウントを減らし、ゼロになったときに、これまでに開いている(すべての)ファイルを削除します。 )。
  3. アプリケーションの起動と終了中に、作成されたサブフォルダー(tempディレクトリの下)をクリーンアップしてみてください。タイマーを使用して定期的なクリーンアップを試みることもできます。
于 2010-12-21T05:06:12.563 に答える