简体   繁体   English

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

[英]Delphi 7 32 bits execute and wait 64 bits process

I used to use the function below to start and wait unil the end of a process. 我曾经使用下面的函数启动并等待unil结束进程。

It works fine for starting and waiting for 32 bits process on a 32 bits or 64 bits OS. 它适用于在32位或64位OS上启动和等待32位进程。

But on a 64 bits OS, it returns immediately when i launch a 64 bits process (WaitForSingleObject = WAIT_OBJECT_0). 但是在64位操作系统上,当我启动64位进程(WaitForSingleObject = WAIT_OBJECT_0)时它会立即返回。

For example, if my app (32 bits), launch mstsc.exe on a 32 bits OS it is ok but it don't wait on a 64 bits OS certainly because mstsc.exe is a 64 bits program. 例如,如果我的应用程序(32位),在32位操作系统上启动mstsc.exe就可以,但它不会在64位操作系统上等待,因为mstsc.exe是一个64位程序。

Any solution ? 有解决方案吗

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;

My guess is that the following happens: 我的猜测是发生以下情况:

  1. You have a 32 bit process running in the WOW64 emulator under 64 bit Windows. 您在64位Windows下的WOW64仿真器中运行了32位进程。
  2. You attempt to start a new process named mstsc.exe . 您尝试启动名为mstsc.exe的新进程。
  3. The system searches on the path for that and finds it in the system directory. 系统在路径上搜索并在系统目录中找到它。
  4. Because you run under WOW64, the system directory is the 32 bit system directory, SysWOW64. 因为您在WOW64下运行,所以系统目录是32位系统目录SysWOW64。
  5. The process starts and immediately detects that it is a 32 bit process running under WOW64 under a 64 bit system. 该过程启动并立即检测到它是在64位系统下在WOW64下运行的32位进程。
  6. The 32 bit mstsc.exe then determines that it needs to start the 64 bit version of mstsc.exe , which it does, passing on any command line arguments, and then immediately terminates. 然后32位mstsc.exe确定它需要启动mstsc.exe的64位版本,它会传递任何命令行参数,然后立即终止。

This would explain why your new process immediately terminates. 这可以解释为什么您的新流程会立即终止。

Some possible solutions: 一些可能的解决方

  1. Disable file system redirection before you start the new process. 在启动新进程之前禁用文件系统重定向。 Obviously you should re-enable it immediately afterwards. 显然你应该在之后立即重新启用它。
  2. Create a small 64 bit program that lives in the same directory as your executable, whose sole job is to launch programs. 创建一个小的64位程序,该程序与可执行文件位于同一目录中,其唯一的工作是启动程序。 You can start this process and ask it to launch the other process. 您可以启动此过程并要求它启动其他过程。 That would allow you to escape from the clutches of the emulator and its redirection. 这将允许您逃离模拟器的离合器及其重定向。

In the case of launching mstsc.exe from a 32 bits program on a 64 OS, I modified the function like this (it is a first try not the definitive version) ans it works like a charm ! 在从64位OS上的32位程序启动mstsc.exe的情况下,我修改了这样的功能(这是第一次尝试而不是最终版本),它就像一个魅力!

Thank you @DavidHeffernan ! 谢谢@DavidHeffernan!

But be aware that if you don't know what process will be lauched (and its behavio) you need to consider @RemyLebeau global solution. 但请注意,如果您不知道将推出什么流程(及其行为),您需要考虑@RemyLebeau全球解决方案。

Thanks you ! 谢谢 !

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM