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.

How to switch from an SCC API SVN client to the native SVN interface


If you have been using the Subversion (SVN) source code control system for your PowerBuilder applications for a while, you have likely been using an SCC API implementation client (such as PBSCC Proxy, PushOK, etc.) to connect PowerBuilder to SVN. If you are considering switching to the native SVN interface provided by PowerBuilder then you probably do not want to lose the history of all the changes you made during all those years of development. Although this is not covered in the PowerBuilder documentation, it is relatively simple to do.

Read more

PowerBuilder Equivalents to Windows API Datatypes


At some point in your PowerBuilder career, you will need to call a Windows API (or WinAPI, for short) function. The WinAPI specifications are heavily dependent on type definitions created in C/C++ via the #define preprocessor directive. The use of type defintions helps the readability of Windows code, but it unfortunately and effectively hides the actual underlying datatype - making it difficult for you to correctly code the PowerBuilder external function declaration needed to call the API function.

Some time ago I published a four-part series of PowerBuilder tutorials that explain the ins and outs of interfacting PowerBuilder apps with the Windows API, but I realize the many developers are very busy and do not have the luxury of sufficient spare time needed to read that much material. In case you are interested and have the time, I have included URLs to those tutorials at the end of this article.

This article consists of two tables. The first table lists many of the most commonly-seen WinAPI type definitions and their PowerBuilder equivalents. The second table lists the PowerBuilder datatypes and their WinAPI equivalents, if any. For your convenience, I am also providing the URLs to several useful resources you may find helpful when coding external function declarations.

Common Windows API Type Definitions to PowerBuilder Datatypes

The following table maps many of the most commonly-used WinAPI type definitions to their PowerBuilder equivalents:

