windows 凭证提示问题,CredUnPackAuthenticationBuffer 错误 50

Problem with windows credential prompt, CredUnPackAuthenticationBuffer error 50

我正在尝试显示 Windows 默认凭据提示并以字符串形式检索用户名、密码和域。

我正在使用此文档:

CredUIPromptForWindowsCredentialsW

CredUnPackAuthenticationBufferW

当出现提示时,我输入随机用户名和密码(例如,用户名:test,密码:test123),按回车键,函数 CredUnPackAuthenticationBuffer() 失败并显示 ERROR_NOT_SUPPORTED

代码:

#include <Windows.h>
#include <wincred.h> //Link library Credui.lib for CredUIPromptForWindowsCredentials() to work
#include <iostream>
#include <string>

//Display error in console and close application
void DisplayConsoleError(const WCHAR* errorMessage, const WCHAR* fName);

int wmain(int argc, WCHAR* argv[])
{
        CREDUI_INFO cuiInfo;
    cuiInfo.cbSize = sizeof(CREDUI_INFO);
    cuiInfo.hbmBanner = nullptr;
    cuiInfo.hwndParent = nullptr;
    cuiInfo.pszCaptionText = L"CaptionText";
    cuiInfo.pszMessageText = L"MessageText";

    DWORD dwAuthError = 0;
    ULONG dwAuthPackage = 0;

    LPVOID outCredBuffer = nullptr;
    ULONG outCredBufferSize = 0;
    BOOL credSaveCheckbox = false;

    DWORD dwError = 0;
    DWORD lastError = 0;

    dwError = CredUIPromptForWindowsCredentials(
        &cuiInfo, 
        dwAuthError, 
        &dwAuthPackage, 
        nullptr, 
        NULL, 
        &outCredBuffer, 
        &outCredBufferSize, 
        &credSaveCheckbox, 
        CREDUIWIN_CHECKBOX | CREDUIWIN_GENERIC);

    if (dwError == ERROR_SUCCESS)
    {
        DWORD maxUserNameSize = CREDUI_MAX_USERNAME_LENGTH;
        DWORD maxDomainNameSize = CREDUI_MAX_DOMAIN_TARGET_LENGTH;
        DWORD maxPasswordLength = CREDUI_MAX_PASSWORD_LENGTH;

        LPWSTR szUserName = new WCHAR[maxUserNameSize];
        LPWSTR szDomain = new WCHAR[maxDomainNameSize];
        LPWSTR szPassword = new WCHAR[maxPasswordLength];

        DWORD dwCredBufferSize = outCredBufferSize;     //ULONG to DWORD

        DWORD lastError = 0;
        dwError = CredUnPackAuthenticationBuffer(
            CRED_PACK_GENERIC_CREDENTIALS,
            &outCredBuffer,
            dwCredBufferSize,
            szUserName,
            &maxUserNameSize,
            szDomain,
            &maxDomainNameSize,
            szPassword,
            &maxPasswordLength
        );
        lastError = GetLastError();

        //Check for error
        if (dwError == FALSE)
        {
            DisplayConsoleError(L"Blah", L"CredUnPackAuthenticationBuffer", lastError);
        }
        else
        {
            std::wcout << L"username " << szUserName << std::endl;
            std::wcout << L"domain " << szDomain << std::endl;
            std::wcout << L"password " << szPassword << std::endl;
        }

    }
    else
    {
        lastError = dwError;
    }

    SecureZeroMemory(outCredBuffer, outCredBufferSize);
    CoTaskMemFree(outCredBuffer);

    return lastError;
} 

另外在 VS2019 中调试 CredUIPromptForWindowsCredentials() 失败(加载符号有问题?),但编译后的 .exe 工作正常。作为解决方法,我将调试器附加到进程。

我是 winapi 的初学者,所以如果有人能解释为什么会出现此错误,我做错了什么以及如何修复此代码,我将不胜感激。

编辑 将错误检查移至 SecureZeroMemory()CoTaskMemFree() 函数上方,以避免在检查错误消息之前调用其他 API 函数, 但错误仍然存​​在。

