Java получить параметры файла LNK и цель - PullRequest
0 голосов
/ 30 мая 2018

Я хотел бы извлечь некоторую информацию из файла .lnk на Java, в частности всю цель (с параметрами командной строки после исходного .exe), а также рабочий каталог.

В вопросе Парсер ярлыка Windows (.lnk) в Java? по пользователю Zarkonnen мы можем найти библиотеку WindowsShortcut, созданную несколькими пользователями сообщества.См. Code Bling s answer здесь .

Однако на данный момент эта библиотека предоставляет доступ только к самому пути к файлу, но не к аргументам командной строки или рабочимдиректории (или любой другой дополнительной информации, которая может быть внутри файла ярлыка).

Я пытался найти способ получить дополнительную информацию, используя библиотеку 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 голосов
/ 02 июня 2018

Ваш вопрос действительно хорош.На дату вашего вопроса класс WindowsShortcut , на который вы ссылаетесь, реализует только код для получения пути к файлу, на который указывает ярлык, но не предоставляет никаких дополнительных данных внутри файла ярлыка.Но это открытый исходный код, поэтому давайте расширим его!

Давайте сначала проведем небольшое исследование

В неофициальной документации Джесси Хагера *1010* мы находим следующее:

 ______________________________________________________________________________
|                                                                              |
|  **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, и это сработало как прелесть.

Я сделал запрос на удаление с моими изменениями наОригинальный репо, до этого вы также можете найти полный код здесь .

...