使用 Windows Vista 的凭据提供程序创造自定义的登录体验.docx

上传人:sk****8 文档编号:3151886 上传时间:2019-05-23 格式:DOCX 页数:18 大小:78.09KB
下载 相关 举报
使用 Windows Vista 的凭据提供程序创造自定义的登录体验.docx_第1页
第1页 / 共18页
使用 Windows Vista 的凭据提供程序创造自定义的登录体验.docx_第2页
第2页 / 共18页
使用 Windows Vista 的凭据提供程序创造自定义的登录体验.docx_第3页
第3页 / 共18页
使用 Windows Vista 的凭据提供程序创造自定义的登录体验.docx_第4页
第4页 / 共18页
使用 Windows Vista 的凭据提供程序创造自定义的登录体验.docx_第5页
第5页 / 共18页
点击查看更多>>
资源描述

1、桌面安全使用 Windows Vista 的凭据提供程序创造自定义的登录体验Dan Griffin本文讨论: 新的凭据提供程序体系结构 为什么弃用了基于 GINA 的身份验证 多因素 (Multi-factor) 身份验证 开发和调试凭据提供程序本文使用了以下技术: Windows Vista、C+目录 新旧两种体系结构的比较 混合凭据提供程序 要求 设计 混合凭据提供程序 混合方式的实现 改进的可能性 测试和调试 智能卡和初始化 Windows Vista 在平台集成方面为开发人员提供了许多新的机会。新的凭据提供程序模型是变动最大的方面之一,由于它的出现,实现操作系统支持的新用户身份验证方案

2、变得容易 了许多。它已取代了 GINA(图形标识与身份验证)模型,而直言不讳地说,后者一向因为开发人员难以理解和实现以及昂贵的 Microsoft 支持费用而广为诟病。那么 Windows 登录插件接口的一个变化竟会如此令人兴奋,其原因何在?用户打开计算机时首先看到的是登录屏幕。由于登录体验是由凭据提供程序来控制和管理的,这使得自定 义登录体验以及集成最符合组织需要的身份验证方法变得容易了许多。简而言之,凭据提供程序为开发和实现更好、更可靠的安全性提供了一种更容易的方式。新旧两种体系结构的比较我不想过细地阐述基于 GINA 的登录体系结构。不过,花点时间比较一下这两个体系结构,帮助您更好地理解

3、新的体系结构以及其中的变动,这也很值当。在 Windows Vista 之前的环境中,每个会话都有一个 winlogon 实例,它负责控制该会话的交互式登录序列。(图 1 显示了 Windows XP 和 Windows Server 2003 旧的登录体系结构。)在刚启动的系统中,控制台位置的交互式登录始终在会话 0 中执行。会话 0 承载运行系统服务以及其他关键进程,包括“本地安全机构”(Local Security Authority) 进程。(换句话说,在会话 0 中运行的许多进程都没有在图 1 中显示出来。)图 1 GINA 登录体系结构 计算机上已注册的 GINA 加载到 winl

4、ogon 进程空间中。(还可能加载一个称作“GINA 链接”的配置,但测试和支持这样的复杂配置很困难。)最后,GINA 调用 LogonUser 以及相关的身份验证 API。在 Windows Vista 中,会话 0 不再用于交互式登录(请参见图 2)。这有利于提高安全性,因为现在已有一个会话边界将所有的计算机进程与各个用户的进程分隔开来。此外,现在对内核全局命名空间的控制也更加严格,因为默认情况下由用户应用程序创建的对象已不在内核全局命名空间之内。图 2 新的登录体系结构 除会话 0 之外的每一个会话仍会有一个 winlogon 实例。图 2 显示,系统中已注册了几个凭据提供程序,并已通过

5、新的 LogonUI 进程加载。在由哪个组件负责显示登录图形界面方面也有一个重要的改动。以前,这是由 GINA 来处理的,因此,显示界面的工作可能一直由第三方组件来完成。在新的体系结构中,这是由操作系统的一个内置组件 LogonUI 来负责完成的。那 么每个提供程序的用户提示行为在新的模型中是如何实现的呢?“凭据提供程序”体系结构要求每个提供程序都要列举说明它所需要的 UI 元素。例如,在某个指定的方案中,提供程序可能会向 LogonUI 表明它需要两个编辑框、两个标题、一个复选框和一个位图。然后,LogonUI 为凭据提供程序显示这些控件。这对实现以前讨论的目标大有帮助,即用一致的外观和方法

