Independently designed the NPAPI development framework

Source: Internet
Author: User

After more than a year of plug-in Development, I am familiar with the working mechanism of plug-ins. During the development of plug-ins, I used np_entry.cpp, npn_gate.cpp, npp_gate.cpp, and pluginbase In the sdk. h these files greatly improve the efficiency of plug-in development and make the development process simple and efficient. However, some shortcomings and minor bugs are also found during use. During the development process, I have modified these files to meet my development needs. Although the changes can meet my needs, there is always an idea to rewrite the framework. I found a very valuable test plug-in instance code in Firefox source code because I excluded a bug and studied it, combine the files in the above sdks and the npruntime instance prepared for the scriptable plug-in. In combination, you can write your own plug-in development framework code. This article describes how to write this plug-in development framework and the working mechanism of the NPAPI plug-in, hope that beginners of plug-in development will have a clear understanding of the NPAPI plug-in after reading this article; also hope that friends who are familiar with plug-in development will be able to have new insights on the plug-in and experience new things after reading this article; I also hope that all those who have any comments or suggestions on plug-in development or the framework proposed in this article can communicate with me. This article focuses on the development of the NPAPI plug-in for Firefox browsers on the windows platform. It is generally applicable to other browsers that support the NPAPI plug-in mechanism on the windows platform, in addition, it should be the same as the basic principle of developing the NPAPI plug-in on other platforms. However, this article does not guarantee that other platforms or browsers are identical. Let's get down to the truth. The essence of plug-ins is a dynamic link library for browser calls. It is a dll file on windows and so file on unix platforms. However, the NPAPI plug-in standardizes the interface of this dynamic library and specifies which basic functions the interface needs to implement. Since it is a dynamic library, the plug-in can be searched for root sources from the interface definition, regardless of which plug-in code can be found. the following description is in the def file: EXPORTSNP_GetEntryPoints @ 1NP_Initialize @ 2NP_Shutdown @ 3. There may be another one: NP_GetMIMEDescription @ 4. It is necessary to check the functions implemented by these interfaces. The NP_GetEntryPoints code: [cpp] NPError OSCALL NP_GetEntryPoints (NPPluginFuncs * pFuncs) {if (! FillPluginFunctionTable (pFuncs) {return NPERR_INVALID_FUNCTABLE_ERROR;} return NPERR_NO_ERROR;} NPError OSCALL NP_GetEntryPoints (NPPluginFuncs * pFuncs) {if (! FillPluginFunctionTable (pFuncs) {return NPERR_INVALID_FUNCTABLE_ERROR;} return NPERR_NO_ERROR;} Very simple. The called function name already describes the function of this interface: Fill in the plug-in function table. Next let's take a look at NP_Initialize. The Code is as follows: [cpp] NPError OSCALL NP_Initialize (NPNetscapeFuncs * aNPNFuncs) {NPError rv = fillNetscapeFunctionTable (aNPNFuncs! = NPERR_NO_ERROR) return rv; return NS_PluginInitialize ();} NPError OSCALL NP_Initialize (NPNetscapeFuncs * aNPNFuncs) {NPError rv = Response (aNPNFuncs); if (rv! = NPERR_NO_ERROR) return rv; return NS_PluginInitialize ();} Similarly, the called function name already describes the function of the interface: Fill in the browser function table. The NP_Shutdown interface is self-explanatory, and the end work is done by this interface. In addition, NP_GetMIMEDescription is an interface for the browser to obtain the MIME type description supported by the plug-in. It is optional (at least, I think so ). In addition, in the NP_Initialize function, macro definition # if defined (XP_UNIX )&&! Defined (XP_MACOSX) # endif directly calls the function that fills the plug-in function table. It means that on UNIX or MAC, the NP_Initialize function implements the NP_Initialize and NP_GetEntryPoints functions on windows. As a result, we can infer that the browser and the plug-in are directly establishing a relationship. First, the browser uses the functions provided by the plug-in end to fill in a function finger table (the browser calls the plug-in function to implement the function we developed ), then, the browser fills in a function pointer table provided by the browser to the function called by the plug-in, and notifies the plug-in (the plug-in uses the function pointer table to call the function provided by the browser ). The fillPluginFunctionTable function parameter is a pointer to the NPPluginFuncs structure, and the fillNetscapeFunctionTable parameter is a pointer to the NPNetscapeFuncs structure. The plug-in we developed mainly aims to allow the browser to implement our specified functions, therefore, the main work of plug-in development is to implement the function to fill the NPPluginFuncs structure. The function used to fill the structure of the NPNetscapeFuncs has been implemented by the browser and can be used in the plug-in. To facilitate the call of functions implemented on the browser end, we have defined a bunch of global functions starting with "2_" for our use. To help us clearly know which function interfaces should be implemented for the browser, defines a bunch of global functions starting with NPP. The work of developing plug-ins is now to implement functions starting with NPP _ and associate these NPP _ and 2npp _ functions with the previous two structures NPPluginFuncs and NPNetscapeFuncs. How to contact us? Let's see the code: many statements similar to the following in the fillPluginFunctionTable function: [cpp] pFuncs-> newp = NPP_New; pFuncs-> destroy = NPP_Destroy; pFuncs-> newp = NPP_New; pFuncs-> destroy = NPP_Destroy; where pFuncs is the pointer of the NPPluginFuncs structure, the above two statements associate NPP_New and NPP_Destroy (these are functions implemented by our plug-in developers) with newp and destroy in the NPPluginFuncs structure. The newp pointer that the browser calls the NPPluginFuncs structure is the NPP_New that we implement. Let's take a look at the implementation of the NPN_GetValue function. The Code is as follows: [cpp] NPError NPN_GetValue (NPP instance, NPNVariable variable, void * value) {return sBrowserFuncs-> getvalue (instance, variable, value);} NPError NPN_GetValue (NPP instance, NPNVariable variable, void * value) {return sBrowserFuncs-> getvalue (instance, variable, value );} the corresponding function in the NPNetscapeFuncs structure is called directly. Therefore, we call NPN_GetValue to call the getvalue in the structure of the NPNetscapeFuncs. In fact, the work of linking NPP _ and nnpn uginfuncs with NPNetscapeFuncs is almost the same, so we have various frameworks developed by the NPAPI plug-in, the most basic role of these frameworks is to do this. With the framework, we can develop plug-ins to focus on implementing the functions of functions starting with NPP. With this guiding ideology, write a plug-in with only one header file and one cpp file (of course, there are also rc and def files), compile and generate the dll in Firefox about: the plugins page shows our plug-ins. For this code, see the attachment provided in this Article. I will name it aemo. It should be an alpha demo!: Http://download.csdn.net/detail/z6482/4913874 object-oriented development plug-ins believe that the vast majority of plug-in developers are to choose C ++ to develop plug-ins, the use of C ++ object-oriented plug-in development for a certain degree of encapsulation, this allows us to focus more on the actual functions of the plug-in the development process. To achieve this goal, our most direct idea is to encapsulate the functions starting with NPP _ into a class, when developing plug-ins, we only need to implement the corresponding functions in the class according to our actual functional requirements. Let's see how the sdk works: [cpp] NPError NPP_NewStream (NPP instance, NPMIMEType type, NPStream * stream, NPBool seekable, uint16_t * stype) {if (! Instance) return NPERR_INVALID_INSTANCE_ERROR; nsPluginInstanceBase * plugin = (nsPluginInstanceBase *) instance-> pdata; if (! Plugin) return NPERR_GENERIC_ERROR; return plugin-> NewStream (type, stream, seekable, stype);} NPError NPP_NewStream (NPP instance, NPMIMEType type, NPStream * stream, NPBool seekable, uint16_t * stype) {if (! Instance) return NPERR_INVALID_INSTANCE_ERROR; www.2cto. comnsPluginInstanceBase * plugin = (nsPluginInstanceBase *) instance-> pdata; if (! Plugin) return NPERR_GENERIC_ERROR; return plugin-> NewStream (type, stream, seekable, stype);} the function code is relatively simple. The function is to convert the pdata of an instance to a class, then, call the NewStream member function of the class. Therefore, to implement the NPP_NewStream function, you only need to implement the NewStream function of the nsPluginInstanceBase class. This section briefly describes how to associate pdata of an instance with nsPluginInstanceBase. See the code snippet in NPP_New: [cpp] nsPluginInstanceBase * plugin = NS_NewPluginInstance (& ds); if (! Plugin) return NPERR_OUT_OF_MEMORY_ERROR; instance-> pdata = (void *) plugin; nsPluginInstanceBase * plugin = NS_NewPluginInstance (& ds); if (! Plugin) return NPERR_OUT_OF_MEMORY_ERROR; instance-> pdata = (void *) plugin; here NS_NewPluginInstance creates an object of the nsPluginInstanceBase class (the object of its subclass is accurate ), then convert the object pointer to a void pointer and assign it to the pdata of the instance. In this way, the relationship between the instance and the created object is established. After completing the above operations, we have completed NPP _ FUNCTION encapsulation. Here is another wonderful thing to note: the instance is an NPP structure, in NS_NewPluginInstance, this instance is used to create a plug-in instance object, that is, the object contains a pointer to the instance, and the pdata of the subsequent instance points to the object we created, in this way, you can access the plugin object through the instance and access the instance through the plugin object. Maybe you don't think this is rare, but if you need to create multiple classes during the development of plug-ins. These classes need to share some data with the plugin object, so you can add an NPP member to these classes and point to this instance. Then, sharing data becomes very interesting. Of course, you can also use C ++'s inherent data sharing methods (such as youyuan) to share data, but I prefer this method! NsPluginInstanceBase is the base class of a plug-in instance. This base class defines several pure virtual functions, when creating a plug-in, we only need to use this class as the base class to derive a subclass and implement the functions defined as pure virtual functions to generate a simplest plug-in, if you have other requirements, you can override other virtual functions based on the actual function. Without the implementation of other functions of this base class, we need to implement all NPP-related functions each time we write, even if there is no function, at least one empty function body is required. For example, NPP_Print is usually not required. If nsPluginInstanceBase is not available, we need to write such code void NPP_Print (NPPrint * printInfo) {return;} Every time. Even if we copy it every time, it is uncomfortable, with the nsPluginInstanceBase encapsulation, we only need not override this virtual function when deriving a subclass. Therefore, nsPluginInstanceBase can be said to perfectly encapsulate the NPP _ function, so that we can develop plug-ins from so tedious work to focus only on the implementation of functions. After adding the class implementation method, I made a plug-in similar to the previous one, which is bemo, beta version demo. For the code, see the attachment provided in this Article.: Http://download.csdn.net/detail/z6482/4913883 plug-in interface Scriptable plugin, the complete expression should be called with scripting programming interface plug-in (cross-browser NPAPI extensions, commonly called npruntime, cross-browser NPAPI Extension function, it is usually called npruntime. In short, it adds interfaces and attributes that can be accessed in JS scripts to common plug-ins ). Briefly describe the entire process. When the browser finds that JS calls some interfaces or attributes of the plug-in object, it will call NPP_GetValue to obtain an NPObject object, we can create such an object by calling NPN_CreateObject and calling NPN_RetainObject to obtain and return it to the browser. The browser calls the HasProperty, GetProperty, and SetProperty of the object based on the obtained object to perform related operations. If this is not necessary, we need to call NPN_ReleaseObject to notify the browser to release the object. This operation is performed in the destructor of the instance all over again. It is not difficult to add a scripted interface. You can create an nsScriptObjectBase class similar to nsPluginInstanceBase. This class must be derived from the NPObject class and an NPP object must be created to save the corresponding plug-in instance. Write the Code following the npruntime instance code and make some modifications in the file: complete all global variables with static member variables of the class. Perform some simple tests and finally generate a framework that can be used to develop general plug-ins and develop a script-based interface plug-in. There are three main files: npfrmwk. h. npfrmwkbase. h and npfrmwk_entry.cpp. Everything is in the code. The next section uses this section to generate a scripted interface plug-in. This section briefly describes how to use this framework to develop an NPAPI plug-in. This section is the same as the code in the next section: demo_frmwk framework instructions for manual File Creation (rc file). You can also add new files to VS after the project is created, there are too many demos. Therefore, this demo is named fdemo and the generated dll is named npfdemo. dll to create the npfdemo file. rc. The content is as follows: [cpp] # include <winver. h> ////////////////////////////////////// //////////////////////////////////////// /// Version // VS_VERSION_INFO versioninfo fileversion 1, 0, PRODUCTVERSION, distinct 0x3fL # ifdef _ debug fileflags 0x1L # else FILEFLAGS 0x0L # endif FILEOS delimiter FILETYPE VFT_DLL FILESUBTYPE 0x0L begin block "StringFileInfo" begin block "BEGIN" begin value Company" Name "," JumuFENG.zcf.org "VALUE" FileDescription "," demo plugin for our own NPAPI framework "VALUE" FileVersion "," 1.0.0.1 "VALUE" InternalName "," npfdemo. dll "VALUE" LegalCopyright "," Copyright (C) 2012 "VALUE" MIMEType "," application/x-frmwk-demo "VALUE" OriginalFilename "," npfdemo. dll "VALUE" ProductName "," Test Plug-in "VALUE" ProductVersion "," 1.0.0.1 "end block" VarFileInfo "BEGIN VALUE "Translation", 0x409,125 2 END # include <winver. h> ////////////////////////////////////// //////////////////////////////////////// /// Version // VS_VERSION_INFO versioninfo fileversion 1, 0, PRODUCTVERSION, FILEFLAGSMASK 0x3fL # ifdef _ debug fileflags 0x1L # else FILEFLAGS 0x0L # endif FILEOS vos?windows32 FILETYPE VFT_DLL FILESUBTYPE writable BLOCK "StringFileInfo" begin block "cannot BE" Gin value "CompanyName", "JumuFENG.zcf.org" VALUE "FileDescription", "demo plugin for our own NPAPI framework" VALUE "FileVersion", "1.0.0.1" VALUE "InternalName", "npfdemo. dll "VALUE" LegalCopyright "," Copyright (C) 2012 "VALUE" MIMEType "," application/x-frmwk-demo "VALUE" OriginalFilename "," npfdemo. dll "VALUE" ProductName "," Test Plug-in "VALUE" ProductVersion "," 1.0.0.1 "end block" VarFileI Nfo "begin value" Translation ", 0x409,125 2 ENDEND this file can be created by VS, but you need to modify the VALUE in the corresponding block description to the above content, of course, CompanyName and other entries need to modify the value you want to set according to the actual situation. After the preceding file is created, open VS (VS2010 is used) to create a win32 application, and select create dll in settings. Note: select the project above. After creating a project. You can add existing items to the project. Select the three framework files provided in this article: npfrmwk. h, npfrmwkbase. h, npfrmwk_entry.cpp, and npfdemo. rc. Add the new item and add the def file. Npfdemo. def file content is as follows: library npfdemo plugin @ 1NP_Initialize @ 2NP_Shutdown @ 3NP_GetMIMEDescription @ 4 Add a new class derived from nsPluginInstanceBase for the project: CFrmwkPlugin, the header file is automatically named as FrmwkPlugin. h. The implementation file is named FrmwkPlugin. cpp. We need to create two classes here. One is the CFrmwkPlugin class and the other is the CScriptPluginObject class derived from nsScriptObjectBase. Set the project properties, add the header file containing the npapi directory, and add it to the properties-> C/C ++-> additional include directory. Of course, you can also add the npapi. h, npruntime. h. npfunctions. h. Copy these files directly to the project and add them to the project as described above without adding the include directory. Next, we will create the FrmwkPlugin. h file and FrmwkPlugin. the cpp file is modified to implement the functions that must be implemented in two classes and several static member functions that are equivalent to global functions. The Code will not be copied here, please refer to the Code provided in this article for implementation! The file uses pre-compiled commands to determine whether to compile the script-based interface. If you need to compile a script-based interface, you need to set properties-> Preprocessor-> Add ENABLE_SCRIPT_OBJECT to the pre-processing definition, of course, you can add # define ENABLE_SCRIPT_OBJECT in the source file to achieve the same effect. If you do not need to compile a scripted interface, you can directly compile and generate the operation. To facilitate the development of plug-ins and reduce repetitive work, I used C # To develop a small tool to complete the above operations. After necessary settings, I can automatically generate def files, rc files, and class FrmwkPlugin. h and FrmwkPlugin. cpp file. Of course, the names of these files can be specified. If the framework I provided is not downloaded, you can use this tool to generate and export the three files of the framework. h. npfrmwkbase. h. npfrmwk_entry.cpp. Furthermore, you can use this tool to export files such as the most basic headers of the Development plug-in, such as npapi. h and npruntime. h. In short, I hope this tool will allow you to do as little work as possible to complete plug-in development, have fun! Is one of the tools: the information to be filled in includes the file name, mimetype type, and plug-in instance class name, all other items have default values, or the related information is automatically filled in based on the information entered. You can manually modify the default value or automatically enter the default value. You can select the file type to be generated in the top line. If you select the first line, the generated file does not contain the scriptable interface. The file is very simple. Select the second item to generate content related to scriptable, without adding the ENABLE_SCRIPT_OBJECT pre-compiled macro. Select the third item to generate a file with the ENABLE_SCRIPT_OBJECT pre-compiled macro, script interfaces are not supported by default. To support this function, you only need to set the precompiled macro ENABLE_SCRIPT_OBJECT in the project properties. You can select whether to generate a VS2010 project file for the VS project option on the check box of www.2cto.com. If you select this option, the Framework file is automatically generated in the project file at the same time, the generated project file can be opened directly with VS2010. After the inclusion directory is set, the simplest plug-in dll can be generated. You can also add this project to other solutions in. If this option is not selected, the necessary files are generated and a new project is created. This method can be used for VS of other versions, however, you must note that the def file cannot be directly added to the newly created Project. Otherwise, the generated dll may have problems on the test page. The correct method is to use VS to add new items, add a blank def file and copy the def file generated by this tool to the blank def file. Other files can be directly added to. We recommend that you do not use this tool to generate VS projects, because each project file has a different GUID, and this tool does not have the ability to automatically generate guids, the GUID used is the GUID used to create the project during the test.

Related Article

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.