WinAPI Type Definition or Datatype Equivalent PB Datatype
Comment
BOOL Boolean Boolean (True/False) value. A 4-byte integer in Windows. A 2-byte integer in PowerBuilder. PB automatically promotes/demotes the value to the appropriate datatype when it is used as an argument in an external function call.
BOOLEAN Byte Boolean (True/False) value. An 8-bit, unsigned integer. NOTE: Not the same datatype as BOOL, yet it is also used for True/False values.
BYTE Byte An 8-bit, unsigned integer.
Byte Array (block of memory Blob A block of memory is typically referenced by a pointer (the address of the first array element) in Windows.
CONST** Constant** A directive that conveys to the compiler that the value is to remain unchanged during execution. (** => NOT a datatype)
double (C/C++) Double A basic C/C++ language datatype, not a WinAPI-defined type definition.
DWORD UnsignedLong or ULong A 32-bit unsigned integer.
FLOAT Real Rarely used in WinAPI, but included here for completness.
HANDLE Longptr A generic handle (ID number) to an undetermined Windows resource.
HBITMAP Longptr A handle to a bitmap.
HBRUSH Longptr A handle to a brush.
HDC Longptr A handle to a device context.
HDROP Longptr A handle to an internal drop structure, used in drag/drop operations.
HFILE Longptr A handle to a file.
HFONT Longptr A handle to a font.
HICON Longptr A handle to an icon (you should be starting to see a pattern by now, I hope).
HINSTANCE Longptr A handle to an instance (same as HMODULE).
HMENU Longptr A handle to a menu.
HMODULE Longptr A handle to a module (same as HINSTANCE).
HMONITOR Longptr A handle to a display monitor.
HRESULT Long A return code used by COM interfaces. NOTE: This is NOT a Windows handle, although its name would imply that it contains a Windows handle.
HWND Longptr A handle to a window or a control. All controls are implemented as subclassed windows, so a handle for a control is actually a handle to a window.
INT Long A signed 32-bit integer (NOT a PowerBuilder Int, which is 16-bits long.
INT16 Integer (or Int) A signed 16-bit integer.
INT32 Long A signed 32-bit integer.
INT64 LongLong A signed 64-bit integer.
INT8 -none- A signed 8-bit integer. NOTE: The PowerBuilder Byte datatype is an unsigned 8-bit integer.
INT_PTR Longptr A signed integer (32-bit or 64-bit, depending on the process/app bitness. Used in Windows for pointer arithmetic.
LANGID Integer (or Int) A language identifier.
LONG Long A signed 32-bit integer.
LONGLONG LongLong A signed 64-bit integer.
LONG_PTR Longptr A signed integer (32-bit or 64-bit, depending on the process/app bitness. Used in Windows for pointer arithmetic.
LONG32 Long A signed 32-bit integer.
LONG64 LongLong A signed 64-bit integer.
LPARAM Longptr A Windows event message parameter.
LPCSTR Longptr A pointer to a constant, null-terminated string (array) or ANSI characters.
LPCVOID Longptr A pointer to a constant of undetermined datatype.
LPCWSTR Longptr A pointer to a constant, null-terminated string (array) of Unicode ("Wide") characters.
LPVOID Longptr A pointer to a value of undetermined datatype.
LPDWORD Longptr A pointer to a DWORD (an unsigned 32-bit integer).
LPWORD Longptr A pointer to a WORD (an unsigned 16-bit integer).
LPWSTR Longptr A pointer to a null-terminated string (array) of Unicode ("Wide") characters.
PVOID Longptr A pointer to a value of undetermined datatype.
QWORD -none- An unsigned 64-bit integer. NOTE: The PowerBuilder LongLong datatype is a signed 64-bit integer.
SHORT Integer (or Int) A signed 16-bit integer.
UINT UnsignedLong (or ULong) An unsigned 32-bit integer.
ULONG UnsignedLong (or ULong) An unsigned 32-bit integer.
ULONGLONG -none- An unsigned 64-bit integer. NOTE: The PowerBuilder LongLong datatype is a signed 64-bit integer.
USHORT UnsignedInt (or UInt) An unsigned 16-bit integer.
VOID Any A value of undetermined datatype. Means "returns no value" when describing a function's return value.
WCHAR Character (or Char) A Unicode ("Wide") character.
WORD Integer (or Int) A signed 16-bit integer.
WPARAM Longptr A Windows event message parameter.

Please be aware that WinAPI type definitions can be "nested." For example, HICON is defined as HANDLE. HANDLE is defined as PVOID. PVOID is defined as a pointer to any datatype. Therefore, HICON is a pointer, which can be either a 32-bit integer or a 64-bit integer, depending on the bitness of the application/process... and this translates to a Longptr in PowerBuilder.

Here is a URL to online documentation describing these and additional various WinAPI type definitions:

https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types

The following URL is a staring point for documentation on Windows API functions and structures:

https://learn.microsoft.com/en-us/windows/win32/apiindex/api-index-portal

Many WinAPI functions indicate success/failure status via the function's return value. In the event of a failed call, an internal error number may be set within the Windows operating system. You can obtain this numeric error code via the GetLastError WinAPI function, but deciphering what an error code value means can be problematic. If you have Visual Studio installed, you can examing the header file named "winerror.h" to find the name of nearly all error codes, or you can instead visit the following URL:

https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes

PowerBuilder Datatypes to Windows Type Datatypes and Type Definitions

The following table maps the PowerBuilder datatypes to their WinAPI equivalents:

PowerBuilder Datatype Size (Bytes) Equivalent WinAPI Type Definition or Datatype Comment
Any 8 or 12 n/a An internal PowerBuilder structure. Its size depends on the target compilation bitness. When used in a structure object, an Any assumes the size and characteristics of the argument parameter is represents. There is no WinAPI equivalent.
Blob 4 or 8 BYTE array An array of type BYTE (i.e., a pointer), so the size depends on the target compilation bitness.
Boolean 2 BOOL BOOL is a 4-byte integer in WinAPI, but a PowerBuilder Boolean is 2 bytes. PB automatically promotes/demotes the value to the appropriate datatype when it is used as an argument in an external function call.
Character (or Char) 2 WCHAR Unicode character. "W" stands for "wide," i.e., Unicode.
Date 4 or 8 -none- A pointer to an internal PowerBuilder structure, so the size depends on the target compilation bitness. There is no WinAPI equivalent.
Datetime 4 or 8 -none- A pointer to an internal PowerBuilder structure, so the size depends on the target compilation bitness. There is no WinAPI equivalent. See the note that follows this table.
Decimal 8 -none- There is no WinAPI equivalent.
Double 8 double (C/C++)  
Integer (or Int) 2 SHORT  
Long 4 INT or Long  
LongLong 8 LONGLONG  
Longptr 4 or 8 LONG_PTR A signed 32-bit or 64-bit integers. Its size depends on the target compilation bitness.
Real 4 FLOAT Rarely used in WinAPI.
String 4 or 8 LPWSTR A null-terminated array of Unicode characters (i.e., a pointer), so the size depends on the target compilation bitness.
Time 4 or 8 -none- A pointer to an internal PowerBuilder structure, so the size depends on the target compilation bitness. There is no WinAPI equivalent.
UnsignedInteger (or UnsignedInt or UInt) 2 USHORT or WORD  
UnsignedLong (or ULong) 4 DWORD  

Note:

The SYSTEMTIME structure in the WinAPI specifies a date and time, using individual members for the month, day, year, weekday, hour, minute, second, and millisecond, which is roughly equivalent to the PowerBuilder Datetime datatype. There are no supplied functions to convert values between the two formats, but they can be created by a PB developer relatively easily.

Interfacing PowerBuilder Applications to Window API Functions

There is a series of PowerBuilder tutorials online in the Appeon Community that will help you master the intricacies of interfacing PB apps with Windows API functions. You can access this series of tutorials via the following URLs:

https://community.appeon.com/articles-blogs/tutorials-articles/2-powerbuilder/302-interfacing-pb-applications-with-the-windows-api-part-1

https://community.appeon.com/articles-blogs/tutorials-articles/2-powerbuilder/303-interfacing-pb-applications-with-the-windows-api-part-2

https://community.appeon.com/articles-blogs/tutorials-articles/2-powerbuilder/304-interfacing-pb-applications-with-the-windows-api-part-3

https://community.appeon.com/articles-blogs/tutorials-articles/2-powerbuilder/305-interfacing-pb-applications-with-the-windows-api-part-4

 

PowerBuilder Icons


Update on 23-OCT-2024:  The icons have apparently been moved to a new home:

https://www.appeon.com/sites/default/files/pictures/Downloads/CodeSample/PB10_Icons.zip

https://www.appeon.com/sites/default/files/pictures/Downloads/CodeSample/Silk Icons.zip

https://www.appeon.com/sites/default/files/pictures/Downloads/CodeSample/WinXP Icons.zip

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Earlier, one of our members asked about obtaining a set of the PB Classic icons. I've got those, along with two other sets of Icons available for your use. These icons sets are:

 - PB 10 icons

 - the Silk icons

 - the WinXP icons

Read more

Tile Menu Style using Datawindow Object


Updated sample with added features from pbdev.id blog

Have you ever wanted Windows Tile Menu Style on your application? this datawindow object can give you way to have it.
Just add row data to set Image, Text and size of the tile.

Read more

REST Enhancements in PowerBuilder 2019


REST support was added to PowerBuilder in 2017 R2 and enhanced in 2017 R3.  PowerBuilder 2019 contains additional significant enhancements to REST support, including the following:

  • RetrieveOne method – For REST methods return one row
  • Submit method - sends request and returns data in one operation
  • SetRequestHeader behavior modified
  • GZIP compression handled automatically
  • Send[Method]Request, where method can be Get, Put, Post, Patch, Delete
  • Get and Set OAuth token methods
  • Get and set JWT token methods

 

Read more

Free My GUI! - Multi-Threading in PowerBuilder


In this follow-up to the article titled “’Haunted Apps’ – How to Avoid Ghost (Unresponsive) Windows”, you’ll learn about the multi-threading capabilities available to PowerBuilder applications and how multi-threading can be used to perform tasks that typically freeze the application’s Graphical User Interface (GUI). Multi-threading can be utilized for many purposes, but this discussion will focus primarily on the use case of long-running data retrieval requests.

This article covers what you need to know in order to get started using multi-threading in PowerBuilder. A new example application that can be easily customized to test multi-threaded data retrieval in your development environment(s) is now available in the PowerBuilder section of CodeXchange. An expanded, but slightly earlier version of this article is included in the example application’s download package that explains the objects and code in detail.

Read more

Find Articles by Tag

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