6、来广泛支持不断修改完善的用户验证方案。负 责“凭据提供程序”开发的 Microsoft 开发团队原以为外部开发人员会更愿意基于 COM 来开发插件模型。然而,在 Windows Vista 开发周期的早期阶段,新接口最初的内部设计(类似于 GINA)完全基于 LoadLibrary 和函数指针。之后,基于 COM 的重新设计吸取了第一次的教训,使得设计出来的界面更加简洁和易用。 现在我们转到示例代码,来帮助引导我们深入了解凭据提供程序接口。 混合凭据提供程序此新插件模型的计时功能臻于完美(当然,或许早就应该有这样的功能了)。现在,开发人员可以更轻松地满足多因素身份验证方案需求,同时提供与 Mi

7、crosoft 原有的相一致的登录体验。尽 管如此,新的接口仍显得相当抽象。有关它的描述说明也同样令人费解,让人感到乏味!要想了解它,一个让人能提起兴趣的方式就是体验一下新凭据提供程序的设 计、开发和测试过程。而且,这可以很好地弥补 Microsoft 提供的现有文档的不足 有关指针方面的内容,请参阅侧栏“其他资源”。我创建了一个示例,即“混合凭据提供程序”,它会演示一些全新的功能。混合凭据提供程序允许将用户名、密码和域名存储在智能卡上。插入智能卡后,用户会自动登录。(可从MSDN 杂志网站下载示例代码。)我没有重新编写代码,而是将以下三个来源的代码合在一起: Microsoft Window

8、s SDK 中提供的基于密码的凭据提供程序示例。 以前的 PropCert 示例,同样来自 SDK。其核心是一个用于读取基于证书的智能卡凭据的 Win32 线程。 我的文章(刊载于 2006 年 11 月发行的MSDN 杂志)中包含的示例代码。这篇文章讨论了如何通过托管代码与 Windows 智能卡子系统建立接口。对 于我在 2006 年 11 月发表的那篇文章中所提供的示例代码,我需要作进一步的说明。凭据提供程序体系结构及其主机只支持本机代码。尽管我的第一篇文章讲的主要是托管代码,但其 中也包含了一个本机帮助程序 DLL,以便于公开新的智能卡模块接口。混合凭据提供程序便基于这个帮助程序 DL

9、L。如需该 DLL 的完整源代码,同样可以通过 2006 年 11 月发表的那篇文章随附的下载内容中获得。总之,混合凭据提供程序的代码中有很大一部分都不是新写的。其最终结果是将测试和调试时间减到最少。实际上,核心调试阶段花费了不到一天的时间,这证明了新接口的易用性。现在详细地讨论一下我使用此示例凭据提供程序所要执行的操作。 要求构思此混合凭据提供程序时,我希望达到以下这些要求: 使之基于智能卡运行 最大限度地增加代码的重用 最大限度地减少额外配置和基础结构需求因 此我采用了我的所谓混合方法,换言之就是密码(为了安全起见)加智能卡(为了方便起见)。由于混合提供程序的概念是基于用户名和密码的,因此

10、我将从 Platform SDK 分离出来的密码提供程序示例作为我设计该方法的起点。然后,我添加了来自 SDK 的 PropCert 示例;其中包括了用于枚举智能卡读卡器、卡和数字证书的逻辑过程。我觉得我要做的就是,将 PropCert 中基于证书的逻辑代码替换为用于读取我自己的凭据数据的一些新代码,然后简单地将这两个示例连在一起就可以了!由于我们将从智能卡读取密码登录信息,这意味着还有一个需求:一个使用该凭据初始化智能卡的工具。初始化工具将放在最后讨论。根据这些要求,我们来看一看凭据提供程序体系结构的设计以及它如何影响我的示例代码设计。设计我们先从运行时凭据提供程序的角度来讨论一下凭据提供程

11、序体系结构的设计。虽 然我尚未详细讨论混合示例,但我将使用它作为分析运行中的新凭据提供程序体系结构的基础。为了便于讨论,我的示例代码包含了调试跟踪。此跟踪包含从每个已 实现的凭据提供程序例程进行的 OutputDebugString 调用。在这些跟踪调用中,我使用两个缩写。对新的 ICredentialProvider 接口(请参见图 3)的调用以“Provider:” 开头。对 ICredentialProviderCredential 接口(请参见图 4)的调用以“Credential:”开头。请注意,所有凭据提供程序相关接口都是在新的公共头文件 credentialprovider.h

