Comments
L W wrote: Dear Sir, Please do forward a Google Wave Invitation to lvw.iv4 (at) gmail (dot) com, at your earliest convenience? Much appreciated!
Cloud Computing
Conference & Expo
November 2-4, 2009 NYC
Register Today and SAVE !..

SYS-CON.TV
Today's Top SOA Links


Calling PowerBuilder NVOs in C#
PBNI answers the call

How can we reuse PowerBuilder NVOs in .NET applications? Before PowerBuilder 9.0, the answer was PowerBuilder automation or a three-tier solution.

In the latter case that meant hosting all the NVOs in EAServer as middle-tier components. Beginning with version 9, PowerBuilder offers a new interface to interact with the PowerBuilder VM - the PowerBuilder Native Interface (PBNI). In this article I will explain how to use PBNI in unmanaged C++ code and marshal the parameters to C# managed code so that you can invoke PowerBuilder NVOs from C#.

Introducing PBNI (PowerBuilder Native Interface)
PBNI is a new feature introduced with PowerBuilder 9.0. It is only available in the enterprise versions and is installed under %PowerBuilder install%\ SDK\PBNI. You can find all the required header files to use PBNI under the include directory.

PBNI is a standard programming interface that enables developers to extend the functionality of PowerBuilder. Using PBNI, you can create visual and nonvisual extensions to PowerBuilder (including marshaler extensions) and also embed the PowerBuilder virtual machine (PBVM) into C++ applications. Compared with PowerBuilder automation, PBNI has many advantages:

  • It is not just reusing existing NVOs. PowerBuilder can be extended using PBNI to provide capabilities such as XML parsing and Web service integration.
  • The solution is not COM-based, therefore no registry settings are required and it can be deployed to non-Windows platforms.
  • More languages can reuse PowerBuilder components; for example, Java-based applications can use JNI to invoke PowerBuilder via PBNI.
  • Many PowerBuilder built-in features can be moved to PowerBuilder extensions so that the PowerBuilder core can be very small and the deployment size can vary depending on which features the user needs.
How It Works
PBNI provides predefined C++ interfaces to allow the PBVM interact to with other languages (see Figure 1). Table 1 describes some important interfaces.

Calling PowerBuilder NVO from Unmanaged Code
To invoke a PowerBuilder NVO using PBNI, you need to follow these steps:

1.  Identify the required PowerBuilder library files and the method signature string in the NVO. This can be done using the PowerBuilder library painter. Right-click the method in the NVO and select "Properties". The signature string is shown in the "Signature" text field (see Figure 2). Another way to do it is using pbsig100.exe, which is a command-line tool shipped with PBNI SDK:

pbsig100 <pbl file name>.

Here is a smple output of pbsig100.exe showing the methods' signature strings of NVO n_automation:

PB Object Name: automation

PB Object Name: n_automation

public function string fn_barcode
(string specimenid, string
specimen_formatted)
   /* SSS */
public subroutine fn_workdraft
(string connstr, string
specimenid)
   /* QSS */

PBNI uses the NVO's name, method name, and the signature string to find the method to call.

2.  Call LoadLibrary() to load the PBVM DLL. In version 10, the PBVM DLL is called pbvm100.dll.

3.  Use GetProcAddress() to get the address of the "PB_GetVM" method and then call the PB_GetVM() method to get a reference to the PBVM.

4.  Call CreateSession() to create a IPB_Session instance. You can store the IPB_Session reference in a class member or a global variable to reuse the session. Because creating the session is a heavy process, it should be done only once.

5.  Call the FindGroup() method of the IPB_Session instance to find the NVO group. The group name should be the same as the NVO's name.

6.  Call the FindClass() method of the IPB_Session instance with the group ID and class name. The class name should be the NVO's name. You may feel confused here; what is the point of the group definition? It makes more sense when you try to find a window and controls in the pbl. For example, in a window definition w_1, w_1 is a group, and w_1 and the controls contained in it are all classes of group w_1.

7.  Call the NewObject() method of the IPB_Session instance to create an instance of the class returned by FindClass().

8.  Call the GetMethodID() method of the IPB_Session instance to get a reference of the method you want to call. Please make sure to give the correct function name and signature string - (see step 1)

9.  Call the InitCallInfo() method of the IPB_Session instance to initialize a PBCallInfo structure.

10.  Fill in the parameters and call InvokeObjectFunction() to invoke the method.

11.  Retrieve the return value using the PBCallInfo structure.

12.  Release the PBCallInfo reference.

13.  Release the IPB_Session instance and call FreeLibrary() to unload the PBVM DLL. This step should be done in the destructor of the class or at the moment when you are done with PBNI calls.

It sounds like a lot steps, but it is much easier when you see the sample code in Listing 1. In the following example, the PBNI calls are wrapped in a C++ class called CPBInvoker. The DLL loading and IPB_Session initialization are done in the constructor and the clean up is done in the destructor of the class. For the sample, the method we want to call is in an NVO named n_automation and the method name is fn_barcode with a method signature string of "SSS", meaning it returns a string and takes two string type parameters.

How to Pass Parameters
PBCallInfo is the structure to pass parameters and the return value in/out of the method. The structure contains a pointer pArgs to the IPB_Arguments interface that has two methods:

  1. GetCount obtains the number of arguments in a method call.
  2. GetAt obtains the value at a specific index of the pArgs member of the PBCallInfo structure. For each argument, GetAt returns a pointer to the IPB_Value interface.
The IPB_Value interface has a corresponding method to set the value for different data types, for example, SetString sets the string value and SetInt sets the int value and so on.

It's a little tricky to get the return value. If the method returns a simple type, such as int, you can use PBCallInfo returnValue->GetInt() to retrieve the value. If the return value requires a memory block, such as a string, you must do this:

pbstring ret = ci.returnValue->
   GetString();
// str has the string value you want
   LPCTSTR str = _session-
   >GetString(ret) );

About David Huo
David Huo works for the iAnywhere Solutions
consulting team

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

How can we reuse PowerBuilder NVOs in .NET applications? Before PowerBuilder 9.0, the answer was PowerBuilder automation or a three-tier solution.


Your Feedback
PBDJ News Desk wrote: How can we reuse PowerBuilder NVOs in .NET applications? Before PowerBuilder 9.0, the answer was PowerBuilder automation or a three-tier solution.
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021

SYS-CON Featured Whitepapers
ADS BY GOOGLE