1

拡張機能としてサードパーティの親プロセスにロードされるDLLがあります。このDLLから、CreateProcess APIを使用して外部プロセス(自分自身)をインスタンス化します。これは99.999%のケースでうまく機能しますが、突然失敗して永続的に機能しなくなることがあります(親プロセスを再起動することでこれを解決できるかもしれませんが、これは望ましくないため、問題を解決するまではお勧めしません)。失敗は、CreteProcess()がエラーを報告しなくても外部プロセスが呼び出されなくなったことと、GetExitCodeProcess()が128を返すことによって示されます。これが私が行っていることの簡略化されたバージョンです。

STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;

PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));

if(!CreateProcess(
    NULL,   // No module name (use command line). 
    "<my command line>",
    NULL,   // Process handle not inheritable. 
    NULL,   // Thread handle not inheritable. 
    FALSE,  // Set handle inheritance to FALSE. 
    CREATE_SUSPENDED,  // Create suspended.
    NULL,   // Use parent's environment block. 
    NULL,   // Use parent's starting directory. 
    &si,    // Pointer to STARTUPINFO structure.
    &pi))   // Pointer to PROCESS_INFORMATION structure.
{
    // Handle error.
}
else
{
    // Do something.

    // Resume the external process thread.
    DWORD resumeThreadResult = ResumeThread(pi.hThread);
    // ResumeThread() returns 1 which is OK
    // (it means that the thread was suspended but then restarted)

    // Wait for the external process to finish.
    DWORD waitForSingelObjectResult =  WaitForSingleObject(pi.hProcess, INFINITE);
    // WaitForSingleObject() returns 0 which is OK.

    // Get the exit code of the external process.
    DWORD exitCode;
    if(!GetExitCodeProcess(pi.hProcess, &exitCode))
    {
        // Handle error.
    }
    else
    {
        // There is no error but exitCode is 128, a value that
        // doesn't exist in the external process (and even if it
        // existed it doesn't matter as it isn't being invoked any more)
        // Error code 128 is ERROR_WAIT_NO_CHILDREN which would make some
        // sense *if* GetExitCodeProcess() returned FALSE and then I were to
        // get ERROR_WAIT_NO_CHILDREN with GetLastError()
    }

    // PROCESS_INFORMATION handles for process and thread are closed.
}

外部プロセスは、Windowsエクスプローラーまたはコマンドラインから手動で呼び出すことができ、それ自体で問題なく起動します。そのように呼び出されると、実際の作業を行う前に、ログファイルが作成され、それに関する情報がログに記録されます。しかし、上記のように呼び出されると、このロギング情報はまったく表示されないため、外部プロセスのメインスレッドがmain()に入らないと想定しています(現在、その想定をテストしています)。

問題を回避するためにできることは少なくとも1つあります(スレッドを中断して開始しないでください)が、最初に障害の原因を最初に理解したいと思います。誰かがこれを引き起こす可能性のあるものとそれを修正する方法を知っていますか?

4

3 に答える 3

1

デスクトップヒープメモリを見てください。

基本的に、デスクトップ ヒープの問題はリソースの枯渇に帰着します (たとえば、プロセスの開始が多すぎるなど)。アプリがこれらのリソースを使い果たすと、新しいプロセスを開始できなくなり、CreateProcess の呼び出しがコード 128 で失敗するという症状の 1 つが発生します。

実行するコンテキストにも何らかの影響があることに注意してください。たとえば、サービスとして実行すると、コンソール アプリでコードをテストしている場合よりもはるかに速くデスクトップ ヒープが不足します。

この投稿には、デスクトップ ヒープに関する多くの有益な情報があります。

Microsoft サポートにも役立つ情報がいくつかあります。

于 2008-10-23T17:44:04.553 に答える
1

GetExitCodeProcessに関する MSDN の記事からの引用:

プロセスが終了した場合、次の終了ステータスが返されます。

  • ExitProcess または TerminateProcess 関数で指定された終了値
  • プロセスのメインまたは WinMain 関数からの戻り値
  • プロセスを終了させた未処理の例外の例外値

あなたが説明したシナリオを考えると、最も可能性の高い原因は3番目の未処理の例外だと思います。作成したプロセスのソースを見てください。

于 2008-09-26T12:47:39.247 に答える
0

あなたのコードサンプルから私が考えることができる2つの問題があります

1. creatprocess コマンドの最初の 2 つのパラメーターの使用法を最初に取得します。パスをハード コードし、notepad.exe を呼び出して、それが表示されるかどうかを確認します。メモ帳が実行されるまで、これを微調整してください。

2.コメントに反して、新しいプロセスのcurrentdirectoryパラメーターをNULLとして渡した場合、プロセスの現在の作業ディレクトリを使用して、親の開始ディレクトリではなく、新しいプロセスを開始します。

新しいパスで解決できない dll の依存関係が原因で、外部プロセス exe が適切に開始できないと想定しています。

ps : デバッガーで @err,hr を監視すると、最後のエラー コードの説明が表示されます。

于 2008-09-28T17:53:34.843 に答える