You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

管理员安装程序中如何始终获取当前用户的LocalAppData路径?

解决方案

一、始终获取原始用户的LocalAppData路径

当程序通过UAC提升后,进程运行在管理员上下文,直接调用SHGetKnownFolderPath会返回管理员账户的路径。要获取触发UAC的原始用户路径,需通过模拟原始用户会话实现,步骤如下:

  • 打开当前进程的令牌,获取链接到原始用户的令牌(TokenLinkedToken属性)
  • 模拟该原始用户,调用SHGetKnownFolderPath获取路径
  • 取消模拟并释放资源

示例代码(C++):

#include <windows.h>
#include <shlobj.h>
#include <sddl.h>

WCHAR* GetOriginalUserLocalAppData() {
    HANDLE hCurrentToken = NULL;
    HANDLE hLinkedToken = NULL;
    WCHAR* pszPath = NULL;

    // 打开当前进程令牌
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &hCurrentToken)) {
        goto Cleanup;
    }

    // 获取链接令牌(对应原始用户)
    DWORD dwSize = sizeof(HANDLE);
    if (!GetTokenInformation(hCurrentToken, TokenLinkedToken, &hLinkedToken, dwSize, &dwSize)) {
        // 无链接令牌,说明是管理员用户自身提升,直接获取当前路径
        SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &pszPath);
        goto Cleanup;
    }

    // 模拟原始用户
    if (ImpersonateLoggedOnUser(hLinkedToken)) {
        SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &pszPath);
        RevertToSelf();
    }

Cleanup:
    if (hCurrentToken) CloseHandle(hCurrentToken);
    if (hLinkedToken) CloseHandle(hLinkedToken);
    return pszPath;
}

注意:使用完返回的路径后,需调用CoTaskMemFree释放内存。

二、判断当前用户是否为跨账号UAC提升(原本非管理员)

要判断是否是普通用户输入管理员凭据完成的提升,可通过比较当前进程令牌与原始用户令牌的SID是否不同实现:

  • 获取当前进程令牌的用户SID
  • 获取链接令牌的用户SID
  • 对比两个SID,若不同则说明是跨账号提升(原本用户非管理员)

示例代码(C++):

BOOL IsCrossAccountElevation() {
    HANDLE hCurrentToken = NULL;
    HANDLE hLinkedToken = NULL;
    BOOL bResult = FALSE;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hCurrentToken)) {
        goto Cleanup;
    }

    // 获取链接令牌
    DWORD dwSize = sizeof(HANDLE);
    if (!GetTokenInformation(hCurrentToken, TokenLinkedToken, &hLinkedToken, dwSize, &dwSize)) {
        // 无链接令牌,说明是管理员自身提升,不是跨账号
        goto Cleanup;
    }

    // 获取当前用户SID
    TOKEN_USER* pCurrentUser = NULL;
    dwSize = 0;
    GetTokenInformation(hCurrentToken, TokenUser, NULL, 0, &dwSize);
    pCurrentUser = (TOKEN_USER*)LocalAlloc(LPTR, dwSize);
    if (!GetTokenInformation(hCurrentToken, TokenUser, pCurrentUser, dwSize, &dwSize)) {
        goto Cleanup;
    }

    // 获取原始用户SID
    TOKEN_USER* pLinkedUser = NULL;
    dwSize = 0;
    GetTokenInformation(hLinkedToken, TokenUser, NULL, 0, &dwSize);
    pLinkedUser = (TOKEN_USER*)LocalAlloc(LPTR, dwSize);
    if (!GetTokenInformation(hLinkedToken, TokenUser, pLinkedUser, dwSize, &dwSize)) {
        goto Cleanup;
    }

    // 对比SID
    if (!EqualSid(pCurrentUser->User.Sid, pLinkedUser->User.Sid)) {
        bResult = TRUE;
    }

Cleanup:
    if (hCurrentToken) CloseHandle(hCurrentToken);
    if (hLinkedToken) CloseHandle(hLinkedToken);
    if (pCurrentUser) LocalFree(pCurrentUser);
    if (pLinkedUser) LocalFree(pLinkedUser);
    return bResult;
}

如果该函数返回TRUE,则说明当前是普通用户通过输入管理员凭据完成的UAC提升,此时可提示用户选择其他安装位置(比如原始用户的LocalAppData或公共目录)。

内容的提问来源于stack exchange,提问作者Michael Chourdakis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 12:45:26