Chapter 26

Writing a Plug-In with Borland C++5.x


CONTENTS


Introduction

Borland C++ 5 provides a good alternative to Microsoft for Windows plug-in developers. Borland's Integrated Development Environment (IDE) allows a plug-in developer to edit, compile, run, and debug a plug-in without leaving the environment. Resources required for plug-in DLLs are easily edited within the IDE. Borland ships a number of libraries in the product, including Standard C++, Standard C, Services, Container Class, WinSys, ObjectComponents Framework (OCF), and ObjectWindows Library (OWL). OWL also has Windows Sockets classes for direct socket communications using TCP/IP.

This chapter is a step by step guide to building a Netscape Navigator plug-in using Borland C++ 5. The example does not use a class library such as OWL. It is based on the Non-MFC sample found earlier in Chapter 22. Using OWL and its Twindow class to develop a plug-in is discussed after the example.

Where to Find the Files

If you want to build this sample plug-in, you need to create a directory and put in it some files borrowed from the Non-MFC sample on the CD-ROM. These files are in the \CODE\NOMFC, \CODE\INC, and \CODE\COMMON directories. You need the files shown in the following lists.

For the \CODE\NOMFC directory, you need these files:

For the \CODE\INC directory, you need these files:

For the \CODE\COMMON directory, you need this file:

Put all five files in the same directory to match this example.

Preparing the Files for the Borland Compiler

After you copy the files to a new directory, a few modifications must be made so that the Borland compiler works properly. First, you must change the included header file paths and then reprototype the DLL entry points.

  1. All the CPP files include Netscape headers in relative paths for the Microsoft example. Change these to local, like this:
    #include "..\inc\npapi.h"
    should be
    #include "npapi.h"
    You can also delete the include of stdafx.h in npwin.cpp. This file is for Microsoft's class library and is not needed for Borland.
  2. The file npwin.cpp contains three exported functions:
    NPError WINAPI NP_EXPORT NP_GetEntryPoints(NPPluginFuncs* pFuncs)
    NPError WINAPI NP_EXPORT NP_Initialize(NPNetscapeFuncs* pFuncs)
    NPError WINAPI NP_EXPORT NP_Shutdown()
    Borland needs these to be public externals. Put an extern "C" in front of each routine:
    extern "C" NPError WINAPI NP_EXPORT NP_GetEntryPoints(NPPluginFuncs* pFuncs)
    extern "C" NPError WINAPI NP_EXPORT NP_Initialize(NPNetscapeFuncs* pFuncs)
    extern "C" NPError WINAPI NP_EXPORT NP_Shutdown()

The Example

The next three sections give step by step instructions for creating a plug-in from scratch with Borland's IDE. The first section shows you how to set up a new project that creates a Windows plug-in DLL. The next section shows how to build the plug-in. Lastly, the third section covers testing and debugging your Borland built plug-in.

Setting Up the Project

Your first task is to create the project with all the appropriate files. Steps 1 through 7 and their associated figures show how to create the project with the Target Expert, create and modify a new resource, add new files, and modify the library definition file for new Windows DLL entry points.

Step 1: Create a New Project

After you have started the Borland IDE, use the File|New|Project menu item to create a new project. Now the Target Expert should be up. Specify your project path and name in the top entry field. In Figure 26.1, you can see a project path and name of d:\src\plugin\npplugin. This should be the same path in which you put the files previously. To make your life easier, begin the project name with np. Navigator requires plug-in DLLs to begin with np or the plug-in will not be loaded. It's a good idea to follow this convention throughout your project.

Figure 26.1 : Using the Target Expert.

Select a Target Type of Dynamic Library (.DLL). Platform should be Win32, and Target Model should be GUI. Deselect all class libraries and pick Static for linkage. The New Target dialog should look like the dialog shown in Figure 26.1.

Step 2: Delete npplugin.cpp

For the purposes of this example, npplugin.cpp is not needed and should be deleted. Right-click on this file in the view and select Delete Node. Figure 26.2 shows the menu that results from a right mouse click and the option to delete a node (file, in this case) is highlighted.

Figure 26.2 : Deleting a node.

