Issues & Workarounds

In this section we list and describe the most common problems that we encounter during porting projects.

No matter how good the porting procedure is, there are some fundamental differences between CTD and .NET that have to be addressed manually.

Format Strings

In .NET all format strings must use the invariant format. Ice Porter automatically converts SAL format strings to .NET compliant format strings when porting controls. However, it is impossible for Ice Porter to determine if it´s a string constant or is used as a format string and it is also impossible to convert localized symbols at runtime.

If your application is using localized format strings you have to change them by hand (or write a custom function that changes the strings at runtime) because you only know the locale that was used for those strings. .NET will localize the invariant format strings at runtime using Windows settings or the locale that is configured programmatically for the running application.

For example:

Sal.FmtFormatNumber(nValue, "#.##0,00");

Is invalid and should be changed manually to:

Sal.FmtFormatNumber(nValue, "#,##0.00");

SalCompileAndEvaluate Expressions

Expressions that are executed by SalCompileAndEvaluate are string and are written in the original application using SAL syntax.

However the built-in interpreter in the PPJ Framework uses C# syntax. As a result some expressions may need to be fixed manually. In alternative we can provide a plug-in custom parser that supports SAL syntax.

For example:

Call SalCompileAndEvaluate('SalMessageBox("Hello, World", "", 0)')

Works very well without any manual interaction. Reading and writing a variable, calling a function, accessing a member of an object and similar simple operations work without any change.

What needs to be changed are the boolean operators, operators precedence and string concatenation.

SAL SyntaxC# Synta

n = 1

n == 1

s || "test"

s + "test"

b1 AND b2

b1 && b2

b1 OR b2

b1 || b2

NOT b1


One particular tricky issue is the difference between the single equal symbol in SAL and the double equal symbol in C#. In Team Developer an expression like "n = 1" is interpreted to test the value of "n" against 1 and return TRUE or FALSE. In C# it's executed as an inline assignment and 1 is assigned to n.

The same expression in C# should be "n == 1". The problem is that the original expression is legal, but it's executed differently.

For this reason, inline assignments are disabled by default and executing an assignment in SalCompileAndEvaluate() without the keyword "Set" causes an exception.

If you are sure that all your interpreted exceptions are safe in this respect, you can enable inline assignments in the PPJ Framework by using:

PPJ.Runtime.Scripting.Script Engine.AllowInlineAssignments = true;

The PPJ Framework allows for the substitution of the parser. The default parser is for C#, but it is possible to use a parser for VB or for SAL syntax as well. See Custom Parsers.

Number/Boolean Type Mismatch

In Team Developer the Number and Boolean types are exactly the same and may be mixed without any problem.

After porting, the new code will use either SalNumber or SalBoolean and the two are also compatible. However, when there is a receive parameter of type SalNumber, you cannot pass a SalBoolean type, or viceversa. This kind of mismatch causes a compiler error and must be resolved by hand.

Handle Type Mismatch

It's common to find Window handles, File handles, Sql handles and Session handles mixed and misused.

In Team Developer there was really no difference between the handles and one could assign the various types to each other without even a warning.

After porting, the wrong assignments will generate compiler errors and have to be fixed by hand.

VisMenu Functions

All the VisMenu functions are supported in the PPJ.Runtime.Vis library.

However, some functions have an added parameter that was missing in the Team Developer library.

This change causes compilation errors that have to be fixed by hand. The missing parameter is the form that owns the menu.

The VisMenu functions with the added parameter are:

  • Vis.MenuCheck

  • Vis.MenuDisabl

  • Vis.MenuEnable

  • Vis.MenuGetCount

  • Vis.MenuGetPopupHandle

  • Vis.MenuIsChecked

  • Vis.MenuIsEnabled

  • Vis.MenuUncheck

COM Properties

C# doesn't support properties with arguments, other than the default indexer property. Therefore the COM wrapper code generated by IP for parameterized properties doesn't work and needs to be changed by hand using reflection.

External Functions with Receive Strings

All strings in Team Developer are ANSI string and it is possible that an external custom DLL alters the content of the passed string addressing it like a simple text buffer.

After porting all strings are UNICODE. Therefore, unless the external function declaration specifically declares the string argument as a receive parameter, any modifications applied to the string buffer in the external custom DLL is lost.

.NET Objects Created as COM Objects

In case the original SAL application mapped existing .NET objects as COM objects, the ported .NET application will fail to create them at runtime as COM objects because the .NET runtime detects that they are .NET objects and doesn't create the COM callable wrapper.

In this case you can either change the code to use the .NET class directly, or simply change the internals of the COM wrappers created by Ice Porter from using COM interfaces to using the .NET class directly.


Some Team Developer applications use WM_NCCREATE to change the style of the window using SetWindowLong(GWL_STYLE) and to remove the frame.

Usually this is done to create splash windows. This technique will not work in .NET because the .NET Framework re-applies the window styles in various places. Code using WM_NCCREATE should be removed and the regular .NET properties should be used.

Receive Object References

In Team Developer object arguments are always passed by reference. This means that if the SAL code assigns a value to an object argument, the variable in the caller functions is altered. Few SAL developers are aware of this "feature", which may result in corrupted variables at runtime.

Ported code always generated object argument by value to eliminate this serious potential problem and to avoid generating redundant syntax all over the application.

However, in the few cases where this functionality was actually desired by the developer, it is necessary to change the parameter declaration by hand and add the ref or out keywords.

SalTblPopulate Error Handling

In Team Developer when an invalid SQL statement is used with SalTblPopulate it simply returns FALSE and no When SqlError section is reached.

Ported code behaves in a different way: an invalid SQL statement raises an exception when used with SalTblPopulate. That means it is different to Team Developer but consistent with SqlPrepare and other Sql calls.

Last updated