Working with callbacks |
PBInvoke library documetation > Advanced > Working with callbacks |
PowerBuilder does not support PowerScript code to be directly called from external functions.
As of PB9 there is a possibility to write a C++ extension for that task using PBNI. However, implementing callbacks using PBNI has the following limitations:
Also, there are additional limitations not related to PBNI.
PBInvoke has support for declaring and using callbacks directly in PowerScript code without these limitations.
In order to declare a callback you need the following steps:
Example:
// in n_cst_timerproc's constructor (inherited from n_pi_method) n_pi_core lnv_core lnv_core.of_declare("& typedef VOID CALLBACK TimerProc(& HWND hwnd, & UINT uMsg, & UINT_PTR idEvent, & DWORD dwTime & );& ") of_declare_callback("TimerProc") |
Use n_pi_method.of_get_addr() to get the numeric value of the callback address ready to be passed to an
external function which accepts function pointers of this type.
Example:
n_cst_timerproc lnv_timerproc lnv_timerproc = Create n_cst_timerproc // ef_SetTimer is an external function, alias for WinAPI SetTimer ll_timer = ef_SetTimer(0, 0, 1000, lnv_timerproc.of_get_addr()) |
In the ue_callback event, callback parameters can be retrieved by calling of_get_param("paramname").
The return value is passed to the caller of the callback using usual RETURN operator. Note, that PBInvoke
does not support the following types as return types of callbacks:
However, pointers or references to those type are supported.
Example:
ulong hwnd ulong uMsg ulong idEvent ulong dwTime // retrieve parameters hwnd = of_get_param("hwnd") uMsg = of_get_param("uMsg") idEvent = of_get_param("idEvent") dwTime = of_get_param("dwTime") // process event ... Return 0 |
All context data needed by a callback can be stored in the instance variables of the callback object
(which is a descendant of n_pi_method).
That is possible because PBInvoke generates a unique phisical address (function pointer) for each callback object, and when an external function calls your callback via that address, PBInvoke maps that call exactly to your object.
Marshalling parameters between C++ and PB is a slow operation (compared to PB external functions calls) due to
the flexibility PBInvoke provides. If a PB callback is used as a handler for intercepting GUI messages (e.g. via
calling SetWindowsHookEx), then it may cause slow repaint of UI, or even a hang for a long time, because UI
generates huge amount of messages, most of which are ignored by the callback but take time for marshalling.
PBInvoke provides an optimization for that case. For callbacks used with SetWindowsHookEx WinAPI function, it's
possible to setup a filter for message ID's which are processed by the callback. If a message ID does not pass the
filter, the PowerScript code of the callback will not be called and all the processing will be done in C++
according to the rules described in MSDN for SetWindowsHookEx hooks: call CallNextHookEx.
In order to activate the message filter you must call of_set_windows_hook_filter() immediately after calling
SetWindowsHookEx().
Syntax:
Example:
// This code is part of CustomSaveAs sample, which demonstrates // using callbacks for customizing Windows Shell 'Save As' dialog. Long ll_hInstance, ll_hThreadID ll_hInstance = inv_GetWindowLong.of_invoke(al_windowhandle, n_pi_winapi.GWL_HINSTANCE) ll_hThreadID = inv_GetCurrentThreadId.of_invoke() il_hHook = inv_SetWindowsHookEx.of_invoke(n_pi_winapi.WH_CALLWNDPROCRET, this.of_get_addr(), ll_hInstance, ll_hThreadID) // IMPORTANT! As number of messages sent to UI related windows hooks is really huge, // processing them all in PowerScript is inefficient, and probably will hang the UI. // PBInvoke can efficiently filter hook messages by message id. // The following call enables this feature. // of_set_windows_hook_filter must be called immediately after SetWindowsHookEx() // The args: hook handle, hook type, and array of message ids which pass via filter to the hook. of_set_windows_hook_filter(il_hHook, n_pi_winapi.WH_CALLWNDPROCRET, & {n_pi_winapi.CB_ADDSTRING, n_pi_winapi.CB_SETCURSEL} ) // Currently only WH_CALLWNDPROCRET, WH_CALLWNDPROC, WH_GETMESSAGE hook types are // supported with this filtering feature |
© 2003-2011 Desta, Ltd. All rights reserved. | SupportDesk |