C/C ++: build your own plug-in Framework (2)

Source: Internet
Author: User
C/C ++: build your own plug-in Framework (2) zz2010-06-15

Translator raof01

Http://blog.chinaunix.net/u/12783/showart_1086995.html

This article is the second article about developing cross-platform C ++ plug-ins. The first article describes the problem in detail, explores some solutions, and introduces the plug-in framework. This section describesOn the plug-in framework, plug-in-based system design, plug-in life cycle, and internal General Plug-In Framework. Be careful: the code is distributed across all parts of the article.

Plug-in system-based architecture
Plug-in-based systems can be divided into three loosely coupled parts:A main system or application with its own special object model; plug-in manager; and plug-in itself.The plug-in complies with the interfaces and protocols of the plug-in Manager and implements object model interfaces. Let's use an actual example. The primary system is a round-based game. The game takes place on a battlefield with various monsters. A hero fights with a monster until he or all the monsters die.

List 1 is the definition of the Hero class:
# Ifndef hero_h
# Define hero_h
# Include <vector>
# Include <map>
# Include <boost/shared_ptr.hpp>
# Include "object_model/object_model.h"

Class hero: Public iactor
{
Public:
Hero ();
~ Hero ();
// Iactor Methods

Virtual void getinitialinfo (actorinfo * info );
Virtual void play (iturn * turninfo );
PRIVATE:
};
# Endif

List 1

Battlemanager is the engine that drives the game. It initializes hero and monster and places them on the battlefield. It then calls the play () method of each actor (hero or monster) to attack each collection.

Hero and monster implement the iactor interface. Hero is a built-in game object with reserved behavior. On the other hand, monster is implemented by plug-ins. This allows the game to expand to more new monster and separate the development of the new monster from the development of the game engine. The work of pluginmanager is to abstract the fact that monster is generated by plug-ins and presented to battlemanager, just like hero. This solution allows some built-in monster to be released along with the game. These monster are statically linked, not implemented using plug-ins. Battlemanager should not even know that there is a plug-in. It should be operated at the C ++ object level. This also makes it very easy to test, because you can create fake monster in the test code without writing a complete plug-in.

Pluginmanager itself can be generic or specific. The General Plug-In manager does not know the specific underlying object model. When a C ++ pluginmanager instantiates a new object implemented in the plug-in, it must return a common interface, so that the caller must convert the instance to the actual interface. This looks ugly, but it is necessary. A custom plug-in manager knows your object model and can operate on the underlying object model. For example, a pluginmanager customized for our game can have the createmonster () method that returns the iactor interface. The pluginmanager I show is generic, but I will show how easy it is to put a specific layer of the Object Model on it. This is a standard practice, because you do not want your application code to handle Explicit conversions.

Plug-in system life cycle
Now it's time to figure out the lifecycle of the plug-in system. Applications, pluginmanager, and plug-ins participate in this complex activity according to a strict protocol. The good news is that most of the general plug-in frameworks can place these things well. When necessary, the application obtains the access permission of the plug-in. The plug-in only needs to implement some functions that will be called at that time.

Static plug-in registration
Plug-ins deployed in the static library and statically linked to the application are static plug-ins. The registration can be completed automatically, provided that the database defines a global registrant object and the constructor of this object is automatically called. However, it cannot work on all platforms, such as M $ windows. The optional method is to explicitly tell pluginmanager to initialize the static plug-in by passing a special initialization function. Because all static plug-ins are statically linked to the main program, each Init () should have a unique name and must be of the pf_initplugin type. A good practice is to name it <plugin Name> _ initplugin (). The following is a prototype of the init () function of the static plug-in:

Extern "C" pf_exitfunc
Staticplugin_initplugin (const pf_platformservices * Params)

Explicit initialization creates a tightly coupled relationship between the main program and static plug-ins, because the main program needs to know which plug-ins are linked recently during compilation to initialize them. If all static plug-ins follow certain conventions so that the build process can find them and generate the corresponding initialization code, this process can be automatically executed as part of the build process.

