codeblocks中plugin的实现

快乐虾 http://blog.csdn.net/lights_joy/ [email protected]

本文适用于

codeblocks-8.02

vs2005

 

 

 

1.1     Plugin 加载

Codeblocks plugin 放在可执行文件目录下的 share\CodeBlocks\plugins 子目录中,全部以 DLL 的形式存在。在 codeblock 启动时会调用如下函数:

int PluginManager::ScanForPlugins( const wxString& path)

{

………………………………… ..

    wxDir dir(path);

    wxString filename;

    wxString failed;

    bool ok = dir.GetFirst(&filename, PluginsMask, wxDIR_FILES);

    while (ok)

    {

…………………… .

        // load manifest

        m_pCurrentlyLoadingManifestDoc = 0;

        if (ReadManifestFile(filename))

        {

            if (LoadPlugin(path + _T( '/' ) + filename))

                ++count;

            else

                failed << _T( '\n' ) << filename;

        }

        delete m_pCurrentlyLoadingManifestDoc;

        m_pCurrentlyLoadingManifestDoc = 0;

        ok = dir.GetNext(&filename);

}

………………………………… ..

}

在上述代码中,将首先读取与 dll 同名的 manifest ,其实它就是一个放在 share/codeblocks 子目录下的同名 zip 文件,这个 zip 文件中两个文件: manifest.xml configuration.xrc ,其实这两个文件都是 XML 文档, manifest.xml 描述了这个插件的功能,作者等信息,而另一个文件则是一些配置信息。

在读取 manifest 成功后将调用 LoadPlugin 函数:

bool PluginManager::LoadPlugin( const wxString& pluginName)

{

    // clear registration temporary vector

    m_RegisteredPlugins.clear();

 

    // load library

    m_CurrentlyLoadingFilename = pluginName;

    m_pCurrentlyLoadingLib = LibLoader::LoadLibrary(pluginName);

    if (!m_pCurrentlyLoadingLib->IsLoaded())

    {

        Manager::Get()->GetLogManager()->LogError(F(_T( "%s: not loaded (missing symbols?)" ), pluginName.c_str()));

        LibLoader::RemoveLibrary(m_pCurrentlyLoadingLib);

        m_pCurrentlyLoadingLib = 0;

        m_CurrentlyLoadingFilename.Clear();

        return false ;

    }

 

    // by now, the library has loaded and its global variables are initialized.

    // this means it has already called RegisterPlugin()

    // now we can actually create the plugin(s) instance(s) :)

 

    // try to load the plugin(s)

    std::vector<PluginRegistration>::iterator it;

    for (it = m_RegisteredPlugins.begin(); it != m_RegisteredPlugins.end(); ++it)

    {

        PluginRegistration& pr = *it;

        cbPlugin* plug = 0L;

        try

        {

            plug = pr.createProc();

        }

        catch (cbException& exception)

        {

            exception.ShowErrorMessage( false );

             continue ;

        }

 

        // all done; add it to our list

        PluginElement* plugElem = new PluginElement;

        plugElem->fileName = m_CurrentlyLoadingFilename;

        plugElem->info = pr.info;

        plugElem->library = m_pCurrentlyLoadingLib;

        plugElem->freeProc = pr.freeProc;

        plugElem->plugin = plug;

        m_Plugins.Add(plugElem);

 

        SetupLocaleDomain(pr.name);

 

        Manager::Get()->GetLogManager()->DebugLog(F(_T( "%s: loaded" ), pr.name.c_str()));

    }

 

    if (m_RegisteredPlugins.empty())

    {

        // no plugins loaded from this library, but it's not an error

        LibLoader::RemoveLibrary(m_pCurrentlyLoadingLib);

    }

    m_pCurrentlyLoadingLib = 0;

    m_CurrentlyLoadingFilename.Clear();

    return true ;

}

这个函数首先调用 LibLoader::LoadLibrary 加载 DLL ,实际上它就是使用 LoadLibrary 这个 API 来加载 DLL

在加载完成后,按照注释的说明,这个 DLL 中应该调用 RegisterPlugin 函数进行自我注册,这其中当然包括创建实例这样回调函数,然后上述函数很自然地使用这样的回调函数创建 Plugin 的实例。然后用一个 PluginElement 来描述它,这个 plugElem 将用于主界面的菜单等位置。

从上述代码还可以看出,插件至少应该能创建一个 cbPlugin 的实例。

1.2     插件注册

从调用过程的注释可以知道,在加载 DLL 时,它应该能够调用 RegisterPlugin codeblock 进行注册,下面以 astyle 这个插件为例看看它的注册过程。

在这个插件中定义了一个全局变量:

namespace

{

    PluginRegistrant<AStylePlugin> reg(_T( "AStylePlugin" ));

}

除此之外没有其它东西可以在 DLL 加载时执行代码,看看 PluginRegistrant 这个类:

/** @brief Plugin registration object.

    *

  * Use this class to register your new plugin with Code::Blocks.

  * All you have to do is instantiate a PluginRegistrant object.

  * @par

  * Example code to use in one of your plugin's source files (supposedly called "MyPlugin"):

  * @code

  * namespace

  * {

  *     PluginRegistrant<MyPlugin> registration("MyPlugin");

  * }

  * @endcode

  */

template < class T> class PluginRegistrant

{

    public :

        /// @param name The plugin's name.

        PluginRegistrant( const wxString& name)

        {

             Manager::Get()->GetPluginManager()->RegisterPlugin(name, // plugin's name

                                                                &CreatePlugin, // creation

                                                                &FreePlugin, // destruction

                                                                &SDKVersion); // SDK version

        }

 

        static cbPlugin* CreatePlugin()

        {

            return new T;

        }

 

        static void FreePlugin(cbPlugin* plugin)

        {

            delete plugin;

        }

 

        static void SDKVersion( int * major, int * minor, int * release)

        {

            if (major) *major = PLUGIN_SDK_VERSION_MAJOR;

            if (minor) *minor = PLUGIN_SDK_VERSION_MINOR;

            if (release) *release = PLUGIN_SDK_VERSION_RELEASE;

        }

};

由此可见,在主程序加载 DLL 后还将调用 PluginRegistrant ::CreatePlugin 这个回调函数,而这个回调函数将创建一个 AStylePlugin 的实例。

1.3     Plugin 功能实现

仍以 astyle 为例进行分析。 Codeblocks plugin 分为几类:

cbCompilerPlugin

cbDebuggerPlugin

cbToolPlugin

cbMimePlugin

cbCodeCompletionPlugin

cbWizardPlugin

astyle 要完成代码格式化的功能,因而它选择了 cbToolPlugin 进行扩展:

class AStylePlugin : public cbToolPlugin

{

  public :

    AStylePlugin();

    ~AStylePlugin();

    int Configure();

    int GetConfigurationGroup() const { return cgEditor; }

    cbConfigurationPanel* GetConfigurationPanel(wxWindow* parent);

    int Execute();

    void OnAttach(); // fires when the plugin is attached to the application

    void OnRelease( bool appShutDown); // fires when the plugin is released from the application

};

呵呵,看着好像挺简单的。

 

 

你可能感兴趣的:(xml,.net,F#,Blog)