java检索lnk文件参数和目标

时间:2018-05-29 22:53:38

标签: java lnk

我想从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());
}

有谁知道这样做的方法?

Screenshot of the properties of shortcut file with command line and working directory highlighted

1 个答案:

答案 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