12、中定义的。Figure 4 ICredentialProviderCredential 接口 ICredentialProviderCredential : public IUnknownHRESULT STDMETHODCALLTYPE Advise( /* in */ ICredentialProviderCredentialEvents *pcpce);HRESULT STDMETHODCALLTYPE UnAdvise( void);HRESULT STDMETHODCALLTYPE SetSelected( /* out */ BOOL *pbAutoLogon);HRESULT S

13、TDMETHODCALLTYPE SetDeselected( void);HRESULT STDMETHODCALLTYPE GetFieldState( /* in */ DWORD dwFieldID,/* out */ CREDENTIAL_PROVIDER_FIELD_STATE *pcpfs,/* out */ CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE *pcpfis);HRESULT STDMETHODCALLTYPE GetStringValue( /* in */ DWORD dwFieldID,/* stringout */ L

14、PWSTR *ppsz);HRESULT STDMETHODCALLTYPE GetBitmapValue( /* in */ DWORD dwFieldID,/* out */ HBITMAP *phbmp);HRESULT STDMETHODCALLTYPE GetCheckboxValue( /* in */ DWORD dwFieldID,/* out */ BOOL *pbChecked,/* stringout */ LPWSTR *ppszLabel);HRESULT STDMETHODCALLTYPE GetSubmitButtonValue( /* in */ DWORD d

15、wFieldID,/* out */ DWORD *pdwAdjacentTo);HRESULT STDMETHODCALLTYPE GetComboBoxValueCount( /* in */ DWORD dwFieldID,/* out */ DWORD *pcItems,/* out */ DWORD *pdwSelectedItem);HRESULT STDMETHODCALLTYPE GetComboBoxValueAt( /* in */ DWORD dwFieldID,DWORD dwItem,/* stringout */ LPWSTR *ppszItem);HRESULT

16、STDMETHODCALLTYPE SetStringValue( /* in */ DWORD dwFieldID,/* stringin */ LPCWSTR psz);HRESULT STDMETHODCALLTYPE SetCheckboxValue( /* in */ DWORD dwFieldID,/* in */ BOOL bChecked);HRESULT STDMETHODCALLTYPE SetComboBoxSelectedValue( /* in */ DWORD dwFieldID,/* in */ DWORD dwSelectedItem);HRESULT STDM

17、ETHODCALLTYPE CommandLinkClicked( /* in */ DWORD dwFieldID);HRESULT STDMETHODCALLTYPE GetSerialization( /* out */ CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE *pcpgsr,/* out */ CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *pcpcs,/* out */ LPWSTR *ppszOptionalStatusText,/* out */ CREDENTIAL_PROVIDE

18、R_STATUS_ICON *pcpsiOptionalStatusIcon);HRESULT STDMETHODCALLTYPE ReportResult( /* in */ NTSTATUS ntsStatus,/* in */ NTSTATUS ntsSubstatus,/* out */ LPWSTR *ppszOptionalStatusText,/* out */ CREDENTIAL_PROVIDER_STATUS_ICON *pcpsiOptionalStatusIcon);Figure 3 ICredentialProvider 接口 ICredentialProvider

19、: public IUnknownHRESULT STDMETHODCALLTYPE SetUsageScenario( /* in */ CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,/* in */ DWORD dwFlags);HRESULT STDMETHODCALLTYPE SetSerialization( /* in */ const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION*pcpcs);HRESULT STDMETHODCALLTYPE Advise( /* in */ ICredentialP

20、roviderEvents *pcpe,/* in */ UINT_PTR upAdviseContext);HRESULT STDMETHODCALLTYPE UnAdvise( void);HRESULT STDMETHODCALLTYPE GetFieldDescriptorCount( /* out */ DWORD *pdwCount);HRESULT STDMETHODCALLTYPE GetFieldDescriptorAt( /* in */ DWORD dwIndex,/* out */ CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR *ppcpfd

21、);HRESULT STDMETHODCALLTYPE GetCredentialCount( /* out */ DWORD *pdwCount,/* out */ DWORD *pdwDefault,/* out */ BOOL *pbAutoLogonWithDefault);HRESULT STDMETHODCALLTYPE GetCredentialAt( /* in */ DWORD dwIndex,/* out */ ICredentialProviderCredential *ppcpc);了解这些缩写后,我们来看图 5 中的调试事件列表,这些事件是在某一示例方案期间发生的(我

22、会详细介绍其中的大部分事件)。用于生成调用序列的方案非常简单。首先将 Windows Vista 工作站加入域。然后用您的用户名、密码和域名配置智能卡。再将智能卡插入连接到该工作站的读卡器。然后重新启动系统。Figure 5 混合凭据提供程序调用序列 1. The system boots2. LogonUI.exe process is created3. Credential provider DLLs are loaded4. Provider:CreateInstance 5. User presses Ctrl+Alt+Del6. Provider:SetUsageScenario

