This article describes the techniques and code used during my presentations at the Carolina Code Camp 2012 and at the May 2012 meeting of the North Carolina PowerBuilder User Group.
The techniques described here utilize Visual Basic .NET (coded in Visual Studio 2010) with the Interop Forms Toolkit available from Microsoft. The Interop Forms Toolkit was originally intended as a ‘bridge’ between the VB 6 world and VB.NET. It allows you to host any .NET control in any Win32 application that supports COM. The current version supports Visual Studio 2005, 2008, and 2010.
In this example, we are creating a horizontal track bar control to use in a PB application (PB12.5). Why not use the PB control, you say? Well, we want one which allows us to control the background color.
First, create a project in Visual Studio and under ‘Visual Basic’ – ‘Windows’ choose the VB6 Interop UserControl. Give the control a meaningful name at the bottom, I picked ‘vb_trackbar
’.
In the Solution Explorer, you should see a number of components which are automatically created. Almost all the work is done in the ‘InterobUserControl.vb’ element
Double click on the ‘InteropUserControl.vb’ element to bring it up in design mode so the actual control can be built.
Choose a Trackbar from the tools window in Visual Studio...
...and drop it on the usercontrol. Rearrange its size and position as appropriate.
Now choose a Label and drop it on the control.
Change the backcolor of the trackbar to yellow; the name to TB; the Margin to 0,0,0,0; the Maximum to 100; the TickFrequency to 10; and the TickStyle to Both.
Modify the background color of the label and the usercontrol itself to yellow. Rename the control to ‘IOP_Trackbar
’, the label to ‘LB_Value
’, and give the label a border.
Right click on the ‘InteropUserControl.vb’ element from the Project window and choose ‘View Code’.
You will see code like this (this is from Visual Studio 2010).
Here is the code to add.
Public Event tbScroll()
Public Event tbValuechanged()
Private Sub TB_Scroll(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles TB.Scroll
LB_Value.Text = TB.Value.ToString()
RaiseEvent tbScroll()
End Sub
Private Sub TB_Valuechanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles TB.ValueChanged
RaiseEvent tbValuechanged()
End Sub
Public Sub tbSetBackColor(ByVal testval As Integer)
Dim myColor As Color = ColorTranslator.FromWin32(testval)
TB.BackColor = myColor
LB_Value.BackColor = myColor
BackColor = myColor
End Sub
Public Shadows Property TBBackgroundColor() As Integer
Get
Return ActiveXControlHelpers.GetOleColorFromColor(TB.BackColor)
End Get
Set(ByVal value As Integer)
TB.BackColor = ActiveXControlHelpers.GetColorFromOleColor(value)
End Set
End Property
Public Shadows Property TBValue() As Integer
Get
Return TB.Value
End Get
Set(ByVal value As Integer)
TB.Value = value
End Set
End Property
In the first portion, there are two events we want to expose to PowerBuilder so we can write code in our PB app to respond to the control. These are ‘tbScroll
’ and ‘tbValuechanged
’. One is triggered in response to the Scroll event on the trackbar (which we named ‘TB
’) and the other by the Valuechanged
event. In the tbScroll
event, we are setting the Text
in the label (we called it ‘LB_Value
’) on the userobject
to the Value
property of the Trackbar
.
We also are creating a method, tbSetBackColor
, which can be called from our PB app to set the background colors of the userobject
, trackbar
, and label
.
Finally, we are exposing two properties of the Trackbar
so we can either set or get them from our PB app. These are called ‘TBBackgroundColor
’ and ‘TBValue
’.
The last thing we need to do in Visual Studio is to add an Interface to the project so the events we are exposing can be seen from within PowerBuilder. From the Project menu, choose ‘Add New Item’.
Then under the ‘Common Items’, choose ‘Interface’.
In the code for the interface, replace it with the following:
<guid("ca16a9e8-02c7-43d2-90f6-4ef30885a338"),> _
Public Interface iIOP_Trackbar
<dispid(1)> _
Sub tbScroll()
<dispid(2)> _
Sub tbValuechanged()
End Interface</dispid(2)>
The first thing to do now is to replace the example GUID with one of your own (Visual Studio can generate one). Also give the Interface a more meaningful name – ‘iIOP_Trackbar
’ in this example. Within the interface definition are the two events which will be visible from within PowerBuilder.
With this done, you can now build the solution from the ‘Build’ menu.
This will create and register the DLL on the machine.
Now in PowerBuilder, the control will be available when you choose to add a userobject
.
The events are visible in Powerscript.
Now in the tbscroll
event on our ole control, we put the following:
long ll_val
//report on the current value of the control
//this uses the
ll_val = ole_1.object.event tbvalue()
//move the PB control
htb_1.position = ll_val
// show value
st_1.text = string(ll_val)
Code in the tbvaluechanged
event on the ole control:
sle_2.text =
Code to set the color of the ole control.
long ll_color
// set the desired color on the control
IF sle_1.text = string(RGB(0,174,221)) THEN
ll_color = 15780518
ELSE
ll_color = RGB(0,174,221)
END IF
// call method on .Net control to set the background colors
ole_1.object.event tbsetbackcolor(ll_color)
// get the color value using the
sle_1.text = string(ole_1.object.tbbackgroundcolor())
Running the application gives the following:
See the original control background color. Clicking the Set Color button gives this:
Moving the trackbar ole control results in this:
There are a couple of things to look out for when using the techniques described here. The first is that any events exposed via the .NET Interface must have some sort of Powerscript in them within PB. Failure to do this results in an ‘unhandled exception’ application crash. There may be some way to prevent this from within Visual Basic but I am not sure.
The other issue is that if you have to change your VB.NET component, you must re add it to your window/form within PowerBuilder. Usually, I will add a second ole object to the existing window, transfer all the code from the old ole control, delete the original control, and finally rename the new control to that of the old control. This is the biggest issue I have with working with ‘roll your own’ ole controls. If anyone knows of a workaround for this, I would like to hear it.
Visual Studio and PB files can be downloaded from here.
The video presentation of this is on YouTube.
CodeProject