ملف تكوين التطبيق لا يقرأ عند الطلب يسمى عبر shellexecute
-
18-09-2019 - |
سؤال
لدي تطبيق .NET تم إطلاقه عبر برنامج Delphi باستخدام Shellexecute. لسوء الحظ عند إطلاقه بهذه الطريقة، لا يبدو أن التطبيق يقرأ ملف app.config الخاص به بشكل صحيح، كما لو كان الملف غير موجود.
لقد حاولت اختبار التطبيق في سيناريوهات أخرى، على سبيل المثال استدعاء من اختصار مع تعيين دليل العمل إلى مجلد مختلف ويتم تشغيله بشكل جيد.
عدل] Environment.CurrentDirectory ترجع دليل برنامج دلفي.
أي أفكار ستكون موضع تقدير حقا.
هتافات،
جوامع
المحلول 2
حسنا، لقد بحثت عنها قليلا ولا يبدو أن هناك حل بسيط وأنيق.
أسهل طريقة جولة يبدو أنها تسمي برنامج .NET وسيط ثم يدير التطبيق المستهدف عبر Process.Start ويمرر المعلمات. ليس مثاليا ولكنه أبسط من الحلول الأخرى التي وجدتها حتى الآن.
نصائح أخرى
من الواضح أن العملية التي تفرخها لا يمكن التعامل مع حقيقة أن دليل العمل ليس هو نفسه.
يمكنك فتح الملف باستخدام 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;