Tips for PowerBuilder 5, 6, 7, 8

 

Some of these tips answer very frequently asked questions. Others are just plain interesting.  Most are from 

public postings on PB newsgroups & lists -- some by our staff, many by others. In some cases we lost 

track of the name of the author. If we have included in this list something that you wrote, and if you would like 

attribution, please drop us a line. If you would like to make some other kind of correction or your own contribution,

we'd be delighted to hear from you.


Topics 


Alter Table

Alter Table - Adding not-null columns

Array - Changing from bounded to unbounded 

Autologoff Bitwise and - Alternative 

Colours 

Command line parsing 

Connecting to multiple databases 

DDLB and dddw events 

DDDW calculator and calendar 

Deployment - dlls 

Directory exists 

Directory file list without a window 

Disable close 

Dot notation - limitations in 5.0.0x 

DW - changing the presentation style 

DW - currentrow() and getrow() 

DW column - highlighting of current row 

DW column - setting value of computed column 

DW - referencing computed fields 

DW - finding column names at runtime 

DW - finding controls at runtime 

DW - preventing focus loss on tabbing from last row or column 

DW GetRow() bug fix 

DW grids, changing 

DW - group by N 

DW horizontal lines every rows 

DW retrieval argument using aggregate function 

DW update error, row changed between retrieve and update 

Enter key - make it emulate the tab key 

Environment variables 

FindFirstFile api 

Free disk space 

Hex strings 

Login - Getting netware login name 

Login - Netware 

Mail - Sending from PB app 

Message Object - extending 

Mouse Position 

Multi-language support 

Network Drives 

PFC DDDW - multiple rows from a lookup 

PFC Help toolbar button 

PFC Numeric service - hex extensions 

PFC Transactions - optimistic locking, one opinion 

PFC Windows - placing controls 

Set default printer from within PB 

Sql/Oracle PB bug 

Stored Procedure with Output Parameter

RMB Menus 

TCP/IP address 

Window Events 

Window - Centre on opening

 

 

ALTER TABLE

 

1. Export syntax of the table to the log. 

2. Save the log as a SQL file

3. Drop the table.

4. Go into the DBA Admin painter, open the SQL file that contains the syntax of the table.

5. Make changes.

6. Execute the SQL. This will create the table again with the field options changed.

 

 

 

ALTER TABLE - ADDING NOT-NULL ATTRIBUTES OR COLUMNS

 

A table doesn’t have to be dropped or empty to add a NOT NULL constraint.  You have only to …

  - make sure all rows are indeed not null on the target field

  - write and run the alter statement in the DBA painter

You have to leave and re-enter the painter to see the changes.

 

If new not null columns are to be added you either have to start with an empty table or do it in 3 steps: 

first add the column, then fill in some values and finally set it to not null.

 

Back to top

 

 

 

ARRAY – CHANGING FROM BOUNDED TO UNBOUNDED

 

string lsNull [ ], lsBounded [ 5 ], lsUnbounded [ ]

// assume lsUnbounded has been populated elsewhere.

lsUnbounded = ls_Null

lsUnbounded = ls_Bounded

 

Now unbounded array will contain the values of the bounded array, dimensioned at 5.

 

Back to top

 

 

 

AUTOLOGOFF

 

To autologoff after an hour of inactivity, place code in events as follows:

 

           1. application idle event: gnv_app.event pfc_idle()                

           2. appmanager contructor event: Idle(3600)

           3. appmanager pfc_idle event: halt close

 

If you are familiar with the workings of the Idle event, then you could have it start a timer on your frame window in PB5, 

and there is a timer NVO in PFC 6.0. Both of these will trigger a timer event after the specified time length has expired. 

 

Method 1:

Quick & dirty: log out any open transactions, and call a HALT CLOSE. This will force the application to close 

immediately without any further processing. If you want open windows to be able to perform specific processing 

before the app closes, then try something like Method 2.

 

Method 2:

Since you are using PFC, you could use the sheetmanager application service to pull a list of open sheet windows. 

