C++ Windows 凭据提供程序进度屏幕
Posted
技术标签:
【中文标题】C++ Windows 凭据提供程序进度屏幕【英文标题】:C++ Windows Credential Provider Progress Screen 【发布时间】:2018-08-20 17:00:03 【问题描述】:我正在开发一个自定义凭据提供程序,我必须显示一个带有取消按钮的进度屏幕。我在一些凭据提供程序和 pgina 插件中看到,当凭据提供程序工作时,屏幕会显示一个带有取消按钮的按钮。我附上了它的截图。我已经设法使用以下代码显示带有确定按钮的错误屏幕:
*pcpgsr = CPGSR_NO_CREDENTIAL_NOT_FINISHED;
SHStrDupW(L"Authentication Failed", ppwszOptionalStatusText);
*pcpsiOptionalStatusIcon = CPSI_ERROR;
现在我需要用取消按钮显示这个进度屏幕。任何建议如何实现?另外,当这个按钮被按下时,如何处理触发的事件?
【问题讨论】:
不管怎样,我现在和@js.hrt 处于同一位置。我正在研究凭据提供程序并愿意放置取消按钮。这个问题解决了吗?我只是想显示取消按钮并使其基于线程工作,因此它不会干预主线程 【参考方案1】:据我了解,您想在后台做一些事情,向用户展示“等待屏幕”。
您必须为后台工作运行一个单独的线程,并更改您的凭证磁贴的布局,以使只有一个带有“等待...”内容且没有提交按钮的文本元素可见。
一旦您的后台线程完成其工作,您可以显示提交按钮并让用户继续登录。
例如,查看嵌入式Smartcard Credential Porvider
及其在插入和移除卡时的行为。
【讨论】:
是的,你没看错。是的,我目前已经按照您的建议实施了它(我隐藏了所有其他元素,只显示了文本“请稍候......”)。但是在这种方法中,没有取消按钮。例如,如果一个后台线程正在运行并且用户想要取消并返回更改身份验证方法(假设有不同的身份验证方法可用),他将如何做到这一点?他将不得不等待该过程完成或超时。所以我需要包含一个取消按钮。 虽然,我们也可以通过 SetDeselected() 方法处理这个问题,但我需要采用屏幕截图中显示的方法(带有取消按钮) 必须尝试使用CPFT_COMMAND_LINK
元素。
据我所知 CPFT_COMMAND_LINK 是一个超链接。可以显示为按钮吗?
@js.hrt 不,超链接是链接样式的控件(下划线文本),但它是可点击的!【参考方案2】:
@js.hrt 您可以将主线程作为对话框运行,而您的后台线程执行该工作。取消按钮将是对话框中的控件,允许取消它。如果您需要更多信息,请告诉我,我可以提供一些详细信息,因为我们就是这样做的。
@js.hrt 简而言之,您需要两个类:对话框和线程。 当您创建一个对话框时,它将创建一个线程,它将运行您需要的内容,并显示取消按钮。单击它将终止您的线程。下面的一些代码。希望对您有所帮助。
class Thread
public:
Thread(GUI* object);
virtual ~Thread();
bool start( bool )
::CreateThread( NULL, 0, threadRun, lpParameter, dwCreationFlags,
&m_dwThreadId );
static DWORD WINAPI threadRun( void* lpVoid )
DWORD dwReturn( 0 );
dwReturn = m_object->yourProcessToRun();
return dwReturn;
protected:
GUI* m_object;
Runnable* m_lpRunnable;
;
然后,为您的 UI 类,类似于此
#include "atlwin.h"
class GUI: public CDialogImpl<GUI>
public:
enum IDD = IDD_FOR_YOUR_DIALOG ;
GUI();
~GUI();
BEGIN_MSG_MAP(GUI)
MESSAGE_HANDLER(WM_INITDIALOG,OnInitDialog)
COMMAND_ID_HANDLER(ID_CANCEL,OnCancel)
MESSAGE_HANDLER(WM_TIMER,OnTimer)
MESSAGE_HANDLER(WM_DESTROY,OnDestroy)
END_MSG_MAP()
LRESULT OnInitDialog(UINT,WPARAM,LPARAM, BOOL&)
myThread = new Thread(this);
m_nTimerID = SetTimer(1,3000,NULL);
myThread->start();
LRESULT OnCancel(WORD,WORD,HWND,BOOL& )
if(NULL != myThread)
DWORD exitCode = 0;
myThread->getExitCode(exitCode);
if(exitCode == STILL_ACTIVE)
myThread->terminate();
delete myThread;
myThread = NULL;
EndDialog(IDCANCEL);
return true;
LRESULT OnTimer(UINT,WPARAM wParam,LPARAM,BOOL&)
if(wParam != m_nTimerID)
return FALSE;
m_timerticks++;
return FALSE;
LRESULT OnDestroy(UINT,WPARAM,LPARAM,BOOL&)
KillTimer(m_nTimerID);
return FALSE;
virtual int yourProcessToRun() ;
void onFinishProgress(int retCode = IDOK)
if (retCode != IDCANCEL)
delete myThread;
myThread = NULL;
KillTimer(m_nTimerID);
EndDialog(retCode);
private:
Thread* myThread;
UINT m_nTimerID;
UINT m_timerticks;
;
对话框的资源可能是这样的:
IDD_FOR_YOUR_DIALOG DIALOGEX 0, 0, 309, 80
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP
| WS_CAPTION
CAPTION "Whatever"
FONT 8, "MS Shell Dlg", 400, 0, 0x0
BEGIN
PUSHBUTTON "Cancel",ID_CANCEL,113,50,84,14
CTEXT "Static",IDC_FOR_SOMETHING,7,7,295,20
END
@js.hrt 如果你不介意发布你的代码,我会让它运行。 无法直接评论您的消息,因为我受站点限制 要求
【讨论】:
谢谢。你能举例说明你是如何显示对话框的吗? 我正在尝试您的代码,但出现了很多错误。我是 C++ 新手,因此在识别问题时遇到困难。你能告诉我要包含哪些文件以及如何使这个示例工作吗?【参考方案3】:@js.hrt 根据您的要求。
class Thread
public:
Thread(GUI* object);
virtual ~Thread();
bool start( bool )
::CreateThread( NULL, 0, threadRun, lpParameter, dwCreationFlags,
&m_dwThreadId );
static DWORD WINAPI threadRun( void* lpVoid )
DWORD dwReturn( 0 );
dwReturn = m_object->yourProcessToRun();
return dwReturn;
protected:
GUI* m_object;
Runnable* m_lpRunnable;
; 然后,为您的 UI 分类,类似于此
#include "atlwin.h"
class GUI: public CDialogImpl<GUI>
public:
enum IDD = IDD_FOR_YOUR_DIALOG ;
GUI();
~GUI();
BEGIN_MSG_MAP(GUI)
MESSAGE_HANDLER(WM_INITDIALOG,OnInitDialog)
COMMAND_ID_HANDLER(ID_CANCEL,OnCancel)
MESSAGE_HANDLER(WM_TIMER,OnTimer)
MESSAGE_HANDLER(WM_DESTROY,OnDestroy)
END_MSG_MAP()
LRESULT OnInitDialog(UINT,WPARAM,LPARAM, BOOL&)
myThread = new Thread(this);
m_nTimerID = SetTimer(1,3000,NULL);
myThread->start();
LRESULT OnCancel(WORD,WORD,HWND,BOOL& )
if(NULL != myThread)
DWORD exitCode = 0;
myThread->getExitCode(exitCode);
if(exitCode == STILL_ACTIVE)
myThread->terminate();
delete myThread;
myThread = NULL;
EndDialog(IDCANCEL);
return true;
LRESULT OnTimer(UINT,WPARAM wParam,LPARAM,BOOL&)
if(wParam != m_nTimerID)
return FALSE;
m_timerticks++;
return FALSE;
LRESULT OnDestroy(UINT,WPARAM,LPARAM,BOOL&)
KillTimer(m_nTimerID);
return FALSE;
virtual int yourProcessToRun() ;
void onFinishProgress(int retCode = IDOK)
if (retCode != IDCANCEL)
delete myThread;
myThread = NULL;
KillTimer(m_nTimerID);
EndDialog(retCode);
private:
Thread* myThread;
UINT m_nTimerID;
UINT m_timerticks;
; 对话框的资源可能是这样的:
IDD_FOR_YOUR_DIALOG DIALOGEX 0, 0, 309, 80
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP
| WS_CAPTION
CAPTION "Whatever"
FONT 8, "MS Shell Dlg", 400, 0, 0x0
BEGIN
PUSHBUTTON "Cancel",ID_CANCEL,113,50,84,14
CTEXT "Static",IDC_FOR_SOMETHING,7,7,295,20
END
【讨论】:
【参考方案4】:我假设您正在寻找IConnectableCredentialProviderCredential::Connect()
。
您需要实现IConnectableCredentialProviderCredential
interface 并将您的逻辑放到Connect()
函数中。在按下提交按钮后立即调用它。
Connect()
函数将为您提供IQueryContinueWithStatus
接口。在这个界面中需要定期调用QueryContinue()
函数来处理取消按钮或者一些系统事件。
更多信息请看这篇文章:https://docs.microsoft.com/en-us/windows/win32/api/credentialprovider/nf-credentialprovider-iconnectablecredentialprovidercredential-connect
【讨论】:
以上是关于C++ Windows 凭据提供程序进度屏幕的主要内容,如果未能解决你的问题,请参考以下文章