2

ShellExecuteを使用してDelphiプログラムを介して起動される.NETアプリケーションがあります。残念ながら、この方法で起動すると、ファイルが存在しないかのように、アプリケーションがapp.configファイルを正しく読み取っていないように見えます。

他のシナリオでアプリケーションをテストしてみました。たとえば、作業ディレクトリを別のフォルダに設定してショートカットから呼び出すと、正常に実行されます。

[編集]Environment.CurrentDirectoryプロパティは、Delphiプログラムのディレクトリを返します。

どんなアイデアでも本当にありがたいです。

乾杯、

ジェームズ

4

2 に答える 2

1

少し調べてみましたが、シンプルでエレガントなソリューションはないようです。

最も簡単な方法は、中間の.NETプログラムを呼び出して、Process.Startを介してターゲットアプリケーションを実行し、パラメーターを渡すことです。理想的ではありませんが、これまでに見つけた他のソリューションよりも簡単です。

于 2010-02-05T12:04:47.757 に答える
1

どうやら、あなたがスポーンするプロセスは、作業ディレクトリがそれ自身のものではないという事実を処理することができません。

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;
于 2010-02-05T10:51:32.960 に答える