This documentation applies to KeePass 2.x plugins. 2.x plugins are fundamentally
different from 1.x plugins. 1.x plugins cannot be loaded by KeePass 2.x.
Requirements
Before you can start developing a KeePass plugin, you need the following
prerequisites:
Step-by-Step Tutorial
Start your favorite IDE and create a new C# Class Library project
(for the .NET Framework, not .NET Standard/Core).
In this tutorial, the example plugin we're developing is called SimplePlugin .
The first thing you need to do now is to add a reference to KeePass:
go to the references dialog and select the KeePass.exe file
(from the portable ZIP package).
After you added the reference, the namespaces KeePass and
KeePassLib should be available.
It is important that you reference an official KeePass.exe ,
not a development snapshot or own build, because otherwise your
plugin will be incompatible with official KeePass builds.
All KeePass plugins need to derive from a base KeePass plugin class
(Plugin in the KeePass.Plugins namespace).
By overriding methods and properties of this class, you can customize
the behavior of your plugin.
A minimal plugin looks like this:
using System;
using System.Collections.Generic;
using KeePass.Plugins;
namespace SimplePlugin
{
public sealed class SimplePluginExt : Plugin
{
private IPluginHost m_host = null;
public override bool Initialize(IPluginHost host)
{
if(host == null) return false;
m_host = host;
return true;
}
}
}
You can find a fully documented and extended version of this simple
plugin on the KeePass plugins web page.
This plugin does exactly nothing, but it shows some important conventions
already, which must be followed by all plugins:
- The namespace must be named like the DLL file without extension. Our DLL
file is named
SimplePlugin.dll , therefore the namespace must
be called SimplePlugin .
- The main plugin class (which KeePass will instantiate when it loads your
plugin) must be called exactly the same as the namespace plus "Ext".
In this case: "SimplePlugin" + "Ext" = "SimplePluginExt".
- The main plugin class must be derived from the
KeePass.Plugins.Plugin
base class.
The Initialize function is the most important one and you
probably will always override it. In this function, you get an interface
to the KeePass internals: an IPluginHost interface reference.
Through this interface you can access the KeePass main menu, the currently
opened database, etc. The Initialize function is called immediately
after KeePass loads your plugin. All initialization should be done in this
method (not in the constructor of your plugin class!). If you
successfully initialized everything, you must return true . If
you return false , KeePass will immediately unload your plugin.
A second function that you will need very often is the Terminate
method:
public override void Terminate()
{
}
This function is called shortly before KeePass unloads your plugin. You cannot
abort this process (it's just a notification and your last chance to clean up
all used resources, etc.). Immediately after you return from this method, KeePass
can unload your plugin. It is highly recommended to free all resources in this
method (not in the destructor of your plugin class!).
We're almost done! We now need to tell KeePass that
our file is a KeePass plugin. This is done by editing the Version Information Block
of the file. Open the file version editing dialog (in Visual Studio 2005: right-click
onto the project name → 'Properties' → button 'Assembly Information').
All fields can be assigned freely except the Product Name field (for more information
see Plugin Conventions). This field must be set to
"KeePass Plugin " (without the quotes).
That's it! Now try to compile your plugin and copy the resulting DLL
file into the KeePass directory. If you start KeePass and go to the plugins
dialog, you should see your plugin in the list of loaded plugins.
Providing Menu Items
Many plugins provide menu items (with subitems, if necessary)
in prominent locations like the 'Tools' menu, the entry context menu, etc.
Such a menu item can be supplied to KeePass by overriding the
GetMenuItem method of your plugin class
(which derives from the Plugin base class).
In this method, the plugin can construct and return a ToolStripMenuItem ,
which KeePass will then show in the appropriate location.
Users should be able to associate the menu item with your plugin.
Typically, plugins set the text of the menu item to the name of the plugin or
a string that starts with the name of the plugin. For example, a plugin 'Abcd'
that wants to provide one menu item only (for accessing the plugin options)
could set the text of the menu item to 'Abcd Options'.
If the plugin supports multiple commands, set the menu item's text to
the plugin name (e.g. 'Abcd') and add a subitem for each command.
The GetMenuItem method should always construct and return
a new ToolStripMenuItem . Do not cache the menu item
or any of its subitems for
later purposes (KeePass may invoke the GetMenuItem method
multiple times and show the menu items in multiple places; if your plugin
would cache a menu item, trying to show it in multiple places would
result in problems, because a ToolStripMenuItem can have
only one parent item).
If you want to update the state of subitems (like disabling certain items
or showing checkmarks), you can do this for instance
in an anonymous method that handles the DropDownOpening
event of the returned menu item (this way you do not need to remember
menu item references manually); see
SamplePlugin
for an example.
KeePass takes ownership of the returned menu item (and its subitems).
The plugin should not add or remove the item to/from any menu itself;
KeePass will do this.
If your plugin does not provide a menu item in the location specified
by the PluginMenuType parameter t ,
return null .
Example:
public override ToolStripMenuItem GetMenuItem(PluginMenuType t)
{
// Provide a menu item for the main location(s)
if(t == PluginMenuType.Main)
{
ToolStripMenuItem tsmi = new ToolStripMenuItem();
tsmi.Text = "Abcd Options";
tsmi.Click += this.OnOptionsClicked;
return tsmi;
}
return null; // No menu items in other locations
}
private void OnOptionsClicked(object sender, EventArgs e)
{
// Called when the menu item is clicked
}
For an example how to create a menu item with subitems (and
update their states dynamically), see the
SamplePlugin
example plugin.
Plugin Conventions
File version information block:
KeePass uses the file version information block to detect if a DLL file is a
KeePass plugin and retrieves information from it to show in the plugins dialog.
The fields are used as follows:
- Title: Should contain the full name of the plugin.
- Description: Should contain a short description (not more than 5 lines)
of your plugin.
- Company: Should contain the author name of the plugin.
- Product name: Must be set to
"KeePass Plugin" (without
the quotes).
- Copyright: Not used by KeePass; freely assignable by the plugin.
- Trademarks: Not used by KeePass; freely assignable by the plugin.
- Assembly version: Should be set to the version of your plugin.
- File version: Should be set to the version of your plugin. It is up
to you how you are versioning your plugin builds, but it should be a scheme that
allows version comparisons (by comparing the version components).
Do not use asterisks for creating a version number at build time.
- GUID: Not used by KeePass; freely assignable by the plugin.
Name, namespace and class name:
If you want to use the name "KeePass" as part of the name of
your plugin, directly prepend/append a non-numeric prefix/suffix.
For example, "KeePassSync" is ok, but "KeePass Sync" is not.
The namespace must be named like the DLL file without
extension. For example, if the DLL file is named SecretImporter.dll ,
you must call the namespace SecretImporter .
The plugin class must be named like the namespace plus "Ext".
For the SecretImporter plugin, this would be SecretImporterExt .
Update Checking
The update check of KeePass ≥ 2.18 can also check for plugin updates.
Update check support is optional; plugins don't have to support update
checks.
In order to support update checks, plugin developers need to do the following:
- Provide version information file.
When an end-user invokes an update check, KeePass downloads a version information
file, which specifies the current version numbers of one or more plugins.
Every plugin author hosts an own version information file.
The format of the version information file is described in detail below.
- Let KeePass know.
In order to be able to check the plugin's version, KeePass must know where
your version information file is located. To let KeePass know,
override the
UpdateUrl string property of your plugin class
(the one derived from Plugin )
to return the full, absolute URL of your version information file.
This should be an https:// URL
(for backward compatibility, KeePass also supports http://
and ftp:// , but for security reasons https://
should be used).
Plugin developers have to update their version information file each time
they release new versions of their plugins.
Version information file format.
- The file is a simple text file. It must be encoded using UTF-8 without
a byte order mark (KeePass ≥ 2.21 supports UTF-8 BOMs in version information
files, but for compatibility with KeePass < 2.21 it is recommended
not to use a BOM).
All line endings are supported.
- The first line of the file must start with a separator character of
your choice. The separator character may be any character,
but it must not appear within plugin names and versions.
Suggested is '
: '.
- Each of the following lines specifies a plugin name and its currently
available version, separated by the separator character that was specified in
the header line.
- As plugin name, the value of the 'Title' field in the version information
block of the plugin must be specified.
For managed plugins, this is the value specified using the
AssemblyTitle assembly attribute.
- As version number, the value of the file version in the version information
block of the plugin must be specified.
For managed plugins, this is the value specified using the
AssemblyFileVersion assembly attribute.
Trailing .0 may be removed
(e.g. specify 1.3 instead of 1.3.0.0 ).
- The file must end with a line containing only the separator character.
- You may optionally compress your version information file using GZip
(note this is not the same as Zip). The file
name must then end with "
.gz ".
Example. Let's assume you're developing two plugins: MyPlugin1
(version 1.5) and MyPlugin2 (version 1.13.2.17). Then your version
information file could look as follows:
:
MyPlugin1:1.5
MyPlugin2:1.13.2.17
:
If you've developed multiple plugins, it is recommended to create one
version information file, list all your plugins in this file and specify
the URL of the file in all your plugins. When KeePass checks for updates,
it'll download your version information file only once.
This reduces network traffic and is faster than downloading a version information
file for every plugin separately.
Signing. Since KeePass 2.34,
you can optionally digitally sign your version information file using RSA / SHA-512.
Can KeePass 2.x Plugins be Written in Unmanaged C++?
Yes and no. You can write the logic of your plugin in unmanaged C++ (native
Win32 APIs can be used). However, you must provide a managed interface to your plugin,
i.e. you must export a managed class derived from the Plugin base class
as described in the tutorial.
Also, managed C++ is required to modify the KeePass internals (entries,
groups, main window, ...).
For an example how to use unmanaged APIs in a managed C++ plugin assembly,
see the
SamplePluginCpp
example plugin.
It is highly recommended to develop plugins in C#, not in C++, due to
compatibility reasons (in the case of native plugins, separate 32- and
64-bit builds are necessary; native plugins do not run on Unix-like
systems; etc.).
PLGX Files
PLGX is an optional plugin file format for KeePass ≥ 2.09.
Instead of compiling your plugin to a DLL file, the plugin source code
files can be packed into a PLGX file and KeePass will compile the plugin
itself when loading it.
The main advantage of the PLGX approach is the compatibility with
custom KeePass builds.
A DLL plugin references an official KeePass build, and unless there
is a change within KeePass that breaks the plugin, the plugin is
also compatible with all future KeePass builds that are compiled
with the same assembly signing key (strong name).
This applies to all operating systems.
Especially, a DLL plugin that does not use any Windows-specific
function works fine on Linux with a KeePass build from the
official portable ZIP package.
However, some Linux packages compile KeePass from the source code;
such builds are not signed at all or are signed with a different
assembly signing key and are thus incompatible with DLL plugins.
In contrast, PLGX plugins are compatible with custom KeePass builds,
because KeePass can adjust the KeePass reference of the plugin
before compiling it.
Another advantage of the PLGX approach is a strong compatibility detection.
In the case of a DLL plugin, an incompatibility (caused by an API
change within KeePass) is detected by the runtime when the plugin tries
to call/access the method/class, not at loading time.
So, an incompatibility is detected late and might crash KeePass.
In contrast, when using the PLGX format, an incompatibility is
detected immediately at loading time: if there is a problem, the
compile process fails and KeePass can show an informative
plugin incompatibility message to the user.
For DLL plugins, KeePass performs an own compatibility check,
which does not detect all incompatibilities though;
PLGX is superior here.
Regarding security, DLL plugins are better, because they can be
digitally signed (Authenticode). Furthermore, DLL plugins are typically
loaded slightly faster (because they can be loaded directly; no
plugin cache).
For users, the procedure to install a DLL plugin is exactly the
same as for a PLGX plugin; both need to be copied into the 'Plugins'
folder.
| DLL | PLGX |
Compatibility with custom builds (Linux) |
Partial. |
 |
