Coding restrictions

Although PowerScript is essentially a compiled language, it is quite tolerant. For the sake of performance, the PowerBuilder .NET compiler is not designed to be as tolerant as the PowerBuilder native compiler. To be able to compile your applications with .NET, you should avoid certain practices in your PowerScript code.

The following language-level items apply when you plan to transform a PowerBuilder application to a Windows Forms or Web Forms application.

Syntax issues

Avoid the GoTo statement Jumping into a branch of a compound statement is legal in PowerBuilder, because the concept of scope inside a function does not exist in PowerScript. For example, the following code works well in PowerBuilder:

if b = 0 then
    label: …
else
end if
goto label

This PowerScript translates conceptually into the following C# code:

if (b == 0)
{	// opening a new scope
    label: …
}
else
{
}
goto label; 

Since a GoTo statement is not allowed to jump to a label within a different scope in .NET, the C# code would not compile. For this reason, avoid using GoTo statements.

Avoid calling an indirect ancestor event in an override event Suppose that there are three classes, W1, W2, and W3. W1 inherits from Window, W2 inherits from W1, and W3 inherits from W2. Each of these classes handles the clicked event. In the Clicked event of W3, it is legal to code the following in PowerScript:

call w1::clicked

However, in C#, calling the base method of an indirect base class from an override method is not allowed. The previous statement translates into the following C# code, which might produce different behavior:

base.clicked();

In this example, a possible workaround is to move code from the Clicked event of the indirect ancestor window to a window function, and then call the function, rather than the original Clicked event, from the descendant window.

Semantic issues

Do not use the This keyword in global functions A global function is essentially a static method of a class. Although the PowerBuilder compiler does not prevent you from using the This pronoun in a global function, the C# compiler does not allow this.

Do not change an event's signature The PowerBuilder compiler does not prevent you from changing the signature of an event defined by its super class, but .NET does not allow this. For example, suppose the w_main class contains the following event:

Event type integer ue_update(int e)

The subclasses of the w_main class should not change the parameters or the return type of the event.

Do not change the access modifier of an inherited function to public If your application contains a class that inherits from another class, do not change to public access the access modifiers of functions whose access level in the parent class was protected or private. The PowerBuilder compiler does not prevent you from changing the access modifier of a function in an inherited class from protected or private to public, but if you attempt to deploy a .NET target that contains such a function, you receive an error indicating that a private or protected function cannot be accessed.

Do not code Return statements in Finally clauses PowerBuilder allows you to code a Return statement in the Finally clause of a Try-Catch-Finally-End-Try statement, but C# does not support Return statements in Finally clauses. If your code includes such statements, the compiler returns the error “Return statement cannot be used in finally clause.”

External functions

Differences in passing a structure by reference PowerBuilder allows you to declare an external function that has a parameter of type Structure passed by reference. For example:

Subroutine CopyMemory(ref structure s, int size) library "abc.dll"

The s parameter can accept any datatype that is a pointer to something.A PowerBuilder external function is mapped to the .NET Platform Invoke functionality. This functionality requires that the structure passed into the external function be exactly of the type declared. Therefore, when compiling the following PowerScript code, the PowerBuilder .NET compiler issues an error, because the parameter, li, references a LogInfo structure, which is different from the function’s declared structure class.

LogInfo li
CopyMemory(ref li, 20)   // error!

To solve this problem, you can declare an additional external function as follows:

Subroutine CopyMemory(ref LogInfo li, int size) library "abc.dll"

Structures as parameters in .NET Applications External functions that have structures for parameters must be passed by reference rather than value if you call them in a .NET Windows Forms or .NET Web Forms application when the parameter is a const pointer. For example, a PowerScript call to the SystemTimeToFileTime function in kernel32.dll could use the following declaration, with the first parameter being passed by value and the second parameter by reference:

Function boolean SystemTimeToFileTime(os_systemtime lpSystemTime, ref os_filedatetime lpFileTime) library "KERNEL32.DLL"

For .NET Windows Forms or Web Forms applications, you must modify the declaration to pass both parameters by reference:

Function boolean SystemTimeToFileTime(ref os_systemtime lpSystemTime, ref os_filedatetime lpFileTime) library "KERNEL32.DLL"

The SystemTimeToFileTime function is declared as a local external function and used in pfc_n_cst_filesrvunicode, pfc_n_cst_filesrvwin32, and other operating-system-specific classes in the pfcapsrv.pbl in the PFC library. If you use this library in a .NET Windows Forms or Web Forms application, you must change the declaration as described above.

Allocate space before passing a string by reference Before passing a string to an external function by reference in PowerBuilder, you should allocate memory for the string by calling the Space system function. In subsequent calls to the function, if you pass the same string to the function, PowerBuilder continues to work well even if the string becomes empty, because memory allocated for the string is not yet freed by the PowerBuilder VM.

This is not the case in the .NET environment. If the string passed to an external function by reference is empty, and if the external function writes something to the string, an exception is thrown. Therefore, you must make sure to allocate enough space for a string before passing it to an external function by reference.