:: MVP ::
|
|
:: RSS ::
|
|
|
Для начала вспомним, в чем разница между абсолютным и относительным путями?
Абсолютный путь (например, C:\Windows) неизменен и интерпретируется одинаково независимо от текущей рабочей папки,
в то время как относительный путь не включает одно или несколько имен родительских папок (начиная с корня диска),
заменяя их либо обозначением .. (две точки, например, ..\autoexec.bat), либо ссылаясь на файлы внутри текущей папки
(например, System32\calc.exe). Ярлыки с относительными путями могут быть актуальны для флэшек, которые на разных
компьютерах могут иметь разную букву, но при этом всегда будут запускать файл, на который они ссылаются.
Ярлыки с абсолютным путем создаются в Windows очень легко, чего не скажешь о ярлыках с относительным путем. А если мы
хотим добиться работоспособности таких ярлыков как в Windows 7, так и, скажем, в Windows XP - все, приехали, тушите свет!
Однако не все так плохо, выход есть. Посмотрим на следующую файловую структуру (попутно обратив внимание на пробелы в именах
каталогов и файлов, это важно, и нужно про это не забыть).
В папке _files есть 2 папки - files и output. Папка files содержит файлы, для которых нужно создать ярлыки с относительными
путями в папке output. В конечном итоге должно получиться следующее:
Так как все ярлыки складываются в одну папку, для исключения конфликта имен я решил давать имена, отражающие относительный путь
до этих файлов, за исключением специальных имен вида ..\, при этом обратный слеш (\) я меняю на нижнее подчеркивание (_).
Разберем, как будет выглядеть относительный путь для ярлыка на файл _files\files\1 2.txt. Так как ярлык будет лежать в папке
_files\output\, то нужно будет подняться на один уровень вверх, и в итоге относительный путь будет выглядеть так:
..\files\1 2.txt.
Но ярлык с таким путем создать не получится. Корректная команда для запуска файла по относительному пути должна иметь следующий
вид:
%comspec% /C "start /B /D ..\files\ ..\files\1" "2.txt"
|
%comspec% - то же самое, что и %windir%\system32\cmd.exe
Вызываем консоль и выполняем команду start. Обратите внимание на то, как указывается путь к файлу. Сначала указывается каталог,
в котором находится нужный нам файл, затем указывается тот же самый каталог, но уже с файлом. Попутно отмечаем что кавычки
обрамляют все пробелы, которые имеются в относительном пути и названии файла, это важно!
Посмотрим на код примера, решающего описанную выше задачу:
function CreateShortcut(const CmdLine, Args, IconFile, LinkFile: string): IPersistFile;
begin
// Код функции создания ярлыка смотрите в прилагаемом примере
end;
procedure MakeLnkFile(fName, OutputDir: string);
function Claer(Dir: string; const Pattern: string): string;
var
i, Сount: Integer;
begin
Сount := 0;
for i := 1 to Length(Pattern) do
begin
if i > Length(Dir) then
Break;
if Dir[i] = Pattern[i] then
Inc(Сount)
else
Break;
end;
if Сount > 0 then
Result := Copy(Dir, Сount+1, Length(Dir)-Сount);
end;
var
&Path, &File, &Dots: string;
begin
// Вычисляем путь к файлу, обрамляя пробелы двойными кавычками
&Path := ExtractFilePath(fName);
&Path := Claer(&Path, OutputDir);
&Path := IncludeTrailingPathDelimiter(TRegEx.Replace(&Path, '(\s+)', '"$1"'));
// Вычисляем, на сколько уровней вверх нужно подняться
&Dots := Claer(IncludeTrailingPathDelimiter(OutputDir), fName);
&Dots := TRegEx.Replace(&Dots, '[^\\]+', '..');
// Вычисляем имя файла, обрамляя пробелы двойными кавычками
&File := ExtractFileName(fName);
&File := TRegEx.Replace(&File, '(\s+)', '"$1"');
CreateShortcut('%comspec%',
'/C "start /B /D ' + &Dots+&Path + ' ' + &Dots+&Path+&File + '"',
&Dots + Claer(fName, OutputDir),
IncludeTrailingPathDelimiter(OutputDir) +
ChangeFileExt(TRegEx.Replace(Claer(fName, OutputDir), '\\+', '_'), '.lnk'));
end;
function SearchFiles(Dir: string; const OutputDir: string): Boolean;
var
isFound: Boolean;
sRec: TSearchRec;
begin
isFound := FindFirst(IncludeTrailingPathDelimiter(Dir) + '*.*', faAnyFile, sRec) = 0;
while isFound do
begin
if (sRec.Name <> '.') and (sRec.Name <> '..') then
if (sRec.Attr and faDirectory) = faDirectory then
begin
if not SearchFiles(IncludeTrailingPathDelimiter(Dir) + sRec.Name, OutputDir) then
Exit;
end
else
// Для найденного файла создаем ярлык
MakeLnkFile(IncludeTrailingPathDelimiter(Dir) + sRec.Name, OutputDir);
isFound := FindNext(sRec) = 0;
end;
FindClose(sRec);
Result := IOResult = 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SearchFiles(
ExtractFilePath(Application.ExeName) + '..\..\_files\files\',
ExtractFilePath(Application.ExeName) + '..\..\_files\output\');
ShellExecute(Handle, 'open',
PChar(ExtractFilePath(Application.ExeName) + '..\..\_files\output\'),
'', '', SW_SHOWNORMAL);
end;
|
Теперь можно переносить каталог _files куда угодно, ярлыки будут исправно работать, главное не менять структуру вложенных каталогов.
.: Пример к данной статье :.
|
При использовании материала - ссылка на сайт обязательна
|
|