Once Initialization is complete, the static plug-in registers all its object types to pluginmanager.

Dynamic plug-in loading
Dynamic plug-ins are more common. They should all be deployed in a dedicated directory. The application should call the loadall () method of pluginmanager and pass in the directory path. Pluginmanager scans all files in the directory and loads each dynamic library. Applications can also call the load () method to load separate plug-ins.

Plug-in Initialization
Once the dynamic library is loaded successfully, pluginmanager looks for the function entry point called rpf_initplugins. If this entry point is found, pluginmanager calls this function and passes an f_platformservices struct to initialize it. This struct contains pf_pluginapi_version for the plug-in to negotiate with the main program version and determine whether the plug-in can work normally. If the application version is not suitable, the plug-in may cause initialization to fail. Pluginmanager logs the problem and continues to load the next plug-in. From the perspective of pluginmanager, loading or initializing a plug-in failed is not a serious error. The application can perform some additional checks to ensure that the loaded plug-ins are enumerated, so that it can check whether any important plug-ins are not loaded.

 

Listing two contains the pf_initplugin function:

# Include "cpp_plugin.h"
# Include "plugin_framework/plugin. H"
# Include "killerbunny. H"
# Include "stationarysatan. H"

Extern "C" plugin_api apr_int32_t exitfunc ()
{
Return 0;
}
Extern "C" plugin_api pf_exitfunc pf_initplugin (const pf_platformservices * Params)
{
Int res = 0;
Pf_registerparams RP;
RP. version. Major = 1;
RP. version. Minor = 0;
RP. programminglanguage = pf_programming1_age_cpp;
// Regiater killerbunny

RP. createfunc = killerbunny: Create;
RP. destroyfunc = killerbunny: destroy;
Res = Params-> registerobject (const apr_byte_t *) "killerbunny", & RP );
If (RES <0)
Return NULL;
// Regiater stationarysatan

RP. createfunc = stationarysatan: Create;
RP. destroyfunc = stationarysatan: destroy;
Res = Params-> registerobject (const apr_byte_t *) "stationarysatan", & RP );
If (RES <0)
Return NULL;
Return exitfunc;
}

 

Listing two

 

Object Registration
If the version negotiation succeeds, the plug-in should register all the object types it supports to the plug-in manager. The purpose of registration is to provide functions for applications such as pf_createfunc and pf_destroyfunc for later use. This arrangement allows the plug-in to control the actual creation and destruction of objects, including the resources they use, such as memory, but allows applications to control the number of objects and their lifecycles. Of course, you can also use Singleton mode to return instances of the same object.

You can complete registration by preparing registration records (pf_registerparams) for each object type and calling the registerobject () function pointer in the pf_platformservices (passed as a parameter to pf_initplugin) struct. Registerobject () accepts a string or "*" that uniquely identifies the object type and pf_registerparams struct. In the next section, I will explain the purpose of the type string and how to use it. The Type string is required because different plug-ins may support multiple object types.
Once the plug-in calls registerobject () control, it returns to pluginmanager. Pf_registerparams contains a version and programming language. The pluginmanager version ensures that it can work with this object type. If the version does not match, registration fails. This is not a serious error. This allows for flexible negotiation. The plug-in tries to register multiple versions of the same type so that it can use the new interface and return to the old interface when the new interface fails. If the plug-in manager is satisfied with pf_registerparams, it stores the struct into the internal data structure that can map the object type to the struct.

When the plug-in registers all its object types, it returns a pointer to pf_exitfunc. This function is called before the plug-in is uninstalled so that the plug-in can clear all resources obtained during its life cycle.

If the plug-in finds that it is not working properly, it clears all resources and returns NULL. In this way, pluginmanager will know that the plug-in Initialization fails and will delete all registrations made by the failed plug-ins.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.