23、(CPUS_LOGON)7. Credential:Initialize 8. Provider:Advise 9. Provider:GetCredentialCount 10. Provider:GetCredentialAt (dwIndex = 0)11. Provider:GetFieldDescriptorCount 12. Provider:GetFieldDescriptorAt (dwIndex = 0)13. Provider:GetFieldDescriptorAt (dwIndex = 1)14. Provider:GetFieldDescriptorAt (dwInd

24、ex = 2)15. Provider:GetFieldDescriptorAt (dwIndex = 3)16. Provider:GetFieldDescriptorAt (dwIndex = 4)17. Credential:GetBitmapValue (dwFieldID = 0; tile image)18. Credential:GetStringValue (dwFieldID = 1; user name field)19. Credential:GetFieldState (dwFieldID = 1; user name field)20. Credential:GetS

25、tringValue (dwFieldID = 2; password field)21. Credential:GetFieldState (dwFieldID = 2; password field)22. Credential:GetSubmitButtonValue (dwFieldID = 3; submit button)23. Credential:GetFieldState (dwFieldID = 3; submit button)24. Credential:GetStringValue (dwFieldID = 4; domain name field)25. Crede

26、ntial:GetFieldState (dwFieldID = 4; domain name field)26. Credential:Advise 27. Credential:GetSerialization 28. Credential:UnAdvise 29. Provider:UnAdvise 30. The WinLogon process calls LogonUser31. Credential:Advise 32. Credential:ReportResult (ntsStatus = 0)33. Credential:UnAdvise首 先,winlogon 启动控制台

27、会话 LogonUI 进程。创建后,LogonUI 枚举在 HKLMSoftwareMicrosoftWindowsCurrentVersionAunticationCredential Providers 下注册的所有凭据提供程序。每个提供程序 DLL 会被加载,并接收到一个 Provider:CreateInstance 调用。对于混合凭据提供程序,这将创建一个 CHybridProvider。(请参见 图 5 中的步骤 1 到 4。)用 户现在将看到登录屏幕。假定用户按了 Ctrl+Alt+Delete 并且每个提供程序都收到了 Provider:SetUsageScenario CPU

28、S_LOGON 通知。这向提供程序表明,用户想进行交互式登录。现在,该混合凭据提供程序将尝试从所插入的任何智能卡中读取凭据。如果找到了一个可读的智能卡,会将一个 CHybridCredential 实例化并将其与当前的 CHybridProvider 关联。 然后将有一个对 Credential:Initialize 的调用。 (请参见图 5 中的步骤 5 到 7。)LogonUI 随后为每个加载的提供程序调用 Provider:Advise。Advise 的目的是为提供程序提供一种机制,将对可见的 UI 元素(当前还未创建)所做的任何预期的更改通知给 LogonUI。内置的智能卡提供程序给出

29、了关于如何使用该机制的一个很好的例子。初始化之后,无论何时插入卡都会增大可用凭据数,而取出卡则会减小该数 字。发生此类情况时,将通过这种机制通知 LogonUI: ICredentialProviderEvents : public IUnknownHRESULT STDMETHODCALLTYPE CredentialsChanged( /* in */ UINT_PTR upAdviseContext);为简单起见,混合凭据提供程序不对卡的插入和取出进行动态处理。因此,它不跟踪通过 Advise 传递给它的 ICredentialProviderEvents 接口。LogonUI 执行的下

30、一个接口调用是调用 Provider:GetCredentialCount,即图 5 中的步骤 9。如果创建了混合凭据(由于插入的智能卡),混合凭据提供程序将执行一些操作。它首先将 GetCredentialCount *pdwCount 输出参数设置为 1。该值指的是提供程序要枚举的凭据图块数。(混合凭据提供程序只能处理 1 个。)首次安装 Windows Vista 并加入域时,您可以根据显示的图块数推断 Microsoft 密码凭据提供程序将什么 pdwCount 值返回到 LogonUI。混 合凭据提供程序然后将 GetCredentialCount *pdwDefault 输出参数设