Step 3: Add a New Resource

Double-click the resource file npplugin.rc in the project view. This brings up the resource editor. Select Resource|New from the main menu. This menu item is highlighted in Figure 26.3.

Figure 26.3 : Creating a new resource.

Step 4: Make a VERSIONINFO Resource

The Netscape Navigator looks for a VERSIONINFO resource in the DLL to determine the plug-in's MIME type, file extension, and file open name. Create a VERSIONINFO resource by selecting the VERSIONINFO item in the New Resource dialog and clicking OK as shown in Figure 26.4.

Figure 26.4 : Creating a VERSIONINFO resource.

Step 5: Add the Plug-In's Resource Information

Add your plug-in's resource information. In this example, the MIME type is x-any/x-mimetype. The file extension is .ext, and the file open name is Test Plug-in (*.ext). Remember that this is a fictitious MIME type and it won't work on an HTTP server without the proper configuration. For the purposes of this example, files are opened on the local drive, which loads your plug-in based on extension rather than MIME type. Figure 26.5 shows the new resource information as a highlighted block of text. Save and close the resource file after adding the new information.

Figure 26.5 : Adding the plug-in's resources.

Step 6: Edit the .DEF File

In the library definition file (npplugin.def, created by the Target Expert), define the library name and its three exported routines: NP_GetEntryPoints, NP_Initialize, and NP_Shutdown. Figure 26.6 shows how the library definition file should look for Borland.

Figure 26.6 : Editing the .DEF file.

Step 7: Add the Files

Right-click on your project view and select Add node. This menu is the same one that is used to delete a node in Figure 26.2. When the Add to Project List dialog comes up (see Figure 26.7), select the files npshell.cpp, npwin.cpp, and npwindow.cpp. Click on the Open button to add them to your project.

Figure 26.7 : Selecting files.

Compiling the Project

Steps 1 through 5 show how to compile the project. First, the project is compiled with a full build and warnings are examined. Then, the DLL output directory is changed and the project is relinked to create a DLL in the Navigator's plugin directory.

Step 1: Build the Project

In the main menu, select Project|Build all to build the whole project. Figure 26.8 shows the location of the Build all menu item. This will be the first build. Later, the DLL output directory will be changed to the Navigator's home directory and the project will be relinked.

Figure 26.8 : Start building the project.

Step 2: Build Complete

When the build is complete, your status should be Success. There will be some warnings for unused parameters. You should see something similar to Figure 26.9 with 297,348 lines compiled and 21 warnings.

Figure 26.9 : The Building npplugin-Complete dialog.

Step 3: Examine the Warnings

Take a look at the warnings. Most are from npshell.cpp. This file contains the plug-in entry points. You can get rid of these warnings by changing the warning level in the compiler options. Most warnings (as shown in Figure 26.10) should be parameter never used.

Figure 26.10 : Looking at the warnings.

Step 4: Change the Final Output Directory

Select Options|Project in the main menu to bring up the project options. Figure 26.11 shows where this menu item is located.

Figure 26.11 : Bringing up project options.

Make the Final Output Directory the Navigator's plugins directory. This allows you to debug the plug-in. Figure 26.12 shows that directory path on this machine:

Figure 26.12 : Changing the final output directory.

d:\Program Files\Netscape\Navigator\Program\plugins

Step 5: Make the Project

Now that the DLL output directory is changed, make the project, which causes it to relink the DLL and write the DLL to the new output directory. You can use the toolbar button for this, as shown in Figure 26.13.

Figure 26.13 : Making the project.

Testing Your Project

To test and debug the Borland created plug-in, you need to create a test file, set a breakpoint in Borland's debugger, load the Navigator executable, and verify the plug-in's resource data. If all goes well, you should be able to hit the breakpoint and display the data filename. The following steps 1 through 8 show how to do this.

Step 1: Create a Test File

Use a text editor to create a test file. Although this plug-in won't read it, the file must have some data in it or Navigator produces an error and the plug-in is not loaded. Make sure you save the file with the proper file extension indicated in the resource. In this case, it is .ext.

Step 2: Set a Breakpoint