Compatibility check |
Weak. |
Strong. |
Authenticode signing support |
 |
 |
No compilation on the user's system |
 |
 |
No plugin cache |
 |
 |
So, both formats have unique advantages and disadvantages.
Dual package.
You can ship a plugin both as a DLL and as a PLGX in one package
(e.g. 'SecretImporter.dll' and 'SecretImporter.plgx' within the same folder).
KeePass will load the most appropriate file
(if KeePass has been signed with the official assembly signing key,
it will load the DLL, otherwise the PLGX).
If KeePass loads the DLL, the PLGX is ignored.
Recommendation.
In any case, provide a DLL file (for security reasons).
If you want to support custom KeePass builds, additionally provide
a PLGX file (i.e. provide a dual package).
Creating PLGX files.
PLGX files can be created from plugin sources by calling KeePass.exe
with the --plgx-create command line option. If you additionally
pass a path to the plugin sources directory (without terminating separator),
KeePass will use this one; otherwise
it'll show a folder browser dialog to allow you selecting the directory. If
you want to pass the directory location using the command line, make sure that
you're specifying a full, absolute path; relative paths will not work.
In order to keep the size of the PLGX file small, it is recommended
that you clean up the plugin sources directory before compiling the PLGX.
Remove all unnecessary binary files (files in the bin
and obj directory); especially, delete any plugin assembly DLL
that you compiled yourself. Temporary files by the IDE
(like .suo and .user files)
can also be deleted.
PLGX features.
- Extensible, object-oriented file format.
- Compression support (data files are compressed using GZip).
.csproj support. KeePass retrieves all information required
for compiling the plugin assembly from the .csproj file in the
plugin sources.
- Embedded resources support.
- Referenced .NET assemblies support. References information is read from
the
.csproj file.
- Referenced custom assemblies support. Third-party assemblies required by the plugin
(references to DLLs) are supported, provided that the third-party assembly is
located in the plugin source code directory (or any subdirectory of it).
- ResX support.
.resx files are automatically compiled to
binary .resources files.
- PLGX cache. PLGX files are compiled once and the generated assembly is stored in a cache.
For all following KeePass starts, no compiling is required.
- PLGX cache maintenance. The size of the PLGX cache can be seen in the KeePass plugins dialog.
Here, the cache can also be marked to be cleared (it will be cleared when KeePass
is started the next time). An option to automatically delete old files from the
cache is supported and enabled by default.
PLGX limitations.
- Only C# is supported (not Visual Basic or any other .NET language).
- The compiler that is included in the .NET Framework supports at most
C# 5. In order to avoid using features of a newer C# version, it is therefore
recommended to set the C# version of your plugin project to 5:
- In Visual Studio 2017 and earlier, open the project properties →
tab 'Build' → button 'Advanced' → set the option 'Language version'
to 'C# 5'.
- In Visual Studio 2019 and later, the project XML file must be edited:
the element '
LangVersion ' must contain '5 '.
For details, see
C# Language Versioning.
- Linked resources (in different assemblies) are unsupported.
- Dependencies on other projects are unsupported (reorganize your project to
use custom assembly references instead).
Defining prerequisites. You can optionally specify a minimum
KeePass version, a minimum installed .NET Framework, an operating system and
the minimum size of a pointer (x86 vs. x64) using the
--plgx-prereq-kp: , --plgx-prereq-net: ,
--plgx-prereq-os: and --plgx-prereq-ptr:
command line options. If one of the plugin prerequisites isn't met, KeePass shows a detailed
error message to the end-user (instead of a generic plugin incompatibility
message). Build example:
KeePass.exe --plgx-create C:\YourPluginDir --plgx-prereq-kp:2.09
--plgx-prereq-net:3.5
Valid operating system values are Windows and Unix .
When running on an unknown operating system, KeePass defaults to Windows.
Pointer sizes (checking for x86 vs. x64) are specified in bytes; for example,
to only allow running on x64, you specify --plgx-prereq-ptr:8 .
Build commands. Optionally you can specify pre-build
and post-build commands using --plgx-build-pre: and
--plgx-build-post: . These commands are embedded in the PLGX file
and executed when compiling the plugin on the end-user's system.
In the build commands, the placeholder {PLGX_TEMP_DIR}
specifies the temporary directory (including a terminating separator),
to which the files were extracted. In the post-build command, {PLGX_CACHE_DIR}
is replaced by the cache directory of the plugin (including a terminating
separator), into which the generated assembly was stored.
These build commands can for example be used to copy additional files into
the cache directory. Example:
KeePass.exe --plgx-create C:\YourPluginDir
--plgx-build-post:"cmd /c COPY """{PLGX_TEMP_DIR}MyFile.txt"""
"""{PLGX_CACHE_DIR}MyFile.txt""""
In order to specify a quote character on the command line, it has
to be encoded using three quotes (this is Windows standard, see
MSDN: SHELLEXECUTEINFOW ). So, the command
line above will actually embed the post-build command
cmd /c COPY "{PLGX_TEMP_DIR}MyFile.txt"
"{PLGX_CACHE_DIR}MyFile.txt"
into the PLGX, which is correct.
It is highly recommended to surround paths including PLGX placeholders
using quotes, otherwise the command will not run correctly if the
path contains a space character (which happens very often).
If you need to run multiple commands, write them into a batch file and
execute it (with cmd ). If you need to perform more complex
build tasks, write an own building executable and run it using the build
commands (typically it is useful to pass the directory locations as arguments
to your building executable), for example:
KeePass.exe --plgx-create C:\YourPluginDir
--plgx-build-post:"{PLGX_TEMP_DIR}MyBuild.exe {PLGX_TEMP_DIR} {PLGX_CACHE_DIR}"
PLGX debugging.
When the command line option --debug is
passed and a PLGX plugin fails to compile, the output of all
tried compilers is saved to a temporary file.
|