Java получить параметры файла lnk и цель

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

В вопросе Синтаксический анализатор ярлыков Windows (.lnk) в Java? пользователя Зарконнен мы можем найти библиотеку WindowsShortcut, созданную несколькими пользователями сообщества. См. Ответ Код Blings здесь.

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

Я попытался найти способ получить дополнительную информацию с помощью библиотеки 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());
}

Кто-нибудь знает, как это сделать?

Java получить параметры файла lnk и цель

эти библиотеки - это то, что было предложено в качестве ответа по этой теме: stackoverflow.com/questions/309495/…

fen 30.05.2018 02:12

`Файл file = (Файл) list.get (0); System.out.println (файл.getAbsolutePath ()); System.out.println (файл.getCanonicalPath ()); System.out.println (file.getPath ()); WindowsShortcut ws = новый WindowsShortcut (файл); System.out.println (ws.getRealFilename ()); LnkParse lp = новый LnkParse (); lp.parse (file.getPath ()); System.out.println (lp.getFullPath ()); System.out.println (lp.getLocalPath ()); System.out.println (lp.getShareName ()); `

fen 30.05.2018 02:16

Я всегда получаю часть something.exe, но не аргументы после нее.

fen 30.05.2018 02:17

Спасибо за разъяснения. Однако, пожалуйста, не предоставляйте важную информацию в комментариях. Я думаю, что ваш вопрос может быть действительно хорошим, если вы отредактируете его со ссылкой на lnk parser вопрос и минимальный воспроизводимый пример с желаемым и фактическим результатом. Я буду поддерживать, как только вы это сделаете.

Max Vollmer 30.05.2018 03:50

Я бы хотел, но мне нечего показать, так как я не знаю, как им пользоваться. Все, что я знаю, это то, что в этом классе нет метода для получения рабочего каталога и аргументов. Я прочитал все, что мог найти в Google, и хотя я нашел несколько ссылок на рабочий каталог и некоторые смещения, содержащиеся в файлах lnk, которые я пытался использовать, имитируя некоторые из устройств, которые использовались для анализа другой информации в этом классе, ничего работал до сих пор. Я предоставил класс, который использовал, и снимок экрана с данными, которые я хочу извлечь. Я не уверен, что любая из моих случайных попыток может помочь кому-либо ответить на эту тему.

fen 30.05.2018 21:02

Я взял на себя смелость переписать ваш вопрос, потому что мне очень нравится проблема, с которой вы столкнулись, и я считаю ее ценным дополнением к StackOverflow. Если вы недовольны изменениями, не стесняйтесь редактировать их снова.

Max Vollmer 02.06.2018 02:29

Спасибо за ваше время и извините, что больше ничем не могу помочь. Я буду работать над тем, что вы разместили, и отправлю еще раз, когда закончу. Я должен был упомянуть, что я никогда не работал с низкоуровневым кодом (манипулирование байтами и т. д.), И я не знаком с этими концепциями, значения 0x18 и тому подобное на самом деле не похожи на то, что я нашел в отношении интересующей меня информации in (более длинные значения ..?), и попытка использовать их вместо этого не дала ожидаемых строк (все, что я получил, было «êÊ € Ķ *} Ê € 6 ± ð} Ê»).

fen 02.06.2018 12:57

Я работал над перетаскиванием приложения Swing, предназначенным для извлечения данных командной строки из ярлыков, чтобы интегрировать их в базу данных и вместо этого использовать их из моего приложения. Еще раз спасибо.

fen 02.06.2018 12:58
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
8
852
1

Ответы 1

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

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

В неофициальная документация Джесси Хагера мы находим это:

 ______________________________________________________________________________
|                                                                              |
|  **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, и он отлично сработал.

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

Другие вопросы по теме