windows - 未向所有用户显示凭据提供程序(包括其他用户)

标签 windows visual-c++ credential-providers

我试图在签名选项中显示所有本地和其他用户(域用户)的凭据提供程序,但我无法这样做。我引用here开发了这个凭证提供程序。 。我对 CSampleprovider.cpp 文件的 _EnumerateCredentials 和 GetCredentialCount 函数进行了以下更改。

获取凭据计数()

HRESULT GetCredentialCount([out] DWORD* pdwCount,
                           [out] DWORD* pdwDefault,
                           [out] BOOL* pbAutoLogonWithDefault)
{
    *pdwDefault = CREDENTIAL_PROVIDER_NO_DEFAULT;
    *pbAutoLogonWithDefault = FALSE;

    if (_fRecreateEnumeratedCredentials)
    {
        _fRecreateEnumeratedCredentials = false;
        _ReleaseEnumeratedCredentials();
        _CreateEnumeratedCredentials();
    }
    DWORD dwUserCount;
    HRESULT hr;

    if (_pCredProviderUserArray != nullptr) {
        hr = _pCredProviderUserArray->GetCount(&dwUserCount);
    }

    if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
        dwUserCount += 1;//display additional empty tile
    }
    *pdwCount = dwUserCount;
    return S_OK;
}

_EnumerateCredentials()

HRESULT CSampleProvider::_EnumerateCredentials()
{
    HRESULT hr = E_UNEXPECTED;


    DWORD dwUserCount;
    if (_pCredProviderUserArray != nullptr)
    {
        //DWORD dwUserCount = 0;
        _pCredProviderUserArray->GetCount(&dwUserCount);
        if (dwUserCount > 0)
        {
            //_pCredential = new CSampleCredential*[dwUserCount];
            for (DWORD i = 0; i < dwUserCount; i++) {
                ICredentialProviderUser* pCredUser;
                hr = _pCredProviderUserArray->GetAt(i, &pCredUser);
                if (SUCCEEDED(hr))
                {
                    //_pCredential[i] = new(std::nothrow) CSampleCredential();
                    _pCredential.push_back(new(std::nothrow) CSampleCredential());
                    if (_pCredential[i] != nullptr)
                    {
                        //logfile << "new CSampleCredential()\n";

                        hr = _pCredential[i]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, pCredUser);

                        if (FAILED(hr))
                        {
                            _pCredential[i]->Release();
                            _pCredential[i] = nullptr;

                        }
                    }
                    else
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    pCredUser->Release();
                }
            }
        }
        //if you are in a domain or have no users on the list you have to show "Other user tile"
        if (DEVELOPING) PrintLn(L"IsOS(OS_DOMAINMEMBER): %d", IsOS(OS_DOMAINMEMBER));
        if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
            if (DEVELOPING) PrintLn(L"Adding empty user tile");
            _pCredential.push_back(new(std::nothrow) CSampleCredential());
            if (_pCredential[_pCredential.size() - 1] != nullptr) {
                hr = _pCredential[_pCredential.size() - 1]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, nullptr);
            }
            else {
                if (DEVELOPING) PrintLn(L"Error adding user: %d", _pCredential.size());
            }
        }

        return hr;
    }
}

我已将 CSampleCredential 类型的私有(private) header 更改为

std::vector<CSampleCredential> _pCredentialVector; 
// SampleV2CredentialCSampleProvider.h

在 CSampleProvider.h 文件中。

当我测试我的这个凭据提供程序时,它工作正常,即,当没有添加域(没有其他用户)时,它在登录选项中为所有本地用户显示,但当添加域(启用其他用户)时,那么我是卡在欢迎壁纸上并且屏幕不断闪烁。

那么,如何在登录选项中为所有本地和域用户(其他用户)显示我的凭据提供程序并克服屏幕闪烁。我是 VC++ 新手,请帮助我。

最佳答案

