我有一个使用ShellExecute通过Delphi程序启动的.NET应用程序。不幸的是,当以这种方式启动时,应用程序似乎没有正确读取其app.config文件,就好像该文件不存在一样。
我已尝试在其他方案中测试该应用程序,例如从工作目录设置为不同文件夹的快捷方式调用它运行正常。
[Edit] Environment.CurrentDirectory属性返回Delphi程序的目录。
任何想法都会非常感激。
干杯,
詹姆斯
答案 0 :(得分: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;
答案 1 :(得分:1)
我研究了一下,似乎没有一个简单而优雅的解决方案。
最简单的方法似乎是调用一个中间的.NET程序,然后通过Process.Start运行目标应用程序并传递参数。不理想,但它比我到目前为止找到的其他解决方案更简单。