31、置为 0。该值是一个从 0 开始的索引值,用于对每个提供程序假定要维护的凭据数组进行索引。如何实现提供程序跟踪其凭据由实施人员来完成,而在一组给定凭据对象的生存期内会一直对 索引进行维护。多 个提供程序枚举一个默认凭据是完全可能的。例如,在当前的方案中,可以预期内置的密码凭据提供程序将枚举它自己的一个默认凭据。LogonUI 如何提示用户从多个默认和非默认凭据中作出选择而不会使用户无从下手?一般来讲,对于每一个凭据,都会向用户显示一个图块,并且会将焦点设置到代表默认凭 据的那个图块。在存在多个默认凭据的情况下,实际的默认凭据是在枚举各个默认凭据时通过一系列优先规则选出的。对于各个凭据而言,如果

32、已有一个没有自动登 录的默认凭据,并且此凭据将要执行自动登录,则它将成为默认凭据。如果此凭据来自最后登录 (LLO) 提供程序并且尚还没有自动登录的默认凭据,则此凭据将成为默认凭据。最后,如果还没有默认凭据,则此凭据将成为默认凭据。尽管说了这么多,我的混合凭据提 供程序的自动登录语义使得该讨论没有什么实际意义。只要枚举的混合凭据包含有效的登录信息,用户就永远都看不到任何图块。下面我将对此稍作解释。我 已提到了与优先规则有关的最后登录提供程序,但应指出,LLO 的意义会根据用户是否正在登录或者它是否是登录后的情况(如桌面锁定或密码更改)而变化。登录时,LLO 提供程序是用于最后的控制台登录的最后

33、一个提供程序。登录后,LLO 提供程序只是用于登录到那个会话的提供程序。其原则就是如果始终用智能卡登录,则智能卡凭据提供程序默认图块将在重新启动后成为默认凭据。但如果因智能卡 丢失而使用密码登录,则解锁时密码凭据提供程序的图块将成为该会话的默认凭据。混 合凭据提供程序始终都会将 *pbAutoLogonWithDefault 输出参数设置为 TRUE。这用于向 LogonUI 发送通知,指示它应立即查询此提供程序的默认凭据以获得登录信息,而无需先向用户发送提示。请注意,通过使用可以存储在注册表中的密码自动登录信息(可 选),内置的密码凭据提供程序也具有相同的功能。实际上,如果 Windows

34、Vista 检测到该计算机上只有一个用户并且没有密码,则这就是默认行为。对于有多个凭据提供程序将 *pbAutoLogonWithDefault 设置为 TRUE 的情况,LogonUI 的行为尚不明确。执 行了 GetCredentialCount 调用之后,LogonUI 将调用 Provider:GetCredentialAt。对于混合凭据提供程序,此例程最多调用一次,它反映此提供程序的最大凭据计数。作为响应,提供程序 会返回该凭据实例的一个与请求的索引对应的 ICredentialProviderCredential 指针。接 下来,LogonUI 调用 Provider:GetFie

35、ldDescriptorCount,提供程序通过此调用返回在其凭据中可以找到的 UI 元素的最大数目。例如,我的密码凭据提供程序示例有五个域:一个位图、一个用户名输入域、一个密码输入域、一个提交按钮和一个域名输入域。即使实际上这些 元素从不显示,您仍可以看到混合凭据提供程序中保存了这些元素。这将完成图 5 中的步骤 11。LogonUI 然后将为每个 UI 元素分别调用一次 Provider:GetFieldDescriptorAt,以便检索其类型。例如,执行了对应于位图索引的调用之后,该示例将返回 CREDENTIAL_PROVIDER_FIELD_TYPE CPFT_TILE_IMAGE。

36、混合凭据提供程序中未使用的一个功能是与只读文本域相对的可写文本域。如果修改了混合凭据提供程序来提示用户输入智能卡 PIN,则此功能将通过 CPFT_PASSWORD_TEXT 来完成。可以显示从智能卡读取的用户名,以便提供某些上下文来提示用户输入信息。但就技术而言,用户名应为只读,因为它已绑定到同样存储在卡上的密码。因 此,可能会使用 CPFT_LARGE_TEXT 字段类型(与 CPFT_EDIT_TEXT 相对)。(有关选项的完整列表,请参见 credentialprovider.h。)完 成字段描述符的枚举之后,LogonUI 将根据每个凭据字段的类型对凭据提供程序执行一系列调用。例如,