当我尝试为所有图 block (包括其他用户图 block )启用自定义凭据提供程序时,我在 GetCredentialCount() 方法和 _EnumerateCredentials() 方法中做了一些更改在 Microsoft 提供的凭据提供程序示例中的 SampleProvider.cpp 文件中。我所做的更改是:

HRESULT CServiceProvider::GetCredentialCount(
_Out_ DWORD *pdwCount,
_Out_ DWORD *pdwDefault,
_Out_ BOOL *pbAutoLogonWithDefault){

*pdwDefault = CREDENTIAL_PROVIDER_NO_DEFAULT;
*pbAutoLogonWithDefault = FALSE;

if (_fRecreateEnumeratedCredentials)
{
    _fRecreateEnumeratedCredentials = false;
    _ReleaseEnumeratedCredentials();
    _CreateEnumeratedCredentials();
}
DWORD dwUserCount;
HRESULT hr;

if (_pCredProviderUserArray != nullptr) {
    hr = _pCredProviderUserArray->GetCount(&dwUserCount);
}

if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
    dwUserCount += 1;//display additional empty tile
}
*pdwCount = dwUserCount;
return S_OK;}



HRESULT CServiceProvider::_EnumerateCredentials(){
HRESULT hr = E_UNEXPECTED;
DWORD dwUserCount;
if (_pCredProviderUserArray != nullptr)
{
    _pCredProviderUserArray->GetCount(&dwUserCount);
    if (dwUserCount > 0)
    {   
        //You need to initialize all the fields in LogonUI for each and every user 
        for (DWORD i = 0; i < dwUserCount; i++) {
            ICredentialProviderUser* pCredUser;
            hr = _pCredProviderUserArray->GetAt(i, &pCredUser);
            if (SUCCEEDED(hr))
            {
                _pCredential.push_back(new(std::nothrow) CUserCredential());
                if (_pCredential[i] != nullptr)
                {
                    hr = _pCredential[i]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, pCredUser);

                    if (FAILED(hr))
                    {
                        _pCredential[i]->Release();
                        _pCredential[i] = nullptr;
                    }
                }
                else
                {
                    hr = E_OUTOFMEMORY;
                }
                pCredUser->Release();
            }
        }
    }
    //if you are in a domain or have no users on the list you have to show "Other user tile"
    if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
        _pCredential.push_back(new(std::nothrow) CUserCredential());
        if (_pCredential[_pCredential.size() - 1] != nullptr) {
            hr = _pCredential[_pCredential.size() - 1]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, nullptr);
        }
    }
    return hr;
}
return hr;

}

现在,如您所见,在检查系统是否连接到域后,我们在调用 Initialize() 方法时发送 nullptr 作为参数之一,我们需要处理该问题通过检查 SampleCredential.cpp 文件中的 if 条件,在 Initialize() 方法中使用 nullptr

