CredentialProvider提供的UI控件与使用方法
前言:在上一篇博客中对CredentialProvider基本概念、个人理解等做了阐述,其中提到CredentialProvider提供了一定的UI控件可供开发者调用,且开发者只可以使用CredentialProvider接口所提供的控件,不可自定义控件或者美化CredentialProvider接口所提供的控件,本文则结合具体的UI控件图例对CredentialProvider所提供的UI控件进行介绍。
CredentialProvider UI控件简介:如图所示,CredentialProvider提供的UI控件共有9种,开发者可以根据需要自行选择组合使用。该图例对应的代码来自开源的样例代码编译部署所得的截图,样例代码地址为:CredentialProviders/V2 Credential Provider Sample at master · alexyack/CredentialProviders
UI控件的定义为CREDENTIAL_PROVIDER_FIELD_TYPE枚举,开发在使用时只需指定需要的控件枚举即可,CREDENTIAL_PROVIDER_FIELD_TYPE的具体定义如下:
// credentialprovider.h:359typedef /* [v1_enum] */
enum _CREDENTIAL_PROVIDER_FIELD_TYPE
{CPFT_INVALID = 0,CPFT_LARGE_TEXT = ( CPFT_INVALID + 1 ) ,CPFT_SMALL_TEXT = ( CPFT_LARGE_TEXT + 1 ) ,CPFT_COMMAND_LINK = ( CPFT_SMALL_TEXT + 1 ) ,CPFT_EDIT_TEXT = ( CPFT_COMMAND_LINK + 1 ) ,CPFT_PASSWORD_TEXT = ( CPFT_EDIT_TEXT + 1 ) ,CPFT_TILE_IMAGE = ( CPFT_PASSWORD_TEXT + 1 ) ,CPFT_CHECKBOX = ( CPFT_TILE_IMAGE + 1 ) ,CPFT_COMBOBOX = ( CPFT_CHECKBOX + 1 ) ,CPFT_SUBMIT_BUTTON = ( CPFT_COMBOBOX + 1 )
} CREDENTIAL_PROVIDER_FIELD_TYPE;
CredentialProvider UI控件的使用:UI控件的使用可以参考上面样例中的common.h,根据个人开发需要添加或者删除对应的控件即可,其中SAMPLE_FIELD_ID中的SFI_NUM_FIELDS必须保留,且只能放在最后一个,其表明自定义凭据所包含的UI字段数量。common.h源码如下所示:
// common.h
// https://github.com/alexyack/CredentialProviders/blob/master/V2%20Credential%20Provider%20Sample/C%2B%2B/common.h#pragma once
#include "helpers.h"// The indexes of each of the fields in our credential provider's tiles. Note that we're
// using each of the nine available field types here.
enum SAMPLE_FIELD_ID
{SFI_TILEIMAGE = 0,SFI_LABEL = 1,SFI_LARGE_TEXT = 2,SFI_PASSWORD = 3,SFI_SUBMIT_BUTTON = 4,SFI_LAUNCHWINDOW_LINK = 5,SFI_HIDECONTROLS_LINK = 6,SFI_FULLNAME_TEXT = 7,SFI_DISPLAYNAME_TEXT = 8,SFI_LOGONSTATUS_TEXT = 9,SFI_CHECKBOX = 10,SFI_EDIT_TEXT = 11,SFI_COMBOBOX = 12,SFI_NUM_FIELDS = 13, // Note: if new fields are added, keep NUM_FIELDS last. This is used as a count of the number of fields
};// The first value indicates when the tile is displayed (selected, not selected)
// the second indicates things like whether the field is enabled, whether it has key focus, etc.
struct FIELD_STATE_PAIR
{CREDENTIAL_PROVIDER_FIELD_STATE cpfs;CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE cpfis;
};// These two arrays are seperate because a credential provider might
// want to set up a credential with various combinations of field state pairs
// and field descriptors.// The field state value indicates whether the field is displayed
// in the selected tile, the deselected tile, or both.
// The Field interactive state indicates when
static const FIELD_STATE_PAIR s_rgFieldStatePairs[] =
{{ CPFS_DISPLAY_IN_BOTH, CPFIS_NONE }, // SFI_TILEIMAGE{ CPFS_HIDDEN, CPFIS_NONE }, // SFI_LABEL{ CPFS_DISPLAY_IN_BOTH, CPFIS_NONE }, // SFI_LARGE_TEXT{ CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_FOCUSED }, // SFI_PASSWORD{ CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, // SFI_SUBMIT_BUTTON{ CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, // SFI_LAUNCHWINDOW_LINK{ CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, // SFI_HIDECONTROLS_LINK{ CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, // SFI_FULLNAME_TEXT{ CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, // SFI_DISPLAYNAME_TEXT{ CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, // SFI_LOGONSTATUS_TEXT{ CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, // SFI_CHECKBOX{ CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, // SFI_EDIT_TEXT{ CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, // SFI_COMBOBOX
};// Field descriptors for unlock and logon.
// The first field is the index of the field.
// The second is the type of the field.
// The third is the name of the field, NOT the value which will appear in the field.
static const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR s_rgCredProvFieldDescriptors[] =
{{ SFI_TILEIMAGE, CPFT_TILE_IMAGE, L"Image", CPFG_CREDENTIAL_PROVIDER_LOGO },{ SFI_LABEL, CPFT_SMALL_TEXT, L"Tooltip", CPFG_CREDENTIAL_PROVIDER_LABEL },{ SFI_LARGE_TEXT, CPFT_LARGE_TEXT, L"Sample Credential Provider" },{ SFI_PASSWORD, CPFT_PASSWORD_TEXT, L"Password text" },{ SFI_SUBMIT_BUTTON, CPFT_SUBMIT_BUTTON, L"Submit" },{ SFI_LAUNCHWINDOW_LINK, CPFT_COMMAND_LINK, L"Launch helper window" },{ SFI_HIDECONTROLS_LINK, CPFT_COMMAND_LINK, L"Hide additional controls" },{ SFI_FULLNAME_TEXT, CPFT_SMALL_TEXT, L"Full name: " },{ SFI_DISPLAYNAME_TEXT, CPFT_SMALL_TEXT, L"Display name: " },{ SFI_LOGONSTATUS_TEXT, CPFT_SMALL_TEXT, L"Logon status: " },{ SFI_CHECKBOX, CPFT_CHECKBOX, L"Checkbox" },{ SFI_EDIT_TEXT, CPFT_EDIT_TEXT, L"Edit text" },{ SFI_COMBOBOX, CPFT_COMBOBOX, L"Combobox" },
};static const PWSTR s_rgComboBoxStrings[] =
{L"First",L"Second",L"Third",
};
其中,CredentialProvider所提供的部分UI控件样式与展示形式并非完全一成不变,如图中所示的CPFT_SUBMIT_BUTTON按钮可以像图中那样附属于CPFT_PASSWORD_TEXT控件右侧以向右的箭头形式显示,也可以以独立形式的按钮显示。若以独立的按钮形式显示,则只可在自定义凭据类中对GetSubmitButtonValue方法中的*pdwAdjacentTo参数赋值为按钮自身所对应的ID值,并将common.h中CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR中的按钮字段所对应的第四个参数指定为CPFG_STANDALONE_SUBMIT_BUTTON即可,具体代码如下:
// TestCredential.cppHRESULT TestCredential::GetSubmitButtonValue(DWORD dwFieldID, _Out_ DWORD *pdwAdjacentTo)
{OutputDebugStringA(__FUNCTION__);HRESULT hr;if (SFI_SUBMIT_BUTTON == dwFieldID){// #########################################################################// 附属于CPFT_PASSWORD_TEXT密码文本控件,密码文本控件对应的字段ID为SFI_PASSWORD//*pdwAdjacentTo = SFI_PASSWORD;// #########################################################################// #########################################################################// 按钮独立显示,则赋值为SFI_SUBMIT_BUTTON*pdwAdjacentTo = SFI_SUBMIT_BUTTON;// #########################################################################hr = S_OK;}else{hr = E_INVALIDARG;}return hr;
}
指定第四个参数为CPFG_STANDALONE_SUBMIT_BUTTON,意思为以标准按钮形式显示,具体如下:
static const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR s_rgCredProvFieldDescriptors[] =
{// 指定第四个参数为CPFG_STANDALONE_SUBMIT_BUTTON,意思为以标准按钮形式显示{ SFI_SUBMIT_BUTTON, CPFT_SUBMIT_BUTTON, L"Submit", CPFG_STANDALONE_SUBMIT_BUTTON},
};
类似的CPFT_COMMAND_LINK链接文本控件,其可以通过指定第四个参数为CPFG_STYLE_LINK_AS_BUTTON而以标准按钮形式显示,具体代码如下:
static const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR s_rgCredProvFieldDescriptors[] =
{{ SFI_HIDECONTROLS_LINK, CPFT_COMMAND_LINK, L"Hide additional controls", PFG_STYLE_LINK_AS_BUTTON},
};
更多的UI可选性显示形式定义见如下GUID定义,开发者可以根据研发需要指定部分UI的显示形式
// ShlGuid.h:669//
// These GUIDs may be assigned to the CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR::guidFieldType
// member by Microsoft ICredentialProvider implementations.
//// {da15bbe8-954sd-4fd3-b0f4-1fb5b90b174b}
DEFINE_GUID(CPFG_LOGON_USERNAME, 0xda15bbe8, 0x954d, 0x4fd3, 0xb0, 0xf4, 0x1f, 0xb5, 0xb9, 0x0b, 0x17, 0x4b);// {60624cfa-a477-47b1-8a8e-3a4a19981827}
DEFINE_GUID(CPFG_LOGON_PASSWORD, 0x60624cfa, 0xa477, 0x47b1, 0x8a, 0x8e, 0x3a, 0x4a, 0x19, 0x98, 0x18, 0x27);// {3e1ecf69-568c-4d96-9d59-46444174e2d6}
DEFINE_GUID(CPFG_SMARTCARD_USERNAME, 0x3e1ecf69, 0x568c, 0x4d96, 0x9d, 0x59, 0x46, 0x44, 0x41, 0x74, 0xe2, 0xd6);// {4fe5263b-9181-46c1-b0a4-9dedd4db7dea}
DEFINE_GUID(CPFG_SMARTCARD_PIN, 0x4fe5263b, 0x9181, 0x46c1, 0xb0, 0xa4, 0x9d, 0xed, 0xd4, 0xdb, 0x7d, 0xea);// {2d837775-f6cd-464e-a745-482fd0b47493}
DEFINE_GUID(CPFG_CREDENTIAL_PROVIDER_LOGO, 0x2d837775, 0xf6cd, 0x464e, 0xa7, 0x45, 0x48, 0x2f, 0xd0, 0xb4, 0x74, 0x93);// {286BBFF3-BAD4-438F-B007-79B7267C3D48}
DEFINE_GUID(CPFG_CREDENTIAL_PROVIDER_LABEL, 0x286bbff3, 0xbad4, 0x438f, 0xb0, 0x7, 0x79, 0xb7, 0x26, 0x7c, 0x3d, 0x48);// {0b7b0ad8-cc36-4d59-802b-82f714fa7022}
DEFINE_GUID(CPFG_STANDALONE_SUBMIT_BUTTON, 0x0b7b0ad8, 0xcc36, 0x4d59, 0x80, 0x2b, 0x82, 0xf7, 0x14, 0xfa, 0x70, 0x22);// {088fa508-94a6-4430-a4cb-6fc6e3c0b9e2}
DEFINE_GUID(CPFG_STYLE_LINK_AS_BUTTON, 0x088fa508, 0x94a6, 0x4430, 0xa4, 0xcb, 0x6f, 0xc6, 0xe3, 0xc0, 0xb9, 0xe2);