美文网首页
Windows 通过快捷方式获取软件所在路径

Windows 通过快捷方式获取软件所在路径

作者: l蓝色梦幻 | 来源:发表于2019-10-11 14:14 被阅读0次

    Windows 快捷方式种类

    Windows 上包含有两种快捷方式:

    1. Non-advertised shortcut (Standard Shortcuts)
    2. Advertised shortcut (Windows Installer Shortcuts)

    Non-advertised shortcut

    Non-advertised shortcut.jpg

    该快捷方式中明显的位置在于存在有 Target。并且 Target 就是运行程序所在位置。

    通过 IShellLink 可以读取出该 Target 值。

    Advertised shortcut

    Advertised shortcut.jpg

    该快捷方式中不存在 Target。并且指向的也不是特定的文件。它由 Windows Installer 创建。支持高级功能,修复等功能。

    通过 IShellLink 读取出的 Target 值是错误的。类似这种:C:\Windows\Installer\{A6D7B449-8F4F-4FA9-B80A-101345AA998A}\***.ico

    如何通过快捷方式获取到准确的安装路径

    通过 MSI 的 API,我们找到了 MsiGetShortcutTarget 接口。该接口用于获取 Advertised shortcut 的路径。当返回为空的时候,快捷方式为 Non-advertised shortcut。详细解析参考 Microsoft

    那么读取路径的思路就来了。

    1. 通过 MsiGetShortcutTarget 读取路径,如果有路径,则快捷方式为 Advertised shortcut,直接返回。
    2. 如果不存在路径,说明该快捷方式为 Non-advertised shortcut, 使用 IShellLink 读取快捷方式的 Target 即可。

    附代码如下:

    HRESULT ResolveShortcut(/*in*/ std::wstring linkFilePath, /*out*/ LPTSTR exePath) {
        HRESULT hRes = E_FAIL;
        IShellLink* psl = nullptr;
    
        TCHAR szPath[MAX_PATH] = { 0 };
        WIN32_FIND_DATA wfd;
    
        exePath[0] = '\0';
    
        CHAR szProductCode[MAX_PATH] = { 0 };
        CHAR szComponentCode[MAX_PATH] = { 0 };
    
        // https://docs.microsoft.com/en-us/windows/win32/api/msi/nf-msi-msigetshortcuttargetw
        DWORD errorCode = MsiGetShortcutTarget(ws2s(linkFilePath).c_str(), szProductCode, nullptr, szComponentCode);
        if (S_OK == errorCode) {
            CHAR szPathSpecial[MAX_PATH] = { 0 };
            DWORD max_size = MAX_PATH;
            INSTALLSTATE nState = MsiGetComponentPath(szProductCode, szComponentCode, szPathSpecial, &max_size);
            if (nState == INSTALLSTATE_LOCAL || nState == INSTALLSTATE_SOURCE) {
                lstrcpyn(exePath, szPathSpecial, MAX_PATH);
                return ERROR_SUCCESS;
            }
        }
    
        // Get a pointer to the IShellLink interface
        hRes = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl);
    
        if (SUCCEEDED(hRes)) {
            // Get a pointer to the IPersistFile interface
            IPersistFile* ppf = nullptr;
            hRes = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
    
            if (!SUCCEEDED(hRes)) {
                return hRes;
            }
    
            // Open the shortcut file and initialize it from its contents
            hRes = ppf->Load(linkFilePath.c_str(), STGM_READ);
            if (SUCCEEDED(hRes)) {
                // 尝试获取到快捷方式的 target 路径。即使目标被删除或者移动。
                hRes = psl->Resolve(nullptr, SLR_UPDATE | SLR_NO_UI);
                if (SUCCEEDED(hRes)) {
                    // 获取 Target 路径
                    hRes = psl->GetPath(szPath, MAX_PATH, &wfd, SLGP_RAWPATH);
                    if (FAILED(hRes)) {
                        ppf->Release();
                        psl->Release();
                        return hRes;
                    }
    
                    std::string dest = szPath;
                    int index = dest.find_first_of('\\');
                    if (index > 2) {
                        std::string sub = dest.substr(1, index - 2);
                        std::string path = getenv(sub.c_str());
                        if (path.length() > 0) {
                            if (path[path.length() - 1] == '\\') {
                                path = path.substr(0, path.length() - 1);
                            }
                            dest.replace(0, index, path);
                        }
                    }
                    strcpy(szPath, dest.c_str());
                    lstrcpyn(exePath, szPath, MAX_PATH);
                }
            }
            ppf->Release();
            psl->Release();
        }
    
        return hRes;
    }
    

    参考资料

    Advertised shortcuts vs. non-advertised shortcuts in windows setup project

    Windows系统没有目标位置的快捷方式及其目标文件获取

    相关文章

      网友评论

          本文标题:Windows 通过快捷方式获取软件所在路径

          本文链接:https://www.haomeiwen.com/subject/zwbtmctx.html