37、对于 CPFT_TILE_IMAGE 字段类型,LogonUI 接下来将调用 Credential:GetBitmapValue。对于 CPFT_LARGE_TEXT 之类的用于用户名编辑框的文本值,随后会调用 Credential:GetStringValue 和 Credential:GetFieldState。由 于已从智能卡读取了我的混合凭据提供程序所需的所有登录信息(用户名、密码和域名),此时可以获得对应于每个文本字段的字符串,这些字符串通过 GetStringValue 的 ppwz 输出参数返回。此时,作为对 GetStringValue 的响应,其他提供程序则可能会返回 NUL

38、L 字符串值,因为用户还没来得及键入任何内容。请注意可能造成混淆的一点:文本字段名是通过 GetFieldDescriptorAt 检索的,而字段中当前的文本值则是通过 GetStringValue 检索的。(字段名或字段标签将显示为空编辑控件中的提示文本。)在完全描述了各种 UI 元素之后, LogonUI 将调用 Credential:Advise。(请参见图 5 中的步骤 26。)它与前面调用的 Provider:Advise 接口的作用类似;每个凭据都可以将影响 LogonUI 的 UI 元素状态的相关更改异步通知给 LogonUI。例如,在取消选择示例密码凭据提供程序的某一凭据图块时

39、,提供程序便使用这一机制。在这种情况下,凭据对象将使用 ICredentialProviderCredentialEvents SetFieldString(请参见 图 6)来清除密码域。这与在 Windows XP 登录屏幕中只键入部分密码然后便暂停时所发生的情况类似。最终,登录对话框将超时,文本将被清除。 Figure 6 ICredentialProviderEvents 接口 ICredentialProviderCredentialEvents : public IUnknownHRESULT STDMETHODCALLTYPE SetFieldState( /* in */ ICr

40、edentialProviderCredential *pcpc,/* in */ DWORD dwFieldID,/* in */ CREDENTIAL_PROVIDER_FIELD_STATE cpfs);HRESULT STDMETHODCALLTYPE SetFieldInteractiveState( /* in */ ICredentialProviderCredential *pcpc,/* in */ DWORD dwFieldID,/* in */ CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE cpfis);HRESULT STDME

41、THODCALLTYPE SetFieldString( /* in */ ICredentialProviderCredential *pcpc,/* in */ DWORD dwFieldID,/* uniquestringin */ LPCWSTR psz);HRESULT STDMETHODCALLTYPE SetFieldCheckbox( /* in */ ICredentialProviderCredential *pcpc,/* in */ DWORD dwFieldID,/* in */ BOOL bChecked,/* in */ LPCWSTR pszLabel);HRE

42、SULT STDMETHODCALLTYPE SetFieldBitmap( /* in */ ICredentialProviderCredential *pcpc,/* in */ DWORD dwFieldID,/* in */ HBITMAP hbmp);HRESULT STDMETHODCALLTYPE SetFieldComboBoxSelectedItem( /* in */ ICredentialProviderCredential *pcpc,/* in */ DWORD dwFieldID,/* in */ DWORD dwSelectedItem);HRESULT STD

43、METHODCALLTYPE DeleteFieldComboBoxItem( /* in */ ICredentialProviderCredential *pcpc,/* in */ DWORD dwFieldID,/* in */ DWORD dwItem);HRESULT STDMETHODCALLTYPE AppendFieldComboBoxItem( /* in */ ICredentialProviderCredential *pcpc,/* in */ DWORD dwFieldID,/* stringin */ LPCWSTR pszItem);HRESULT STDMET

44、HODCALLTYPE SetFieldSubmitButton( /* in */ ICredentialProviderCredential *pcpc,/* in */ DWORD dwFieldID,/* in */ DWORD dwAdjacentTo);HRESULT STDMETHODCALLTYPE OnCreatingWindow( /* out */ HWND *phwndOwner);就完成用户身份验证来说,下一个调用最为让人感兴趣。由于 GetCredentialCount 的 *pbAutoLogonWithDefault 参数已设置为 TRUE,LogonUI 知道默认凭据应已包含验证用户身份所需

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 重点行业资料库 > 建筑建材

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。