User:RMN/Plugin Developer Guide

From Miranda NG
Jump to navigation Jump to search
This page a draft. Please, do not translate or move it.
Todo [en]: This is Miranda IM Plugin Developer Guide1. It needs revision and adaptation according to changes made to Miranda NG project.

Miranda IM consists of the core, internal modules and external modules known as plugins.

Miranda IM Core

The core is a central part of Miranda. It is very light and has only basic things to make other part of the system work. The core implements infrastructure to support modular design of Miranda. There are two main mechanisms provided by the core: hooks and services.

Hooks

Hook is a function that is called to notify the interested entity about some event happens. The core maintains a hook table each entry of which consists of a hook name (string of chars) and a list of hook subscribers. The core also provides the set of functions that operate the hook table to perform the following tasks:

  • Create and destroy an event that can be hooked by someone
  • Hook an event that has been registered in the hook table
  • Notify the subscribers of a particular event (trigger the event)

Naming of a hook should follow the following convention

"Module/Component/Hook" 

A hook being registered to the hook chain must use the following declaration

int EventHook(WPARAM, LPARAM); 

Parameters of a hook are defined by the hook creator and its return value is used to indicate if the hook chain must continue processing or not. You should return false (0) if proceed with the chain processing and true (1) if the processing must be terminated. There are very rare situations in which you need to break the hook chain.

When an event is triggered a hook chain is processed by calling every registered event handler.

There is an ability to set default hook for the event. The default hook is called only in case the hook chain for the event is empty.

Services

Service is a way to publish some functionality using a common interface. The idea is to create an alias to a function that implements a service, so you don't call a functions provided by some module directly but you use it through the service call. The core maintains a table of the services each entry of which consists of a service name (string of chars) and a pointer to a function that implements the service. The following API is provided by the core to deal with services:

  • Create and destroy a service
  • Call a service
  • Check if a particular service exists

Naming of a service should follow the following convention

"Module/Component/Service" 

The function being registered as a service implementation must have the following declaration

INT_PTR ServiceImplementation(WPARAM, LPARAM);

Parameters and return value of a service function are defined by its author with one exception that return value should not be equal to CALLSERVICE_NOTFOUND since it is reserved to indicate the "service not found" error. Description of available services can be found in header files of Miranda IM SDK. The headers contain inline documentation about the services they provide. If a third party plugin module offers some services it should include corresponding header files with a usage and parameters description.

Additional API

Currently the core also provides:

  • Memory management function (allocation, deallocation, reallocation)
  • Threading related routines
  • Localization routines
  • UTF-8 text encoding/decoding

Internal memory management functions help to catch errors with memory allocation. They work similarly to Microsoft's debug CRT in Visual Studio – by marking borders of allocated block with special symbols and instead of real freeing they also just mark the block as free so any father reference to the block will indicate an error.

Multithreading routines used to properly shut down user threads on Miranda exit.

Localization routines offer text translation using different code pages.


Modules

The most of the basic functionality of Miranda resides in internal modules. There are numerous internal modules which implement most of the basic features, they are netlib, protocols, options, history, plugins, useronline and many others. You can find out the full list of internal modules in the source code in "modules" directory. The internal modules provide many services and hookable events which are used by external plugin modules.


Plugin Modules

Plugin is a module which can extend functionality of Miranda IM. Physically it is a DLL file that exports certain functions. During loading the core iterates through the DLL files in the plugin directory and calls WinAPI LoadLibrary function on every module found there, then it checks if a module has the needed functions exported and if everything is right the module becomes loaded into the core. The set of exported functions serves as an interface between a plugin module and the core. The core makes calls to these functions to interact with a plugin.

Plugin Types

The Miranda IM plugins can be divided into three groups: database plugins, contact list plugins and general purpose plugins. The difference between them is in their interface to the core – the exported set of functions.

Firstly, the core checks every loaded module for a general purpose plugin interface, then the core calls MirandaPluginInfo function which returns the plugin description. If everything looks fine the core determines if the module contains more definitely interface of a database or a contact list plugin. These steps are known as plugin API checking. The core reports an error and shuts down Miranda if no database or no contact list plugin has been found.

After a module has been checked for correct API another function is called in the module – Load. This call notifies the plugin that it was successfully loaded by the core and may initialize itself. Please note that you must perform all the significant initialization during this call of Load and not during DLLMain call since there are many restrictions on what you are allowed in the body of DLLMain. Refer to MSDN documentation to know more about DLLMain restrictions. During the call of Load it is guaranteed that the database module is already loaded and ready to work. But any other internal modules are not initialized by that moment.

During Miranda shutdown a reverse process is executed and the core calls Unload function in the plugin so it can clean up itself. The database module is guaranteed to be still loaded during the Unload call.


1 Source