代码之家  ›  专栏  ›  技术社区  ›  James

通过ShellExecute调用应用程序时未读取应用程序配置文件

  •  2
  • James  · 技术社区  · 16 年前

    我曾尝试在其他场景中测试该应用程序,例如,在工作目录设置为其他文件夹的情况下从快捷方式调用,但运行正常。

    任何想法都将不胜感激。

    干杯

    詹姆斯

    2 回复  |  直到 16 年前
        1
  •  1
  •   Ritsaert Hornstra    16 年前

    显然,您生成的进程无法处理工作目录不是它自己的这一事实。

    可以使用CreateProcess()打开该文件。我有一个关于等待的小例子(但你可以删掉它):

    procedure ExecuteAndWaitFor(CommandLine, CurrentDirectory: string; Environment: TStrings);
    var
      List: TList;
      ActiveWin: HWnd;
      i: Integer;
      Ret: Longword;
      SI: TStartupInfo;
      PI: TProcessInformation;
      MadeForeground: Boolean;
      AssociatedCommandLine: string;
    begin
      // find the association ot use
      AssociatedCommandLine := GetAssociatedCommandLine(CommandLine);
      // first we create a list of windows which we need to block...
      List := TList.Create;
      try
        ActiveWin := Windows.GetForegroundWindow;
        // get the list of all visible and active top windows...
        if not Windows.EnumThreadWindows(GetCurrentThreadId,@InternallyThreadWindowCallback,Integer(List)) then RaiseLastOSError;
        // disable all those windows...
        for i := 0 to List.Count - 1 do Windows.EnableWindow(HWnd(List[i]),False);
        try
          // create the process
          System.FillChar(SI,sizeof(SI),0);
          SI.cb := sizeof(SI.cb);
          // todo: environment
          if not Windows.CreateProcess(nil,PChar(AssociatedCommandLine),nil,nil,False,NORMAL_PRIORITY_CLASS,nil,PChar(CurrentDirectory),SI,PI) then RaiseLastOSError;
          // wait until the process is finished...
          MadeForeGround := False;
          repeat
            // process any pending messages in the thread's message queue
            Application.ProcessMessages;
            if not MadeForeground then begin
              Windows.EnumThreadWindows(PI.dwThreadId,@InternallyTopWindowToForeMost,Integer(@MadeForeGround));
            end;
            // wait for a message or the process to be finished
            Ret := Windows.MsgWaitForMultipleObjects(1, PI.hProcess, False, INFINITE, QS_ALLINPUT);
            if Ret = $FFFFFFFF then RaiseLastOSError;
          until Ret = 0;
          // free the process handle
          Windows.CloseHandle(PI.hProcess);
          WIndows.CloseHandle(PI.hThread);
        finally
          // enable all those windows
          for i := 0 to List.Count - 1 do Windows.EnableWindow(HWnd(List[i]), True);
        end;
        Windows.SetForegroundWindow(ActiveWin);
      finally
        List.Free;
      end;
    end;
    

    添加了一些缺少的实用程序功能:

    uses
      SysUtils, Registry;
    
    function GetAssociatedFile(const Extension: string; const RemoveParameters: Boolean = False): string;
    var
      FileClass: string;
      Reg: TRegistry;
      Position: Integer;
    begin
      // initialize
      Result := '';
      // create registry entry
      Reg := TRegistry.Create(KEY_EXECUTE);
      try
        // find the given extension
        Reg.RootKey := HKEY_CLASSES_ROOT;
        FileClass := '';
        if Reg.OpenKeyReadOnly(ExtractFileExt(Extension)) then begin
          FileClass := Reg.ReadString('');
          Reg.CloseKey;
        end;
        if FileClass <> '' then begin
          if Reg.OpenKeyReadOnly(FileClass + '\Shell\Open\Command') then begin
            Result := Reg.ReadString('');
            Reg.CloseKey;
          end;
        end;
      finally
        Reg.Free;
      end;
      // remove the additional parameters
      Position := Pos('"%1"', Result);
      if RemoveParameters and (Position > 0) then
        Result := Trim(Copy(Result, 1, Position - 1))
      else
        Result := Trim(Result);
    end;
    
    function GetAssociatedCommandLine(const CommandLine: string): string;
    begin
      // build the command line with the associated file in front of it
      Result := Trim(GetAssociatedFile(CommandLine, True) + ' ') + '"' + CommandLine + '"';
    end;
    
    function InternallyThreadWindowCallback(Window: HWnd; Data: Longint): Bool; stdcall;
    var
      List: TList;
    begin
      Result := True;
      if (not IsWindowVisible(Window)) or (not IsWindowEnabled(Window)) then Exit;
      List := TList(Data);
      List.Add(Pointer(Window));
    end;
    
    function InternallyTopWindowToForeMost(Window: HWnd; Data: LongInt): Bool; stdcall;
    begin
      Result := True;
      if (not IsWindowVisible(Window)) or (not IsWindowEnabled(Window)) then Exit;
      SetForegroundWindow(Window);
      PBoolean(Data)^ := True;
    end;
    
        2
  •  1
  •   James    16 年前

    我研究了一下,似乎没有一个既简单又优雅的解决方案。

    推荐文章