C#自定义Credential Provider开发:控件取值与弹窗问题咨询
自定义Windows Credential Provider问题解决
问题1:点击命令按钮时无法读取文本框的值
Windows Credential Provider的控件交互模型由系统负责同步控件值到你的Credential实例,而非直接读取控件。解决步骤如下:
- 在实现
ICredentialProviderCredential的自定义Credential类中,为每个编辑框声明成员变量存储值:
private: std::wstring m_szUsername; std::wstring m_szPassword;
- 重写
SetStringValue方法,当系统传递控件字段ID时,将对应值保存到成员变量:
HRESULT STDMETHODCALLTYPE YourCredential::SetStringValue(DWORD dwFieldID, PCWSTR pszValue) { HRESULT hr = S_OK; switch (dwFieldID) { case FIELD_USERNAME: // 替换为你定义的用户名字段ID m_szUsername = pszValue; break; case FIELD_PASSWORD: // 替换为你定义的密码字段ID m_szPassword = pszValue; break; default: hr = E_INVALIDARG; break; } return hr; }
- 在命令按钮的处理方法
OnUserCommand中,直接使用保存的成员变量即可:
HRESULT STDMETHODCALLTYPE YourCredential::OnUserCommand(DWORD dwFieldID, DWORD dwUserCommandID) { if (dwUserCommandID == CMD_TRIGGER_MFA) // 替换为你的命令按钮ID { // 直接调用已保存的文本框值 std::wstring username = m_szUsername; // 后续业务逻辑 return S_OK; } return E_INVALIDARG; }
问题2:打开自定义MFA窗体
登录UI运行在Winlogon安全桌面,普通窗体无法直接显示,需按以下步骤实现:
准备独立的MFA窗体程序:
- 编写基础Win32窗体程序,避免使用依赖用户桌面的特性(如透明效果)
- 添加应用程序清单,设置
requestedExecutionLevel为highestAvailable,确保程序能在安全桌面启动
在Credential类的
OnUserCommand方法中,切换到安全桌面并启动MFA进程:
HRESULT STDMETHODCALLTYPE YourCredential::OnUserCommand(DWORD dwFieldID, DWORD dwUserCommandID) { if (dwUserCommandID == CMD_TRIGGER_MFA) { HDESK hWinlogonDesktop = OpenDesktop(L"Winlogon", 0, FALSE, GENERIC_ALL); if (!hWinlogonDesktop) return HRESULT_FROM_WIN32(GetLastError()); HDESK hOldDesktop = GetThreadDesktop(GetCurrentThreadId()); SetThreadDesktop(hWinlogonDesktop); // 构造启动参数,传递用户名等信息 std::wstring cmdLine = L"YourMFA.exe /user:" + m_szUsername; STARTUPINFO si = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION pi = { 0 }; // 启动MFA进程 BOOL success = CreateProcessAsUser( NULL, NULL, const_cast<LPWSTR>(cmdLine.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ); if (success) { // 等待MFA窗体关闭 WaitForSingleObject(pi.hProcess, INFINITE); DWORD exitCode = 0; GetExitCodeProcess(pi.hProcess, &exitCode); // 根据MFA验证结果更新登录UI状态 if (exitCode == 0) // 假设0表示验证成功 { m_pCredentialProviderEvents->SetFieldState(this, FIELD_SUBMIT, CPFS_VALID); } else { m_pCredentialProviderEvents->SetFieldState(this, FIELD_SUBMIT, CPFS_INVALID); } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } // 切换回原桌面并释放资源 SetThreadDesktop(hOldDesktop); CloseDesktop(hWinlogonDesktop); return S_OK; } return E_INVALIDARG; }
- 注意事项:
- MFA程序需处理命令行参数,接收用户名等信息
- 安全桌面下部分系统API无法使用,需测试窗体兼容性
- 验证完成后,需通过
ICredentialProviderEvents通知登录UI更新控件状态
内容的提问来源于stack exchange,提问作者canowar
相关产品推荐
相关产品推荐