Open the npshell.cpp file and set a breakpoint by clicking in the left margin. In Figure 26.14, a breakpoint is set in the NPP_StreamAsFile API, which will be called with the name of the test file.

Figure 26.14 : Setting a breakpoint.

Step 3: Load the Program

Using the Debug|Load menu, bring up the Load Program dialog. Figure 26.15 shows the location of this menu item.

Figure 26.15 : Bringing up the Load Program dialog.

When the Load Program dialog is up, use the Browse button, find the Navigator executable, and click OK to load it. Figure 26.16 shows Navigator loading from the following path:

Figure 26.16 : Loading the Navigator.

d:\Program Files\Netscape\Navigator\Program\netscape.exe

No arguments are required.

Step 4: Run the Program

Start the Navigator using the Debug|Run menu. Figure 26.17 shows the location of this menu item.

Figure 26.17 : Running the program.

Watch Navigator come up. Figure 26.18 shows Atlas Preview Release 2 initializing.

Figure 26.18 : Atlas comes up.

Step 5: Verify the Plug-In's Resources

First, verify that the plug-in's resource data is correct by bringing up Help|About Plug-ins in the Navigator. Figure 26.19 shows the location of this menu item. The fact that your plug-in is listed in Help|About Plug-ins does not mean that it will execute; it only means that your resources are correct. Navigator does not load a plug-in DLL to get this information.

Figure 26.19 : Using About Plug-ins.

In Figure 26.20, you can see that Navigator has found this plug-in. Verify the MIME type and suffixes. In this case, the MIME type is x-any/x-mimetype and suffixes are ext.

Figure 26.20 : Finding the plug-in.

Step 6: Open the Test File

With File|Open File on the Navigator, prepare to open the test file created earlier. Figure 26.21 shows the location of this menu item.

Figure 26.21 : Files of type.

Make sure that the proper file type is in the Files of type drop down. Figure 26.22 shows how to select a file type of Test Plug-in (*.ext).

Figure 26.22 : Files of type.

Step 7: Hit the Breakpoint

After the test file is opened, you should hit your breakpoint. Verify the filename. Figure 26.23 shows how to hit the breakpoint and see that the data filename is d:\src\plugin\data.ext.

Figure 26.23 : Hitting the breakpoint.

Step 8: Hello World

This sample displays a message indicating that it has subclassed the plug-in window and the URL. In Figure 26.24, you can see that the plug-in is displaying "The plug-in has successfully subclassed the Navigator window!" with URL = file:///D|/src/plugin/data.ext. That funky URL is Netscape's way of locating a file on your local disk drive.

Figure 26.24 : Displaying a message and URL.

All Done

Well, that was really stimulating, wasn't it? This plug-in example doesn't rock the world with its functionality, but hopefully it will help you get started with Borland C++ 5. Most large Borland plug-in endeavors need to use the OWL class library.

Using OWL

The preceding example was based on the Microsoft Non-MFC sample. This sample does not use a class library such as Microsoft's MFC or Borland's OWL. Although a sample using OWL is beyond the scope of this book, here is some minimal information.

Navigator creates a window for the plug-in to use. A handle to this window is provided during the NPP_SetWindow API. You can effectively subclass this window using OWL by creating a TWindow with a valid window handle in NPP_SetWindow. For example, using the wave audio sample, a window derived from OWL's TWindow can be created like this:

pWave->pWindow = new TPluginWindow (pWave, (HWND)window->window, ::Module);

In this case, the TPluginWindow constructor passes on the window handle and module to TWindow like this:

//
// Constructor
//
CPluginWindow::CPluginWindow (CWave *pWave, HWND hWnd, TModule* module)
    : TWindow (hWnd, module)
{
    this->pWave = pWave;
}

Within CPluginWindow, controls can be created in the normal OWL fashion and a response table can be set up.

Conclusion

Use the preceding step by step guide to build a very simple Borland-based plug-in module. Don't forget to modify the source files as outlined in the beginning of this chapter. As you get better with Borland (or if you are already an expert), add the OWL class library.

What's Next?

The next chapter takes you through a similar step by step example of building a plug-in with Microsoft's Visual C++ 4.x.