快乐虾
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文适用于
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
};
呵呵,看着好像挺简单的。