Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

[dev] Trigger Unlock from Plugin

lspcity
2013-03-24
2013-04-10
  • lspcity
    lspcity
    2013-03-24

    I try to implement a way to trigger the open-database-method from a plugin.

    I can call host.MainWindow.OpenDatabase()
    I also have access to the DocumentManager for the LockIOC: host.MainWindow.DocumentManager.ActiveDocument.LockedIoc

    But then KeePass checks if the database was opened successfully:
    if(pd.IsOpen)
    {
    ds.LockedIoc = new IOConnectionInfo(); // Clear lock
    RestoreWindowState(pd);
    }

    Now I clear the LockedIoc --> no problem.
    But RestoreWindowState() for the selected database is a private method. I could copy it to my plugin, but in this private method are other private methods and so on.

    Is there an easy way to trigger the event of unlocking a database?
    Thank you.

     
  • Dominik Reichl
    Dominik Reichl
    2013-03-24

    I'd recommend first using host.MainWindow.OpenDatabase to unlock/open the database, then search for the correct PwDocument object in host.MainWindow.DocumentManager.Documents, test whether the database has been opened successfully (by doc.Database.IsOpen), and if so, call host.MainWindow.MakeDocumentActive(doc) (this will among other things restore the window state).

    Of course the last step should only be performed if the database is expected to be activated. If it's acceptable that the database is opened in the background, simply do not call MakeDocumentActive; KeePass will restore the window state when the user switches to the database's tab.

    Please do not modify the LockedIoc property in a plugin.

    Best regards,
    Dominik

     
  • lspcity
    lspcity
    2013-03-24

    Thank you for your fast reply.

    My code currently looks like this:

    if (!host.Database.IsOpen)
    {
    host.MainWindow.OpenDatabase(host.MainWindow.DocumentManager.ActiveDocument.LockedIoc, null, false);
    }

    But then I get the following error message.
    I think it's because of the attribute LockedIoc which I need to define in OpenDatabase :-/
    When I try to set ioConnection to null nothing happens and I'm no longer able to unlock the database manually.


    See the end of this message for details on invoking
    just-in-time (JIT) debugging instead of this dialog box.

    ** Exception Text **
    System.InvalidOperationException: DragDrop registration did not succeed. ---> System.Threading.ThreadStateException: Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it.
    at System.Windows.Forms.Control.SetAcceptDrops(Boolean accept)
    --- End of inner exception stack trace ---
    at System.Windows.Forms.Control.SetAcceptDrops(Boolean accept)
    at System.Windows.Forms.Control.set_AllowDrop(Boolean value)
    at KeePass.UI.SecureEdit.Attach(TextBox tbPasswordBox, EventHandler evTextChanged, Boolean bHidePassword)
    at KeePass.Forms.KeyPromptForm.OnFormLoad(Object sender, EventArgs e)
    at System.Windows.Forms.Form.OnLoad(EventArgs e)
    at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
    at System.Windows.Forms.Control.CreateControl()
    at System.Windows.Forms.Control.WmShowWindow(Message& m)
    at System.Windows.Forms.Control.WndProc(Message& m)
    at System.Windows.Forms.Form.WndProc(Message& m)
    at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

    ** Loaded Assemblies **
    mscorlib
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.18034 built by: FX45RTMGDR
    CodeBase: file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll
    ----------------------------------------
    KeePass
    Assembly Version: 2.21.0.21106
    Win32 Version: 2.21.0.0
    CodeBase: file:///p:/dev/C%23/keepasshttp/%23portable/KeePass.exe
    ----------------------------------------
    System.Windows.Forms
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.18036 built by: FX45RTMGDR
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0b77a5c561934e089/System.Windows.Forms.dll
    ----------------------------------------
    System.Drawing
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.18021 built by: FX45RTMGDR
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0
    b03f5f7f11d50a3a/System.Drawing.dll
    ----------------------------------------
    System
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.18034 built by: FX45RTMGDR
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0b77a5c561934e089/System.dll
    ----------------------------------------
    System.Xml
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.18034 built by: FX45RTMGDR
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0
    b77a5c561934e089/System.Xml.dll
    ----------------------------------------
    System.Configuration
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.17929 built by: FX45RTMREL
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0b03f5f7f11d50a3a/System.Configuration.dll
    ----------------------------------------
    KeePassHttp
    Assembly Version: 2.21.0.0
    Win32 Version: 1.1.4.0
    CodeBase: file:///C:/Users/Lukas/AppData/Local/KeePass/PluginCache/9hMAAnVEAN07yfCTJyni/KeePassHttp.dll
    ----------------------------------------
    System.Security
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.18021 built by: FX45RTMGDR
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Security/v4.0_4.0.0.0
    b03f5f7f11d50a3a/System.Security.dll
    ----------------------------------------
    Newtonsoft.Json
    Assembly Version: 3.5.0.0
    Win32 Version: 3.5.0.0
    CodeBase: file:///C:/Users/Lukas/AppData/Local/KeePass/PluginCache/9hMAAnVEAN07yfCTJyni/Newtonsoft.Json.DLL
    ----------------------------------------

    ** JIT Debugging **
    To enable just-in-time (JIT) debugging, the .config file for this
    application or computer (machine.config) must have the
    jitDebugging value set in the system.windows.forms section.
    The application must also be compiled with debugging
    enabled.

    For example:

    <configuration>
    <system.windows.forms jitDebugging="true"/>
    </configuration>

    When JIT debugging is enabled, any unhandled exception
    will be sent to the JIT debugger registered on the computer
    rather than be handled by this dialog box.

     
  • Dominik Reichl
    Dominik Reichl
    2013-03-24

    Your code looks good to me.

    The exception indicates a threading problem. Make sure your code is running on the main window thread. If you're running on a different thread, e.g. put the code into a method and call this method using host.MainWindow.Invoke (to run it on the main window thread).

    Best regards,
    Dominik

     
  • lspcity
    lspcity
    2013-03-24

    Wow, great!
    That works pefectly. Thank you!

    if (!host.Database.IsOpen)
    {
        host.MainWindow.Invoke((MethodInvoker)delegate
        {
            host.MainWindow.OpenDatabase(
                host.MainWindow.DocumentManager.ActiveDocument.LockedIoc,
                null,
                false
            );
        });
    }
    
     
  • lspcity
    lspcity
    2013-03-24

    One more improvement:

    When the invoke is called it starts blinking in the background.
    Is it also possible to bring it into foreground, even if it's minimized to tray?

    I already tried to call host.MainWindow.BringToFront(), but doesn't work.
    Also the open-dialog doesn't blink if KeePass is minimized and OpenDatabase() is called.

     
    Last edit: lspcity 2013-03-24
  • Dominik Reichl
    Dominik Reichl
    2013-03-24

    You can restore the KeePass window (from tray or from taskbar) by calling host.MainWindow.EnsureVisibleForegroundWindow(true, true).

    Note this might trigger an automatic unlock, thus you might want to run your other code after the window restoration.

    If the window does not come to the foreground when calling EnsureVisibleForegroundWindow, Windows has prevented it, e.g. in order to not disturb the user when he's working in a different window; the KeePass window then just blinks in the taskbar.

    Best regards,
    Dominik

     
  • lspcity
    lspcity
    2013-03-24

    Some weeks ago I also tried the function EnsureVisibleForegroundWinodw and I got an error. Now I understand "why" and "how" I can call it correctly: With host.MainWindow.Invoke()!

    Thank you.
    Now it works great :-)

    By the way, it's for unlocking the database when requesting credentials with KeePassHttp

     
  • lspcity
    lspcity
    2013-03-29

    Is it possible to determine whether the OpenDatabase-Dialog is already visible or was already triggered?

    Situation 1: KeePass is restored and automatically triggers an unlock --> if this fails, I trigger it again

    Situation 2: KeePass already shows the unlock dialog --> I trigger it again and a second (!) dialog will be shown

    My code is the following:

    host.MainWindow.Invoke((MethodInvoker)delegate
    {
        host.MainWindow.EnsureVisibleForegroundWindow(true, true);
    });
    
    if (!db.IsOpen)
    {
        host.MainWindow.Invoke((MethodInvoker)delegate
        {
            host.MainWindow.OpenDatabase(host.MainWindow.DocumentManager.ActiveDocument.LockedIoc, null, false);
        });
    }
    
     
    Last edit: lspcity 2013-03-29
  • lspcity
    lspcity
    2013-04-05

    Any suggestions?

     
  • Paul
    Paul
    2013-04-05

    Dominik may be able to help.

    cheers, Paul

     
  • Dominik Reichl
    Dominik Reichl
    2013-04-05

    Sorry for the late reply; for some reason I didn't get a notification e-mail for your post.

    You can test whether the master key dialog is displayed by

    bool bKpf = ((KeePass.UI.GlobalWindowManager.TopWindow as KeyPromptForm) != null);
    

    One disadvantage of this approach is that when the user e.g. opens the key file browser dialog (from the master key dialog) on the secure desktop, the above code will evaluate to false, because the master key dialog is only the second-topmost window.

    Thus I would instead recommend to test whether no sub-dialog is opened at all.

    bool bNoDialog = (KeePass.UI.GlobalWindowManager.WindowCount == 0);
    

    Best regards,
    Dominik

     
  • lspcity
    lspcity
    2013-04-10

    Thank you!
    The last one works very well for me.

    Best regards
    Lukas