Introduction to PBNI

About this chapter

This chapter provides a brief introduction to the PowerBuilder Native Interface.

About PBNI

PBNI is a standard programming interface that enables developers to extend the functionality of PowerBuilder. Using PBNI, you can create extensions to PowerBuilder -- nonvisual, visual, and marshaler extensions -- and embed the PowerBuilder virtual machine (PBVM) into C++ applications. Through the Java Native Interface (JNI) and PBNI, Java applications can also communicate with the PBVM.

Code samples

This documentation contains two complete but very simple examples that illustrate some basic principles of using the PowerBuilder Native Interface (PBNI): Nonvisual extension example and Creating a PowerBuilder object to be called from C++. For more real-world examples, see the PBNI section of the PowerBuilder Code Samples website at https://www.appeon.com/developers/library/code-samples-for-pb.

The following diagram illustrates the two-way communication, with both PowerBuilder extensions and external applications, that PBNI provides for the PBVM. As the diagram shows, a PowerBuilder extension communicates with the PBVM through the IPB_Session interface, and the PBVM communicates with the extension through an interface derived from IPBX_UserObject.

C++ and Java extensions communicate with the PBVM through the IPB_VM and IPB_Session interfaces.

Figure: Interaction between the PBVM and external applications and extensions

Understanding PowerBuilder extensions

A PowerBuilder extension is just what its name suggests: an extension to PowerBuilder functionality provided by you, by a third party, or by Appeon. All PowerBuilder extensions communicate with the PBVM through an interface called IPB_Session. This interface and other PBNI objects and interfaces are described in The elements of PBNI.

PowerBuilder provides its own extensions, including a PBDOM XML parser and classes that support SOAP clients for Web services (obsolete). In future releases, Appeon might develop more new features as PBNI extensions instead of embedding them in the PowerBuilder VM (PBVM), so that the size of the PBVM can be minimized. Extensions are also available from third party contributors; for the latest samples and utilities, see the PBNI section of the PowerBuilder Code Samples website at https://www.appeon.com/developers/library/code-samples-for-pb.

Nonvisual extensions

The most frequently used type of PowerBuilder extension is a nonvisual extension. Nonvisual extensions provide a way to call C and C++ functions from PowerBuilder with more flexibility than the previous solution of declaring a function in a script. They also allow you to use object-oriented techniques when working with external objects.

A nonvisual extension is a DLL, written in C++, that exposes one or more native classes and/or global functions. Classes are used in a PowerBuilder application as though they were class user objects created in PowerBuilder -- a native class is simply a PowerScript class that is implemented in C++. Global functions in an extension are used like global functions declared in the Function painter.

Nonvisual extensions allow you to use datatypes in C++ that map to standard PowerBuilder datatypes. PBNI provides predefined datatypes that map to PowerBuilder datatypes, so that you can use PowerBuilder datatypes when you invoke the methods of the native class, and the native class can use predefined types to call back into PowerBuilder. For more information about predefined types, see PBNI Types and Return Values

You can use native classes to call back into the PBVM from the C++ code and trigger PowerBuilder events and invoke functions. You can also call external functions that require callback functions. For example, if your PowerBuilder application uses an extension that is a SAX XML parser, the SAX parser can send information back to the PowerBuilder application about the items it has encountered in the XML document that it is parsing. In response, the PowerBuilder application can send back instructions on how to handle those items.

Possible uses for a nonvisual extension include:

  • A wrapper for a Component Object Model (COM) component that references a user-defined COM interface that cannot be mapped to a PowerBuilder datatype

  • A PowerBuilder interface for database backups and administration using the SQL Anywhere dbtools (which require callback functions)

  • Wrappers for any open source C++ libraries that provide standard utilities

PowerBuilder extensions run faster than standard PowerBuilder user objects because they are compiled in native machine code instead of PowerBuilder pseudocode (Pcode). PBNI complies with the C++ specification, so well-programmed code is portable at the source code level.

