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

.net 通过ShellExecute调用应用程序时未读取应用程序配置文件,.net,delphi,app-config,shellexecute,.net,Delphi,App Config,Shellexecute,我有一个.NET应用程序,它是通过使用ShellExecute的Delphi程序启动的。不幸的是,当以这种方式启动时,应用程序似乎无法正确读取其app.config文件,就好像该文件不存在一样 我曾尝试在其他场景中测试该应用程序,例如,在工作目录设置为其他文件夹的情况下从快捷方式调用,但运行正常 [编辑]Environment.CurrentDirectory属性返回Delphi程序的目录 任何想法都将不胜感激 干杯 James显然,您生成的进程无法处理工作目录不是它自己的这一事实 可以使用Cr

我有一个.NET应用程序,它是通过使用ShellExecute的Delphi程序启动的。不幸的是,当以这种方式启动时,应用程序似乎无法正确读取其app.config文件,就好像该文件不存在一样

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

[编辑]Environment.CurrentDirectory属性返回Delphi程序的目录

任何想法都将不胜感激

干杯


James

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

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

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

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;
使用
SysUtils,注册表;
函数GetAssociatedFile(常量扩展名:string;常量RemoveParameters:Boolean=False):string;
变量
FileClass:string;
注册:树木学;
位置:整数;
开始
//初始化
结果:='';
//创建注册表项
Reg:=TRegistry.Create(KEY\u EXECUTE);
尝试
//查找给定的扩展名
Reg.RootKey:=HKEY_CLASSES_ROOT;
FileClass:='';
如果注册表为OpenKeyReadOnly(ExtractFileExt(扩展名)),则开始
FileClass:=Reg.ReadString(“”);
注册关闭键;
结束;
如果文件类为“”,则开始
如果Reg.OpenKeyReadOnly(FileClass+'\Shell\Open\Command'),则开始
结果:=Reg.ReadString(“”);
注册关闭键;
结束;
结束;
最后
注册免费;
结束;
//删除附加参数
位置:=位置(“%1”,结果);
如果移除参数和(位置>0),则
结果:=修剪(复制(结果,1,位置-1))
其他的
结果:=修剪(结果);
结束;
函数GetAssociatedCommandLine(const CommandLine:string):string;
开始
//使用前面的关联文件生成命令行
结果:=Trim(GetAssociatedFile(CommandLine,True)+'+''''+'''+''+'命令行+'''”;
结束;
函数InternallyThreadWindowCallback(窗口:HWnd;数据:Longint):Bool;stdcall;
变量
名单:TList ;;
开始
结果:=真;
如果(非IsWindowVisible(窗口))或(非IsWindowEnabled(窗口))则退出;
列表:=TList(数据);
添加(指针(窗口));
结束;
函数InternallyTopWindowToForest(窗口:HWnd;数据:LongInt):Bool;stdcall;
开始
结果:=真;
如果(非IsWindowVisible(窗口))或(非IsWindowEnabled(窗口))则退出;
SetForegroundWindow(窗口);
PBoolean(数据)^:=真;
结束;

我对它进行了一些研究,似乎没有一个既简单又优雅的解决方案


最简单的方法似乎是调用一个中间的.NET程序,然后通过Process.Start运行目标应用程序并传递参数。不理想,但它比我目前找到的其他解决方案更简单。

谢谢,不幸的是,我不太可能更改Delphi程序,因此如果可能,我将更改.NET程序。在这种情况下,请确保您从完整路径读取设置文件,例如,获取本地appdata目录并从那里使用一个固定的子目录。我可能在我的原始帖子中没有明确说明,但我需要app.config文件在使用ConfigurationManager类的任何地方自动使用。“我的程序使用了一些第三方库,这些库会自动从app.config文件加载它们的设置,但它们工作不正常。@詹姆斯:那么,您一方面有一个无法更改的Delphi应用程序,另一方面您自己的应用程序有一些无法更改的第三方DLL。问题是当前工作目录在启动时不正确。->你应该在问题中澄清这一点。也许您可以将当前目录设置为在应用程序中执行的第一件事,或者在启动时直接加载DLL。在这种情况下,您确实需要一些启动程序应用程序来启动您的应用程序,并将CWD正确设置为DLL的预期值。嗨,Ritsaert,我的问题发布得相当匆忙,因为我有一个截止日期,但我确实在我的原始帖子中提到,在正常启动程序时,我已经测试了更改工作目录的效果,并且仍然有效。我确实在Main方法的早期尝试过更改工作目录,但没有解决问题。我认为问题不在于工作目录,而在于进程如何创建以及.NET如何工作的一些副作用。无论如何,我已经解决了这个问题,并且我已经将你的答案标记为有用,所以请让我们就此结束。
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;