HRESULT CUserCredential::Initialize(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,
_In_ CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR const* rgcpfd,
_In_ FIELD_STATE_PAIR const* rgfsp,
_In_ ICredentialProviderUser* pcpUser){
HRESULT hr = S_OK;
_cpus = cpus;
_nNextScreenID = e_ARSNone;

GUID guidProvider;
LPOLESTR clsid;

if (pcpUser != nullptr) {
    pcpUser->GetProviderID(&guidProvider);
    StringFromCLSID(guidProvider, &clsid);
    CoTaskMemFree(clsid);
    _fIsLocalUser = (guidProvider == Identity_LocalUserProvider);
}
else {
    _fIsLocalUser = true;//CP V1 or Domain
}

// Copy the field descriptors for each field. This is useful if you want to vary the field
// descriptors based on what Usage scenario the credential was created for.
for (DWORD i = 0; SUCCEEDED(hr) && i < ARRAYSIZE(_rgCredProvFieldDescriptors); i++)
{
    _rgFieldStatePairs[i] = rgfsp[i];
    hr = FieldDescriptorCopy(rgcpfd[i], &_rgCredProvFieldDescriptors[i]);
}

// Initialize the String value of all the fields.
if (SUCCEEDED(hr))
{
    hr = SHStrDupW(L"SomeLable1", &_rgFieldStrings[SFI_LABEL]);
}

if (SUCCEEDED(hr))
{
    hr = SHStrDupW(L"SomeLable2", &_rgFieldStrings[SFI_LARGE_TEXT]);
}


if (SUCCEEDED(hr))
{
    hr = SHStrDupW(L"", &_rgFieldStrings[SFI_PASSWORD]);
}

if (SUCCEEDED(hr))
{
    hr = SHStrDupW(L"Somelabel4", &_rgFieldStrings[SFI_SUBMIT_BUTTON]);
}


hr = S_OK;
if (SUCCEEDED(hr))
{
    if (pcpUser != nullptr) {
        hr = pcpUser->GetStringValue(PKEY_Identity_QualifiedUserName, &_pszQualifiedUserName);//get username from the LogonUI user object
        PWSTR pszUserName1;
        pcpUser->GetStringValue(PKEY_Identity_UserName, &pszUserName1);
        if (_fIsLocalUser) {
            PWSTR pszUserName;
            pcpUser->GetStringValue(PKEY_Identity_UserName, &pszUserName);
            if (pszUserName != nullptr)
            {
                wchar_t szString[256];
                StringCchPrintf(szString, ARRAYSIZE(szString), L"User Name: %s", pszUserName);
                if (DEVELOPING) PrintLn(szString);
                hr = SHStrDupW(pszUserName, &_rgFieldStrings[SFI_LARGE_TEXT]);
                CoTaskMemFree(pszUserName);
            }
            else
            {
                hr = SHStrDupW(L"User Name is NULL", &_rgFieldStrings[SFI_LARGE_TEXT]);
            }
        }
        else {
            if (DEVELOPING) PrintLn(L"Domain user, skip SFI_LARGE_TEXT");
        }
    }
    else {
        PWSTR connectedDomainName = getNetworkName();
        wchar_t szString[256];
        StringCchPrintf(szString, ARRAYSIZE(szString), L"Sign in to: %s", connectedDomainName);
        hr = SHStrDupW(szString, &_rgFieldStrings[SFI_DOMAIN_NAME_TEXT]);

        if (DEVELOPING) PrintLn("Unknown user -> display LoginName");
        hr = SHStrDupW(L"", &_pszQualifiedUserName);
        _fUserNameVisible = true;
        _rgFieldStatePairs[SFI_LOGIN_NAME].cpfs = CPFS_DISPLAY_IN_SELECTED_TILE;//unhide login name
        //switch focus to login
        _rgFieldStatePairs[SFI_LOGIN_NAME].cpfis = CPFIS_FOCUSED;
        _rgFieldStatePairs[SFI_PASSWORD].cpfis = CPFIS_NONE;
        //Don't panic!!!
    }
}
if (pcpUser != nullptr)
{
    hr = pcpUser->GetSid(&_pszUserSid);
}
return hr;}

使用上面的代码,您可以解决闪烁(这是 CP 崩溃)的问题,并为所有用户图 block 启用凭据提供程序。

关于windows - 未向所有用户显示凭据提供程序(包括其他用户),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55967533/

相关文章:

windows - 在 Windows CE 手持设备上禁用键盘 regedit 不起作用

c++ - 在编写 Windows 桌面应用程序时,我应该在哪里跟踪我的窗口句柄?

c++ - 返回分配的局部变量

java - c++ static 关键字对大括号有什么作用?

c++ - Credential Providers V2 - 提交后添加代码并检查用户密码

windows - 如何 awk -f 最后一个之后的所有内容\

c++ - 我没有看到注册表项,即使 GetLastError 返回全 0

c++ - 获取成员函数的内存地址?

windows - 凭据提供程序通过网络通信