Visual extensions

Visual extensions can be used as if they were PowerBuilder visual user objects -- you can place them in windows or on other visual controls. Visual extensions allow you to create a subclass of the Windows procedure (winproc) of a visual component so that you can use the latest "look and feel" for your applications.

Marshaler extensions

Marshaler extensions act as bridges between PowerBuilder and other components, such as Enterprise JavaBeans (EJB) components, Java classes, Web services, and CORBA components. PowerBuilder provides a marshaler extension for creating clients for EJB components running in any J2EE-compliant application server. Other techniques for calling EJBs from PowerBuilder do not provide a standard way to marshal PowerBuilder requests to other components and unmarshal the result back to PowerBuilder.

Embedding the PBVM in a C++ application

Many PowerBuilder users have developed sophisticated custom class user objects that handle intensive database operations or other functionality. Such objects can already be used in external applications. However, limitations on the use of some datatypes and of overloaded functions, as well as other coding restrictions, diminishes the value of this technique.

To have direct access to a custom class user object running in the PBVM, and to take advantage of PBNI functions for data access and exchange, you can load the PBVM in the C++ application, create a session, and invoke the custom class user object's functions from the external application.

Communication between the PBVM and a C++ application is based primarily on two interfaces: IPB_VM and IPB_Session.

Interacting with Java

To call Java classes from PowerBuilder, you can build a marshaler extension that invokes Java methods through JNI, as described in Creating Marshaler Extensions You can also use JNI to allow Java to call into PowerBuilder through C or C++. For an example, see the PowerBuilder Code Samples website at https://www.appeon.com/developers/library/code-samples-for-pb.

The elements of PBNI

To enable the features described in the previous section, PBNI provides interfaces, structures, global functions, and helper classes. These elements are described in more detail in the reference section of this guide. See PBNI Interfaces, Structures, and Methods This section provides an overview.

Interfaces

The IPB_VM interface is used to load PowerBuilder applications in third-party applications and interoperate with the PowerBuilder virtual machine (PBVM).

IPB_Session is an abstract interface that defines methods for performing various actions such as accessing PowerScript data, creating PowerBuilder objects, and calling PowerScript functions.

The IPB_Value and IPB_Arguments interfaces enable you to pass values between the PowerBuilder VM and PowerBuilder extension modules.

The IPB_Value interface represents a PowerBuilder value, which could be one of the PowerBuilder standard datatypes such as integer, long, string, and so forth. It provides information about each variable, including its type, null flag, access privileges, array or simple type, and reference type.

The IPB_Arguments interface represents the arguments passed to a PowerScript function and is used to access the data.

The IPB_ResultSetAccessor and IPB_RSItemData interfaces enable you to access data in a DataWindow or DataStore.

All PowerBuilder native classes inherit from the IPBX_NonVisualObject interface or the IPBX_VisualObject interface, which in turn inherit from the IPBX_UserObject interface. You must implement the Invoke method in the inherited class to enable PowerBuilder to invoke methods in the native class.

Marshaler extensions contain a class that inherits from the IPBX_Marshaler interface. You must implement the InvokeRemoteMethod method in the inherited class to enable PowerBuilder to invoke methods on remote objects represented by a proxy.

Structures

The PBCallInfo structure holds arguments and return type information for function calls between PBNI and PowerBuilder. To access the information in PBCallInfo, use the IPB_Arguments interface.

The PBArrayInfo structure stores information about arrays.

The PB_DateData, PB_TimeData, and PB_DateTimeData structures are used to pass DataWindow and DataStore data.

Global functions

Every PowerBuilder extension object must export global functions that enable the PowerBuilder VM to create instances of the object and use its methods. The PBX_GetDescription function describes the classes and functions in the extension. The PBX_CreateNonVisualObject function enables the PBVM to create instances of the nonvisual classes in an extension, and the PBX_CreateVisualObject function does the same for visual classes.

Helper classes

