Форум: "Прочее";
Текущий архив: 2009.11.01;
Скачать: [xml.tar.bz2];
ВнизРазбор командной строки на имя файла и параметры Найти похожие ветки
← →
Eraser © (2009-09-01 20:24) [40]> [28] DVM © (01.09.09 19:55)
> В случае с "выполнить" он не выполняет C:\Program Files\Far\Far.exe
> /min
в висте и 7 выполняет.
/// <summary>Разделение командной строки на путь к файлу и параметры запуска</summary>
/// <param name="ACommandLine">Командная строка</param>
/// <param name="AFilePath">Путь к файлу</param>
/// <param name="AParams">Параметры запуска</param>
procedure SplitCommandLine(ACommandLine: string; var AFilePath, AParams: string);
var
sFile, sParams: string;
sSource: PWideChar;
StringArray: TStringArray;
I, J: Integer;
begin
sFile := "";
sParams := "";
ACommandLine := Trim(ACommandLine);
if FileExists(ACommandLine) then
begin
sFile := ACommandLine;
sParams := "";
end
else
begin
// Ищем вхождение существующего файла.
StringArray := Explode(" ", ACommandLine);
for I := 0 to Length(StringArray) - 1 do
begin
sFile := Trim(sFile + " " + StringArray[I]);
if FileExists(sFile) then
begin
// Файл найден, принимаем оставшуюся часть строки за параметры.
for J := I + 1 to Length(StringArray) - 1 do
sParams := Trim(sParams + " " + StringArray[J]);
Break;
end;
end;
if not FileExists(sFile) then
begin
// Если файл так и не удалось выделить.
// Определяем, указаны ли ковычки.
if Pos(""", sFile) = 1 then
begin
// Ковычки найдены, извлекаем путь с их учетом.
sSource := PChar(sFile);
sFile := SysUtils.AnsiExtractQuotedStr(sSource, Char("""));
sParams := sSource;
end
else
begin
sFile := StringArray[0];
sParams := "";
for I := 1 to Length(StringArray) - 1 do
sParams := Trim(sParams + " " + StringArray[I]);
end;
end;
end;
AFilePath := sFile;
AParams := sParams;
end;
вряд ли подойдет для 100% случаев, но в целом поведение "выполнить" повторяет.
← →
Anatoly Podgoretsky © (2009-09-01 20:25) [41]> DVM (01.09.2009 20:10:36) [36]
Поскольку именя реальные для данной машины и видимо полные, то решение есть и очень простое. Надо выделять слева направо и направо и проверять FileExists/
Например для С:\Program Files\Folder X\File.exe параметры, проверка идет так
1. C:\Program - No
2. С:\Program Files - No
3. С:\Program Files\Folder - No
4. С:\Program Files\Folder X - No
5. С:\Program Files\Folder X\File.exe - Yes
На шаге пять получен правильный вариант и все что правее это параметры
В алгоритме шаги ограничиваются пробелом и ключом (-/)
← →
Eraser © (2009-09-01 20:26) [42]> [40] Eraser © (01.09.09 20:24)
в догонкуfunction Explode(const ASeparator, ASource: string; ALimit: Integer = 0): TStringArray;
var
SepLen: Integer;
F, P: PChar;
begin
SetLength(Result, 0);
if (ASource = "") or (ALimit < 0) then
Exit;
if ASeparator = "" then
begin
SetLength(Result, 1);
Result[0] := ASource;
Exit;
end;
SepLen := Length(ASeparator);
P := PChar(ASource);
while P^ <> #0 do
begin
F := P;
P := AnsiStrPos(P, PChar(ASeparator));
if (P = nil) or ((ALimit > 0) and (Length(Result) = ALimit - 1)) then
P := StrEnd(F);
SetLength(Result, Length(Result) + 1);
SetString(Result[High(Result)], F, P - F);
F := P;
while (P^ <> #0) and (P - F < SepLen) do
Inc(P);
end;
end;
← →
DVM © (2009-09-01 20:30) [43]
> Eraser © (01.09.09 20:24) [40]
Важные замечания, которые не учитывает функция:
1) У файла может не быть расширения
2) У файла может не быть пути (путь файла должен быть восстановлен после просмотра %PATH% и прочих системных папок)
Что такое TStringArray и Explode?
← →
Eraser © (2009-09-01 20:34) [44]> [43] DVM © (01.09.09 20:30)
> Важные замечания, которые не учитывает функция:
согласен.
> Explode?
> TStringArraytype
TStringArray = array of string;
← →
DVM © (2009-09-01 20:34) [45]
> Anatoly Podgoretsky © (01.09.09 20:25) [41]
> Например для С:\Program Files\Folder X\File.exe параметры,
> проверка идет так
>
> 1. C:\Program - No
> 2. С:\Program Files - No
> 3. С:\Program Files\Folder - No
> 4. С:\Program Files\Folder X - No
> 5. С:\Program Files\Folder X\File.exe - Yes
>
Ошибка запросто может возникнуть на первом же шаге, т.к. в пути необязательно указано расширение файла, а следовательно, если на диске будет файл C:\Program.exe то он будет взят за искомый этим алгоритмом что неверно!
← →
Eraser © (2009-09-01 20:36) [46]> [45] DVM © (01.09.09 20:34)
> Ошибка запросто может возникнуть на первом же шаге, т.к.
> в пути необязательно указано расширение файла, а следовательно,
> если на диске будет файл C:\Program.exe то он будет взят
> за искомый этим алгоритмом что неверно!
тут надо эксперементальным путем смотреть, как реализовано у MS, в любом случае, думаю какие-то ноухау там вряд ли применяются.
← →
DVM © (2009-09-01 20:38) [47]
> Eraser © (01.09.09 20:36) [46]
> тут надо эксперементальным путем смотреть, как реализовано
> у MS
Этим и занимаюсь, предположительно просмотр идет с конца, тогда описанной проблемы в [45] вроде бы не должно быть.
← →
DVM © (2009-09-01 20:43) [48]В Shlwapi.dll есть две функции, котрыми мог пользоваться эксплорер, это:
PathRemoveArgsW(), PathGetArgsW(), проверил, они тоже спотыкаются об имя файла с пробелами и без кавычек, тупо отрезают считают все что до первого пробела именем, остальное параметрами.
← →
TIF © (2009-09-01 21:14) [49]> Потому что второй myexe является параметром.
Правильно.
И мой алгоритм работает аналогично:
А)
> начать проверку с конца и остановиться на первом пробеле,
> после этого сказав - стоп! Всё что слева - путь, всё что
> справа - параметры
или если нет \
Б)
> успешно доходим до начала строки, а оринтируемся на последний
> с конца (первый с начала) пробел
> Разбираем слева направо строку C:\Program Files\Folder\File
> /param
Вариант А - ибо есть \
← →
TIF © (2009-09-01 21:17) [50]> и остановиться на первом пробеле,
ЧОрт. Вру, вру, вру... Не на первом. Отпадает. Тогда до последнего пробела перед \
← →
DVM © (2009-09-01 21:24) [51]
> TIF © (01.09.09 21:14) [49]
Зря мучишся, вот тебе командная строка:
file name1 file name2
Никаких тебе \ и прочего.
Тем не менее, при наличии на диске file name1.exe в одной из доступных папок он будет запущен и ему параметром будет передан file name2
← →
TIF © (2009-09-01 21:41) [52]> он будет запущен
У меня не будет:
> У меня "Выполнить" в Windows такого не понимает.
PS: win 7
← →
DVM © (2009-09-01 21:45) [53]
> TIF © (01.09.09 21:41) [52]
> У меня "Выполнить" в Windows такого не понимает
Так речь не о Пуск - > Выполнить же. Я про автозагрузку - там проблем нет, все выполняется.
← →
TIF © (2009-09-01 22:16) [54]> Я про автозагрузку
Как всегда в винде везде всё по-разному %-\
← →
DVM © (2009-09-01 22:30) [55]Короче, вот реализация, которая меня более-менее устроила, по крайней мере разобрала все имеющиеся ключи у меня в реестре.
unit uCmdLineHelper;
interface
uses
Windows, SysUtils;
function SplitCommandLine(CmdLine: string; var FileName, Arguments: string): boolean;
implementation
function GetParamStr(P: PChar; var Param: string): PChar;
var
i, Len: Integer;
Start, S: PChar;
begin
while True do
begin
while (P[0] <> #0) and (P[0] <= " ") do
Inc(P);
if (P[0] = """) and (P[1] = """) then Inc(P, 2) else Break;
end;
Len := 0;
Start := P;
while P[0] > " " do
begin
if P[0] = """ then
begin
Inc(P);
while (P[0] <> #0) and (P[0] <> """) do
begin
Inc(Len);
Inc(P);
end;
if P[0] <> #0 then
Inc(P);
end
else
begin
Inc(Len);
Inc(P);
end;
end;
SetLength(Param, Len);
P := Start;
S := Pointer(Param);
i := 0;
while P[0] > " " do
begin
if P[0] = """ then
begin
Inc(P);
while (P[0] <> #0) and (P[0] <> """) do
begin
S[i] := P^;
Inc(P);
Inc(i);
end;
if P[0] <> #0 then Inc(P);
end
else
begin
S[i] := P^;
Inc(P);
Inc(i);
end;
end;
Result := P;
end;
//------------------------------------------------------------------------------
function ParamCountFromCommandLine(CmdLine: PChar): Integer;
var
S: string;
P: PChar;
begin
P := CmdLine;
Result := 0;
while True do
begin
P := GetParamStr(P, S);
if S = "" then Break;
Inc(Result);
end;
end;
//------------------------------------------------------------------------------
function ParamStrFromCommandLine(CmdLine: PChar; Index: Integer): string;
var
P: PChar;
begin
P := CmdLine;
while True do
begin
P := GetParamStr(P, Result);
if (Index = 0) or (Result = "") then Break;
Dec(Index);
end;
end;
//------------------------------------------------------------------------------
procedure SplitCommandLine1(const CmdLine: string; var ExeName, Params: string);
var
Buffer: PChar;
Cnt, I: Integer;
S: string;
begin
ExeName := "";
Params := "";
Buffer := StrPCopy(StrAlloc(Length(CmdLine) + 1), CmdLine);
try
Cnt := ParamCountFromCommandLine(Buffer);
if Cnt > 0 then begin
ExeName := ParamStrFromCommandLine(Buffer, 0);
for I := 1 to Cnt - 1 do begin
S := ParamStrFromCommandLine(Buffer, I);
if Pos(" ", S) > 0 then S := """ + S + """;
Params := Params + S;
if I < Cnt - 1 then Params := Params + " ";
end;
end;
finally
StrDispose(Buffer);
end;
end;
//------------------------------------------------------------------------------
procedure SplitCommandLine2(CmdLine: string; var FilePath, Arguments: string);
var
i: integer;
TempStr: string;
begin
CmdLine := Trim(CmdLine);
FilePath := "";
Arguments := "";
if CmdLine = "" then Exit;
CmdLine := StringReplace(CmdLine, """, "", [rfReplaceAll]);
TempStr := "";
for i := 1 to Length(CmdLine) do
begin
TempStr := TempStr + CmdLine[i];
if FileExists(TempStr) then
begin
FilePath := TempStr;
Delete(CmdLine, 1, i);
Arguments := Trim(CmdLine);
Break;
end;
end;
end;
//------------------------------------------------------------------------------
function ExpandEnvironment(const CmdLine: string): string;
var
Buff: array[0..MAX_PATH - 1] of Char;
Ret: DWORD;
begin
Ret := ExpandEnvironmentStrings(PChar(CmdLine), Buff, MAX_PATH);
if Ret = 0 then
Result := CmdLine
else
SetString(Result, Buff, Ret);
end;
//------------------------------------------------------------------------------
function SearchPath(FileName: string): string;
var
Buff: array[0..MAX_PATH] of Char;
n: PChar;
Len: integer;
begin
Result := "";
if FileExists(FileName) then
begin
Result := FileName;
exit;
end;
Len := Windows.SearchPath(nil, PChar(FileName), ".exe", MAX_PATH, Buff, n);
if Len > 0 then
SetString(Result, Buff, Len);
end;
//------------------------------------------------------------------------------
function SplitCommandLine(CmdLine: string; var FileName, Arguments: string): boolean;
begin
result := false;
CmdLine := ExpandEnvironment(CmdLine);
SplitCommandLine1(CmdLine, FileName, Arguments);
FileName := SearchPath(FileName);
if FileName = "" then
SplitCommandLine2(CmdLine, FileName, Arguments);
Result := FileName <> "";
end;
end.
← →
Игорь Шевченко © (2009-09-01 23:21) [56]Система парсит строку запуска слева направо (что, в общем-то очевидно), если имя файла не заключено в кавычки, то после очередного найденного пробела запускается цикл поиска \, если символ найден, то пробел считается частью имени файла, если не найден, то считается, что имя файла закончилось до этого пробела.
Поэтому файл "run me please.exe" без кавычек запустить не получится
← →
DVM © (2009-09-01 23:45) [57]
> Игорь Шевченко © (01.09.09 23:21) [56]
> Поэтому файл "run me please.exe" без кавычек запустить не
> получится
Но только не в случае запуска такой строки из реестра!
Можете проверить:
1) В папке Windows создайте копию блокнота с именем run me.exe
2) создайте в ключе HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run новый параметр типа REG_SZ со значением run me please.txt
3) Логофф/логон юзера
Запустится блокнот и предложит создать файл please.txt
← →
Eraser © (2009-09-02 00:08) [58]> [56] Игорь Шевченко © (01.09.09 23:21)
это в давно устаревших версиях ОС.
← →
DVM © (2009-09-02 00:50) [59]Небольшая поправка к [55]. Как раз для того, чтобы он корректно воспринимал строки вида run me please.txt
function SearchPath(FileName: string): string;
var
Buff: array[0..MAX_PATH - 1] of Char;
n: PChar;
Len: integer;
begin
Result := "";
if FileExists(FileName) then
begin
Result := FileName;
exit;
end;
Len := Windows.SearchPath(nil, PChar(FileName), nil, MAX_PATH, Buff, n);
if Len > 0 then
SetString(Result, Buff, Len);
end;
//------------------------------------------------------------------------------
procedure SplitCommandLine2(CmdLine: string; var FilePath, Arguments: string);
var
i: integer;
TempStr, a, b: string;
begin
CmdLine := Trim(CmdLine);
FilePath := "";
Arguments := "";
if CmdLine = "" then Exit;
CmdLine := StringReplace(CmdLine, """, "", [rfReplaceAll]);
TempStr := "";
for i := 1 to Length(CmdLine) do
begin
TempStr := TempStr + CmdLine[i];
a := TempStr;
a := SearchPath(a);
if FileExists(a) then
begin
FilePath := a;
Delete(CmdLine, 1, Length(TempStr));
Arguments := Trim(CmdLine);
Break;
end;
end;
if FilePath <> "" then Exit;
TempStr := "";
for i := 1 to Length(CmdLine) do
begin
TempStr := TempStr + CmdLine[i];
b := TempStr + ".exe";
b := SearchPath(b);
if FileExists(b) then
begin
FilePath := b;
Delete(CmdLine, 1, Length(TempStr));
Arguments := Trim(CmdLine);
Break;
end;
end;
end;
← →
Игорь Шевченко © (2009-09-02 01:13) [60]
> это в давно устаревших версиях ОС.
Э...а что это - "давно устаревшие версии ОС" ?
← →
Игорь Шевченко © (2009-09-02 01:20) [61]DVM © (01.09.09 23:45) [57]
Действительно выполняется. Я скопировал notepad.exe в run me please.exe и в реестре создал параметр со значением run me please foo
Запустился блокнот. Windows XP SP3.
Осталось выяснить, это поведение происходит на уровне CreateProcess или таки несколько на более высоком уровне. Но пример писать лень.
← →
brother © (2009-09-02 05:29) [62]я воообще проблеммы не понимаю...
C:\Program Files\Flashget\flashget.exe /min
>
> Я никак не могу понять, как он понимает где здесь имя файла,
> где параметр? Кавычек нет, слеш в параметре тоже необязателен.
C:\Program Files\Flashget\ - путь тк он корректен (пробел тож в счет)
flashget.exe - имя файла тк. есть расширение и фактически C:\Program Files\Flashget\flashget.exe он присутствует
/min - dct все что после пробела - параметр...
я что-то упустил?
← →
brother © (2009-09-02 05:34) [63]имхо, кавычками пользователь явно объявляет, что я вляется именем файла и путями, исключая нужность парсить...
> Осталось выяснить, это поведение происходит на уровне CreateProcess
> или таки несколько на более высоком уровне.
имхо - CreateProcess...
← →
DVM © (2009-09-02 07:51) [64]
> brother © (02.09.09 05:29) [62]
> я что-то упустил?
Упустил тот момент, что пути, которые я разбираю, уже имеются в реестре, и их внешний вид вне зависимости от моих желаний и может быть от нормального до вот такого: run me please.exe,
но т.к. с точки зрения системы такое допустимо, то мне надо так же. Только запускать эти файла не надо, мне иконки с них тащить надо, а это возможно только вытащив полный и нормальный путь к файлу.
← →
DVM © (2009-09-02 07:56) [65]
> имхо - CreateProcess...
Если бы это было реализовано в CreateProcess, то Пуск -> Выполнить хватало бы пути вида run me please.exe. Однако ж не понимает, в XP по крайней мере. Следовательно ни CreateProcess, ни даже ShellExecute не обладают способностью понимать такие пути. Очевидно, эксплорер разбирает сначала сам, а потом уже ShellExecute.
← →
Skyle © (2009-09-02 08:16) [66]
> DVM © (02.09.09 07:56) [65]
Очевидно, эксплорер разбирает сначала сам, а потом уже ShellExecute.
В этом смысле интересно было бы попробовать альтернативный шелл, астон какой-нибудь или far.
← →
brother © (2009-09-02 08:39) [67]> а это возможно только вытащив полный и нормальный путь к
> файлу.
тогда [62] +
начинать слева до первого \ , тк имя файла без расширения не предвидится)
← →
DVM © (2009-09-02 08:42) [68]
> brother © (02.09.09 08:39) [67]
Да я уже собственно сделал. Работает пока без нареканий. Вытащил все пути.
← →
brother © (2009-09-02 08:42) [69]> Работает пока без нареканий. Вытащил все пути.
парсишь слева или справа?
← →
DVM © (2009-09-02 08:45) [70]
> парсишь слева или справа?
слева, прибавляя по одному символу, каждый раз проверяя нет ли файла среди доступных в Path и т.д. каталогах, если нет, то проверяю еще раз прибавив .exe на конце.
← →
Anatoly Podgoretsky © (2009-09-02 09:51) [71]> brother (02.09.2009 05:29:02) [62]
Упустил, расширение тоже не обязательно и тут возможны варианты, подразумевалось .ехе а запустился .сом
← →
Anatoly Podgoretsky © (2009-09-02 09:53) [72]> DVM (02.09.2009 07:51:04) [64]
И этот момент тоже упустил.
← →
Anatoly Podgoretsky © (2009-09-02 09:57) [73]> DVM (02.09.2009 08:45:10) [70]
Это же неправильно (по символам и с прибавлением .exe), могут быть file.exe и filename.exe в одной папке и получается, что вместо filename.exe будет использовано file.exe и такая ситуация норма.
← →
DVM © (2009-09-02 10:56) [74]
> Anatoly Podgoretsky ©
> И этот момент тоже упустил.
> могут быть file.exe и filename.exe в одной папке и получается
Я об этом писал выше, и именно поэтому я говорил парсить справа налево, хотя это тоже не 100% гарантия. Но похоже тут уже ничего не поделаешь.
← →
DVM © (2009-09-02 10:58) [75]
> Anatoly Podgoretsky © (02.09.09 09:51) [71]
>
> > brother (02.09.2009 05:29:02) [62]
>
> Упустил, расширение тоже не обязательно и тут возможны варианты,
> подразумевалось .ехе а запустился .сом
Об этом тоже думал, но пока решил COM не учитывать. Если по хорошему там еще и BAT и CMD файлы.
← →
Anatoly Podgoretsky © (2009-09-02 11:10) [76]> DVM (02.09.2009 10:56:14) [74]
Ну я могу повторить - полного решения нет.
← →
Anatoly Podgoretsky © (2009-09-02 11:11) [77]> DVM (02.09.2009 10:58:15) [75]
Естественно, что это подразумевается.
← →
brother © (2009-09-02 11:41) [78]> пути, которые я разбираю, уже имеются в реестре
> Если по хорошему там еще и BAT и CMD файлы.
О_О и иконки из них тырить ваще круто)
← →
DVM © (2009-09-02 12:11) [79]
> brother © (02.09.09 11:41) [78]
> О_О и иконки из них тырить ваще круто)
А что у тебя в окне папки BAT и CMD файлы не обозначены иконками? Прямо так черное место вместо иконки?
← →
brother © (2009-09-02 13:52) [80]> Прямо так черное место вместо иконки?
мы же понимаем, откуда система берет эти иконки)
Страницы: 1 2 3 вся ветка
Форум: "Прочее";
Текущий архив: 2009.11.01;
Скачать: [xml.tar.bz2];
Память: 0.65 MB
Время: 0.008 c