Tech Articles


PBNI Extension Framework


Addressing the complexities of PBNI

PowerBuilder Native Interface (PBNI) allows developers to extend the capabilities of PowerBuilder by implementing features in C++ or using third-party libraries. However, the traditional process for creating these extensions can be cumbersome.

For a simple sum function with 9 lines of code...

... you have to write 63 lines of code just to make it callable from PowerBuilder and for every change, you have to make PB-specific modifications in three files:

A more efficient approach

The PBNI framework introduces a more streamlined development experience. By leveraging the framework, developers can focus on the core logic of their extensions without being bogged down by the repetitive setup and boilerplate code inherent in traditional PBNI development. The framework handles much of the underlying plumbing, allowing for a cleaner and more maintainable codebase.

For example, where previously developers would need to manually implement the PBX_GetDescription, PBX_CreateNonVisualObject, and Invoke functions, the framework simplifies this with a class registration macro.

Without the framework:

// main.cpp
PBXEXPORT LPCTSTR PBXCALL PBX_GetDescription() {
   static const TCHAR desc[] = {
      "class arithmetic from nonvisualobject \n" \
      "function int f_add(int a,int b)\n" \
      "end class \n"
   };
   return desc;
}

PBXEXPORT PBXRESULT PBXCALL PBX_CreateNonVisualObject (
   IPB_Session* pbSession,
   pbobject        pbobj,
   LPCSTR          xtraName,
   IPBX_NonVisualObject   **obj ) {
   if (strcmp(xtraName, "arithmetic") == 0) {
         *obj = new arithmetic;
   }
   return 0;
};

With the framework:

// arithmetic.cpp
#include "arithmetic.h"

namespace Inf {
  INF_REGISTER_CLASS(arithmetic, L"u_pbni_arithmetic");
  
  INF_REGISTER_FUNC(f_add, L"of_add", L"ai_left", L"ai_right");
  PBInt arithmetic::f_add(PBInt arg0, PBInt arg1) {
    return arg0 + arg1;
  };
}

This approach significantly reduces the amount of code required and centralizes the registration of classes and functions, making the development process faster and less error-prone.

Quick start

This guide will help you set up your environment to build your first PBNI extension using the framework template.

Prerequisites

First, ensure you have the following tools installed:

  1. PowerBuilder 2022 R3 (also compatible with other versions) 
  2. Visual Studio (MSBuild): https://visualstudio.microsoft.com/
  3. CMake: https://cmake.org/
  4. Conan: https://conan.io/

Setup conan

  1. If PowerBuilder is not installed in the default path (C:/Program Files (x86)/Appeon), you must set an environment variable PB_DIRECTORY that points to the corresponding directory.
  2. Add the Informaticon remote repository by running this command in your terminal:
    conan remote add inf-conan https://artifactory.informaticon.com/artifactory/api/conan/conan
  3. Have Conan detect your default environment settings:
    conan profile detect
  4. Change the default Conan profile (usually found at %userprofile%/.conan2/profiles/default) or create a new one with the following settings. This profile tells Conan to build for a 32-bit architecture and specifies compiler settings.
    # %userprofile%/.conan2/profiles/default
    [settings]
    arch=x86 # change this to x86_64 for 64bit builds
    build_type=Debug # change this to MinSizeRel for release builds
    compiler=msvc
    compiler.cppstd=20
    compiler.runtime=static
    compiler.version=194 # Corresponds to MSVC v143 (VS 2022)
    os=Windows
    
    [options]
    *:pb_version=22.0 # Change this to 25.0 to use PowerBuilder 2025

Code the extension

With your environment configured, you can now build the extension.

    1. Clone the template repository.
    2. Modify the project for your needs / program your library:
      • Create a .cpp and an .h file in the src directory containing your C++ code.
        // arithmetic.h (example)
        namespace Inf {
            class arithmetic : public PBNI_Class {
            public:
                PBInt f_add(PBInt, PBInt);
            };
        }
        
        // arithmetic.cpp (example)
        #include "arithmetic.h"
        
        namespace Inf {
            INF_REGISTER_CLASS(arithmetic, L"u_pbni_arithmetic");
        
            INF_REGISTER_FUNC(f_add, L"of_add", L"ai_left", L"ai_right");
            PBInt arithmetic::f_add(PBInt arg0, PBInt arg1) {
                return arg0 + arg1;
            }
        }
        
      • In the CMakeLists.txt file, replace °°°PACKAGE_NAME°°° with your desired project name.
      • In the CMakeLists.txt file, replace °°°SOURCE_FILES°°° with the relative paths to your source files.
        add_library(${PROJECT_NAME} SHARED
        	src/arithmetic.cpp
        	src/arithmetic.h
        )