Several helper classes, such as PBObjectCreator, PBArrayAccessor, and PBEventTrigger, make it easier to program with PBNI.

Interaction between an extension and the PBVM

The following diagram summarizes how an extension interacts with the PBVM.

Figure: Interaction between an extension and the PowerBuilder VM

The PBNI SDK

When you install PowerBuilder, the Software Development Kit (SDK) for PBNI is installed in the %AppeonInstallPath%\PowerBuilder [version]\SDK\PBNI directory. The SDK tools, pbsig190 and pbx2pbd190, are also installed in the %AppeonInstallPath%\PowerBuilder [version]\IDE directory so that they are available in your path.

The SDK contains the components shown in the following table.

Component

Description

pbx2pbd190.exe

A tool that generates a PBD file from a PowerBuilder extension file. The extension file is a DLL file that must export a set of PBNI functions. The DLL is usually called a PBX and can be given the suffix .pbx.

pbsig190.exe

A tool that generates a set of strings representing the return type and arguments of each function in a PBL. Use these strings to call PowerBuilder functions from external modules.

include\pbni.h

A header file that defines the structures and interfaces used to build PowerBuilder extensions.

include\pbarray.h

A header file that contains helper classes that make it easier to create arrays and access data in them.

include\pbfield.h

A header file that contains helper classes that make it easier to access data in fields.

include\pbtraits.h

A header file used by pbarray.h and pbfield.h that provides specializations for the pbvalue_type enumerated types.

include\pbext.h

A header file that defines the functions that PowerBuilder extension functions must export.

include\pbevtid.h

A header file that maps the PowerBuilder event IDs to event names for use in visual extensions.

include\pbnimd.h

A header file that defines machine-dependent datatypes used in pbni.h.

include\pbrsa.h

A header file that defines interfaces and structures used to access DataWindow and DataStore data.

src\pbarray.cpp

A source file that must be added to your project if you want to use the following helper classes defined in pbarray.h:

PBArrayAccessor

PBObjectArrayAccessor

PBBoundedArrayCreator

PBBoundedObjectArrayCreator

PBUnboundedArrayCreator

PBUnboundedObjectArrayCreator

src\pbfuninv.cpp

A source file that must be added to your project if you want to use the following helper classes defined in pbni.h:

PBGlobalFunctionInvoker

PBObjectFunctionInvoker

PBEventTrigger

src\pbobject.cpp

A source file that must be added to your project if you want to use the following helper class defined in pbni.h: PBObjectCreator.

wizards\VCProjects 8.0

A Microsoft Visual Studio 2005 wizard that makes it easier for you to create PBNI projects.

wizards\VCProjects 7.1

A Microsoft Visual Studio .NET 2003 wizard that makes it easier for you to create PBNI projects.

wizards\VCProjects 7.0

A Microsoft Visual Studio .NET 2002 wizard that makes it easier for you to create PBNI projects.

wizards\VCWizards

Files required by the Visual Studio wizards.

pbni.chm

Help file for PBNI.


Comparing PBNI and JNI

If you have used the Java Native Interface (JNI), which allows Java applications and C and C++ modules to interoperate, you might find it helpful to be aware of the similarities in the two interfaces and the differences between them.

The IPB_VM interface in PBNI is analogous to the JavaVM type, and the IPB_Session interface in PBNI is analogous to JNIEnv. For JNI, you use the javap command to obtain a string that encodes the signature of each method in a native class. For PBNI, the pbsig190 tool performs the same function.

The major difference between the two interfaces is in how a native function or class is declared.

In JNI, you must use the native keyword to declare that a function is native, but you cannot simply declare a class as native. You must define your classes in Java source code, use the javah tool to generate a C header file that defines a C prototype for each native method, then implement the individual C or C++ functions, using #include to include the generated header file.

PBNI provides an object-oriented approach -- you declare a class as native in the C++ code by inheriting from the IPBX_NonVisualObject or IPBX_VisualObject struct.