【问题标题】:How do I create a shortcut (.lnk) with a relative target?如何创建具有相对目标的快捷方式 (.lnk)?
【发布时间】:2011-03-26 00:22:47
【问题描述】:
我的磁盘上的 dir\program\prog.exe 中有一个可执行文件
我想在 DoK 的根目录上有一个可执行文件的快捷方式,即 prog.lnk 将引用 dir\program\prog.exe。
但是,prog.lnk 似乎没有相对目标。当 DoK 分配不同的驱动器号时,这是一个问题,具体取决于它连接到的 PC。
除了将 prog.exe 放在根目录中的明显建议之外,还有什么建议吗?
(最终,我想在安装时使用 nsis 执行此操作)
谢谢,
罗尼
【问题讨论】:
标签:
windows
installation
nsis
shortcut
【解决方案1】:
如果我们假设 cmd.exe 对于所有 Windows 安装都在同一个绝对路径上(可能,但不是万无一失),您可以找出 .lnk 文件来像这样启动 cmd
cmd.exe /c start /d. your command here
/d 设置目录为.lnk文件所在目录
启动命令可能还有其他有用的选项(例如 /b)
【解决方案2】:
虽然快捷方式可以包含到目标的相对路径(.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 似乎可以工作,但我不确定是否会在生产代码中使用它
一个更好的解决方案是像 Oleg 建议的那样创建一个小的 NSIS 应用程序(NSIS 应用程序可以在 .exe 的末尾包含嵌入式数据,它可以在运行时从自身读取等。)
【解决方案3】:
安装“相对”
我正在使用一些技巧。该方法显示在此屏幕截图中:
它启动 explorer.exe,然后像这样传递一个相对路径:
%windir%\explorer.exe path\to\your\files\youFileName.example
我为此使用small tool called "Relative"。安装后,您可以右键单击一个文件,然后选择Create relative shortcut...。然后它会弹出一个Save as... 框。这不像简单的拖放那样舒服,但它有帮助。 (它还为它创建的链接使用自己的特殊图标。因此,链接中不再有原始图标。见上文。您可能喜欢也可能不喜欢。)
【解决方案4】:
你是对的。您不能在可移动媒体上使用快捷方式 (.lnk),因为就像您自己写的一样,可移动媒体在不同情况下可能有不同的驱动器号。
如果您需要在驱动器的根目录中添加某些内容,请使用 CMD、VBS 或 JS 而不是快捷方式。在某些情况下,还使用标准 EXE,它使用像 INI 文件这样的配置文件从另一个子目录启动另一个程序。 CD/DVD 的典型做法是在插入磁盘后启动安装程序。可能这种方式也可以满足您的要求吗?
【解决方案5】:
我相信 NT 4 Resource Kit 命令SHORTCUT.exe 会创建相对链接的快捷方式。我希望 Microsoft 将创建一个新的受支持实用程序或 Powershell Cmdlet 以促进相关 .lnk 文件的创建或使 NTFS 链接更像 Linux 符号链接。在那之前,我为此目的使用 .cmd/.bat 和 .ps1 文件。
Program.cmd
@"%~dp0Relative\Path\Program.exe" %*
- @ = 抑制命令回显。
- %~dp0 = 展开到脚本目录。
- Relative\Path = 可以包含 .. 来备份目录。
- %* = 将脚本接收到的任何参数传递给 Program.exe。
Program.ps1
不幸的是,尽管 .cmd/.bat 文件可以从任何上下文(运行对话框、CMD 提示、Powershell 中、双击文件资源管理器等)运行,但它们无法调用存储在 UNC 路径中的内容。为了在 UNC 路径中公开内容,在 Powershell 中(我为 Git 和 Mercurial 等工具执行此操作),我将创建上述脚本的 Powershell 版本。
&"$PSScriptRoot\Relative\Path\Program.exe" @args
- & = 将 Powershell 置于命令模式,以便运行引号中的字符串。
- "" = 包含一个字符串,扩展任何变量。
- $PSScriptRoot = 展开到脚本的目录。
- Relative\Path = 可以包含 .. 来备份目录。
- @args = 将脚本接收到的任何参数传递给 Program.exe。