Inherit all of them from an application sheet ancestor and add a custom user event that will be triggered on all open 

windows. Something like ue_IdleTimeout(). It will need a return code so the calling script will know when all the 

processing is complete.

 

Instead of using an ancestor application sheet, you could also code this in w_master if you are using a copy of the 

PFE layer for your application. Using w_master would allow you to include any open response windows, etc., 

though you have to figure out how get a reference to the non-sheet windows. Some tweaking to the sheetmanager 

service might work.

 

In the window you declare the event, add the following script:

 

                ib_disableclosequery = True

 

This is a PFC instance variable that will disable all closequery and pfc_Save processing. Add any other globally 

required logic. Then, in the rest of your windows down the inheritance chain, add any other specific logic that is 

necessary. Once this event has been triggered on all open windows, close all transactions, and perform a HALT 

CLOSE just to make sure something didn't get missed

 

Back to top

 

 

 

BITWISE AND - ALTERNATIVE

 

Alternative to pfc's of_BiwiseAnd ().  faster than pfc's.  Here is the comparison (50 calls):

this:  . 1948 secs pfc version     .7168 sec

 

// Function:  of_BitWiseAnd (UnsignedLong aul_value1,UnsignedLong aul_value2)

// Description:   ANDs each bit of the values. this is an iterative function.

//   al_Value1 The first value to be used in the operation.

//   al_Value2 The second value to be used in the operation.

// Returns:   UnsignedLong The result of the AND operation.

// Author: Lijun Yang Date:  4/8/97

 

  UnsignedLong lul_return = 0

  Unsignedlong  lul_multiple = 1

 

  // Check for nulls

  If IsNull(aul_Value1) Or IsNull(aul_Value2) Then

   SetNull(ll_Result)

   Return ll_Result

  End If

 

  // Perform the AND

  Do

    lul_return +=  mod (aul_value1, 2) * mod (aul_value2, 2) * lul_multiple

    aul_value1 = aul_value1 / 2

    aul_value2 = aul_value2 / 2

    lul_multiple *= 2

  Loop Until aul_value1 = 0 AND aul_value2 = 0

 

  RETURN lul_return

 

 

Back to top

 

COLOURS

 

Colors in Windows are stored as 4 byte longs, with one byte each representing the Red, Green, and Blue 

components and fourth byte usually indicating (alpha) transparency. The structure is: 0xAABBGGRR 0x is 

hexadecimal zero, where AA is the alpha (usually 0), BB is the blue component, GG is Green, and RR is red. 

0x00 represents no colour, 0xFF saturation You can easily calculate the colors by the following two methods:

 

1) Use the Windows Calculator. Set the mode to Scientific (View->Scientific). Select Decimal (Dec) mode. 

Enter the number you have, then change to Hex mode.

 

2) Use math. R = mod (Colorvalue, 256); G = mod (Colorvalue /256, 256); B = mod (Colorvalue/65536, 256)

 

The 16 basic colours are listed in Help/RGB. Other colors of note are:

   Buttonface 79741120

   WindowText 41943040

   WindowBackground 1088479456

   Transparent 536870912

   CONSTANT long   BLACK = 0

   CONSTANT long   WHITE = 16777215

   CONSTANT long   LIGHTGREY = 12632256

   CONSTANT long   DARKGREY = 8421504

   CONSTANT long   RED = 255

   CONSTANT long   DARKRED = 128

   CONSTANT long   GREEN = 65280

   CONSTANT long   DARKGREEN = 32768

   CONSTANT long   BLUE = 16711680

   CONSTANT long   DARKBLUE = 8388608

   CONSTANT long   MAGENTA = 16711935

   CONSTANT long   DARKMAGENTA = 8388736

   CONSTANT long   BROWN = 8388736

   CONSTANT long   CYAN = 16776960

   CONSTANT long   YELLOW = 65535

   CONSTANT long   PALEYELLOW = 1226487

   CONSTANT long   WINDOWBACKGROUND = 1090519039

   CONSTANT long   BUTTONFACE =  79741120

   CONSTANT long   WINDOWTEXT = 33554432

   CONSTANT long   APPWORKSPACE = 276856960

