Как создать ярлык (.lnk) с относительной целью?

У меня есть исполняемый файл на моем диске на ключе в каталоге dir\program\prog.exe Я хотел бы иметь ярлык для исполняемого файла в корневом каталоге DoK, то есть prog.lnk будет ссылаться на dir\program\prog .исполняемый.

Однако похоже, что у prog.lnk не может быть относительной цели. Это проблема, когда для DoK будут назначены разные буквы дисков, в зависимости от того, к какому ПК он подключен.

Любые предложения, кроме очевидного размещения prog.exe в корневом каталоге?

(в конечном счете, я хотел бы сделать это во время установки с помощью nsis)

Спасибо,

Рони


person ronys    schedule 05.08.2010    source источник


Ответы (5)


Хотя ярлыки могут содержать относительный путь к цели (файлы .lnk имеют флаг с именем SLDF_HAS_RELPATH) NSIS не поддерживает создание чего-либо, кроме «обычных» ярлыков, поэтому вам нужно напрямую записывать двоичные данные (формат .lnk довольно стабилен и задокументирован MS)

!macro FileWriteHexBytes h b
push ${h}
push ${b}
call FileWriteHexBytes
!macroend
Function FileWriteHexBytes
exch $9
exch
exch $0
push $1
push $2
loop:
    StrCpy $2 $9 2
    StrLen $1 $2
    IntCmp $1 2 0 end
    FileWriteByte $0 "0x$2"
    StrCpy $9 $9 "" 2
    goto loop
end:
pop $2
pop $1
pop $0
pop $9
FunctionEnd


Function CreateRelativeLnk
exch $9
exch
exch $0
push $1
FileOpen $0 "$0" w
StrCmp $0 "" clean
!insertmacro FileWriteHexBytes $0 "4C0000000114020000000000C000000000000046"
!insertmacro FileWriteHexBytes $0 48010400 ;flags
!insertmacro FileWriteHexBytes $0 00000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000

StrLen $1 $9 ;must be < 255!
FileWriteByte $0 $1
FileWriteByte $0 0
FileWrite $0 "$9" ;relative target path

!if 0
;The icon is problematic, does not seem like it works with relative paths (but you can use system icons...)
StrCpy $9 "explorer.exe"
StrLen $1 $9
FileWriteByte $0 $1
FileWriteByte $0 0
FileWrite $0 "$9"
!else
!insertmacro FileWriteHexBytes $0 05003e2e657865 ;fake default .exe icon
!endif

clean:
FileClose $0
pop $1
pop $0
pop $9
FunctionEnd

Назовите это так:

push "$temp\testlink.lnk"
push "testdir\testapp.exe" ;full path to this is $temp\testdir\testapp.exe
call CreateRelativeLnk

Хотя сгенерированный .lnk, кажется, работает, я не уверен, что буду использовать его в производственном коде.

Гораздо лучшим решением является создание небольшого приложения NSIS, как предлагает Олег (приложения NSIS могут содержать встроенные данные в конце .exe, которые они могут считывать из себя во время выполнения и т. д.).

person Anders    schedule 06.08.2010
comment
Документация по формату файла .lnk: msdn.microsoft.com/en-us/library/ dd871305.aspx - person n611x007; 12.09.2013

Если мы предположим, что cmd.exe будет находиться на одном и том же абсолютном пути для всех установок Windows (вероятно, но не надежно), вы можете разобрать файл .lnk для запуска cmd следующим образом.

cmd.exe /c start /d. your command here

/d устанавливает каталог в каталог файла .lnk

Могут быть и другие полезные параметры для команды запуска (например, /b).

person Elijah    schedule 24.08.2010

Установить относительный

Я использую небольшой хак. Подход показан на этом снимке экрана:

Он запускает explorer.exe, а затем передает относительный путь следующим образом:

%windir%\explorer.exe path\to\your\files\youFileName.example

Для этого я использую небольшой инструмент Relative. После его установки вы можете щелкнуть файл правой кнопкой мыши и выбрать Create relative shortcut.... Затем появится окно Save as.... Это не так удобно, как простое перетаскивание, но помогает. (Он также использует свой собственный специальный значок для создаваемых им ссылок. Таким образом, у вас больше нет исходного значка в ссылке. См. выше. Вам это может понравиться или не понравиться.)

person basil    schedule 04.09.2013

Ты прав. Вы не можете использовать ярлыки (.lnk) на съемном носителе, потому что, как вы сами написали, съемный носитель может иметь разные буквы дисков в разных ситуациях.

Если вам нужно иметь что-то в корневом каталоге диска, используйте CMD, VBS или JS вместо ярлыка. В некоторых ситуациях можно также использовать стандартный EXE-файл, который использует файл конфигурации, такой как файл INI, для запуска другой программы из другого подкаталога. Обычной практикой для CD/DVD является запуск программы установки после вставки диска. Возможно, этот способ подойдет и для ваших требований?

person Oleg    schedule 05.08.2010

Я полагаю, что команда NT 4 Resource Kit SHORTCUT.exe создаст ярлыки с относительными ссылками. Я бы хотел, чтобы Microsoft создала новую поддерживаемую утилиту или командлет Powershell, чтобы облегчить создание относительных файлов .lnk или сделать ссылки NTFS более похожими на символические ссылки Linux. До тех пор я использую для этой цели файлы .cmd/.bat и .ps1.

Program.cmd

@"%~dp0Relative\Path\Program.exe" %*
  • @ = Подавляет эхо команды.
  • %~dp0 = расширяется до каталога скрипта.
  • Relative\Path = может включать .. для резервного копирования каталога.
  • %* = передает любые параметры, полученные сценарием, в Program.exe.

Программа.ps1

К сожалению, хотя файлы .cmd/.bat будут запускаться из любого контекста (диалоговое окно запуска, приглашение CMD, в Powershell, двойной щелчок в проводнике и т. д.), они не могут вызывать объекты, хранящиеся в пути UNC. Для демонстрации вещей в пути UNC в Powershell (я делаю это для таких инструментов, как Git и Mercurial), я создам Powershell-версию приведенного выше скрипта.

&"$PSScriptRoot\Relative\Path\Program.exe" @args
  • & = переводит Powershell в командный режим, чтобы запускалась строка в кавычках.
  • "" = содержит строку, расширяющую любые переменные.
  • $PSScriptRoot = расширяется до каталога скрипта.
  • Relative\Path = может включать .. для резервного копирования каталога.
  • @args = передает любые параметры, полученные сценарием, в Program.exe.
person Nathan Hartley    schedule 29.05.2016