PowerBuilder, disable system menu`s close button

ulong ll_parent_hwnd
ulong ll_sys_menu_hwnd
ulong ll_sys_menu_close_flags
ulong ll_ret

n_cst_numerical u_num

ll_parent_hwnd = Handle(this.parentwindow())

ll_sys_menu_hwnd = GetSystemMenu(ll_parent_hwnd, FALSE)

ll_sys_menu_close_flags = GetMenuState(ll_sys_menu_hwnd, SC_CLOSE, MF_BYCOMMAND )

ll_ret = u_num.of_bitwiseand(ll_sys_menu_close_flags , MF_DISABLED)

ib_close_prev_enabled = (ll_ret = 0)

If ib_close_prev_enabled Then
EnableMenuItem (ll_sys_menu_hwnd, SC_CLOSE, MF_BYCOMMAND + MF_DISABLED + MF_GRAYED)
End If


And to enable it later:

If ib_close_prev_enabled Then
EnableMenuItem (GetSystemMenu(handle(parentwindow()), FALSE), SC_CLOSE, MF_BYCOMMAND + MF_ENABLED)
End If


PowerBuilder, different DD list values for each row, another way

The Ol’ Hidden Items in the Dddw Problem Part II

Make a second copy of the Color column and have this always contain all the rows in its dddw.  This second column is never filtered.

When the row is not the current row, display the column with the unfiltered dddw and hide the filter column.  If the row is the current row, show the column with the filtered dddw, and hide the column with the dddw with all the possible rows.  To do this, add the following expression to the visibility attribute of the column with the dddw which gets filtered:

IF (CurrentRow() = GetRow(), 1, 0)

The column with the dddw which always contains all the values will have the following expression in its visibility attribute:

IF (CurrentRow() = GetRow(), 0, 1)

PowerBuilder, different DD list values for each row

Source http://www.pbdr.com/pbtips/dw/fltrdddw.htm

Step 1 – declare instance variables

boolean ib_dropdowndropped = False
boolean ib_dropdownredrawn = True

Step 2 – extend the pbm_dropdown event

ib_dropdowndropped = True
ib_dropdownredrawn = False
ib_dropdownredrawn = True

Step 3 – extend the pbm_ncpaint event

If (ib_dropdowndropped And ib_dropdownredrawn) Then
 ib_dropdowndropped = False
 ib_dropdownredrawn = False
 ib_dropdownredrawn = True
End If

Step 4 – write the of_Filter (boolean ab_switch) subroutine

datawindowchild ldwc
long ll_getitemnumber
string ls_setfilter = ""

If (ab_switch) Then
 ll_getitemnumber = GetItemNumber(GetRow(), "order_status_id")
 If (ll_getitemnumber = 1) Then // cancelled -> cancelled
  ls_setfilter = "(order_status_id = 1)"
 ElseIf (ll_getitemnumber = 2) Then // confirmed -> confirmed
  ls_setfilter = "(order_status_id = 2)"
 ElseIf (ll_getitemnumber = 3) Then // new -> cancelled, new, pending
  ls_setfilter = "(order_status_id = 1) or (order_status_id = 3) or
(order_status_id = 4)"
 ElseIf (ll_getitemnumber = 4) Then // pending -> cancelled, confirmed,
  ls_setfilter = "(order_status_id = 1) or (order_status_id = 2) or
(order_status_id = 4)"
 End If
End If

GetChild("order_status_id", ldwc)

Bowerbuilder datawindow autosize problem

You have a datawindow. Datawindow has an Autosize Height set to Details band. You insert a row, set a long string value to some field expecting that field to be auto-sized. And it is, but you don’t see a text as Details band does not auto-size. What to do? Whan way to fix this is to call Sort() somewhere after you set v the value fro the datawindow to refresh and auto-size to take effect. But that does not work all times ( for example … you dont want to sort data now). Another way is to set:

dw.Modify ( ‘DataWindow.Header.Height.AutoSize=yes’)

This will also make datawindow to resize all the bands and auto-size will take effect then.

Calling .NET from PowerBuilder

To call .NET for PowerBuilder best option is to create Class Library in Visual Studio. Sign it. In project properties, Application, Assembly Information…, check “Make assembly COM-Visible”.

Sign it class library (project properties, Signing…).

In project properties, Application, Assembly Information…, check “Make assembly COM-Visible”.

Optional, add these attributes to your class:

Register created DLL in command lime like:

regasm /tlb “path/to/dll/file.dll” /codebase

Use it from PowerBuilder like:


OLEObject obj

Integer li_rc

obj = CREATE OLEObject
li_rc = obj.ConnectToNewObject("ClassLibrary1.Class1")

IF li_rc < 0 THEN

DESTROY obj MessageBox("Connecting to COM Object Failed",     "Error: " + String(li_rc)) Return

MessageBox("Connecting to COM Object Failed",     "Error: " + String(li_rc)) Return


ELSE obj.ShowMe()END IF



To call some web service from this DLL you add service reference and then:

[code lang=”csharp”]
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress address =
new EndpointAddress("http://web-service-url");
var client = new ServiceReference1.YourWebServiceClient(binding, address);

var b = client.YourWebServiceMethod();

List services problem in Windows 10 and PowerBuilder .NET 12.5

Windows 10 / PowerBuilder .NET 12.5

Trying to make web service client and list services I get an error:

Windows SDK for .Net Framework 4.0 was not installed. Please install it before use this feature.

Tried to install Microsoft Windows SDK for Windows 7 and .NET Framework 4 (ISO) but that did not help.

So I downloaded ProcessMonitor to check what for PowerBuilder .NET is looking and cannot find.  Found that it is looking for [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v7.1\WinSDK-NetFx40Tools-x86] and does not find it.

In my registry, I had tools in v8.0A WinSDK-NetFx35Tools-X86, so I just for test I made this new registry entry:

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v7.1\WinSDK-NetFx40Tools-x86]
“ComponentName”=”Microsoft Visual Studio 2012 Multi-targeting Utilities for .NET Framework 3.5”
“InstallationFolder”=”C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\bin\\”

And after that, list services now work in PowerBuilder .NET 12.5





PowerBuilder 12.5.2 / Windows 10: trouble installing .NET 4.0 SDK

For PowerBuilder WCF client to work it needs .NET 4.0 SDK. But trouble is that this SDK is provided only for Windows 7. And trying to install it on Windows 10 gives an error. The solution I found is to uninstall Microsoft Visual C++ redistributable packages and only then installing SDK for .NET 4.0, then it works.

PowerBuilder and Norwegian/Finish/Serbian string to date conversion on Windows 10

Problem is in system locale on Windows 10.
In Windows 10 Microsoft changed date time formats for some regions:
Finnish, Norwegian Bokmål (“Norway” and “Svalbard and Jan Mayen” variants), Serbian (variants “Cyrillic, Kosovo”, “Latin, Montenegro”, “Latin, Serbia” and “Latin, Kosovo”).
It was internally changed so that it has now the same separator in date and time parts.
For example, previously format was “01.01.2001 11:01” now is “01.01.2001 11.01”.
It is so even if in regional settings user sets “:” as time separator.
It was reported in other systems that on Windows 10 DateTime.Parse(DateTime.Now.ToString()) no longer works correctly for described regions.
More info: http://www.heikniemi.net/hardcoded/2015/08/windows-10-breaks-net-date-parsing-in-certain-locales/
As in my case system locale for users cannot be changed to any other and it is unknown if and when MS will release any fix, solution in PB should be found.
My proposal would be:
Create function DATE in for example w_sheet window so all other windows inherit it.
public function date date (string astr_string);
n_cst_datetime dtm
return dtm.of_getdate(astr_string)
end function
Create helper function of_getdate in pfc_n_cst_datetime:
public function date of_getdate (string astr_date);
return Date(DateTime(astr_date))
end function
So, whenever Date( data ) is called in itemchanged (or other) event, our function would be used instead and it would return correct converted date.

PowerBuilder and SQL Sever ‘row changed between retrieve and update’ error.

One issue I was working on was triggering ‘row changed between retrieve and update‘ error on DataWindowupdate. Code was kinda simple, just retrieve some values in DataWindow, move some values to Deleted buffer and then call update. No other data manipulations etc. Found that table had some database trigger that was fired on delete. Disabled the trigger and there error message was gone. So trigger was causing that. Trigger also was quite simple, just cursor going through deleted rows and selecting and updating few values in other tables.

Googling told me that in Microsoft SQL server, if a table has an insert, update, or delete trigger, the number of affected rows returned to the SQLNRows property of the Transaction object after an INSERT, UPDATE, or DELETE command depends on the driver. With an ADO.NET driver, the value returned is the sum of the rows affected by the command itself and the trigger. When you are connected to Microsoft SQL Server using ADO.NET or OLE DB, you can set the RecheckRows run time database parameter (introduced in PowerBuilder 10.5) to 1 to recheck how many rows of data were affected by the INSERT, UPDATE, or DELETE command itself and return that value in the SQLNRows property. Setting RecheckRows to 1 before issuing an INSERT, UPDATE, or DELETE command causes a SELECT @@ROWCOUNT command to be executed. To improve performance, you should set it only when required, and reset it to the default value of 0 after use. Example: SQLCA.DBParm=”RecheckRows=1″.

Another solution could be setting SET NOCOUNT { ON | OFF } in trigger itself. SET NOCOUNT ON stops the message that shows the count of the number of rows affected by a Transact-SQL statement or stored procedure from being returned as part of the result set. When SET NOCOUNT is ON, the count is not returned. When SET NOCOUNT is OFF, the count is returned. The @@ROWCOUNT function is updated even when SET NOCOUNT is ON. SET NOCOUNT ON prevents the sending of DONE_IN_PROC messages to the client for each statement in a stored procedure. For stored procedures that contain several statements that do not return much actual data, or for procedures that contain Transact-SQL loops, setting SET NOCOUNT to ON can provide a significant performance boost, because network traffic is greatly reduced.

As I had to make fix in PowerBuilder application, adding QLCA.DBParm=”RecheckRows=1″ before and QLCA.DBParm=”RecheckRows=0″ after Update call solved this problem.