Values for the upper color bits

  2^25 - Window Text

  2^26 - buttonface

  2^27 - scrollbar background

  2^28 - app. wrokspace

  2^29 - transparent

  2^30 - Window Background

  2^31 - unused

  2^32 - unused

 

Back to top

 

 

 

COMMAND LINE PARSING

 

string ls_cmd, ls_arg[]

integer i, li_argcnt

 

// Get arguments and strip blanks from start and end of string

ls_cmd  = Trim( commandParm () )

 

li_argcnt = 1

DO WHILE Len(ls_cmd ) > 0

        // Find first blank

        i =Pos( ls_cmd, " " )

        // If no blanks (only one argument), set i to point to the hypothetical character after end of string

        if i =0 then i =Len(ls_cmd) + 1

        // Assign the arg to the arg array.No. of chars copied is one less than position of the space found with Pos

        ls_arg[li_argcnt] =Left( ls_cmd, i - 1 )

        // Increment the argument count for the next loop

        li_argcnt = li_argcnt + 1

   // Remove the argument from the string so the next argument becomes first

        ls_cmd =Replace( ls_cmd, 1, i, "" )

LOOP

 

Back to top

 

 

 

CONNECTING TO MULTIPLE DATABASES

 

// enable transaction registration (the registration service is need when using more than one database)

gnv_app.of_SetTrRegistration(TRUE)

// register SQLCA (the connection to the first database which was connect to the usual way)

gnv_app.inv_trregistration.of_Register(SQLCA)

 

// connect to and register ABRN_MRS database (the second database)

// create 2nd transaction object; n_tr gtr2 must be declared global

gtr2 = CREATE n_tr  

// copy connection info from the first database called SQLCA to the second database

// called gtr2 - it copies the user id, password, database name, server name, etc. from

// the definition of the first database connection to the definition of the second database connection

il_return = SQLCA.of_CopyTo(gtr2) 

// re-assign the database name to the second definition

gtr2.Database = "your_2nd_database_name"

// re-assign the server name to the second definition - if it's different

gtr2.ServerName = "your_2nd_server_name"

// connect to the second database

ll_return = gtr2.of_Connect()

If ll_return <> 0 then MessageBox("Error", "Unable to connect.")

// register the second database with the registration service

gnv_app.inv_trregistration.of_Register(gtr2)

 

Now whenever you want to retrieve data from the 2nd database, you would write in the window's open event

  li_return = dw_1.of_SetTransObject(gtr2)

  dw_1.retrieve()

 

Back to top

 

 

 

DDLB AND DDDW EVENTS

 

There is an undocumented way to get to a lot of DDDW / DDLB events. Whenever an event occurs in the 

datawindowchild it sends a notification code to the parent DW.  This code can be intercepted in the user 

event mapped to pbm_command datawindow event.  If you want to experiment to determine which events 

you can intercept, try adding the code below to ue_command mapped to pbm_command:

 

mle_status.text += "hwndchild = " + String(hwndchild) + ", " + "childid = " + String(childid) + ", " + &

                                "notificationcode = " + String(notificationcode) + "~r~n"

 

The code needed to intercept the dropdown arrow in the ddlb is:

 

int li_rc

li_rc = this.GetChild("ddlbtest", ldwc_ddlb)

IF childid = Handle(ldwc_ddlb) THEN

CHOOSE CASE notificationcode

CASE 1

Post Event ue_DDLBRowFocusChanged()    

                END CHOOSE

END IF

 

Other events:

     Event                                 ActionID from WordParm

     Clicked                                             1281

     RowFocusChanged                      2048, 2049

     RightMouseButtonDown               2314

     Left Button Up                                 2313

     Retrieve End                                    769

     MouseMove                                     2311

 

Back to top

 

 

 

DDDW CALCULATOR AND CALENDAR

 

