2010-02-05 46 views
2

我有一個.NET應用程序通過使用ShellExecute的Delphi程序啓動。不幸的是,當以這種方式啓動時,應用程序似乎沒有正確讀取它的app.config文件,就好像文件不存在一樣。當通過ShellExecute調用應用程序時,應用程序配置文件不被讀取

我已經嘗試在其他場景中測試應用程序,例如,從工作目錄設置爲不同的文件夾的快捷方式調用,它運行良好。

[編輯] Environment.CurrentDirectory屬性返回Delphi程序的目錄。

任何想法將非常感激。

乾杯,

詹姆斯

回答

1

那麼我研究了一下,似乎沒有要一個既簡單又優雅的解決方案。

最簡單的方法似乎是調用一箇中間.NET程序,然後通過Process.Start運行目標應用程序,並傳遞參數。不理想,但比迄今爲止我找到的其他解決方案更簡單。

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; 
+0

謝謝, 不幸的是,我不太可能能夠改變Delphi程序,所以如果可能的話我會改變.NET程序。 – James 2010-02-05 10:59:50

+0

在這種情況下,請嘗試確保您從完整路徑中讀取設置文件,例如,獲取本地appdata目錄並從那裏使用固定的子目錄。 – 2010-02-05 13:49:42

+0

我可能沒有在我原來的文章中說清楚,但是我需要app.config文件在使用ConfigurationManager類的任何地方自動使用。我的程序使用了一些第三方庫,它們會自動從app.config文件加載它們的設置,並且它們無法正常工作。 – James 2010-02-06 21:32:13

相關問題