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

如何为CredUIPromptForWindowsCredentials()预填充用户名字段

实现目标

从CredUIPromptForWindowsCredentials接口返回结果中提取明文密码用于后续校验,同时给凭据弹窗的用户名字段设置默认填充值,避免用户随意修改。

现存问题
  • 使用CREDUIWIN_GENERIC标记调用接口时,用户名字段无默认值,用户可随意修改
  • 尝试替换为CREDUIWIN_ENUMERATE_CURRENT_USER标记后,返回的密码为加密格式,无法直接读取明文
  • 不清楚pulAuthPackage参数的正确配置方式
原有实现代码
BOOL save = false;
DWORD authPackage = 0;
LPVOID authBuffer;
ULONG authBufferSize = 0;

CREDUI_INFO credUiInfo;

static WCHAR username[CREDUI_MAX_USERNAME_LENGTH * sizeof(WCHAR)] = { 0 };
static WCHAR password[CREDUI_MAX_PASSWORD_LENGTH * sizeof(WCHAR)] = { 0 };
DWORD uLen = CREDUI_MAX_USERNAME_LENGTH;
DWORD pLen = CREDUI_MAX_PASSWORD_LENGTH;

credUiInfo.pszCaptionText = TEXT("Authentication");
credUiInfo.pszMessageText = TEXT("Please enter your Key in \"Password\".");
credUiInfo.cbSize = sizeof(credUiInfo);
credUiInfo.hbmBanner = NULL;
credUiInfo.hwndParent = NULL;

LPVOID inBuffer = NULL;
ULONG inBufferSize = 0;


HRESULT rc = CredUIPromptForWindowsCredentials(&(credUiInfo), 0, &(authPackage), inBuffer, inBufferSize, &authBuffer, &authBufferSize, &(save), CREDUIWIN_GENERIC);

if (rc == ERROR_SUCCESS)
{
    CredUnPackAuthenticationBufferW(0, authBuffer, authBufferSize, username, &uLen, NULL, 0, password, &pLen);

    wstring ws(password);
    string res(ws.begin(), ws.end());
    return res;
}
正确实现方法

不需要使用CREDUIWIN_ENUMERATE_CURRENT_USER标记,保持CREDUIWIN_GENERIC标记即可拿到明文密码,预填充用户名的核心是提前构造输入认证缓冲区传入接口,而非修改标记或手动赋值pulAuthPackage:

  • 提前定义需要默认填充的用户名字符串
  • 调用CredPackAuthenticationBufferW函数,传入CRED_PACK_GENERIC_CREDENTIALS标记,将预设用户名打包为符合接口要求的输入缓冲区,域名字段传NULL即可
  • 将打包好的缓冲区作为pvInAuthBuffer参数传入CredUIPromptForWindowsCredentials,弹窗打开时就会自动填充预设的用户名
  • 接口返回后调用CredUnPackAuthenticationBufferW解包时,第一个参数同样传入CRED_PACK_GENERIC_CREDENTIALS标记,即可正确解出明文密码
  • pulAuthPackage参数不需要提前手动赋值,接口调用成功后会自动填充实际使用的认证包ID,不需要额外配置

注意:所有申请的缓冲区使用完成后要调用CoTaskMemFree释放,密码字段使用完成后要及时清空内存,避免敏感信息残留。

修正后代码示例
BOOL save = false;
DWORD authPackage = 0;
LPVOID authBuffer = NULL;
ULONG authBufferSize = 0;

CREDUI_INFO credUiInfo;

WCHAR username[CREDUI_MAX_USERNAME_LENGTH] = {0};
WCHAR password[CREDUI_MAX_PASSWORD_LENGTH] = {0};
DWORD uLen = CREDUI_MAX_USERNAME_LENGTH;
DWORD pLen = CREDUI_MAX_PASSWORD_LENGTH;

// 配置需要默认填充的用户名
const WCHAR* defaultUsername = L"your_default_username";

credUiInfo.pszCaptionText = TEXT("Authentication");
credUiInfo.pszMessageText = TEXT("Please enter your Key in \"Password\".");
credUiInfo.cbSize = sizeof(credUiInfo);
credUiInfo.hbmBanner = NULL;
credUiInfo.hwndParent = NULL;

LPVOID inBuffer = NULL;
ULONG inBufferSize = 0;
// 第一次调用获取输入缓冲区所需大小
CredPackAuthenticationBufferW(CRED_PACK_GENERIC_CREDENTIALS, 
    (LPWSTR)defaultUsername, 
    NULL, // 需要默认填充密码则传入对应密码字符串,否则传NULL
    NULL, 
    &inBufferSize);
inBuffer = CoTaskMemAlloc(inBufferSize);
// 第二次调用完成缓冲区打包
CredPackAuthenticationBufferW(CRED_PACK_GENERIC_CREDENTIALS,
    (LPWSTR)defaultUsername,
    NULL,
    inBuffer,
    &inBufferSize);

HRESULT rc = CredUIPromptForWindowsCredentials(&(credUiInfo), 0, &(authPackage), 
    inBuffer, inBufferSize, 
    &authBuffer, &authBufferSize, 
    &(save), CREDUIWIN_GENERIC);

// 释放输入缓冲区
if (inBuffer) CoTaskMemFree(inBuffer);

if (rc == ERROR_SUCCESS)
{
    // 传入对应标记解包,即可拿到明文密码
    BOOL unPackRc = CredUnPackAuthenticationBufferW(CRED_PACK_GENERIC_CREDENTIALS, 
        authBuffer, authBufferSize, 
        username, &uLen, 
        NULL, 0, // 不需要解析域名字段则传NULL
        password, &pLen);
    
    // 释放输出缓冲区
    CoTaskMemFree(authBuffer);
    
    if (unPackRc)
    {
        wstring ws(password);
        string res(ws.begin(), ws.end());
        // 清空密码内存,避免敏感信息残留
        SecureZeroMemory(password, sizeof(password));
        return res;
    }
}
return "";

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 01:48:46