DisplayConsoleError:

void DisplayConsoleError(const WCHAR* errorMessage, const WCHAR* fName, DWORD lastError)
{
    std::cout << std::endl;
    std::cout << "Error\t" << std::endl;
    std::wcout << L"In function:\t" << fName << std::endl;
    std::cout << "Code:\t" << lastError << std::endl;
    std::cout << std::endl;
}

编辑 2 考虑到@RemyLebeau 反馈对代码的更改

看看你代码中的这个函数:

CredUnPackAuthenticationBuffer(
            CRED_PACK_GENERIC_CREDENTIALS,
            &outCredBuffer,
            dwCredBufferSize,
            szUserName,
            &maxUserNameSize,
            szDomain,
            &maxDomainNameSize,
            szPassword,
            &maxPasswordLength
        );

您需要将 &outCredBuffer 更改为 outCredBuffer

#include <Windows.h>
#include <wincred.h> //Link library Credui.lib for CredUIPromptForWindowsCredentials() to work
#include <iostream>
#include <string>

//Display error in console and close application
void DisplayConsoleError(const WCHAR* errorMessage, const WCHAR* fName, DWORD lastError)
{
    std::cout << std::endl;
    std::cout << "Error\t" << std::endl;
    std::wcout << L"In function:\t" << fName << std::endl;
    std::cout << "Code:\t" << lastError << std::endl;
    std::cout << std::endl;
}

int wmain(int argc, WCHAR* argv[])
{
    CREDUI_INFO cuiInfo;
    cuiInfo.cbSize = sizeof(CREDUI_INFO);
    cuiInfo.hbmBanner = nullptr;
    cuiInfo.hwndParent = nullptr;
    cuiInfo.pszCaptionText = L"CaptionText";
    cuiInfo.pszMessageText = L"MessageText";

    DWORD dwAuthError = 0;
    ULONG dwAuthPackage = 0;

    LPVOID outCredBuffer = nullptr;
    ULONG outCredBufferSize = 0;
    BOOL credSaveCheckbox = false;

    DWORD dwError = 0;
    DWORD lastError = 0;

    dwError = CredUIPromptForWindowsCredentials(
        &cuiInfo,
        dwAuthError,
        &dwAuthPackage,
        nullptr,
        NULL,
        &outCredBuffer,
        &outCredBufferSize,
        &credSaveCheckbox,
        CREDUIWIN_CHECKBOX | CREDUIWIN_GENERIC);

    if (dwError == ERROR_SUCCESS)
    {
        DWORD maxUserNameSize = CREDUI_MAX_USERNAME_LENGTH;
        DWORD maxDomainNameSize = CREDUI_MAX_DOMAIN_TARGET_LENGTH;
        DWORD maxPasswordLength = CREDUI_MAX_PASSWORD_LENGTH;

        LPWSTR szUserName = new WCHAR[maxUserNameSize];
        LPWSTR szDomain = new WCHAR[maxDomainNameSize];
        LPWSTR szPassword = new WCHAR[maxPasswordLength];

        DWORD dwCredBufferSize = outCredBufferSize;     //ULONG to DWORD

        DWORD lastError = 0;
        dwError = CredUnPackAuthenticationBuffer(
            CRED_PACK_GENERIC_CREDENTIALS,
            outCredBuffer,
            dwCredBufferSize,
            szUserName,
            &maxUserNameSize,
            szDomain,
            &maxDomainNameSize,
            szPassword,
            &maxPasswordLength
        );
        lastError = GetLastError();

        //Check for error
        if (dwError == FALSE)
        {
            DisplayConsoleError(L"Blah", L"CredUnPackAuthenticationBuffer", lastError);
        }
        else
        {
            std::wcout << L"username " << szUserName << std::endl;
            std::wcout << L"domain " << szDomain << std::endl;
            std::wcout << L"password " << szPassword << std::endl;
        }

    }
    else
    {
        lastError = dwError;
    }

    SecureZeroMemory(outCredBuffer, outCredBufferSize);
    CoTaskMemFree(outCredBuffer);

    return lastError;
}