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
Другие вопросы по тегам