0

I would like to extract some info from a .lnk file in Java, specifically the entire target (with command line parameters after the initial .exe) and the working directory as well.

In the question Windows shortcut (.lnk) parser in Java? by user Zarkonnen we can find the WindowsShortcut library created by multiple community users. See Code Blings answer here.

However, as of now, this library provides only access to the file path itself, but not to command line arguments or working directory (or any other additional info that might be inside a shortcut file).

I tried to figure out a way to get the additional info using the WindowsShortcut library, but didn't succeed. The library only provides me with a getRealFilename() method:

public static void main(String[] args) throws Exception
{
    WindowsShortcut windowsShortcut = new WindowsShortcut(new File("C:\test\test.lnk"));
    System.out.println(windowsShortcut.getRealFilename());
}

Does anyone know of a way to do this?

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

8
  • those libraries are what was proposed as an answer on this topic: stackoverflow.com/questions/309495/… Commented May 30, 2018 at 0:12
  • ` File file = (File)list.get(0); System.out.println(file.getAbsolutePath()); System.out.println(file.getCanonicalPath()); System.out.println(file.getPath()); WindowsShortcut ws = new WindowsShortcut(file); System.out.println(ws.getRealFilename()); LnkParse lp = new LnkParse(); lp.parse(file.getPath()); System.out.println(lp.getFullPath()); System.out.println(lp.getLocalPath()); System.out.println(lp.getShareName());` Commented May 30, 2018 at 0:16
  • I always get the anything.exe part but not the arguments after it. Commented May 30, 2018 at 0:17
  • Thanks for your clarifications. However please don't provide essential information in comments. I think your question has potential to be a really good one, if you edit it with a reference to the lnk parser question and a minimal reproducible example with desired and actual output. I will upvote once you've done that. Commented May 30, 2018 at 1:50
  • 1
    I took the liberty of rewriting your question, because I really like the problem you were facing and think it's a valuable addition to StackOverflow. If you're unhappy with the changes, feel free to edit it again. Commented Jun 2, 2018 at 0:29

1 Answer 1

1

Your question is really good. As of the date of your question the WindowsShortcut class you refer to only implements code to get the path to the file pointed to by a shortcut, but doesn't provide any further data inside a shortcut file. But it's open source, so let's extend it!

Let's do some research first

In the inofficial documentation by Jesse Hager we find this:

 ______________________________________________________________________________
|                                                                              |
|  **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.             |
|_____|____________________________________|___________________________________|

So we know that we can check the flags byte for the existence of these additional strings. And we already have access to the flags byte prepared in our WindowsShortcut class.

Now we only need to know where those strings are stored in the shortcut file. In the inofficial documentation we also find this structure:

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

So the strings we are interested in come directly after the File locator info block. Which is neat, because the existing WindowsShortcut class already parses the File locator info to get the file path.

The docs also say that each string consists of a length given as unsigned short and then ASCII characters. However, at least under Windows10, I encountered UTF-16 strings and implemented my code accordingly.

Let's implement!

We can simply add a few more lines at the end of the parseLink method.

First we get the offset directly after the File locator info block and call it next_string_start, as it now points to the first additional string:

final int file_location_size = bytesToDword(link, file_start);
int next_string_start = file_start + file_location_size;

We then check the flags for each of the strings in order, and if it exists, we parse it:

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;
}

The getUTF16String method is simply:

private static String getUTF16String(final byte[] bytes, final int off, final int len) {
    return new String(bytes, off, len, StandardCharsets.UTF_16LE);
}

And finally we need members and getters for those new Strings:

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;
}

I tested this under Windows 10 and it worked like a charm.

I made a pull request with my changes on the original repo, until then you can also find the complete code here.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.