Reading the Command Line Parameters from a .lnk file

0

I already have the option to read the target file using JUCE or using the code below. But I also need to be able to read the command line parameters. Something I couldn't figure out yet. I tried the LibLnk library but couldn't find any example on how to actually use it. Any help will be much appreciated. Thanks.

#include <vector>
using namespace std;

String ReadLnkFile(const String strFullLinkFileName)
{
    //-------------------------------------------------------------------------
    // How to read the target's path from a .lnk-file:
    //-------------------------------------------------------------------------
    // Problem:
    //
    //    The COM interface to shell32.dll IShellLink::GetPath() fails!
    //
    // Solution:
    //
    //   We need to parse the file manually. The path can be found like shown
    //   here, if the shell item id list is present. In case it is not present
    //   we have to assume A = -6, but not to parse/decode byte 76 and 77.
    //
    //  +---------------------+-----------------------------------------------+
    //  | Index               | Description                                   |
    //  +---------------------+-----------------------------------------------+
    //  |                   0 | 'L' (magic value)                             |
    //  +---------------------+-----------------------------------------------+
    //  |                 ... | ...                                           |
    //  +---------------------+-----------------------------------------------+
    //  |                  76 | A_0                                           |
    //  +---------------------+-----------------------------------------------+
    //  |                  77 | A_1 (16 bit) [w/o shell item id list: A = -6] |
    //  +---------------------+-----------------------------------------------+
    //  |                 ... | ...                                           |
    //  +---------------------+-----------------------------------------------+
    //  |         78 + 16 + A | B_0                                           |
    //  +---------------------+-----------------------------------------------+
    //  |     78 + 16 + A + 1 | B_1                                           |
    //  +---------------------+-----------------------------------------------+
    //  |     78 + 16 + A + 2 | B_2                                           |
    //  +---------------------+-----------------------------------------------+
    //  |     78 + 16 + A + 3 | B_3 (32 bit)                                  |
    //  +---------------------+-----------------------------------------------+
    //  |                 ... | ...                                           |
    //  +---------------------+-----------------------------------------------+
    //  |          78 + A + B | PATH_STR_0                                    |
    //  +---------------------+-----------------------------------------------+
    //  |      78 + A + B + 1 | PATH_STR_1                                    |
    //  +---------------------+-----------------------------------------------+
    //  |      78 + A + B + 2 | PATH_STR_2                                    |
    //  +---------------------+-----------------------------------------------+
    //  |                 ... | ...                                           |
    //  +---------------------+-----------------------------------------------+
    //  |                 ... | 0x00                                          |
    //  +---------------------+-----------------------------------------------+
    //-------------------------------------------------------------------------

    //-------------------------------------------------------------------------
    // Get the .lnk-file content:
    //-------------------------------------------------------------------------

    FILE* pFile = fopen(strFullLinkFileName.toRawUTF8(), "rb");
    if (!pFile)
        return string("");
    vector<unsigned char> vectBuffer;
    unsigned char byte = '?';
    while ((byte = (unsigned char)fgetc(pFile)) != (unsigned char)EOF)
        vectBuffer.push_back(byte);
    fclose(pFile);

    //-------------------------------------------------------------------------
    // Check the magic value (first byte) and the GUID (16 byte from 5th byte):
    //-------------------------------------------------------------------------
    // The GUID is telling the version of the .lnk-file format. We expect the
    // following GUID (HEX): 01 14 02 00 00 00 00 00 C0 00 00 00 00 00 00 46.
    //-------------------------------------------------------------------------

    if (vectBuffer.size() < 20)
        return string("");
    if (vectBuffer[0] != (unsigned char) 'L') //test the magic value
        return string("");
    if ((vectBuffer[4] != 0x01) || //test the GUID
        (vectBuffer[5] != 0x14) ||
        (vectBuffer[6] != 0x02) ||
        (vectBuffer[7] != 0x00) ||
        (vectBuffer[8] != 0x00) ||
        (vectBuffer[9] != 0x00) ||
        (vectBuffer[10] != 0x00) ||
        (vectBuffer[11] != 0x00) ||
        (vectBuffer[12] != 0xC0) ||
        (vectBuffer[13] != 0x00) ||
        (vectBuffer[14] != 0x00) ||
        (vectBuffer[15] != 0x00) ||
        (vectBuffer[16] != 0x00) ||
        (vectBuffer[17] != 0x00) ||
        (vectBuffer[18] != 0x00) ||
        (vectBuffer[19] != 0x46))
    {
        return string("");
    }

    //-------------------------------------------------------------------------
    // Get the flags (4 byte from 21st byte):
    //-------------------------------------------------------------------------
    // Check if it points to a file or directory!
    //-------------------------------------------------------------------------
    // Flags (4 byte little endian):
    //        Bit 0 -> has shell item id list
    //        Bit 1 -> points to file or directory
    //        Bit 2 -> has description
    //        Bit 3 -> has relative path
    //        Bit 4 -> has working directory
    //        Bit 5 -> has commandline arguments
    //        Bit 6 -> has custom icon
    //-------------------------------------------------------------------------

    unsigned int i = 20;
    if (vectBuffer.size() < (i + 4))
        return string("");
    unsigned int dwFlags = (unsigned int)vectBuffer[i]; //little endian format
    dwFlags |= (((unsigned int)vectBuffer[++i]) << 8);
    dwFlags |= (((unsigned int)vectBuffer[++i]) << 16);
    dwFlags |= (((unsigned int)vectBuffer[++i]) << 24);

    bool bHasShellItemIdList = (dwFlags & 0x00000001) ? true : false;
    bool bPointsToFileOrDir = (dwFlags & 0x00000002) ? true : false;

    if (!bPointsToFileOrDir)
        return string("");

    //-------------------------------------------------------------------------
    // Shell item id list (starts at 76 with 2 byte length -> so we can skip):
    //-------------------------------------------------------------------------

    int32 A = -6;
    if (bHasShellItemIdList)
    {
        i = 76;
        if (vectBuffer.size() < (i + 2))
            return string("");
        A = (unsigned char)vectBuffer[i]; //little endian format
        A |= (((unsigned char)vectBuffer[++i]) << 8);
    }

    //-------------------------------------------------------------------------
    // File location info:
    //-------------------------------------------------------------------------
    // Follows the shell item id list and starts with 4 byte structure length,
    // followed by 4 byte offset for skipping.
    //-------------------------------------------------------------------------

    i = 78 + 4 + A;
    if (vectBuffer.size() < (i + 4))
        return string("");
    unsigned int B = (unsigned int)vectBuffer[i]; //little endian format
    B |= (((unsigned int)vectBuffer[++i]) << 8);
    B |= (((unsigned int)vectBuffer[++i]) << 16);
    B |= (((unsigned int)vectBuffer[++i]) << 24);

    //-------------------------------------------------------------------------
    // Local volume table:
    //-------------------------------------------------------------------------
    // Follows the file location info and starts with 4 byte table length for
    // skipping the actual table and moving to the local path string.
    //-------------------------------------------------------------------------

    i = 78 + A + B;
    if (vectBuffer.size() < (i + 4))
        return string("");
    unsigned int C = (unsigned int)vectBuffer[i]; //little endian format
    C |= (((unsigned int)vectBuffer[++i]) << 8);
    C |= (((unsigned int)vectBuffer[++i]) << 16);
    C |= (((unsigned int)vectBuffer[++i]) << 24);

    //-------------------------------------------------------------------------
    // Local path string (ending with 0x00):
    //-------------------------------------------------------------------------

    i = 78 + A + B + C;
    if (vectBuffer.size() < (i + 1))
        return string("");

    string strLinkedTarget = "";
    for (; i < vectBuffer.size(); ++i)
    {
        strLinkedTarget.append(1, (char)vectBuffer[i]);
        if (!vectBuffer[i])
            break;
    }


    //Return if empty:
    if (strLinkedTarget.empty())
        return string("");

    //-------------------------------------------------------------------------
    // Convert the target path into the long format (format without ~):
    //-------------------------------------------------------------------------
    // GetLongPathNameA() fails it the target file doesn't exist!
    //-------------------------------------------------------------------------

    char* szLinkedTargetLongFormat = new char[MAX_PATH + 1];
    if (!szLinkedTargetLongFormat)
        return string("");
    if (!::GetLongPathNameA(
        strLinkedTarget.c_str(),
        szLinkedTargetLongFormat,
        MAX_PATH))
    {
        return strLinkedTarget; //file doesn't exist
    }
    string strLinkedTargetLongFormat(szLinkedTargetLongFormat);
    delete[] szLinkedTargetLongFormat;

    return String(strLinkedTargetLongFormat);
}```
c++
windows
juce

1 Answer

0

So I ended up using the parser above as it is, the .exe file itself.

{
    String appArguments;
    ChildProcess checkLink;
    String checkLinkCommand = "\"" + parent->workPath + "Launcher/App/lnk_parser_cmd.exe\" \"" + appPath + "\"";
    //
    if (checkLink.start(checkLinkCommand))
    {
        StringArray theoutput = StringArray::fromLines(checkLink.readAllProcessOutput());

        for (int xx = 0; xx < theoutput.size(); xx++)
        {
            if (theoutput[xx].substring(0, 9).contains("Arguments"))
            {
                String appArg2 = theoutput[xx].fromFirstOccurrenceOf(":", false, false);
                //
                for (int ww = 0; ww < appArg2.length(); ww++)
                {
                    if (appArg2[ww] != ' ' && appArg2[ww] != 9)
                    {
                        appArguments = "<" + appArg2.substring(ww);
                        break;
                    }
                }
                break;
            }
        }
        //
.........
    }
    else
    {
        WMessageBox("Error checking linked file!", checkLinkCommand);
    }
}```

User contributions licensed under CC BY-SA 3.0