|
This documentation applies to KeePass 1.x plugins (all versions
≥ 1.15). 1.x plugins are fundamentally different from 2.x plugins.
2.x plugins cannot be loaded by KeePass 1.x.
A detailed SDK documentation is available here:
Plugin SDK Documentation.
Requirements
Before you can start developing a KeePass plugin, you need the following
prerequisites:
- Latest KeePass source code package. You can get it from the
KeePass website.
- A C++ development IDE / compiler.
- Windows Platform SDK.
The KeePass plugin API uses some concepts of the Component Object Model (COM)
standard.
If you don't have experience with COM, the following pages are recommended
for reading:
Step-by-Step Tutorial
Start your favorite IDE and create a new Win32 Project (application
type DLL, empty project).
In this tutorial the example plugin we're developing is called TestPlugin .
Create two files in the new project: a C++ source file (TestPlugin.cpp)
and a header file (TestPlugin.h).
In order to access the KeePass interfaces, you have to include a header
file from the KeePass SDK: put an #include statement in the
TestPlugin.h file, which includes the file
KeePassLibCpp/SDK/KpSDK.h from the KeePass source code.
Windows DLLs may optionally implement a DllMain function. So
if you want one (not required by KeePass though),
implement a default one now in the TestPlugin.cpp file (just always return
TRUE ):
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
UNREFERENCED_PARAMETER(hinstDLL);
UNREFERENCED_PARAMETER(fdwReason);
UNREFERENCED_PARAMETER(lpvReserved);
return TRUE;
}
The next step is to create a plugin class, which must implement the
IKpPlugin interface. So, lookup the IKpPlugin interface
(abstract C++ class) and design a class that implements all these methods.
Details about the methods can be found in the
Plugin SDK Documentation.
Now export a function, which KeePass will use to create
an instance of your plugin class:
KP_EXPORT HRESULT KP_API KP_I_CREATEINSTANCE_DECL(REFIID riid,
void** ppvObject, IKpUnknown* pAPI);
In this function, you'll need to create an instance of your plugin class
and store an interface pointer of the type requested by KeePass (riid )
in the ppvObject parameter. The pAPI parameter is
an interface pointer to the KeePass API, which you should store for later use
in case you're able to return a valid plugin interface.
KeePass is currently offered only as ANSI application, not Unicode.
Therefore, go to Project → Test Plugin Properties and choose
Multi Byte as character set.
It is recommended (but not required) to statically link with the
runtime library (and MFC, if you're using it). To do this, go to
Project → Test Plugin Properties → C/C++ → Code Generation
and choose a runtime library not ending with '-DLL'.
The last step before building your plugin is to add a version information
resource. So, go to the 'Resources' tab of the plugin project
and add a resource of type 'Version'. Here, set the product name to
KeePass Plugin . All other fields can be freely set to strings
of your choice.
Example. You can find a fully documented and extended version of this simple
plugin on the KeePass plugins web page ("Test Plugin").
Plugin Conventions and Recommendations
Conventions:
- The DLL file must have a version information resource, in which
the product name is set to
KeePass Plugin . KeePass uses this
to determine whether the DLL is a KeePass plugin or not (i.e. if you don't
create a version information resource with this string, KeePass will not load
your DLL file).
- 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.
- A KeePass plugin must export the following function:
KP_EXPORT HRESULT KP_API KP_I_CREATEINSTANCE_DECL(REFIID riid,
void** ppvObject, IKpUnknown* pAPI);
KeePass will call this function to create an instance of your plugin class.
You have to return an interface of type riid in the ppvObject
parameter, if your plugin class supports this interface (return S_OK ).
Otherwise set ppvObject to NULL and return
E_NOINTERFACE . You may store the pAPI interface pointer
for later use. KeePass guarantees that the pointer is valid as long as it has
a pointer to your plugin class instance.
Important: explicitly check for which interface KeePass is asking (riid ),
otherwise your plugin is not upward-compatible and might crash in future KeePass
versions.
- A KeePass plugin may optionally export the following functions:
KP_EXPORT HRESULT KP_API KP_I_INITIALIZELIB_DECL(IKpUnknown* pAPI);
KP_EXPORT HRESULT KP_API KP_I_RELEASELIB_DECL(IKpUnknown* pAPI);
KeePass will call the first function after the DLL is loaded, and the second
one shortly before the DLL is unloaded.
You should not store the pAPI interface pointer for later use.
Consider the pointers as temporary; they might become invalid as soon as you
return from KP_I_INITIALIZELIB_DECL or KP_I_RELEASELIB_DECL .
The pAPI interface pointer values passed to KP_I_INITIALIZELIB_DECL
and KP_I_RELEASELIB_DECL are not guaranteed to be the same as each
other, or as the pointer value passed to KP_I_CREATEINSTANCE_DECL .
- The protocol is
DllMain (if present),
KP_I_INITIALIZELIB_DECL (if present),
KP_I_CREATEINSTANCE_DECL ,
plugin interface methods,
KP_I_RELEASELIB_DECL (if present).
- KeePass is using the multi-byte character set. Therefore, make sure that
you're also compiling your plugin in multi-byte character set mode, not
Unicode.
Recommendations:
- All plugin files should begin with a common prefix. For example, if your
plugin is called VariousImport, the DLL file might be named
VariousImport.dll and its help file VariousImport.html.
If you don't use a common prefix, users might run into overwriting problems
when installing multiple plugins, because all plugins must be copied into
the KeePass application directory. For example, if there's a plugin that ships
with a ReadMe.txt file and another plugin that also ships with such a file,
the latter overwrites the readme file of the first, or the user chooses not to
overwrite and the readme file of the second plugin is not available. Using
a common prefix avoids this problem.
- The version information block should at least be available in English
(USA) language.
- There are two implementations of the
IKpConfig interface.
One implementation is identified by CLSID_KpConfig , the other by
CLSID_KpConfig_ReadOnly . The first one supports both reading
and writing, the second one only reading. It is highly recommended that
you use the second implementation, if you only want to read configuration
items.
Trying to write using the CLSID_KpConfig_ReadOnly implementation
will assert if KeePass is compiled in Debug mode, and will fail in Release
mode (and might possibly destroy parts of the current configuration).
Upgrading Plugins from ≤ 1.14 to ≥ 1.15
When upgrading a plugin from KeePass ≤ 1.14 to ≥ 1.15, it is
highly recommended that you create a new project file, start from scratch
and copy / fill out the interface methods with the old code.
Notes:
- There is no
KeePass.lib file anymore. The new plugin architecture
is based on interfaces. Including the
KpSDK.h header file is all you need to do.
Do not compile with any of the files in the KeePass source code or include
any other header file than KpSDK.h .
- Previously a command line prefix was registered by setting the
cmdLineArgPrefix member of the plugin information structure.
In the new architecture, the command line prefix must be returned by the
GetProperty member method of the plugin interface when being
called with the KPPS_COMMANDLINEARGPREFIX parameter.
Your GetProperty might look like this:
STDMETHODIMP_(LPCTSTR) CYourPluginImpl::GetProperty(LPCTSTR lpName)
{
if(lpName == NULL) return NULL;
if(_tcscmp(lpName, KPPS_COMMANDLINEARGPREFIX) == 0)
return _T("mypluginprefix.");
return NULL;
}
The plugin should not access the KeePass command line until after all
plugins have been loaded. This is because at that time
KeePass of course can't call the GetProperty method of your plugin yet and
consequently doesn't know the prefix yet (and this will lead to 'unknown
command line option' warnings). Instead, perform command line dependent
initialization when KeePass calls your OnMessage handler
method with the KPM_DELAYED_INIT code.
Detailed Documentation of All Interfaces
See the Plugin SDK Documentation.
Plugin Framework for C++
Thanks to Bill Rubin, there's an optional Plugin Framework available, facilitating the
development of KeePass plugins in C++. The features in detail:
- Complete implementation of the
IID_IKpUnknown interface.
- Implementation of the
IID_IKpPlugin interface, except for the
OnMessage member function, which is always application-specific.
- Ability to get smart pointers to any other KeePass interface,
including
IKpAPI , IKPCommandLine ,
IKpCommandLineOption , IKpConfig ,
IKpDatabase , IKpFullPathName , and IKpUtilities .
- Implementation of the
KpCreateInstance function, which the plugin
must export from its DLL.
- Comprehensive error checking of COM handshaking for Items 3 and 4.
If an error is found, PFK displays a message box containing all
information about the error. Without this feature, a plugin will,
in most cases, silently fail to load. In other cases, it will
fail to perform its function.
- Convenience utilities to display a message box, translate a
Windows error code into a natural language string, and declare a
standard string independently of character type.
- Compile-time checking of constructor invocations for smart COM
pointers. Without this feature, it is difficult for a developer
to interpret compiler error messages caused by using the wrong
smart COM pointer constructor.
- The PFK code avoids defining macros. Instead templates, inline
functions, typedefs, and other C++ constructs maintain safe
design practices, with no runtime penalty.
There's also a Test Plugin available using the Plugin Framework.
|
|