To use the  Drop Down Calendar or the Drop Down Calculator with the editmask style column you will need to use 

the "NONE" style service option.

 

1. Create a computed field with a bitmap() expression to the right of the datawindow column:

   BitMap("calendar.bmp")

where "calendar.bmp" may be a small calendar or a drop down arrow. Give the computed field a name; 

say "ship_date_arrow".

 

2. Enable the DDCalendar service with the "NONE" option:

  This.of_SetDropDownCalendar(TRUE)

  This.iuo_calendar.of_SetInitialValue(FALSE)

  This.iuo_calendar.of_SetAlwaysRedraw(FALSE)

  This.iuo_calendar.of_SetCloseOnClick(TRUE)

  This.iuo_calendar.of_SetCloseOnDClick(TRUE)

This.iuo_calendar.of_Register("ship_date",iuo_calendar.NONE)

 

3. Add code to the DW clicked event to drop the Calendar:

  IF dwo.name = "ship_date_arrow" THEN

       IF IsValid(iuo_calendar) THEN

               this.SetColumn("ship_date")

               this.event pfc_ddcalendar()

       END IF

  END IF

 

Back to top

 

 

 

DEPLOYMENT - DLLS

 

5.X

 

It is mandatory to have the deployment kit on your client machine. It doesn't matter if you are building machine code or 

p-code executable. In either case you need deployment kit. But you may reduce the number of DLLs to be deployed 

depending on what features you used in your application. Following gives the list of DLLs which are optional. For 

more information see Powersoft Document 4427.

 

All Platforms

pbbgr050.dll   Business graph engine

pbdwe050.dll  DW engine

pbrte050.dll    Runtime engine

pbrtf050.dll     Runtime functions

pbshr050.dll   Stg mgr, dec, print, ...

pbtyp050.dll   System object/function definitions

pbitxt50.dll     DW Import text (optional)

 

Win16, Win32

pbroi050.dll   OLE 2 support

pbtra050.dll   Database interface - trace of any database

pbdbl050.dll   Database interface - msg handler for pbsyb, pbmdi, pbnet (optional)

pbdbt050.dll   Database interface - msg handler for pbsyc (optional)

pbdpb050.dll  Dist PB - local driver (optional)

pbdse050.dll  Distributed PB (optional)

pbidbf50.dll    DW Import Dbase (optional)

pbin5050.dll   Database interface - Informix 5.0 (optional)

pbmdi050.dll  Database interface - MDI (optional)

pbmss050.dll Database interface - MS SQL Server 6.0 (optional)

pbo71050.dll  Database interface - Oracle 7.1 (optional)

pbodb050.dll  Database interface - ODBC (optional)

pbor7050.dll   Database interface - Oracle 7.0 (optional)

pborc050.dll   ORCA (optional)

pbosc050.dll  Dist PB - open server client (optional)

pbrtc050.dll    Rich text support (optional)

pbsmi050.dll   Dist. PB (optional)

pbsyb050.dll   Database interface - Sybase dblib interface (Microsoft lib linked) (optional)

pbsyc050.dll   Database interface - Sybase ctlib interface (optional)

pbwsc050.dll   Dist PB - winsock client (optional)

 

Win32

 

pbwss050.dll  Dist PB - winsock server (optional)

pbnpc050.dll   Dist PB - named pipe client (optional)

pbnps050.dll   Dist PB - named pipe server (optional)

pbo72050.dll   Database interface - Oracle 7.2 (optional)

pboss050.dll   Dist PB - open server server (optional)

pbsyt050.dll    Database interface - Sybase dblib interface (Sybase lib linked) (optional)

PFCCOM32.DLL – required for PFC apps

 

Win16

 

pboui050.dll  OLE 2 user interface

pbvbx050.dll  VBX

pbibm050.dll  Database interface - IBM (optional)

pbnet050.dll   Database interface - net gateway (optional)

And! -- PFCCOMM.DLL, PFCFLSRV.DLL

 

 

6.5

 

pbdwe60.dll         datawindow engine

pbmss60.dll