3

ここに私の問題があります: C# プログラムから既に実行中のプロセスを閉じる必要があります。問題は、プロセスがアイコン (タスクバーに最小化) として実行されるようになり、ユーザーが少なくとも 1 回開かない限り (無人マシンでは決して起こらない)、メイン ウィンドウが表示されないことです。

私が持っている他の要件は、アプリケーションが強制終了されずに閉じられることです。メモリバッファをディスクに書き込むために必要です-それを強制終了するとデータが失われます。

これが私がこれまでに試したことです:

        foreach (Process proc in Process.GetProcesses())
        {
            if (proc.ProcessName.ToLower().StartsWith("myapp"))
            {
                if (proc.MainWindowHandle.ToInt32() != 0)
                {
                    proc.CloseMainWindow();
                    proc.Close();
                    //proc.Kill();  <--- not good!
                }
            }
        }

ウィンドウが最小化されたときにMainWindowHandle == 0であることを発見した後、 if句を追加しました。ifを削除しても解決しません。CloseMainWindow()Close( ) も機能しません。Kill()はありますが、上記のように、私が必要としているものではありません。

難解な Win32 API 関数の使用を含め、どんなアイデアも受け入れられます :)

4

4 に答える 4

2

これはうまくいくはずです:

[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr FindWindow(string className, string windowName);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

private const int WM_CLOSE = 0x10;
private const int WM_QUIT = 0x12;

public void SearchAndDestroy(string windowName) 
{
    IntPtr hWnd = FindWindow(null, windowName);
    if (hWnd == IntPtr.Zero)
        throw new Exception("Couldn't find window!");
    SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}

一部のウィンドウは に応答しないためWM_CLOSEWM_QUIT代わりに を送信する必要がある場合があります。これらの宣言は、32 ビットと 64 ビットの両方で機能するはずです。

于 2008-09-21T06:43:46.350 に答える
1

タスクバーにある場合は、ウィンドウが表示されます。それとも、タスクバーの通知領域 (別名 SysTray) にあるということですか? その場合、まだウィンドウがあります。

Win32 アプリケーションには、慣例を除いて、実際には「メイン ウィンドウ」がありません (メイン ウィンドウは、WM_DESTROY に応答して PostQuitMessage を呼び出し、メッセージ ループを終了させるウィンドウです)。

プログラムが実行されている状態で、Spy++ を実行します。プロセスが所有するすべてのウィンドウを見つけるには、メイン メニューから [スパイ] -> [プロセス] を選択する必要があります。これにより、プロセスのツリーが表示されます。そこから、スレッドにドリルダウンし、次にウィンドウにドリルダウンできます。これにより、プロセスにどのウィンドウがあるかがわかります。ウィンドウ クラスとキャプションを書き留めます。これらを使用すると、後で FindWindow (または EnumWindows) を使用してウィンドウ ハンドルを見つけることができます。

ウィンドウ ハンドルを使用すると、WM_CLOSE または WM_SYSCOMMAND/SC_CLOSE (ウィンドウ キャプションの「X」をクリックするのと同じ) メッセージを送信できます。これにより、プログラムが正常にシャットダウンするはずです。

ここでは、Win32 の観点から話していることに注意してください。これを .NET プログラムから機能させるには、P/Invoke またはその他のトリックを使用する必要がある場合があります。

于 2008-09-21T06:33:30.867 に答える
0

ここにいくつかの答えと説明があります:

rpetrich : 以前にあなたの方法を試しましたが、問題は、ウィンドウ名がわからないことです。ユーザーごと、バージョンごとに異なります。exe 名だけが一定のままです。私が持っているのはプロセス名だけです。上記のコードでわかるように、プロセスの MainWindowHandle は 0 です。

ロジャー: はい、タスクバーの通知領域のことです - 説明ありがとうございます。PostQuitMessageを呼び出す必要があります。ウィンドウではなくプロセスのみを指定すると、方法がわかりません。

Craig : 喜んで状況を説明したいと思います。アプリケーションにはコマンド ライン インターフェースがあり、何を行うか、結果をどこに保存するかを指示するパラメータを指定できます。ただし、実行中の場合は、停止して結果を取得する唯一の方法は、トレイ通知で右クリックして [終了] を選択することです。

今、私のユーザーはアプリをスクリプト化/バッチ処理したいと考えています。彼らはバッチからそれを開始するのにまったく問題はありませんでした(exe名と一連のフラグを指定するだけです)が、実行中のプロセスで行き詰まりました。実行中にプロセスを停止するための API を提供するようにプロセスを変更する人は誰もいないと仮定すると (それはかなり古いものです)、人為的にプロセスを閉じる方法が必要です。

同様に、無人のコンピューターでは、プロセスを開始するスクリプトをタスク スケジューリングまたは操作制御プログラムによって開始できますが、プロセスをシャットダウンする方法はありません。

私の状況が明確になることを願っています。また、助けようとしているすべての人に感謝します!

于 2008-09-21T15:53:48.913 に答える
-1

これを試みている理由を明確にするための質問: プロセスの唯一のユーザー インターフェイスがシステム トレイ アイコンである場合、なぜそれを強制終了し、プロセスを実行したままにするのでしょうか? ユーザーはどのようにプロセスにアクセスしますか? また、マシンが「無人」の場合、トレイ アイコンを気にする必要はありません。

于 2008-09-21T14:06:57.297 に答える