0

我想从 Java 中的 .lnk 文件中提取一些信息,特别是整个目标(在初始 .exe 之后带有命令行参数)和工作目录。

Java 中的 Windows 快捷方式 (.lnk) 解析器问题中? 通过用户Zarkonnen,我们可以找到WindowsShortcut由多个社区用户创建的库。在此处查看Code Bling的答案。

但是,到目前为止,该库仅提供对文件路径本身的访问,而不提供对命令行参数或工作目录(或可能在快捷方式文件中的任何其他附加信息)的访问。

我试图找出一种使用该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());
}

有谁知道这样做的方法?

突出显示命令行和工作目录的快捷方式文件属性的屏幕截图

4

1 回答 1

1

你的问题真的很好。截至您提出问题的日期,您引用的WindowsShortcut 类仅实现代码以获取快捷方式指向的文件的路径,但不提供快捷方式文件内的任何进一步数据。但它是开源的,所以让我们扩展它吧!

让我们先做一些研究

在 Jesse Hager 的非官方文档中,我们发现:

 ______________________________________________________________________________
|                                                                              |
|  **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 下测试了它,它就像一个魅力。

我对原始存储库的更改提出了拉取请求,在此之前您还可以在此处找到完整的代码。

于 2018-06-02T00:17:56.150 回答