Open AIM: Modeless Window Support for Plugins

Have you ever wondered why tab and other navigation keys don’t work in some of the modeless dialog windows created by plugins? The reason for this is because Windows requires applications to call IsDialogMessage() for the currently active modeless window in order to translate the keyboard messages into dialog navigation commands.

This is relatively easy to implement in a standalone application since the code is all compiled and built together. However, in a plugin world you have to create an API to support this since it requires the cooperation between the hosting application, that owns the message pump, and the plugins, that know which modeless window is currently active.

The Open AIM SDK added support for registering the active dialog back in version 1.3 via a property called IAccPluginInfoProp_Windows. This property accepts an array of UINTs that are the window references. In the Windows environment you only have to provide a one-element array with the window handle of the currently active modeless dialog window or an empty array.

Open AIM clients need to listen for changes to IAccPluginInfoProp_Windows and keep track of the currently active dialog window in any plugin. On every window message, Open AIM clients should call IsDialogMessage() if it has at least one active modeless dialog window registered. If the message is handled, then the client is done otherwise the client can continue on with its own processing of the message. If all plugins are working correctly, there should only be one active modeless dialog window at a time even if there is more than one open.

I created a handy little class that you can use to make this easy to manage in your plugins. Here is a part of the header (Download the full source here):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class COpenAIMPluginWindowReg
{
public:
    // Call this once from the first instance of your plugin and
    // a second time, with a null pointer, when the last instance is shutdown.
    static void SetPluginInfoPtr(IAccPluginInfo *pPluginInfo);
 
    // Call this from WM_ACTIVATE
    static void OnActivate(HWND hWnd, WPARAM wParam);
 
private:
    static CComPtr<IAccPluginInfo>  s_spPluginInfo;
 
};

As you can see, this class has just two static methods and thus very simply to use. You call COpenAIMPluginWindowReg::SetPluginInfoPtr(pPluginInfo); from the first instance of your plugin. I typically call this from the IAccPlugin::Init() method and keep track if the number of instances of my plugin that are running. You must also call COpenAIMPluginWindowReg::SetPluginInfoPtr(NULL); when the last instance of your plugin is shutdown.

Then, in every modeless dialog window you create, add a handler for the WM_ACTIVATE message and call:

    COpenAIMPluginWindowReg::OnActivate(hWnd, wParam);

The OnActivate static method takes care of maintaining the IAccPluginInfoProp_Windows property for your plugin as the window is activated and deactivated.

I have released this source under an MIT style license. See the source files for more information. Again you can download the full source here.

Questions? Comments?

Leave a Reply

Powered by WP Hashcash