C++ Окно прогресса поставщика учетных данных Windows
Я занимаюсь разработкой пользовательского поставщика учетных данных, и мне нужно показать экран прогресса с кнопкой отмены. В некоторых провайдерах учетных данных и плагинах pgina я видел, что во время работы провайдера учетных данных отображается экран с кнопкой "Отмена". Я приложил скриншот этого. Мне удалось показать экран ошибок с помощью кнопки Ok, используя следующий код:
*pcpgsr = CPGSR_NO_CREDENTIAL_NOT_FINISHED;
SHStrDupW(L"Authentication Failed", ppwszOptionalStatusText);
*pcpsiOptionalStatusIcon = CPSI_ERROR;
Теперь мне нужно показать этот экран с кнопкой отмены. Любой совет, как это может быть достигнуто? Кроме того, как обрабатывать событие, которое возникает при нажатии этой кнопки?
3 ответа
@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;
};
Затем класс для вашего интерфейса, похожий на этот
#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 Если вы не против опубликовать свой код, я заставлю его работать. Не могу прокомментировать ваше сообщение напрямую, так как я ограничиваюсь требованиями сайта
Как я понимаю ваш сценарий, вы хотите сделать что-то в фоновом режиме, представляя пользователю "экран ожидания".
Вы должны запустить отдельный поток для фоновой работы и изменить макет вашей плитки учетных данных, чтобы оставить видимым только один текстовый элемент с содержимым "Wait..." и без кнопки отправки.
Как только ваш фоновый поток завершит свою работу, вы можете открыть кнопку "Отправить" и позволить пользователю продолжить вход в систему.
Например, посмотрите на встроенные Smartcard Credential Porvider
и его поведение при вставке и удалении карты.
Я полагаю, ты ищешь IConnectableCredentialProviderCredential::Connect()
. Вам необходимо реализоватьIConnectableCredentialProviderCredential
интерфейс и поместите свою логику в Connect()
функция. Вызывается сразу после нажатия кнопки "Отправить". ВConnect()
функция даст вам IQueryContinueWithStatus
интерфейс. В этом интерфейсе вам нужно вызватьQueryContinue()
периодически для обработки кнопки Отмена или некоторых системных событий.
Дополнительные сведения см. В этой статье: https://docs.microsoft.com/en-us/windows/win32/api/credentialprovider/nf-credentialprovider-iconnectablecredentialprovidercredential-connect
@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;
}; Затем класс для вашего интерфейса, похожий на этот
#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