Known issues and bugs
Known issues & bugs
OutlineListbox/Combobox: item values -2 to -6 issue
When populating items in an OutlineListbox, a strange effect can be seen when values are used
between -2 and -6 passed with the VisListLoadChild function.
This piece of code is handled differently in older TD versions (<TD4.2) compared to newer versions (TD4.2 and up).
Including TD5.1 and TD5.2 !
VisListLoadChild( lbTest, nRoot, 0, 0, "This is item text", -2, 0 )
Instead of the wanted text, a replacement text is presented in the listbox.
See screenshot below to compare the same application running in TD3.1 and in TD5.2.
Here you can download the testcase which contains the wParam and lParam conversion routine:
Debugger fails to perform "step-over"
In some situations when debugging, the "step-over" functionality does not work.
Instead it performs a "step-into" or even a "continue run".
One clear and reproducible cause is the use of WM_Enable in the message actions section of top-level windows.
At the time the debugger is activated (when a breakpoint is reached) TD disables all present top level windows and brings the IDE to front. (this is probably to avoid interference of the windows while debugging, a disabled window will not receive any messages, can not be clicked and put to front).
So what happens when code is present on the WM_Enable on a window: When the debugger starts it first does a disable of all windows. This triggers a WM_Enable message on those windows. The code there is executed. This code confuses TD. It expects to start debugging at the breakpoint, but TD is performing the actions on the WM_enable message BEFORE it reaches the breakpoint. So after the WM_Enabled message is processed, the debugger stops at the breakpoint. Now TD's debugger is messed up, it's execution context, current line of code etc etc seem not to correspond anymore. So the debugger is off track and step-into, step-over actions will be erratic and in some cases fail.
Strangely, when you put a breakpoint at the WM_enable message, the debugger does not stop at that breakpoint. And that is obvious, a chicken and egg issue. The debugger will only trigger a WM_Enable when a breakpoint is reached. The breakpoint on the WM_Enable will not be triggered when the debugger is not activated. Even when the debugger triggers WM_Enable, the breakpoint is not active. Seems TD is executing all code under the WM_enable, but it's breakpoint is ignored.
So what solution could there be? I think TD should eat up the WM_Enable message when the debugger disables the windows. Then the code will not be executed and the debugger will not get confused (I think).
In line with this assumption, I created a workaround which actually works. It depends what code is executed at the WM_Enable if you really need it at debug time. In our case, the WM_enable message is used to update GUI objects to reflect the enabled/disabled states. This is not needed at debugtime (the GUI is not visible at that time).
So maybe this trick will work for others having this issue:
At creation of top level windows, detect if the application is running from executable or is running in IDE. When running in IDE, the WM_Enable message should be eaten up so the code is never executed. When running from executable, the WM_Enabled message should be executed.
So this piece of code will do that.
On SAM_Create If SalStrRightX( strArgArray, 3 ) != "exe" Call RegSubclass( hWndForm, WM_ENABLE, hWndNULL, WM_ENABLE, SUBCLASS_FLAG_INSTEAD ) On WM_Enable ... Do actions here ...
You need Subclasser.
It subclasses WM_Enable and will send it to nirvana and eats it up.
The WM_Enabled message actions will never be executed.
Incorrect display of formats in IDE or errors in format conversions at runtime
In the IDE formats in the formats section show strange characters.
Or at runtime, formats are incorrectly processed or displayed on GUI objects.
Inspection of the Windows country settings show no problems. The country is ok and the individual
settings seem correct (number formats, date/time formats are as expected).
Cause of the issue:
There seems to be a Windows bug that sometimes the internal settings for the country are faulty.
But when inspecting them in the Windows configuration for the country settings, apparently there seems nothing wrong.
There is a simple trick to solve this issue.
Go to the Windows configuration for country and select another country and apply.
After that, select the original country and apply again.
This forces Windows to reset all internals for the country which solves the TD issue.
ComProxyVar issue: IDE shows comproxy type but is not internally
I have stumbled upon a very nasty issue concerning instances of type COM Proxy Class.
During conversion of older sources to TD60, I re-generated all ActiveX/COM components using TD60 ActiveX explorer.
Everything is the same: the names of the generated classes and also the methods.
All other sources using the newly created COM apl classes do compile ok.
But on some cases, at runtime the COM instances do not work.
Sometimes they do and sometimes the Create function fails (no runtime TD error messages).
They just return FALSE on the Create method.
When checking the source using the IDE, there seems nothing wrong. Even the ACA shows all methods on the ComProxy instances.
When comparing code which is working against the ones not working there is no visual difference between them.
The objects are all of the same class and the usage is 100% equal. But one works at runtime and the other does not.
So then I opened the faulty sourcecode using a text editor to look at the internal items at the place of the faulty and working code.
Here the working code:
.head 4 + Local variables .head 5 - ComProxyVar: LReportingComponent .head 6 - Class: ClsReportingComponent .head 5 - Boolean: bTemplateFound .head 4 + Actions .head 5 + If LReportingComponent.Create( ) .head 6 - Call LReportingComponent.IsWordTemplateFound( "c:\\test.dot", bTemplateFound ) .head 6 - Call LReportingComponent.Release( )
And here the faulty code:
.head 4 + Local variables .head 5 - FunctionalVar: LReportingComponent .head 6 - Class: ClsReportingComponent .head 5 - Boolean: bTemplateFound .head 4 + Actions .head 5 + If LReportingComponent.Create( ) .head 6 - Call LReportingComponent.IsWordTemplateFound( "c:\\test.dot", bTemplateFound ) .head 6 - Call LReportingComponent.Release( )
Well there is a difference. First line is ok, the next is faulty:
.head 5 - ComProxyVar: LReportingComponent .head 5 - FunctionalVar: LReportingComponent
And now the issue is clear.
Internally TD interprets the LReportingComponent variable as a FunctionalVar.
It should be a ComProxyVar.
So, when changing this in the text editor from FunctionalVar to ComProxyVar, the code works at runtime.
The Create succeeds and the methods work ok.
Another way to fix it in the IDE itself:
Go to the defined variable, comment it and uncomment it. Then save.
By commenting and uncommenting, TD is forced to re-examine the type of the object.
It sees it as a ComProxy type and sets this internally.
After saving, the variable has the correct internal type and the code works.
Issue with this is that you can not see in the IDE there is a problem. The variable IS of the correct type there.
But you can not see that TD has a wrong internal type. So you will not be tipped on the issue.
Probably you will look into the COM component itself.
Recreating the COM apl does not help, as the instance of the COM Proxy class is incorrect.
The COM proxy class itself is ok and works.
So when having many apl's and huge pile of sourcecode utilizing COM Proxy classes, you will not be sure
if the code will work at runtime just by examining the code using the IDE.
You will have to look in the internal source using a text editor. This could be a real issue, because there
could be hundreds of instances spread over hundreds of functions, class variables,window variables etc etc.
And to find them all, comment them and uncommenting them is a huge effort.
To automate the search for these incorrect variables, I created a CDK tool which checks the source.
Open the main application app/apt and the tool will search all variables defined for ComProxy instances.
Then they are checked to see if the internal type is correct. When not, the tool reports them.
Using this you can quickly check your sources for these issues and hopefully saves a lot of time fixing COM issues which
are caused by this problem.
BEWARE: never use this tool on original sources. Always use a backup.
Though this tool will not write back the sources, it is wise not to risk any damage on the sources what so ever.
Here you can download the tool (incl source):
SAM_ContextMenu on multimonitor setups
Issue encountered on all TD versions (incl TD 6.1)
This is from the documentation on SAM_ContextMenu:
SAM_ContextMenu Message Variables wParam -> X coordinate in screen pixels relative to the upper left corner of the screen. lParam -> Y coordinate in screen pixels relative to the upper left corner of the screen.
When the wParam and/or lParam is checked on multi-monitor setups, in some cases the values do not
correspond to the position of the mouse when performing a right mouse click.
In these cases, the action is performed on a monitor which has negative X and/or Y values.
This is in fact correct. When a monitor is placed at the left side of the main monitor, the positions
for X and/or Y have negative values.
See this article for more info on these setups:
How to (re)position windows on multi-monitor setups
According to the docs on SAM_ContextMenu, the wParam and lParam should have the actual positions.
But in these monitor setups they do not. Negative numbers seem to have a much to large value, larger than the monitor setup could ever have.
The SAM_ContextMenu is a wrapper message for the Windows message WM_CONTEXTMENU (or better is acts to be).
And also on WM_CONTEXTMENU, the original wParam and lParam have these large numbers instead of the negative ones.
But the MSDN docs on WM_CONTEXTMENU is clear:
xPos = GET_X_LPARAM(lParam); yPos = GET_Y_LPARAM(lParam);
This means that the raw values for X and Y are transformed using the GET_X_LPARAM and GET_Y_LPARAM macro's
The actual values are two's complement values, which mean that negative numbers are encoded as an unsigned integer.
So values >32767 are negative numbers. Below are the positive ones.
So, to correct the SAM_ContextMenu, the same macro should be applied to yield the negative numbers:
If wParam > 32767 Set xPos = wParam - 65536 Else Set xPos = wParam If lParam > 32767 Set yPos = lParam - 65536 Else Set yPos = lParam
See screenshot below showing a window placed on a monitor having negative X values.
When right clicking on the listbox, without the conversion the location is incorrect and clicks on the listbox
yield the wrong listbox indexes.
Here you can download the testcase:
Backported sources, hang on compile
Sometimes you could encounter that when you have backported a new TD source file to an older one, compiling it seems to hang/crash TD.
Obviously, new TD features which are introduced in the newer TD version can not be compiled in an older TD version.
But the compiler should never crash or hang when compiling the backported source.
Experience has shown that one of the reasons the compiler does not like the backported code is the build settings.
Those settings are stored in unreadable HEX code format as a separate block in the source.
It seems that when new build options are introduced in newer TD versions, the older TD version can not load the build options from the file correctly.
To remedy this, do the following (complete steps) :
- Backport the sourcefile from the newer TD version to the older one (by changing the version number in the file manually)
- Open the backported file in the older TD version IDE
- Go to menu "project/build settings"
- Clear all options (eg target name etc) and enter the needed options again
- save file and reopen
Hopefully the issue on hanging compile is solved now.
When the issue is not solved by the actions described above, you need to delete the build settings manually:
- Open the file in notepad
- Locate the build settings block. It is near the top of the file.
- Delete the complete block. See screenshot below. All yellow marked lines should be deleted.
- Save file
ActiveX libraries can not be saved in text format
When using the ActiveX wizard to generate libraries, they are saved in normal format by default.
Most developers save their sources in text format due to better support in version systems and makes recovery
of corrupted files possible and also text files can be searched using 3rd party tooling.
So many save the files after generation to text format.
But it seems there is a difference between the generated ActiveX libraries when saved in normal or text format.
When visual ActiveX components (like the Webbrowser component) offer events, they should be visible in the coding assistant.
And also then adding events to the component, they should be able to be compiled.
Unfortunately, when the ActiveX library is in text format, the instances of ActiveX components do not show their events.
So you are unable to add a new event !
See sample image below:
When you save the library back to normal format, this issue is gone. Then all events are listed and can be used again.
This means you will not loose important information about the events in the text format file, they are just not used by TD.
This issue is present in all TD versions and is reported to Gupta.
Gupta has assigned defect # TD-18402 but is not yet being fixed.
CStruct 64k limit
You will have to be aware that the next cstruct functions have a 64K limit:
This means that any buffer larger than 64k will be truncated at the 64k boundary.
Other cstruct functions, like CStructAllocFarMem and CStructPutByte do not have this limitation.
This applies to TD versions up to TD 6.3.
The limitation is lifted if TD 7.0 (x86 and x64)
To copy more than 64k to memory or back, you should use WinApi functions memcpy/RtlMoveMemory.
The next sample will show what happens on such large buffers when using the old cstruct functions.
It also contains two new custom functions to replace CStructCopyToFarMem and CStructCopyFromFarMem:
They have the same parameters compared to the cstruct functions and work on any buffer size.
When you are unsure if your application processes data larger than 64k, replace all calls with these PAL functions.
The sample has both ANSI and UNICODE versions.
Here you can download the sample: