Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 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?


> TStringArray

type
 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
15-1251715556
Kolan
2009-08-31 14:45
2009.11.01
Компонент Линия


15-1252009806
Юрий
2009-09-04 00:30
2009.11.01
С днем рождения ! 4 сентября 2009 пятница


6-1209043050
tytus
2008-04-24 17:17
2009.11.01
NetWkstaUserGetInfo - как правильно использовать?


2-1252429844
wah
2009-09-08 21:10
2009.11.01
Oптимизировать загр. txt-файла в StringList и дальше в RichEdit


2-1252477927
AlexDan
2009-09-09 10:32
2009.11.01
bat файл, создание и работа





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский