C++ Windows Credential Provider Progress Screen

后端 未结 4 1807
误落风尘
误落风尘 2021-01-15 09:03

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 sc

相关标签:
4条回答
  • 2021-01-15 09:27

    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.

    0 讨论(0)
  • 2021-01-15 09:29

    @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
    
    0 讨论(0)
  • 2021-01-15 09:34

    I assume you are looking for IConnectableCredentialProviderCredential::Connect(). You need to implement the IConnectableCredentialProviderCredentialinterface and put your logic to the Connect() function. It is called right after Submit button pressed. The Connect() function will give you the IQueryContinueWithStatus interface. In this interface you need to call the QueryContinue() function periodically, to handle Cancel button or some system events.

    For more information look at this article: https://docs.microsoft.com/en-us/windows/win32/api/credentialprovider/nf-credentialprovider-iconnectablecredentialprovidercredential-connect

    0 讨论(0)
  • 2021-01-15 09:43

    @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

    0 讨论(0)
提交回复
热议问题