Delphi 7 32位执行并等待64位进程

时间:2014-05-22 18:20:59

标签: delphi process

我曾经使用下面的函数启动并等待unil结束进程。

它可以在32位或64位操作系统上启动和等待32位进程。

但是在64位操作系统上,当我启动64位进程(WaitForSingleObject = WAIT_OBJECT_0)时它会立即返回。

例如,如果我的应用程序(32位),在32位操作系统上启动mstsc.exe即可,但它不会在64位操作系统上等待,因为mstsc.exe是64位程序。

任何解决方案?

function gShellExecuteAndWait(
                              vHandle     : HWND;
                              vOperation  : string;
                              vFichier    : string;
                              vParametres : string;
                              vRepertoire : string;
                              vAffichage  : Integer;
                              vDuree      : DWORD;
                              var vErreur : string
                             ) : Boolean;
var
  vSEInfo  : TShellExecuteInfo;
  vAttente : DWORD;
begin
  // Initialisation
  Result   := True;
  vErreur  := '';
  vAttente := 0;

  // Initialisation de la structure ShellExecuteInfo
  ZeroMemory(@vSEInfo, SizeOf(vSEInfo));

  // Remplissage de la structure ShellExecuteInfo
  vSEInfo.cbSize       := SizeOf(vSEInfo);
  vSEInfo.fMask        := SEE_MASK_NOCLOSEPROCESS;
  vSEInfo.Wnd          := vHandle;
  vSEInfo.lpVerb       := PAnsiChar(vOperation);
  vSEInfo.lpFile       := PAnsiChar(vFichier);
  vSEInfo.lpParameters := PAnsiChar(vParametres);
  vSEInfo.lpDirectory  := PAnsiChar(vRepertoire);
  vSEInfo.nShow        := vAffichage;

  // L'exécution a réussi
  if ShellExecuteEx(@vSEInfo) then
  begin
    // Attendre la fin du process ou une erreur
    while True do
    begin

      case WaitForSingleObject(vSEInfo.hProcess, 250) of

        WAIT_ABANDONED :
        begin
          Result  := False;
          vErreur := 'L''attente a été annulée.';
          Break;
        end;

        WAIT_OBJECT_0 :
        begin
          Break;
        end;

        WAIT_TIMEOUT :
        begin
          // Initialisation
          vAttente := vAttente + 250;

          // Le délai d'attente n'a pas été atteint
          if vAttente < vDuree then
          begin
            Application.ProcessMessages();
          end

          // Le délai d'attente est dépassé
          else
          begin
            Result  := False;
            vErreur := 'Le délai d''attente a été dépassé.';
            Break;
          end;
        end;

        WAIT_FAILED :
        begin
          Result := False;
          vErreur := SysErrorMessage(GetLastError());
          Break;
        end;
      end;
    end;
  end

  // L'exécution a échoué
  else
  begin
    Result  := False;
    vErreur := SysErrorMessage(GetLastError());
  end;
end;

2 个答案:

答案 0 :(得分:15)

我的猜测是发生以下情况:

  1. 您在64位Windows下的WOW64仿真器中运行了32位进程。
  2. 您尝试启动名为mstsc.exe的新流程。
  3. 系统在路径上搜索并在系统目录中找到它。
  4. 因为您在WOW64下运行,系统目录是32位系统目录,SysWOW64。
  5. 进程启动并立即检测到它是在64位系统下在WOW64下运行的32位进程。
  6. 32位mstsc.exe然后确定它需要启动它所做的mstsc.exe的64位版本,传递任何命令行参数,然后立即终止。
  7. 这可以解释为什么您的新流程会立即终止。

    一些可能的解决方案:

    1. 在启动新进程之前禁用文件系统重定向。显然你应该立即重新启用它。
    2. 创建一个小的64位程序,该程序与可执行文件位于同一目录中,其唯一的工作是启动程序。您可以启动此过程并要求它启动其他过程。这将允许您从仿真器的离合器及其重定向中逃脱。

答案 1 :(得分:1)

