Jeśli moja aplikacja została uruchomiona przy pomocy pliku .bat, to jak w programie mogę odczytać nazwę tego .bat'a?
Czy sposób pozyskania będzie różny dla różnych komend batcha:
start proces.exe
call proces.exe
process.exe
?
@m_Lesiu - najpierw poczytaj sobie o tym, czym te sposoby się różnią:
Sprawdź sobie też opis systemu pomocy w CMD (polecenia help start
i help call
) a zrozumiesz czym się te komendy różnią; IMO jeśli chcesz przekazać uruchamianej aplikacji nazwę pliku wywołującego (wsadowego), możesz to zrobić podając ścieżkę tego pliku w parametrze wywołania.
Chodzi o to, że moja aplikacja może być uruchamiana w przeróżny sposób. Ktoś może ją odpalić dwuklikiem, ktoś wsadzić ją do batcha i wywołać CALL'em ktoś wywołać STATR'em. A ja bym chciał wyświetlić w programie w jaki sposób i ew. z jakiego batcha został wywołany mój program.
@m_Lesiu - a czy rozpoznanie sposobu uruchomienia procesu jest dla Twojej aplikacji koniecznością? Czy ta aplikacja działa zależnie od sposobu uruchomienia? Bo jeśli nie, to takie wodotryski nie będą użytkownikowi potrzebne; Funkcjonalność tych komend jest różna, ale dla plików .exe nie ma większego znaczenia której się użyje;
Według mnie nie za bardzo istnieje możliwość sprawdzenia tego, bo rozruchem programu zajmuje się system i wspomnianych informacji raczej nie przekazuje dalej (oprócz parametrów); Bez względu na to, czy żądanie rozruchu napłynęło z powłoki systemu, pliku wsadowego czy innej aplikacji;
Oczywiście mogę się mylić - na wylot systemu nie znam, jednak nie podejrzewam, żeby była możliwość sprawdzenia i rozróżnienia elementu wywołującego.
Chodzi o to, że niektórzy użytkownicy uruchamiają ten program kilkanaście razy na jednym komputerze, każdą instancję z innymi parametrami.(Załóżmy, że każdy proces z innego batcha.) Okazuje się, że któraś instancja została źle skonfigurowana. I teraz biedny użytkownik nie wie w którym z miliona batchy ma to poprawić. Po czym bierze: widły, pochodnie, woła resztę użytkowników i przychodzą mi do pokoju.
To loguj parametry wywołania.
Takie próby "wyniuchania" czegoś o systemie zwykle są nieprzenośne i przy następnym Windows mogą nie działać.
Logowanie będzie zawsze działać, chyba że użyjesz Windows Events - wtedy tak jak wyżej.
http://stackoverflow.com/questions/30229826/writing-to-the-windows-event-log-using-delphi
Można uzyskać nazwę pliku BAT ale ten kod zadziała tylko w nowszych systemach (chyba od Vista)
type
PROCESS_BASIC_INFORMATION = packed record
ExitStatus: DWORD;
PebBaseAddress: Pointer;
AffinityMask: DWORD;
BasePriority: DWORD;
UniqueProcessId: DWORD;
InheritedUniquePID:DWORD;
end;
function NtQueryInformationProcess(ProcessHandle : THandle; ProcessInformationClass : DWORD; ProcessInformation : Pointer; ProcessInformationLength : ULONG; ReturnLength : PULONG ): LongInt; stdcall; external 'ntdll.dll';
//-----
implementation
{$R *.dfm}
uses
ActiveX,
ComObj;
function GetCommandLineFromPid(ProcessId:DWORD): string;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet: OLEVariant;
begin;
Result:='';
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
//if the pid not exist a EOleException exception will be raised with the code $80041002 - Object Not Found
FWbemObjectSet:= FWMIService.Get(Format('Win32_Process.Handle="%d"',[ProcessId]));
Result:=FWbemObjectSet.CommandLine;
end;
function GetParentCommandLine(): string;
var
hProc: THandle;
ProcessBasicInfo: PROCESS_BASIC_INFORMATION;
ReturnLength: Cardinal;
begin
result:= '';
hProc:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, GetCurrentProcessID);
if hProc > 0 then
begin
//pobranie rodzica procesu
if (NtQueryInformationProcess(hProc, 0, @ProcessBasicInfo, sizeof(ProcessBasicInfo), @ReturnLength) = 0)
and (ReturnLength=SizeOf(ProcessBasicInfo)) then
result:= GetCommandLineFromPid(ProcessBasicInfo.InheritedUniquePID);
CloseHandle(hProc);
end;
end;
procedure TForm1.FormCreate(Sender: TObject); //przyklad uzycia
begin
CoInitialize(nil);
try
Caption:= GetParentCommandLine();
finally
CoUninitialize;
end;
end;
bez względu na sposób uruchamiania w pliku BAT będziesz miał coś w stylu a z tego nazwę pliku to już raczej nie problem:
C:\Windows\system32\cmd.exe /c ""C:\Users\kAzek\Documents\Embarcadero\Studio\Projects\Win32\Debug\test.bat" "
Żeby nie było że to ja taki mądry najważniejsza funkcja GetCommandLineFromPid pochodzi z https://theroadtodelphi.com/2011/07/20/two-ways-to-get-the-command-line-of-another-process-using-delphi/ tam zaprezentowane są 2 sposoby pierwszy z użyciem funkcji WinApi a drugi WMI. Wybrałem drugi, bo pierwszy nie działa dla 64bit procesów (nie znam odpowiedników stałych OffsetProcessParametersx32
i OffsetCommandLinex32
a to najprawdopodobniej przez to nie działa) .