C++ Windows Credential Provider Progress Screen

我怕爱的太早我们不能终老 提交于 2019-12-12 19:20:27

问题


I am developing a custom credential provider and I have to show a progress screen with a cancel button. I have seen in some credentials providers and pgina plugins that a screen is displayed with a Cancel button when credential provider is working. I have attached a screenshot of it. I have managed to show the error screen with an Ok button using the following code:

*pcpgsr = CPGSR_NO_CREDENTIAL_NOT_FINISHED;
SHStrDupW(L"Authentication Failed", ppwszOptionalStatusText);
*pcpsiOptionalStatusIcon = CPSI_ERROR;

Now I need to show this progress screen with a cancel button. Any advice how can it be achieved? Also, how to handle the event that fires when this button is pressed?


回答1:


As I understand your scenario you want to do something in background presenting to the user "wait screen".

You must run a separate thread for background work and change the layout of your credential tile to leave visible only one text element with "Wait..." content and no submit button.

Once your background thread complete its work you may reveal submit button and let user to continue to logon.

For example, have a look at embedded Smartcard Credential Porvider and its behaviour on insertion and removal of the card.




回答2:


@js.hrt You can run your main thread as dialog, while your background thread does the job. The cancel button would be the control in the dialog, allowing to cancel it. If you need more info, let me know, I can provide some details, as this is the way we do it.

@js.hrt Briefly, you need two classes: dialog and thread. When you create a dialog, it will create a thread, which will run what you need, and show cancel button. Clicking on it will terminate your thread. Some code below. Hope it helps.

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;
};

Then, class for your UI, similar to this

#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;
 };

The resource for dialog could be like this:

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 If you don't mind to post your code, I'll make it run. Can't comment to your's message directly, as I limit by site requirements




回答3:


@js.hrt Per your request.

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;

}; Then, class for your UI, similar to this

#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;

}; The resource for dialog could be like this:

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


来源:https://stackoverflow.com/questions/51935430/c-windows-credential-provider-progress-screen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!