在64位操作系统上从32位程序启动mstsc.exe的情况下,我修改了这样的功能(这是第一次尝试而不是最终版本),它就像魅力一样!

谢谢@DavidHeffernan!

但请注意,如果您不知道将推出什么流程(及其行为),您需要考虑@RemyLebeau全球解决方案。

谢谢!

function gShellExecuteAndWait(
                              vHandle     : HWND;
                              vOperation  : string;
                              vFichier    : string;
                              vParametres : string;
                              vRepertoire : string;
                              vAffichage  : Integer;
                              vDuree      : DWORD;
                              var vErreur : string
                             ) : Boolean;
var
  vSEInfo  : TShellExecuteInfo;
  vAttente : DWORD;

  IsWow64Process                 :function(aProcess: THandle; var aWow64Process: Bool): Bool; stdcall;
  Wow64DisableWow64FsRedirection :function(aOldValue :pointer) :Bool; stdcall;
  Wow64RevertWow64FsRedirection  :function(aOldValue :pointer) :Bool; stdcall;


  Wow64 :Bool;
  OldFs :pointer;
begin
  // Initialisation
  Result   := True;
  vErreur  := '';
  vAttente := 0;
  OldFS    := nil;

  IsWow64Process := Windows.GetProcAddress(Windows.GetModuleHandle('kernel32.dll'), 'IsWow64Process');

  if Assigned(IsWow64Process) then
  begin
    IsWow64Process(GetCurrentProcess, Wow64);
  end
  else
  begin
    Wow64 := False;
  end;

  if Wow64 then
  begin
    Wow64DisableWow64FsRedirection := GetProcAddress(Windows.GetModuleHandle('kernel32.dll'), 'Wow64DisableWow64FsRedirection');

    Wow64DisableWow64FsRedirection(OldFS);
  end;


  // Initialisation de la structure ShellExecuteInfo
  ZeroMemory(@vSEInfo, SizeOf(vSEInfo));

  // Remplissage de la structure ShellExecuteInfo
  vSEInfo.cbSize       := SizeOf(vSEInfo);
  vSEInfo.fMask        := SEE_MASK_NOCLOSEPROCESS;
  vSEInfo.Wnd          := vHandle;
  vSEInfo.lpVerb       := PAnsiChar(vOperation);
  vSEInfo.lpFile       := PAnsiChar(vFichier);
  vSEInfo.lpParameters := PAnsiChar(vParametres);
  vSEInfo.lpDirectory  := PAnsiChar(vRepertoire);
  vSEInfo.nShow        := vAffichage;

  // L'exécution a réussi
  if ShellExecuteEx(@vSEInfo) then
  begin
    // Attendre la fin du process ou une erreur
    while True do
    begin

      case WaitForSingleObject(vSEInfo.hProcess, 250) of

        WAIT_ABANDONED :
        begin
          Result  := False;
          vErreur := 'L''attente a été annulée.';
          Break;
        end;

        WAIT_OBJECT_0 :
        begin
          Break;
        end;

        WAIT_TIMEOUT :
        begin
          // Initialisation
          vAttente := vAttente + 250;

          // Le délai d'attente n'a pas été atteint
          if vAttente < vDuree then
          begin
            Application.ProcessMessages();
          end

          // Le délai d'attente est dépassé
          else
          begin
            Result  := False;
            vErreur := 'Le délai d''attente a été dépassé.';
            Break;
          end;
        end;

        WAIT_FAILED :
        begin
          Result := False;
          vErreur := SysErrorMessage(GetLastError());
          Break;
        end;
      end;
    end;
  end

  // L'exécution a échoué
  else
  begin
    Result  := False;
    vErreur := SysErrorMessage(GetLastError());
  end;

  if Wow64 then
  begin
    Wow64RevertWow64FsRedirection := GetProcAddress(Windows.GetModuleHandle('kernel32.dll'), 'Wow64RevertWow64FsRedirection');
    Wow64RevertWow64FsRedirection(OldFs);
  end;
end;