Welcome!

PowerBuilder Authors: Dan Joe Barry, Carmen Gonzalez, Ian Thain, Yakov Werde, Paul Slater

Related Topics: PowerBuilder

PowerBuilder: Article

PowerBuilder 11's .NET Interoperability

Creating and consuming .NET resources

Invoking a Class Within a Namespace
Let’s say I wish to utilize an ArrayList in the System.Collections namespace of MSCORLIB. In an “#IF defined PBDOTNET”, preprocessor block, I’ll declare a variable of type System.Collections.ArrayList, create an instance of ArrayList, then assign its reference to the variable. It’s then a simple matter of invoking the add() method of ArrayList to populate the instance, then concatenate a rudimentary string for this academic example.

For a listing of the limitations of conditional compilation and general constraints for .NET interoperability, please refer to the PowerBuilder 11 documentation.

#if DEFINED PBDOTNET then
            system.collections.ArrayList al
            al = create system.collections.ArrayList
            al.add(“POWERBUILDER 11...”)
            al.add(“VERY”)
            al.add(“PRODUCTIVE”)

            string s
            s = al[0].tostring() + “ “ + al[1].tostring() + “ “ + al[2].tostring() + “!”  // index starts from 0!
            sle_1.text = s
#end if

Note that the instantiation of the ArrayList class was accomplished using “create” syntax rather than “new”. This is a clear indication that the code within the .NET preprocessor code blocks is actually a modified version of PowerScript rather than C#.

Cross-Language Data Exchange
Since the PowerScript compiler does not recognize the code within the .NET preprocessor code blocks, any variables that are declared within the blocks cannot be referenced outside of the blocks. If the developer needs to utilize a value derived from within a preprocessor block, a variable may be declared before the block, assigned a value within the block, then referenced after the block.

When invoking methods of classes within the namespaces of managed assemblies, special care must be taken to use the correct PowerScript datatype equivalent. For example, in the following datatype mapping table shown in Figure 4, take special note that the PowerScript Int data type actually maps to a C# short and a .NET System.Int16. A PowerScript Ulong maps to a C# uint and a .NET System.UInt32.

Access to .NET Language Features
By using the .NET preprocessor code blocks, certain .NET language features may be used by the PowerBuilder developer that are not available to standard Win32 PowerScript:

  • sbyte and ulonglong datatypes
  • Bitwise operators
  • Parameterized constructors
  • Namespaces, interfaces, and developer-defined enumerations
  • .NET index access

For elaborations on the .NET language features that are available within the .NET preprocessor code blocks, please refer to the PowerBuilder 11 documentation.

Exception Handling with .NET Preprocessor Code Blocks
In Win32 deployments of PowerBuilder, exceptions are of two categories: system- and developer-defined. The system-defined exceptions classes like NullObjectError, DivideByZeroError, etc., as well as all developer-defined exceptions are all ultimately inherited from the root Throwable exception class (see Figure 5).

.NET deployment of PowerBuilder targets will have the same exception hierarchy with the difference that Throwable will be inherited from the .NET class System.Exception. Some of the exceptions that will be thrown from .NET classes, with which the developer will choose to interoperate, will be mapped to the following PowerBuilder exception hierarchy members:

            System.DivideByZero => DivideByZeroError
            System.NullReferenceException        => NullObjectError
            System.OutOfRangeException => RuntimeError

If RuntimeError is invoked due to a System.OutOfRangeException, the error message will be “Array boundary exceeded”. Other exceptions thrown from .NET instances will propagate unmodified directly to System.Exception (see Figure 6).

For methods in PowerBuilder .NET Targets for which the developer has chosen not to interoperate, exceptions will continue to behave as they have for Win32 targets.

Let’s look at a couple of code examples of mapped exceptions being thrown.

public class Test
{
  public int div_test(int a)
  {
    return a / 0; 
    //will cause
    //System.DivideByZero
    //Exception
  }
}

The div_test() method of the .NET class Test will throw a System.DivideByZero error...in fact a system-defined error. Any of the three exception classes in the DivideByZeroError>RuntimeError>Throwable PowerBuilder error hierarchy will be able to catch it as shown below.

int i = 10
string s
try
  #if defined PBDOTNET THEN

  Test t = create Test //Test is the .NET class we
                       //defined above.
  i = t.div_test(i) //here an exception will be raised
                    //by div_test function.
  #end if
//catch(DivideByZeroError e)
//catch (RuntimeError e)
//catch (Throwable e)
//any of these 3 lines can catch
//the exception.
  s = e.getMessage()   
end try

But let’s look at the behavior of a developer-defined exception being thrown. Below, the method Test() throws a developer-defined exception MyOwnXcptn.

public MyOwnXcptn:System.Exception
{
}
public class Test
         
  public int div_test(int a)
  {
    a = a / 2;
    throw new MyOwnXcptn();
  }
}

The code fragment below will fail to catch this exception since it relies on the mapping of system-defined exception classes.

int i = 10
string s
try
  #if defined PBDOTNET THEN
  Test t = create Test
  i = t.div_test(i) //here an exception will be raised
                    //by div_test function.
  #end if
//catch(Exception e)
//catch (RuntimeError e)
//catch (Throwable e) //none of these 3 lines can catch
                      //the exception

  s = e.getMessage()   
end try

Since the fragment below has caught the developer-defined exception class, or alternatively its ancestor System.Exception, the error will be successfully caught within the PowerBuilder preprocessor code block.

int i = 10
string s
#if defined PBDOTNET THEN
try
  Test t = create Test
  i = t.div_test(i) //here an exception will be
                    //raised by div_test function.
//catch (MyOwnXcptn e)
//catch (System.Exception e) //any of these 2
                             //lines can catch
                             //the exception
  s = e.getMessage()   
end try
#end if

More Stories By John Strano

John Strano is a Sybase Technology Evangelist and is a charter member of TeamSybase. He has been using PowerBuilder since 1991 and has authored articles for multiple industry periodicals. John has been a Sybase Certified Instructor and has presented Sybase tools on an international basis since 1997. Over the last 17 years John has developed a variety of PowerBuilder applications from single-user scaling up to enterprise-class, web-based projects.

Comments (1) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
Jerry 07/01/08 11:03:10 AM EDT

Anybody have an example that copies a .NET arraylist to a Powerbuilder datawindow or Listview?