View previous topic :: View next topic |
Author |
Message |
mozers
![](images/avatars/gallery/Avatar_pack_1/068.gif)
Joined: 16 Dec 2004 Posts: 82 Location: с Нижнего
|
(Separately) Posted: Sat Feb 05, 2005 08:43 Post subject: [ Статья ] Находим местоположение WINCMD.INI |
|
|
Уважаемые авторы замечательных плагинов и полезных утилит!
Большинству из ваших программ требуется указание точного местоположения файла TOTALCMD.EXE и INI файлов настройки Коммандера.
Каждый автор ищет решение этой проблемы по своему:
Одни (самые умные вообще ничего не ищут, а требуют от пользователя вручную заводить эти пути. Решение, конечно, крайне примитивное. И пользователь может ошибиться с указанием путей, да и тулза оказывается жестко привязанной к одному месту. Если пользователь имеет несколько настроенных профилей ТС, то он вынужден держать несколько копий вашей программы - для каждого профиля отдельно
Другие (слава Богу - таких уже почти не осталось) тупо считают, что эти файлы могут называться только wincmd.ini и wcx_ftp.ini и лежат они исключительно в %WINDIR%. Просто нет слов...
Третьи (кто посообразительней), пытаются анализировать содержимое ветки [HKEY_CURRENT_USER\Software\Ghisler\Total Commander] и увы, тоже не всегда бывают правы.
Этой мини-статейкой я попытаюсь проанализировать опыт тех и других и сделать некоторые выводы. Надеюсь они пригодятся вам в дальнейших разработках.
Итак, начнем с самого простого - TOTALCMD.EXE
Он ВСЕГДА находится по %COMMANDER_PATH%/TOTALCMD.EXE
Учтите только что %COMMANDER_PATH% имеется в переменных окружения только тогда, когда ваша прога стартует из ТС. Для авторов плагинов это всегда - факт, утилита же может стартовать и не из ТС.
Уважаемые авторы, заставьте своего пользователя хотя бы в первый раз запустить вашу тулзу из ТС - она запишет найденный путь, и в дальнейшем ее можно будет стартовать откуда угодно. Поверьте, 99% пользователей будут запускать вашу утилиту именно из ТС, а автоматически найденный ею путь будет лишним доказательством вашего профессионализма!
Теперь про поиск INI файлов
Единственно правильный вариант на сегодня:- Анализируем командную строку ТС, ищем в ней ключи /I и /F и считываем пути к INI оттуда.
- Если в ком.строке ключи не найдены, то проверяем, есть ли в файле %COMMANDER_PATH%/wincmd.ini ключ UseIniInProgramDir (Еще одна беда, свалившаяся на нашу голову вместе с версией 6.5). Если есть - то ищем INI файлы в соответствии со значением этого ключа (подробности - в HELP).
- Если там - пусто, то смотрим в [HKEY_CURRENT_USER\Software\Ghisler\Total Commander].
- Если и там - пусто, то INI лежат в %WINDIR% и названия их - wincmd.ini и wcx_ftp.ini
Важные замечания
- Ключи ком.строки /I и /F могут быть в любом регистре, причем второй по очереди ключ может быть и без слеша.
- Пути в ключах ком.строки и реестра могут задаваться как полным путем, так и относительным. В путях можно использовать любые переменные окружения, включая %COMMANDER_PATH%. Пути могут быть заданы и как LongNames и в формате 8.3
- Если пути к файлам заданы явно (ключах ком.строки или реестре), то файлы инициализации могут иметь ЛЮБОЕ имя.
Ну а теперь - поподробнее про анализ ком.строки
Для плагина TC все решается сравнительно просто. А все потому, что он выполняется внутри процесса TC и поэтому получить командную строку можно просто вызвав API-шную функцию GetCommandLine. Кто понимает, о чем я говорю, тому не составит труда извлечь из нее нужные параметры.
Для внешней утилиты все значительно сложнее Решается эта проблема с использованием ловушек (hooks), труб (pipes) и прочих мудреных вещей. Пройти все круги ада и построить рабочую программу смог только Alexander Asyabrik aka Shura (я о ReloadTC). Других, увы, не знаю
Так вот обломали нас в самом начале пути
Однако, есть возможность получить вожделенные пути и несколько иным способом, если мы вспомним о том, что сам ТС прекрастно осведомлен о местоположении своих INI файлов - достаточно взглянуть на окошко "About".
Итак, вкратце: Находим окно активного экземпляра ТС, шлем ему через SendMessage команду cm_About, считываем через GetWindowText драгоценную инфу, закрываем окошко About. Если на время выполнения этой процедуры запретить обновление окна, то получится почти незаметно
Намеренно не говорю о подводных камнях (а то обсуждать будет нечего , а вот положительные стороны данного подхода - налицо. Одним махом находим местоположения обоих INI файлов совершенно независимо от того, как и где задал их пользователь.
P.S. Всего этого разговора могло бы и не быть, если бы глубокоуважаемый Christian Ghisler ввел в обиход пару псевдо-переменных
$MAIN_INI и $FTP_INI (подобно имеющимся уже $MYPICTURES, $LOCAL_APPDATA, $COMMON_APPDATA, и т.п.). Ему то это сделать - плевое дело!
Представьте, как было бы здорово!
Как вам, к примеру, такая команда в меню "Запуск" ?:
Code: |
Команда: disk:/path/MySuperEditor.exe
Параметры: $MAIN_INI $FTP_INI
|
Кому так же больно как мне - отпишите Орлу нашему... |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
TSergey
Joined: 24 Jan 2005 Posts: 49
|
(Separately) Posted: Sat Feb 05, 2005 19:01 Post subject: |
|
|
Может сюда же выложить функции для плагинов?
Сам сразу и начну:
Code: | function GetFtpIniFileName: string;
var
s, s1, s2 :string;
a: array [0..MAX_PATH] of char;
i, j: integer;
EscEn, QuoteStr, UseProgDir: boolean;
c: char;
reg: TRegistry;
begin
// Разбор командной строки
s := StrPas(GetCommandLine);
i := pos('f=', s);
if i = 0 then i := pos('F=', s);
s1 := '';
if i > 0
then begin
i := i + 2;
EscEn := false;
QuoteStr := false;
j := length(s);
// Разворачиваем параметр с поддержкой кавычек
while (i <= j) do
try
c := s[i];
case c of
#9, ' ':
if QuoteStr
then if EscEn
then begin
s1 := s1 + '\'+ c;
EscEn := false;
end
else s1 := s1 + c
else break;
'"':
if EscEn
then s1 := s1 + '"'
else QuoteStr := not QuoteStr;
'\':
if EscEn
then begin
s1 := s1 + '\';
EscEn := false;
end
else EscEn := true;
else if EscEn
then begin
s1 := s1 + '\'+ c;
EscEn := false;
end
else s1 := s1 + c
end;
finally
inc(i);
end;
if EscEn then s1 := s1 + '\';
end;
UseProgDir := false;
if s1 = ''
then begin
// Обрабатываем каталог Тотал Командера
s := '%COMMANDER_PATH%\wincmd.ini';
s2 := '%COMMANDER_PATH%\wcx_ftp.ini';
ExpandEnvironmentStrings(PChar(s), a, MAX_PATH);
i := GetPrivateProfileInt('Configuration', 'UseIniInProgramDir', 0, a);
UseProgDir := (i and 2) <> 0;
if (i and 4) <> 0 then s1 := s2;
end;
if s1 = ''
then begin
// Проверяем реестр
try
Reg := TRegistry.Create(KEY_READ);
try
Reg.RootKey := HKEY_CURRENT_USER;
if Reg.OpenKeyReadOnly('\Software\Ghisler\Total Commander')
then s1 := Reg.ReadString('FtpIniName')
else s1 := '';
finally
Reg.Free;
end;
except
s1 := '';
end;
if (s1 = '')
then if UseProgDir
then s1 := s2
else s1 := 'wcx_ftp.ini';
end;
if (copy(s1, 1, 2) = '.\')
then begin
delete(s1, 1, 2);
s1 := '%COMMANDER_PATH%\' + s1;
end;
ExpandEnvironmentStrings(PChar(s1), a, MAX_PATH);
result := strpas(a);
end; |
ЗЫ. Вроде проверил работу на своем плагине, но ошибки могут быть.
ЗЗЫ. Анекдот про "длинный_мнемоничный_идентификатор_номер_один" - знаю. ![Twisted Evil](images/smiles/icon_twisted.gif)
Last edited by TSergey on Tue Feb 15, 2005 08:31; edited 2 times in total |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
SCHMaster
![](images/avatars/1741352729481b64eaa04ad.jpg)
Joined: 15 Dec 2004 Posts: 296 Location: Киев
|
(Separately) Posted: Sun Feb 06, 2005 04:59 Post subject: |
|
|
%USERPROFILE%
Еще такая хрень бывает... Под ХР и 2К. |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
mozers
![](images/avatars/gallery/Avatar_pack_1/068.gif)
Joined: 16 Dec 2004 Posts: 82 Location: с Нижнего
|
(Separately) Posted: Sun Feb 06, 2005 14:03 Post subject: |
|
|
SCHMaster
Угу. С %USERPROFILE%, как, впрочем, и со всеми остальными переменными окружения (%TEMP%, %ProgramFiles%, ...) все однозначно.
Если они присутствуют в ключах ком.строки или реестра (в ком.строке, в отличии от реестра, длинные пути надо обязательно задавать в кавычках), то Тотал их понимает, а значит и ваша прога должна их знать...
В общем все учесть - с ума сойти можно... И я все больше склоняюсь к тому, чтоб грабить инфу с About. |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
Nik
![](images/avatars/16882057034dfa425d31979.png)
Joined: 01 Jan 2005 Posts: 583 Location: Киров
|
(Separately) Posted: Sun Feb 06, 2005 15:13 Post subject: |
|
|
В интерфейсе Lister-плагинов есть такая структура:
Code: |
type
tListDefaultParamStruct=record
size,
PluginInterfaceVersionLow,
PluginInterfaceVersionHi:longint;
DefaultIniName:array[0..MAX_PATH-1] of char;
end; |
Так вот, есть извлечь путь к DefaultIniName, то получите каталог, где лежат Ini файлы TC. И никакой лишней мороки... Если конечно имена файлов стандартные. |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
CaptainFlint
![](images/avatars/1538602816566b383536f19.png)
Joined: 14 Dec 2004 Posts: 6151 Location: Москва
|
(Separately) Posted: Sun Feb 06, 2005 15:52 Post subject: |
|
|
SAM
Грабить из About'а может не получиться, если именно в это время, например, в Тотале открыт модальный диалог. В лучшем случае ничего не произойдёт, в худшем - крэш.
Nik
Это путь к INI-файлу настроек самого плагина, а не всего Тотала. |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
Alextp
![](images/avatars/11367635284c67c22159bfc.jpg)
Joined: 06 Feb 2005 Posts: 4957
|
(Separately) Posted: Sun Feb 06, 2005 18:37 Post subject: Пример кода |
|
|
Предлагаю Delphi-функции нахождения путей к wincmd.ini и wcx_ftp.ini.
Из исходника TC Plugins Manager, в нем все работает. Если путь, возвращаемый функцией, не найден, то программа запрашивает путь у пользователя.
Модули RegProc.pas/SProc.pas, которые здесь используются, высылаются емейлом.
Code: | function tcDefDir: string;
begin
//поправка SAM-а, чтобы путь брался из запущенного TC
Result:= SProc.SExpandVars('%COMMANDER_PATH%');
//брать из реестра
if Pos(':\', Result)=0 then
Result:=
GetRegKeyStr(HKEY_CURRENT_USER, 'Software\Ghisler\Total Commander', 'InstallDir',
GetRegKeyStr(HKEY_LOCAL_MACHINE, 'Software\Ghisler\Total Commander', 'InstallDir',
'C:\TotalCmd'));
end;
function tcDefExe: string;
begin
Result:= tcDefDir+'\Totalcmd.exe';
end;
function tcDefIni: string;
begin
Result:=
GetRegKeyStr(HKEY_CURRENT_USER, 'SOFTWARE\Ghisler\Total Commander', 'IniFileName',
GetRegKeyStr(HKEY_LOCAL_MACHINE, 'SOFTWARE\Ghisler\Total Commander', 'IniFileName',
'wincmd.ini'));
if Pos('\', Result)=0 then Insert('%windir%\', Result, 1);
//если путь записан как ".\Wincmd.ini":
if Pos('.\', Result)=1 then
SReplace(Result, '.', tcDefDir);
Result:= SExpandVars(Result);
end;
function tcDefIniFtp: string;
begin
Result:=
GetRegKeyStr(HKEY_CURRENT_USER, 'SOFTWARE\Ghisler\Total Commander', 'FtpIniName',
GetRegKeyStr(HKEY_LOCAL_MACHINE, 'SOFTWARE\Ghisler\Total Commander', 'FtpIniName',
'wcx_ftp.ini'));
if Pos('\', Result)=0 then Insert('%windir%\', Result, 1);
//если путь записан как ".\Wincmd.ini":
if Pos('.\', Result)=1 then
SReplace(Result, '.', tcDefDir);
Result:= SExpandVars(Result);
end; |
_________________ UniViewer - CudaText - LogViewer
Last edited by Alextp on Wed Oct 19, 2005 23:40; edited 2 times in total |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
TSergey
Joined: 24 Jan 2005 Posts: 49
|
(Separately) Posted: Sun Feb 06, 2005 18:43 Post subject: |
|
|
Alextp, а где обработка ситуации, когда ini-файлы передаются в командной строке?
SCHMaster, SAM: Все переменные легко разворачиваются в функции ExpandEnvironmentStrings. |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
Alextp
![](images/avatars/11367635284c67c22159bfc.jpg)
Joined: 06 Feb 2005 Posts: 4957
|
(Separately) Posted: Sun Feb 06, 2005 18:52 Post subject: |
|
|
TSergey wrote: | Alextp, а где обработка ситуации, когда ini-файлы передаются в командной строке? |
Нету.
Подразумевается, что как и в комстроке TC, пользователь сам укажет в PlugMan-е этот ini-файл (через кнопку "Обзор"). _________________ UniViewer - CudaText - LogViewer
|
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
TSergey
Joined: 24 Jan 2005 Posts: 49
|
(Separately) Posted: Sun Feb 06, 2005 18:54 Post subject: |
|
|
Alextp wrote: | TSergey wrote: | Alextp, а где обработка ситуации, когда ini-файлы передаются в командной строке? |
Нету.
Подразумевается, что как и в комстроке TC, пользователь сам укажет в PlugMan-е этот ini-файл (через кнопку "Обзор"). | А смысл заставлять пользователя что-то лишнее вводить, если есть вполне нормальный автоматический способ? |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
Alextp
![](images/avatars/11367635284c67c22159bfc.jpg)
Joined: 06 Feb 2005 Posts: 4957
|
(Separately) Posted: Sun Feb 06, 2005 18:57 Post subject: |
|
|
Ну, ты прав, надо бы еще в ф-ции tcDefIni обрабатывать комстроку TC... |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
Nik
![](images/avatars/16882057034dfa425d31979.png)
Joined: 01 Jan 2005 Posts: 583 Location: Киров
|
(Separately) Posted: Sun Feb 06, 2005 20:45 Post subject: |
|
|
CaptainFlint wrote: |
Nik
Это путь к INI-файлу настроек самого плагина, а не всего Тотала. |
Да, но по-умолчанию Total предлагает размещать файлы настройки плагина в той же папке, где и свои собственные... Проверено на AmpView: ранние версии читали цвет фона Lister из файлов конфигурации, а путь к ним я определял именно таким способом... |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
Gosha
Joined: 02 Feb 2005 Posts: 11
|
(Separately) Posted: Sun Feb 06, 2005 21:57 Post subject: |
|
|
Разрешите высказать свое мнение.
Если кому либо было не лень писать командную строку для запуска TC и в ней указать полный путь до INI файлов, то может его не очень смутит тот факт, что левые программы не всегда находят их. И может быть им даже будет также не лень указать где эти файла всетаки находятся. |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
TSergey
Joined: 24 Jan 2005 Posts: 49
|
(Separately) Posted: Sun Feb 06, 2005 22:12 Post subject: |
|
|
Gosha wrote: | Разрешите высказать свое мнение.
Если кому либо было не лень писать командную строку для запуска TC и в ней указать полный путь до INI файлов, то может его не очень смутит тот факт, что левые программы не всегда находят их. И может быть им даже будет также не лень указать где эти файла всетаки находятся. | Хороший подход: пользователи будут довольны и благодарны. ![Twisted Evil](images/smiles/icon_twisted.gif) |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
mozers
![](images/avatars/gallery/Avatar_pack_1/068.gif)
Joined: 16 Dec 2004 Posts: 82 Location: с Нижнего
|
(Separately) Posted: Mon Feb 07, 2005 00:25 Post subject: |
|
|
CaptainFlint
Quote: | Грабить из About'а может не получиться, если именно в это время, например, в Тотале открыт модальный диалог |
Да вроде такой проблемы не заметил :-/ Ничего не вешается, независимо от открытых окон. Попробуй сам...
Nik
Лишь путь А имя?
Gosha
Quote: | Если кому либо было не лень писать командную строку для запуска TC |
Если кому то было не лень написать в своем плагине/утилите процедуру обнаружения пути к INI файлам, то он получил еще плюсом добрую половину благодарных пользователей, покоренных мастерством автора.
Кстати, по моим данным, у более чем 50 тысяч пользователей (большинство из которых - новички), путь к INI задается с ярлыка и выглядит приблизительно так:
С:\Program Files\Total Commander XP\Profiles\Prof\main.ini
А, впрочем, не хватает ума определить правильно - не определяйте вообще! Лучше позволить пользователю задать путь вручную, чем мучится с неработоспособной прогой. |
|
Back to top |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|