我想从Java中的.lnk文件中提取一些信息,特别是整个目标(在初始.exe之后使用命令行参数)和工作目录。
在用户Windows shortcut (.lnk) parser in Java?
的问题Zarkonnen中,我们可以找到由多个社区用户创建的WindowsShortcut
库。请参阅Code Bling的回答here。
但是,截至目前,此库仅提供对文件路径本身的访问权限,但不提供对命令行参数或工作目录(或可能位于快捷方式文件中的任何其他附加信息)的访问权限。
我试图找出使用WindowsShortcut
库获取其他信息的方法,但没有成功。该库仅向我提供getRealFilename()
方法:
public static void main(String[] args) throws Exception
{
WindowsShortcut windowsShortcut = new WindowsShortcut(new File("C:\test\test.lnk"));
System.out.println(windowsShortcut.getRealFilename());
}
有谁知道这样做的方法?
答案 0 :(得分:0)
你的问题非常好。截至问题发布之日,您引用的WindowsShortcut class仅实现代码以获取快捷方式指向的文件的路径,但不会在快捷方式文件中提供任何进一步的数据。但它是开源的,所以让我们扩展它!
我们先做一些研究
在Jesse Hager的inofficial documentation中,我们发现了这一点:
______________________________________________________________________________
| |
| **The flags** |
|______________________________________________________________________________|
| | | |
| Bit | Meaning when 1 | Meaning when 0 |
|_____|____________________________________|___________________________________|
| | | |
| 0 | The shell item id list is present. | The shell item id list is absent. |
| 1 | Points to a file or directory. | Points to something else. |
| 2 | Has a description string. | No description string. |
| 3 | Has a relative path string. | No relative path. |
| 4 | Has a working directory. | No working directory. |
| 5 | Has command line arguments. | No command line arguments. |
| 6 | Has a custom icon. | Has the default icon. |
|_____|____________________________________|___________________________________|
所以我们知道我们可以检查flags byte
是否存在这些附加字符串。我们已经可以访问flags byte
课程中准备的WindowsShortcut
。
现在我们只需知道这些字符串存储在快捷方式文件中的位置。在非官方文档中,我们也发现了这种结构:
File header
Shell item ID list
Item 1
Item 2
etc..
File locator info
Local path
Network path
Description string
Relative path string
Working directory string
Command line string
Icon filename string
Extra stuff
所以我们感兴趣的字符串直接来自File locator info
块。哪个很好,因为现有的WindowsShortcut
类已经解析了File locator info
以获取文件路径。
文档还说每个字符串由一个长度unsigned short
和ASCII字符组成。但是,至少在Windows10下,我遇到了UTF-16字符串并相应地实现了我的代码。
让我们实施!
我们可以在parseLink
方法的末尾添加更多行。
首先我们在File locator info
块之后直接获得偏移并将其称为next_string_start
,因为它现在指向第一个附加字符串:
final int file_location_size = bytesToDword(link, file_start);
int next_string_start = file_start + file_location_size;
然后我们按顺序检查每个字符串的标志,如果存在,我们会解析它:
final byte has_description = (byte)0b00000100;
final byte has_relative_path = (byte)0b00001000;
final byte has_working_directory = (byte)0b00010000;
final byte has_command_line_arguments = (byte)0b00100000;
// if description is present, parse it
if ((flags & has_description) > 0) {
final int string_len = bytesToWord(link, next_string_start) * 2; // times 2 because UTF-16
description = getUTF16String(link, next_string_start + 2, string_len);
next_string_start = next_string_start + string_len + 2;
}
// if relative path is present, parse it
if ((flags & has_relative_path) > 0) {
final int string_len = bytesToWord(link, next_string_start) * 2; // times 2 because UTF-16
relative_path = getUTF16String(link, next_string_start + 2, string_len);
next_string_start = next_string_start + string_len + 2;
}
// if working directory is present, parse it
if ((flags & has_working_directory) > 0) {
final int string_len = bytesToWord(link, next_string_start) * 2; // times 2 because UTF-16
working_directory = getUTF16String(link, next_string_start + 2, string_len);
next_string_start = next_string_start + string_len + 2;
}
// if command line arguments are present, parse them
if ((flags & has_command_line_arguments) > 0) {
final int string_len = bytesToWord(link, next_string_start) * 2; // times 2 because UTF-16
command_line_arguments = getUTF16String(link, next_string_start + 2, string_len);
next_string_start = next_string_start + string_len + 2;
}
getUTF16String
方法很简单:
private static String getUTF16String(final byte[] bytes, final int off, final int len) {
return new String(bytes, off, len, StandardCharsets.UTF_16LE);
}
最后我们需要成员和吸气者来获得这些新的字符串:
private String description;
private String relative_path;
private String working_directory;
private String command_line_arguments;
public String getDescription() {
return description;
}
public String getRelativePath() {
return relative_path;
}
public String getWorkingDirectory() {
return working_directory;
}
public String getCommandLineArguments() {
return command_line_arguments;
}
我在Windows 10下进行了测试,它就像一个魅力。
我通过对原始回购的更改提出了拉取请求,直到那时您还可以找到完整的代码here。