Build the extension

    1. Install the required dependencies using Conan. This may take some time on the first run as it downloads and builds the necessary libraries.
      conan install . --build=missing
    2. Generate the Visual Studio project files using CMake:
      cmake --preset conan-default
    3. Build the PBNI extension:
      conan build . --build=missing

Use the extension in PowerBuilder

  1. Add the Informaticon Exception Framework to you project:
    1. Download the latest release from Github (e.g. lib.pb.base.exception-framework@1.2.3+pb22-x86-minsizerel.zip for PB2022R3).
    2. Unzip exf1.dll and exf1.pbl into you PowerBuilder project folder.
    3. Add exf1.pbl to your library list.
    4. Integrate the exception framework in the application object:
      // Global variables
      u_exf_error_manager gu_e
      
      // open() event
      gu_e = create u_exf_error_manager
      
      // systemerror() event
      gu_e.of_display(gu_e.of_new_error() &
      	.of_set_nested_error(gu_e.of_get_last_error()) &
      	.of_push(1 /*populateerror()-Return*/) &
      	.of_set_message('systemerror occured') &
      	.of_push('Notice', 'Nested error may be unrelated to this system error.') &
      	.of_set_type('u_exf_re_systemerror'))
      halt
  2. Finally, import the freshly built PBNI dll file into PowerBuilder. You can find it in the build directory, for example: ./out/MinSizeRel/my_project.dll:

Further reading

To learn more, explore the framework and its usage with these resources:

Informaticon has already utilized this framework to develop a range of PowerBuilder extensions, including tools for picture manipulation, QR code generation, and an advanced email and HTTP client. While these specific extensions are not yet open source, the underlying PBNI Framework is available under MIT license for the community to use in their own projects.

Exception Handling

The framework relies heavily on exception handling, each function declares a throws clause.
This is to force us to perform appropriate error handling:

u_pbni_arithmetic lu_arithmetic; lu_arithmetic = create u_pbni_arithmetic
long ll_result

try
	ll_result = lu_arithmetic.of_add(1, 2)
catch (u_exf_ex lu_e)
	// handle the error, e.g.
	// - Rollback the current transaction
	// - Retry
	// - Re-throw the exception to the caller or declare the
	//   exception in your own throws statement
	// - Display it: gu_e.of_display(lu_e)
end try

If you are new to this topic, read this:

Why PBNI remains essential alongside .NET integration

While PowerBuilder's .NET integration is powerful, the PBNI framework offers a fundamentally different and more direct level of integration. Its key advantage is the ability to communicate directly with the PowerBuilder Virtual Machine (PBVM). This allows developers to create custom extensions that behave like native PowerBuilder components, providing a feature set for deep integration and fine-grained control that is distinct from the .NET import functionality.

Comments (0)
There are no comments posted here yet

Find Articles by Tag

Syntax Class Database Object ActiveX PFC DevOps Linux OS Application IDE HTTPClient API DataWindow Jenkins Variable Web API RibbonBar REST SOAP BLOB PBVM Database Table SqlExecutor Oracle Source Control Validation Installation Outlook Export Encryption Debug ODBC PowerBuilder Compiler Bug Deployment Database Connection Sort SDK XML Trial .NET Assembly Source Code Authentication Script C# SQL Server RESTClient NativePDF Interface PostgreSQL ODBC driver Text DragDrop PostgreSQL Configuration Database Table Schema PBDOM Platform TreeView COM Array SqlModelMapper Graph .NET Std Framework Windows OS Window Transaction WinAPI Mobile PDFlib File PowerServer Mobile Visual Studio Import Git Migration CrypterObject JSONGenerator Event Export JSON Web Service Proxy Design Database Profile Azure Menu Performance Branch & Merge Automated Testing Stored Procedure Model GhostScript Messagging iOS JSONParser Expression Import JSON Elevate Conference Android SVN Resize WebBrowser Charts OLE TFS SnapDevelop Icon Database Table Data Event Handling DLL License Excel DataWindow JSON OAuth 2.0 InfoMaker PowerServer Web 32-bit PBNI Service PDF PowerBuilder (Appeon) TLS/SSL RichTextEdit Control Filter DataType Database Open Source SQL Encoding RibbonBar Builder Error PowerScript (PS) Event Handler UI Modernization Testing OrcaScript 64-bit MessageBox TortoiseGit Data Debugging Windows 10 Icons JSON Authorization Repository SnapObjects Database Painter CI/CD OAuth PowerBuilder External Functions .NET DataStore Debugger UI Themes CoderObject UI