Archive for December, 2007

Share and discuss your RX-Plugin Rules and more

Sunday, December 30th, 2007

A fellow “RXer” has been kind enough to create a forum for the sharing and discussion of RX-Plugin rules. You can access it here.

There is also another forum for the discussion of my IM Tweaks plugin which can be accessed here.

So far there is not much information but that should change soon. I will do my best to add to the discussions from time to time.

Open AIM: Modeless Window Support for Plugins

Sunday, December 30th, 2007

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?

Open AIM: How to register a plugin command

Monday, December 17th, 2007

Hello again. I am back. Today I am starting a new series of posts on Open AIM. For this first post, I will start by introducing a handy little function similar to the one I wrote for my plug-ins that makes it easy to register commands that your plug-in will handle.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// The following code is public domain. Written by Gus Verdun
static void RegisterPluginCommand(IAccPluginInfo * pluginInfo, 
                                               int id, UINT flags, 
                                               LPCWSTR pCommand)
{
    CComPtr <IAccCommand> spCommand;
    pluginInfo->AddCommand(id, &spCommand);
    if (spCommand)
    {
        CComBSTR str(pCommand);
        put_Text(spCommand, str);
        put_Flags(spCommand, (AccCommandFlags)flags);
    }
}

I normally call this function from the IAccPlugin::Init method, but you can call it at any time you want to add a command. The first parameter is the IAccPluginInfo interface pointer that is passed to you on the Init() call. The second parameter is the command identifier that is assigned by you and handled in your plugin’s IAccCommandTarget methods. The third parameter, flags, are the AccCommandFlags that let you indicate where you want this command to appear in the UI. Finally, the fourth parameter is the actual text that will be displayed in the client’s UI.

Here is a simple example to define a command that will show only in the plug-in settings page.

RegisterPluginCommand(pPluginInfo, -1, 
     AccCommandFlags_PreferencesUi, 
     OLESTR("Settings...") );

For localization purposes, you can easily change this function to load the command string from a resource. I will leave that as an exercise for you to try.

Hope this helps. Comments? Questions?