08 December 2009

Why you should use the latest update

Bugs and notes come to me by electronic messages. I check them to see if I can reproduce them and if so I make a note to investigate them. Sometimes, the notes lay around my desk for a long time, because 1) I don't have time, or 2) this is more often the reason, the bug is hard to locate. Because of the complexity, after solving I find it sometimes hard to describe the problem and the resolution. You know: "Doctor, when I push here, it hurts there...".
 
The Vista bug has to do with the memory allocation of the string memory for the Ocx.Name property. When you rename the Ocx (in the Form editor) the memory is released before new (string) memory is allocated to store the new name. GFA bombs! Why? Because GFA mixes memory heaps. The problem is located both in the runtime as in the IDE, but I managed to solve it by a Try/Catch structure in the IDE. For that to happen I had to teach myself code insertion in a binary and writing Try/catch handlers in machine language. Well, its my hobby, so it is no problem, but after so much effort I mostly limit myself to a short note: this bug has been solved. But mostly I give an example in the readme or on my site.
 
The Double bug is bad! When a string (LPCHR) contains the maximum number of decimal fraction digits in a certain sequence the algorithm FO used is simply wrong. Copy and paste this in your editor:
 
Const a =  -1.79769313486232e+308
 
Results of floating-point calculations are often stored in strings (for instance a representation in a control). Than used for a calculation the string is converted back using Val or ValDbl. In certain situation this fails and crashes GB, for the exact same reason. The problem: GFA-BASIC uses a general exported DLL function for these conversions (both at editing, compiling and runtime). How do you know when your conversion is wrong or right?? You cannot. Therefore you MUST use the latest update.

13 November 2009

Is GFABASIC 32 compatible to GFABASIC 16?

Yes it is. As a matter of fact I discovered when disassembling the runtime that GFABASIC 32 is much more compatible to GFABASIC 16 than was claimed. The question is; what does compatibility means? Does it mean that GFA-BASIC 16 programs should run without any change? No. Running in a 32-bits environment requires other prerequisites for data handling. An integer is now 32-bits, memory is flat, DLLs have no shared memory, API calls have become obsolete and many new ones are added. So, in this respect any language updated to 32-bits has evolved.

Is GFA-BASIC 32 compatible to the 'On Menu' event handling of GFA-BASIC 32? And compatible to the window and dialog handling? Yes. This is completely implemented, except for 16-bits HandleMessage (if you like to read more about it I might tell you why). There is no holding back for using GetEvent and using Menu(1) !!! It is perfectly well implemented. So, what else do you need?

29 October 2009

Modify the Windows style

For a project I needed to change many window style bits in one session. For this I developed two procedures, one to change the GWL_STYLE and one to change the GWL_EXSTYLE window styles.
$Export
$Export Proc Modify*

Procedure ModifyStyle(hWnd As Handle, lRemove As Long, lAdd As Long)
Local Long Style = GetWindowLong(hWnd, GWL_STYLE)
Style &= ~lRemove
Style |= lAdd
~SetWindowLong(hWnd, GWL_STYLE, Style)
~SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_DRAWFRAME)
EndProc

Procedure ModifyExStyle(hWnd As Handle, lRemove As Long, lAdd As Long)
Local Long ExStyle = GetWindowLong(hWnd, GWL_EXSTYLE)
ExStyle &= ~lRemove
ExStyle |= lAdd
~SetWindowLong(hWnd, GWL_EXSTYLE, ExStyle)
~SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_DRAWFRAME)
EndProc

As you can see, I collected these in a $Library (.lg32). I'm a big fan of libraries and whenever possible I put general subroutines in a compiled module.

I'm aware of some problems with loading of LG32 files, I had them in the past as well. However, and I don't know why, I don't have them anymore ...

26 October 2009

LabelAddr in a GLL

In two recent posts (here and here) I discussed the problems with subclassing the Gfa_hWnd window in a GLL. In fact, it turned out to be impossible using 'normal' Windows API functions. Another solution was required.
The final solution I developed is based on the MS Detours technique from MS Research Labs. However, not even this highly tricky technique worked for me. The GLL still couldn't be unloaded using the Extension Manager Dialog box. Then, I adapted the Detour technique and configured it in such a way that unloading the GLL isn't a problem anymore. Almost two years ago I first started to study the Detours technique, and finally I came up with a solution to full fill my needs.
The adapted method is based on a GFA-BASIC 32 assembly routine, which is injected into the main window procedure of Gfa_hWnd inside the code of the IDE. To complete my mission I had to figure out the address of a label inside a GFA-BASIC subroutine. The injected code has to jump (jmp) to the label's address. However, the addresses of labels in GLLs (GFA Editor Extensions) are not known in advance.
Both the ProcAddr() and LabelAddr() functions are filled in by the compiler at compile time. In addition, a relocation-table is stored with the compiled program. In contrast with loading an EXE, which is performed by the OS, the addresses in a GLL are relocated by the GFA-BASIC 32 IDE when the GLL is loaded. The IDE is capable of adjusting the ProcAddr addresses inside the GLL, but it doesn't adjust the hardcoded LabelAddr values.
It takes a trick to obtain the relocated address of a label. The GLL is loaded into memory and addresses are calculated using an offset. When we know the offset value the hardcoded label addresses can be calculated. The function Gfa_LabelOffset in the next code, does just this. Since the value is constant for the entire GLL, it is stored in a static variable.
Function Gfa_LabelOffset() As Long
Static LabelOffset% = 0
If LabelOffset% == 0
GetRegs : 1
LabelOffset% = _EIP - LabelAddr(1)
EndIf
Return LabelOffset%
EndFunc


The function can be used to obtain the real location of a label as follows:


Local stubAddr% = LabelAddr(stub) + Gfa_LabelOffset
stub:


The LabelAddr(stub) returns the hardcoded value set by the compiler. The real location is then adjusted by the offset value used to relocate all addresses in the GLL.

20 October 2009

EXE behaves different

"My program runs fine in the IDE, but it freezes when the compiled EXE is started." What is happening?
In the past ten years this message pops-up once and a while. At the same time this message is never repeated. The developer reviews his or her program and recognizes a programming bug. Then after the bug is solved, the program runs without any problem. Until now I never (!) encountered a compiler bug that resulted in an erroneous EXE.
Then, how is it possible that the EXE behaves different than the IDE-program? Some things to consider.
  1. The most logical error is a programming error (90% chance).
    I noticed a problem in user-defined types, for instance a member array isn't properly dimensioned, or a Boolean member is used (see the Help File for notes on using Booleans in a Type). Check your Types, but even better review the initialization code of your program.
  2. In Mysterious Errors I described a theory about errors that cannot be reproduced. But again, the programmer is to blame.
  3. The compiler inserts Trace-code between each code line in the IDE. You can disable this with $StepOff and get the same compiler result as an EXE.
  4. An EXE might behave different because the Compiler setting  Full Branch Optimization for EXE is enabled. This is the only option that produces a different result. (1% chance).
  5. Make sure you are aware of the ByRef Bug for Sub procedures. Insert ByVal and ByRef in the procedure headings. Better: use Sub only for event subs.
All in all, look for the problem in your code, not in the compiler. If an EXE works with one OS, but doesn't with another, than we have a possible bug!

14 October 2009

Difference between _Message and _MessageProc

There are two somewhat strange, certainly badly documented, event subs for forms: the Form_Message and Form_MessageProc event. Although they sound much alike, they are quite different. Both events are invoked from inside the window procedure of the form. However _Message() is called only for a handful of messages, but _MessageProc() is called for all messages, regardless of their origin. These subs are defined as:

Sub frm1_Message(hWnd%, Mess%, wParam%, lParam%)
Sub frm1_MessageProc(hWnd%, Mess%, wParam%, 
  lParam%, retval%, ValidRet?)
The _MessageProc event sub With the _MessageProc Sub you can actually filter or influence the behavior of the GB32 window procedure for the Form window class. The _MessageProc is called before GB32 handles the message itself (more or less, maybe later more on this). The sub obtains six message parameters. The first four are the same as defined for a Windows API window procedure. Every message, whether it is obtained from the message queue (the posted messages) or by a direct call from any other source (for instance through SendMessage), is handled in the window procedure. The hWnd parameter is the window to which the message is sent (we already know the objects name: frm and we could obtain the window handle from the object, that would have lowered the number of parameters by one). The Msg parameter is the message number—which is usually a constant such as WM_ACTIVATEAPP or WM_PAINT. The wParam and lParam parameters differ for each message, as does the return value; you must look up the specific message to see what they mean. Often, wParam or the return value is ignored, but not always. The _MessageProc() event sub has two additional parameters (ByRef) that allow you to return a value. For instance, when you want GB32 not to handle a certain message you can set the ValidRet? Boolean variable to True and provide a return value by setting RetVal%. What value RetVal must have is defined in the Windows API SDK. It often says something like: "If you handle this message return zero (or..)". Now let us look at an example. Suppose you want to store the window coordinates of OpenW #1 in the register so the application can use these values to open at the same place. In GB32 you must then handle the sub events Form_ReSize and Form_Moved to store the coordinates. As an alternative you could use Form_MessageProc and handle the WM_EXITSIZEMOVE message as follows:
Sub Win_1_MessageProc(hWnd%, Mess%, wParam%, _

      lParam%, Retval%, ValidRet?)

 Local Int x, y, w, h

 Switch Mess

 Case WM_EXITSIZEMOVE

   GetWinRect hwnd, x, y, w, h

   SaveSetting "MyComp", "ThisApp", "Position",

        Mkl$(x, y, w, h)

   ValiRet? = True : RetVal = 0

 EndSwitch

EndSub
Note the Form_MessageProc() actually _is_ the subclass window procedure for the GB32 windows (Form, Dialog, OpenW, ChildW, ParentW). Subclassing is a built-in feature of GFA-BASIC 32. As such the the OCX control Form is perfectly suited to write custom controls.
The _Message event sub The Form_Message is different: you cannot filter messages and return values, you can only respond to a handful of messages, to WM_SIZE, or WM_PAINT for instance. Why these? Because these are posted messages, messages that are retrieved from the message queue. Note that most posted messages have a accompanying sub event. For instance, a WM_SIZE message results in calling the Form_ReSize event sub. You can use the _Message sub to handle many messages that are otherwise handled in these event subs. All you need to know is which messages are posted. These are all input messages like key and mouse messages, window management messages like moved, sized and wm_paint. You must then, just as in _MessageProc, create a Switch/Case structure to respond to the message. The main disadvantage is that you must interpret the wParam and lParam parameters yourself... The order in which the sub events are called You can easily test in which order the sub events are called. For posted messages, those that are retrieved from the message queue using Sleep, the _Message() event is called before any other sub. Then the message is 'dispatched' to the window procedure and the _MessageProc is called. And at last, the event sub is invoked. For a WM_SIZE message the sequence is: Win_1_Message() Win_1_MessageProc()
Win_1_ReSize (This article was previously posted on the GFA-BASIC Google Pages. It has been edited to remove errors.)

The Sub-ByRef flaw

A call to a Sub procedure using by reference arguments might not update the correct variable. To understand this behavior be sure to understand the differences between ByVal and ByRef arguments. This is explained in the next tip 'Passing values ByRef or ByVal'. Here you have learned that a Sub by default takes arguments as ByRef, making ByRef optional. Unfortunately this is not always true.

When an argument is passed by reference, the procedure is passed the address of the argument variable. When the argument is a global variable the address of the variable is passed as expected. In the following situation the ByRef clause is omitted and the global variable is updated to 100 correctly.

Global a% = 50
MySub(a%)
Print a%   ' 100
Sub MySub(b%)
  b% = 100
EndSub

When a second Sub is called from within MySub passing b% by reference, b% is  not updated as expected. The variable b% is passed by value, rather than by reference!

Sub MySub(b%)
  b% = 100 : NextSub(b%) : Print b%  // still 100
EndSub
Sub NextSub(c%)
  c% = 200    // unexpected: c% is ByVal argument
EndSub

Why this is happening is unclear, but it is easily repaired by using ByRef explicitly in Sub headings.

Sub NextSub(ByRef c%)

Loading a library: fail or success?

When the $Library directive is parsed (triggered when the line is changed) the specified library is loaded and the exported items are added to the Imports tab in the sidebar. When the file is indeed located and opened a message of success is written to Debug Output Window saying "Loading lg32filename".
Any errors caused by the $Library are then due to a corrupt lg32 file.

The "Load lg32 error" message
Programs that contain references to libraries using the $Library directive may occasionally show a "Load lg32 error: filename.lg32" in the status bar. This message is generated when the specified library can't be located at the specified path or, when a path is omitted, in the current active directory, 'My Documents\lg32', or in directories that are searched using the SearchPath API function.
This message should therefore be called: "Lg32 file not found".

Reload project to reset current directory
When a lg32 can't be found the most obvious reason is an unexpected active directory. Sometimes when working at a project the active directory is changed and the project's directory isn't the current any longer. To check for this, simply reload the project, because this sets the current active directory back to the project's folder.

Set default path for Libraries
An undocumented feature is the possibility to set a default path for libraries in the registry. The registry key HKEY_CURRENT_USER\Software\GFA\Basic must contain the key "lg32Path" specifying the default path for the libraries. The key is not present at default, so you must add the key yourself.

07 October 2009

Hooking to handle Gfa_hWnd messages?

In the Why you cannot subclass Gfa_hWnd I explained why the Gfa_hWnd cannot be subclassed to extend the editor's functionality.

Still, I need to intercept and modify messages for the main IDE window Gfa_hWnd. Some kind of subclassing is required. The other feature Windows offers is the 'hooking', known as Windows Hooks. "Hooking is a sort of subclassing, only it isn't associated with a single window, but with a thread or even the whole system. It's a kind of filter of Windows' messages that allow you to override, or add functionalities when a particular message is received." Sounds promising, doesn't it? 

Hooking Example

In fact, I did create a test program. First, two hooks are installed, the WH_GETMESSAGE and the WH_CALLWNDPROC hooks. There are other hooks, but these seem to be the most logical ones. Just to show how hooking might be done in GFA-BASIC 32, I present some code.
After declaring two global Handle variables, the hooks are initialized as follows:

Global Handle hGetMsgHook, hCallWndHook
' Process or modify all messages (of any type) for the system whenever a
' GetMessage or a PeekMessage function is called (WH_GETMESSAGE).
hGetMsgHook = SetWindowsHookEx(WH_GETMESSAGE , ProcAddr( GetMsgProc), App.hInstance, GetCurrentThreadId())

' Process or modify all messages (of any type) whenever a SendMessage
' function is called (WH_CALLWNDPROC).
hCallWndHook = SetWindowsHookEx(WH_CALLWNDPROC , ProcAddr( CallWndProc), App.hInstance, GetCurrentThreadId())

From this code you can see that both hooks are thread wide, meaning all messages for the thread are passed on to the hook filter functions GetMsgProc() and CallWndProc(). This is one of the reasons I didn't use the hook technique to 'subclass' the Gfa_hWnd window. Later more.
The application defined hook filter functions are defined as:

' WH_GETMESSAGE Hook
Function GetMsgProc(ByVal idHook As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  Dim msg As Pointer MSG
  Pointer(msg) = lParam
  If msg.hwnd == GfahWnd && msg.mess > 0 && msg.mess <> 275
    Trace msg.mess
  EndIf
  Return CallNextHookEx(hGetMsgHook, idHook, wParam, lParam)
End Function
'
' WH_CALLWNDPROC Hook
Function CallWndProc(ByVal idHook As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  Dim msg As Pointer MSG
  Pointer(msg) = lParam
  If msg.hwnd == GfahWnd && msg.mess > 0 && msg.mess <> 275
    Trace msg.mess
  EndIf
  Return CallNextHookEx(hGetMsgHook, idHook, wParam, lParam)
End Function

The GfahWnd variable contains the Gfa_hWnd value and MSG is an API user-defined type to store the message parameters. All well known I presume.

Is hooking a solution?
Does Windows Hooking offer a solution to my problem? The answer is no. Subclassing goes further than hooking. Subclassing functions can return values in response to messages, hooking filter functions cannot. Another issue is the use of thread wide filter functions, that are called for every message that is sent through SendMessage or retrieved with GetMessage. Not only do these hook functions significantly drain on system performance, they might also interfere with the application at hand, that is, the program currently being developed and run in the IDE.

I need another solution.

05 October 2009

Why you cannot subclass Gfa_hWnd

In the course of interpreting the disassembly of both the GfaWin32.exe and the run-time I created quite some editor extension procedures. Most of them are rudimentary and should be developed further, but some of them are very useful (at least to me). I always hoped to put them together in one single GLL file and make that GLL available. However, I never came to do that. I had a problem I didn't understand, and thus didn't know how to solve. After unloading that GLL the IDE crashed.

To add new functionality a Windows developer will most likely start by subclassing the window. In fact, subclassing is the most elementary of all modification techniques. I started by subclassing both IDE windows, the main IDE window Gfa_hWnd and the editor window Gfa_hWndEd. The subclassing was performed in the Gfa_Init() procedure and undone in Gfa_Exit(), which seemed logical at the time. However, as said, this caused a (fatal) problem that at that time I couldn't resolve and I reserved it for a later moment to handle. I was convinced it was something I simply overlooked and at that stage it wasn't really an obstacle. The GLL was automatically loaded when the IDE was started and unloaded when it was closed. I never unloaded the GLL by hand using the Editor Extension Manager dialog box.

Sometimes I was annoyed by the problem and tried to find out the cause of it. It turned out that when the GLL was unloaded in the course of closing the IDE, the un-subclassing was performed after the main window was closed. So, the Gfa_hWnd window didn't exist anymore and re-installing the old window procedure didn't cause any problem. But, when I unloaded the GLL when the IDE was active, using the Extension dialog box, it always crashed the IDE. The undoing of the subclassing of Gfa_hWnd was the problem. In fact, you cannot subclass the Gfa_hWnd in a GLL.

My problem was that I didn't understand exactly what I was doing when I was subclassing a window. Let me illustrate by describing the path a WM_COMMAND (a posted) message follows to where it gets actually handled. Here is what happens when you select the GFA-BASIC 32's Editor Extension Manager dialog box, either from the menu-bar or through a shortcut First the OS puts a WM_COMMAND message in the application queue. The program obtains the message in an endless GetMessage loop and dispatches the message to the window procedure (note: the one I tried to subclass). The window procedure invokes the modal dialog box and a new message loop is started to handle the dialog box. Now, after subclassing, the OS invokes the new window procedure rather than the old one, and requires the new procedure to execute the old window procedure using the CallWindowProc() API. So, the old window procedure, which handled the WM_COMMAND, is called from the new window procedure located in the GLL. In fact, when the dialog box is put on the screen and a modal message loop is started, the program is still executing the new window procedure inside the GLL! After closing the dialog box the program will want to return to the location it was called from, the place where CallWindowProc() API was invoked. You see the problem now?

The old window procedure was invoked from inside the new window procedure (located in the GLL), which was just unloaded using the Editor Extension Manager dialog box. There is no place to return to! Ergo, the most elementary technique, subclassing a window to add new functionality, is not possible for Gfa_hWnd in an editor extension.

09 September 2009

Don't use Mul Command

Sometimes a compiler bug pops up. Here is one: the integer math command Mul int, const is buggy! So don't use it. For instance:

Mul j%, 2

Replace it with a mathematical instruction like:

j% = j% *2

or use the function variant:

j% = Mul(j%,2)

This bug is reported when j% is a ByRef parameter of a subroutine. I verified it and it is a bug indeed. I'm not aware of problems in other situation.

18 August 2009

Obtaining the name of the actual procedure (2)

Does a compiled GFA-BASIC 32 application contain debug information? I got interested and disassembled a compiled (EXE) GFA-BASIC 32 application.

I immediately noted why Avira anti-virus complained about compiled GFA-BASIC 32 programs in the past. The GFA-BASIC 32 EXE application start-up code is quite different from ‘normal’ C/C++, VB, and Pascal applications. In fact, there is no such start-up code! The compiled program immediately calls the exported DLL function ‘GfaWin23_5()’ from the GfaWin23.Ocx runtime. The DLL function calculates the start-address of the main program part and executes it. The entire program is executed from inside the GfaWin23_5() function which contains all start-up and program-exit instructions.

My main concern was ‘how is the stack frame of a compiled procedure initialized?’ More on stack frames see http://gfabasic32.blogspot.com/2009/08/obtaining-name-of-actual-procedure.html.

It turns out that the runtime DLL contains two additional INITPROC() functions; I called them INITPROC_EXE() because the call to INITPROC() in the debug version has been replaced to a call to a EXE specific initialization procedure. It still creates a stack frame, but it is a bit smaller because it lacks debug information. In addition, the EXE doesn’t contain symbol information whatsoever. There is no way an EXE can return information about symbols; procedure and variable names and their locations.

15 August 2009

Obtaining the name of the actual procedure

Obtaining information about a currently executing procedure is only possible when the program is running in the IDE. One of the main differences of the debug-version and the stand-alone version (EXE) is the storage of debug information. Sounds logical, doesn't it?
To get a program compiled, the compiler collects all identifiers (procedure names, global and local variables, labels, etc.). The compiler creates memory locations for the variables and compiles source code to object code (machine code instructions). Each procedure gets its own portion of memory whose starting addresses are stored in a table. After compilation the procedure and function calls are corrected to make sure they call the correct object code addresses. After the compiler finishes the connection between an identifier-name and its location is broken. The call to a subroutine in the source code is replaced by a call to a memory address. A reference to a variable is replaced by a reference to a memory location. The compiler creates machine language instructions and uses hardcoded memory locations. There is no room for the original name of the identifiers, be it subroutine names or variable names.
 
However, when a program is compiled inside the IDE (F5) the compiler inserts debug information. How exactly the compiler handles this process I don't know. I do know however, that each subroutine (non-Naked) calls the INITPROC() library routine inside the GfaWin23.Ocx. This library function creates a stack frame for the subroutine. Each function has a stack frame and most compilers create them the similar. Usually you'll find these instructions to create a stack frame:
 
push ebp
mov ebp, esp
 
The INITPROC() function installs a much larger stack frame. The first 96 bytes are used to store an extended exception record to make sure local variables are cleared properly in case of a problem. In GFA-BASIC 32 the use of structural exception handling (SEH) is similar as in C/C++.  The SEH-technique allows to store more information than C/C++ does. GFA-BASIC 32 cleverly uses this freedom to store additional debug information. One of the members of the stack frame contains a 'pointer' to the procedure information that is stored in a table by the compiler. The compiler doesn't delete this (hash) table after it has finished compiling. The GFA-BASIC 32 debug commands get there information from this stack frame member and essentially they use one function to process this stack frame member: CallTree(). CallTree figures out the stack frame of the current subroutine and it is able to figure out the extended stack frames of subroutines that called the subroutine. (It uses the SEH-list to do this.)
 
The first entry of the string that CallTree returns is the procedure that is currently executing. The name of the actual procedure is obtained by invoking:
 
Print CallTree(1)
 
but it only works in the IDE.

14 August 2009

After a good holiday

I hope you had a good holiday, we had. We rented a house at the border of a fjord in Norway, got ourselves a small boat and went out fishing everyday. We definitely want to get a small “hytte” over there.

During the holidays I got some mail at gfabasic32@gmail.com. Some were personal opinions about GFA-BASIC in general and some about GFA-BASIC 32 specifically. Mostly I reply these messages as soon as possible, but sometimes I save them for further examination. In general everybody gets a reply. If you didn’t got one yet, please repost your message.

A new season, a new start. Hope to post more blog entries this season.

27 June 2009

Mysterious errors

I'm puzzled by a few serious but not reproducible errors. The first one occurred many years ago and had to do with the collection of variables during compiling. Another bug occurred in compiling GLLs where the compiler complained about not being able to open the file to save the GLL. Again, another bug complained not being able to initialize a Hash table in a GLL. However, the bug didn't present itself each time the GLL was started. Then there is the bug where a subroutine call in a 22000 line program wouldn't compile because of a variable collection/initialization error. Why aren't these bugs reported more often? They seem to come up only occasionally. I'm starting to think the problem is related to thread-safety errors. The compiler intensively uses functions from the runtime GfaWin23.Ocx, especially the Hash functions. Everything the compiler collects, names, types, data, etc is stored in Hash tables. The Hash tables are actually pointers to a structure with pointers to allocated memory. There is a pointer to an array of strings containing the hash key name, a pointer to an array of data, an array of indices mapping the key to an index, and some more. To create a Hash table the runtime DLL must support thread safety, because another process/thread can not interfere with the allocation of a Hash table. I am not able to conclude that the Ocx is fully thread-safe in this respect. I have seen a lot of thread-protection functions in the runtime disassembly, but they are mostly string related. The Hash functions on the other hand don't provide a locking mechanism. The documentation (Multithread.pdf) states that GFA-BASIC 32 is not completely "reentrant". However which functions suffer from the lack of reentrancy isn't reported. Since these bugs only occur occasionally I wonder if this has to do with two or more threads executing a runtime function the same time. For instance, I believe the Val() function isn't thread-safe (I'm not sure, because it is hard to tell). But what if two processes or threads were calling it the same time? In the early days of the Microsoft C run-time library, math routines were nonnreentrant aswell, and accordingly did not save and restore the registers used on the 80x87 floating-point coprocessor. Why wouldn't GFA-BASIC 32 suffer the same? It didn't get tested that well. Maybe somebody may recognize these contemplations and may tell us about it.

18 June 2009

Patching the GfaWin23.Ocx DLL

It is not a good idea to patch the GfaWin23.Ocx DLL. For instance, recently someone wanted to use the properties and methods of GFA-BASIC's RichEdit Ocx for the newer RichEdit control version 4.0 from MsftEdit.DLL. To accomplish this task the runtime DLL was patched by replacing some ASCII text using a HEX-file-editor. However the GfaWIn23.Ocx is updated regularly and patching each new update isn't an ideal solution to add new features to the BASIC. This got me thinking about adding new functionality to the runtime. In case of the newer RichEdit control I considered three options.

1 Use the WrapRichEd command

Consider the purpose of the patch. By forcing GFA-BASIC 32 to load a different richedit DLL and changing the class name used to create the RichEdit Ocx control, GFA-BASIC 32 will create the newer control when it invokes the statement Ocx RichEdit. Then, the properties and methods of the RichEdit COM interface can be used to manage the control. (Note most properties and methods are simply wrappers for the SendMessage(hwndEd, EM_xxx, wParam, lParam) function. These wrapper functions use an internal structure with state information GFA-BASIC uses to optimize the performance of the COM functions.)

Ok, back in 1999 the first GFA-BASIC 32 beta didn't contain the Ocx command. To wrap a control up in a COM interface GFA-BASIC 32 support(ed) the WrapCtrlName statements, like WrapRichEd. This command assigns a COM interface to a child control. The child control might have been created using a GFA-BASIC control command, like the general Control creation command, or simply by using an API function like CreateWindowEx(). You can still find examples of the use of the Wrap-commands in the \Samples directory. In general it is used as follows:

Dim rtb1 As RichEdit
RichEditCtrl "", 101, x, y, w, h
WrapRichEd 101, V:rtb1, "rtb1"

This encapsulates a RichEdit control with ID = 101 in an Ocx variable rtb1 and sets it event name to "rtb1".

Back to the issue at hand. The window class name of the newer RichEdit control is "RICHEDIT50W'. The current implementation of the Ocx RichEdit (or RichEditCtrl) statement is to load RichEd32.DLL and to create a control with the classname "RichEdit20A". To get a new control we need to load the MsftEdit.DLL first and then create a control of this class using the general command Control. Like this

Global Handle hMsftEdit = LoadLibrary("msftedit.dll")
Assert hMsftEdit
Global Dim rtb As RichEdit
Control "", 3, "RichEdit50w", WS_BORDER, 100, 70, 100, 284
WrapRichEd 3, V:rtb, "rtbev"

The Ocx is now accessible by its variable name rtb and the event subs have the format Sub rtbev_Event(). Great!? Well, this process continues to work until you invoke a window-style property for the RichEdit Ocx, like rtb.BorderStyle=. In this case the control is destroyed and recreated, a process completely hidden for the developer. When the richedit control is recreated, the 'normal' GFA-BASIC 32 DLL code for the creation of a RichEdit Ocx is invoked, which then creates a "RichEdit20A" class control. Implicitly, the version 4.0 richedit control is destroyed and a richedit control of an older version is created. (The properties that cause a recreation of the RichEdit control are .HideSelection, .MultiLine, .ScrollBars, .BorderStyle, .TabStop ). Unless you give up these properties, this doesn't seem an ideal technique.

2 Poke the DLL (Advanced)

Under conditions this is a valid way to go. Only the loaded DLL is affected. The code is modified at runtime, for instance in the initialization process of your program. Such a modification isn't permanent, once your program has finished, the DLL is unloaded and the next time the original GfaWin23.Ocx is loaded again. When you insist on patching the DLL poking at runtime is definitely worth a shot. The API functions to use are VirtualProtextEx() and WriteProcessMemory(). VirtualProtextEx() is required before poking, because in this particular case the data section – which is read-only - of the DLL has to be patched.

In general you can use the addresses as they are showed in a HEX-file editor and poke those addresses. However, the system doesn't guarantee that a DLL is loaded at the preferred base address. In case multiple DLLs require the same base-address Windows may relocate one of the DLLs giving it a new address in (virtual) memory. You can invoke an additional LoadLibray("GfaWin23.Ocx") or GetModuleHandle() to obtain the base-address, of course you must decrement the DLL count immediately by invoking FreeLibrary(). Maybe I come back on this in some other post.

3 Send messages on your own (Preferred method)

When a GFA-BASIC 32 program requires a new or custom control it should proceed the API way. Point. Load the DLL and create a control using Control or CreateWindowEx(). Then send messages to manage the control and use the parent form's _Message sub event to respond to WM_COMMAND messages. When the custom control sends WM_NOTIFY messages use _MessageProc. More on _Message(Proc) see http://gfabasic32.googlepages.com/faqforms

To utilize GFA-BASIC 32 to the most, you can write wrapper functions and put them in a $Library. Most C/C++ include files for custom controls also present C/C++ macros that invoke the SendMessage() API to manage the custom control. You can easily convert them to Function calls and put them in a library.

25 May 2009

Update: Build 1165

Recently I uploaded a new update of GFA-BASIC 32 to http://GFABASIC32.googlepages.com/. The update includes both the GfaWin32.exe, the IDE, and the runtime GfaWin23.Ocx. Both got build number 1165, which you can check from within the Explorer (right-click), and for the runtime by using DllVersion$. For instance: Trace DllVersion$ ' "2.30 Build 1165" Debugging takes time It has been a while since the last update, but I had to do a lot of disassembling. Well, not exactly the disassembling-process itself because that task is performed by a program, but the interpretation of the disassembly. To be able to understand and interpret a disassembly you need to be able to guess what is going on so that you can recognize patterns. To understand the editor part of the disassembly you need to know how an editor is programmed, to understand a DLL-disassembly you are required to have knowledge of DLL programming, etc. Also, to understand the implementation of the COM controls (OCX), you are required to understand the concept of COM and how to develop OCX controls. So, each time I start interpreting a new part of the disassembly I must study the concepts of that particular issue before I can actually begin. To get acquainted with new information some time may pass.

Urgency due to Val-bug But it is time for an update now. The update contains things I have done in the past year, but it got some urgency due to the Val() bug. This bug was first reported in 2001, but I never got to it.

What is going on? A string having 15 digits and starting with the digits "281479…." was converted to the floating-point value 402…. The position of the decimal point and whether the value is positive or negative isn't important. The function responsible for the conversion isn't only invoked by Val() or ValDbl(), but is heavily used by the IDE (both editor and compiler) as well. I'm pretty sure I located the bug and solved it. I'm also pretty sure the string must fulfill the conditions mentioned to get wrongly converted. However, the chance that the string fulfills the first condition (having 15 digits) is rather big, because the floating-point conversion function Str$() often returns a string with 15 digits when the number of digits in the fractional part is indefinitely. However the number must actually start with the mentioned digits to return a wrong value. Over the years the problems with Val() are reported on a regular basis, so this situation occurs. Reason enough to update.

14 May 2009

Atari ST RIP

It has been a while since my last posting. For one a ST->GFA32 porting project came across which turned out to be not portable after all. It gave me an opportunity to actually use an Atari ST again, put a floppy disk in its built-in disk at the side and listen to those cranky noises when it loads. Wow, I actually thought I missed it, but I didn't. In my mind those Atari ST days have became more romanced than they were. The magic of the Atari ST lies in its innovative OS (GEM), but the innovation was magic because this was never seen before in those days.

The Atari 1040ST still stands next to me and each time I enter my room and I look at it, I don't long for those days anymore. The last years I seriously concerned buying an old Atari ST for the sake of old times. However, now it is here, my memories have vanished and are replaced by those that made me take the step to MS-DOS and Windows. The only thing that remains are the heartbeats I recall having when I first got GFA-BASIC to work and produced my first GEM program. I think these beats were the loudest ever heard as a result of a piece of software I created. That must explain romancing the Atari ST. For me, the most valuable lesson learned is to let the Atari ST rest in peace.

22 April 2009

The Command.Picture property

Years ago I asked a question on the GFA MailingList about the .Picture property of the Command Ocx. At design-time the button displays the bitmaps of an ImageList properly, but when the program was run the pictures were showed with a black background. I forgot about it for years, but recently I created a program with buttons (Command Ocx) with images and the problem reappeared. The image assigned to the button was definitely a masked-bitmap, without the transparent color applied. The difference with all those years back ant the present time, is the amount of documentation and interpretation of the dissassembly of the GfaWin23.Ocx. I immediately started a debugsession to see what happened when a iml.ListImages(idx).Picture is assigned to a Command Ocx. The session turned out surprisingly informative, neither the Command nor the ImageList Ocx contained a bug. I was thinking wrongly, I used the wrong ListImage method, I should have used iml.ListImages(idx).ExtractIcon. To begin with, the ImageList control was assigned a bitmap. However the control stores the single images in two separate bitmaps, a mask bitmap and a masked bitmap (because I had set the ImageList.UseMaskColor property). The background color of the bitmap image was blacked out (which I specified using the ImageList.MaskColor property.) I then invoked the following command to give the button a picture, assuming this would provide the Command Ocx with the original image I put into the ImageList control:
cmd.Picture = ImageListToolbar.ListImages(61).Picture
But I assumed wrongly. The .Picture property of the ImageList returned the handle of the masked bitmap only. So, to give a Command Ocx a transparent image from a ImageList Ocx use the .ExtractIcon method.
cmd.Picture = ImageListToolbar.ListImages(61).ExtractIcon
The Command.Picture = pict pseudo-implementation is (without error and IsNothing checks) as follows: type = pict.get_Type handle = pict.get_Handle SendMessage(Command.hWnd, BM_SETIMAGE, (type=1? IMAGE_BITMAP: IMAGE_ICON), handle) Giving the Command.Picture property a Picture object containing an icon will result in a transparent image in a Button control.

08 April 2009

ANSI API functions and RichEdit

Recently someone patched the GfaWin23.Ocx DLL by replacing the "RichEd20.dll" text entry by "MsftEdit.dll" and "RichEdit20A" by "RICHEDIT50W". The patch isn't very difficult since both text entries are equally sized. The patch was made to obtain the functionallity of the RichEdit Control version 4.0 (which for some reason is called 50) by the GFA-BASIC 32 Ocx interface. By pathing the Ocx file this way, he succeeded in using the "msftEdit.dll. So far so good, but the patch raised a question for me. Why would this control only register a "RICHEDIT50W" class and not a "RICHEDIT50A" ANSI variant? What effect would that have on GFA-BASIC 32 using ANSI functions only?

Previous RichEdit control versions (3.0, 2.0) support two window classes "RichEdit20A" for ANSI systems and "RichEdit20W" for UNICODE systems. When you were compiling a program (in C/C++) for a UNICODE program you would use the "RichEdit20W" class in the CreateWindowExW() API function. GFA-BASIC 32 uses the "RichEdit20A" window class to create a RichEdit Ocx using CreateWindowExA. The properties and methods of the RichEdit Ocx are implemented by sending control messages using SendMessageA().

After patching the rich edit control is created by invoking CreateWindowExA and passing a pointer to an ANSI string containing "RICHEDIT50W". How can that work? The new control only supports wide character coding, how can it accept an ANSI string? I think I found the answer. ANSI API functions are redirected to the wide (UNICODE) variant.

When a program is specifically created as a UNICODE application (which is possible only for NT 4.0 and higher) it uses the UNICODE versions of the system API functions. All API functions have an ANSI and a UNICODE variant with different(!) entry points in the system DLLs. For instance, the SendMessage() API comes in two variants: SendMessageA() and SendMessageW(), two different functions. The xW() system functions expect strings formatted in UNICODE format. On UNICODE Windows systems (thus everything above Windows 95/98/Me) the ANSI versions of the API functions first translate a string parameter to UNICODE and then call the xW() version passing the newly created UNICODE string. This makes ANSI programs quite slow when API functions use strings (upto 3 times, see "Under the Hood 1997" by Matt Pietrek).

GFA-BASIC 32 is an ANSI program and invokes only the xA() versions of the Windows API. Therefor, on Windows NT 4 and above any string passed is converted to UNICODE before handled in the xW() version of the function. (GFA-BASIC 32 is not prepared for pure UNICODE systems, it had to run on Winddows 95 as well.) Back to the question, why does the MsftEdit.Dll accept an ANSI string in CreateWindowExA()?Because in turn the CreateWindowExA() calls CreateWindowExW() on any 'not Win95/98/Me' system passing the classname "RICHEDIT50W" as a UNICODE string. This means, according to my findings that the MsftEdit.dll won't run under Windows 95 when used from the patched GFA-BASIC 32 Ocx-dll. These Windows systems don't redirect to a wide version of the API function.

BTW It might be useful to know how GFA-BASIC loads the appropriate richedit dll. Just before a RichEdit Ocx control is created, GFA-BASIC 32 loads the appropriate library, as follows: If hLibRichEd == 0 hLibRichEd = LoadLibraryA("RichEd20.dll") If hLibRichEd == 0 hLibRichEd = LoadLibraryA("RichEd32.dll") If hLibRichEd == 0 Then RaiseErr "OutOfMemory" Endif Endif Then "RichEdit20A" is used in a CreateWindowExA() API call to create a control window of the this class.

04 April 2009

GetFirstVisible method not implemented

The ListView Ocx method .GetFirstVisible isn't implemented and simply returns Null. It is described as "to return a reference to the first ListItem object visible in the internal area of a ListView control". I think FO simply forgot to implement it properly, because many properties and methods return a reference to a Listitem object and a copy/paste action of the relevant GfaOcx23 source code would have sufficed to make the method work. Pitty. However, by using two (not VB-compatible) ListView methods the problem is easily solved. (Actually, it is one property and one method) ListView.TopIndex ListView.ListItem(index%) The ListView.TopIndex get-property returns the index (long integer) of the first visible item. It doesn't return a reference to a ListItem, but returns a long starting with 0. The ListItem(index%) returns a reference to a ListItem object from an index starting with 1. Yes, that is COM combined with Windows API. Anyway to replace the .GetFirstVisible method you should use:
Local ListItem li
// Set li = ListView.GetFirstVisible replacement:
Set li = ListView.ListItem(ListView.TopIndex + 1)

03 April 2009

Pointer and Gfa_Var object

I wasn't finished discussing the Pointer [To] data type. Maybe I should summarize the things I figured out until now:
  • GFA-BASIC 32 is capable of generating two types of code to access data; directly and indirectly using C-like pointer code.
  • A Pointer [To] type variable is 32-bits variable without a VarPtr address. The data memory address is set using Pointer=. Other than this, GFA-BASIC 32 treats the pointer as a normal data type.
  • All ByRef subroutine arguments are Pointer To variables, whose VarPtr-address is set by the caller (instruction that executes the subroutine).

Because of the duality, GFA-BASIC 32 needs to handle a Pointer To variable differently from normal variables. A normal variable has a name and memory location, in fact the variable-name is an alias for a data location. As such a variable name is not known after compiling, all references to the variable name are removed and replaced by assembler instruction theat memory loaction. Therefor a normal variable has only one 'address', either returned by VarPtr (V:) or ArrPtr. A Pointer (32-bits wide) on the other hand is split in two separate units. The address the pointer is stored and the VarPtr address it is pointing to. A Pointer variable has two addresses. This is refelected in the Gfa_Var object. A Gfa_Var object is an item of Gfa_Vars collection, a collection of variables of a certain subroutine. The Gfa_Var has two properties that illustrate this concept:

Gfa_Var.VarPtr Gfa_Var.Addr

In case of a normal variable both properties return the VarPtr address, In case of a pointer the .Addr property returns the address of the Pointer variable and the .VarPtr property the address set using Pointer()=. To help investigate I wrote a small procedure to show the Gfa_Var properties in the Debug Output window. A call to ShowVar is done by including a copy of a Gfa_Vars collection item. In case of the example below, I inspected a global user-defined-type declared as Foo. To obtain a collection of global variables you either use Gfa_Globals or Gfa_Vars(""). To inspect a local variable, execute ShowVar from inside a procedure and use Gfa_Vars0!varname.

ShowVar Gfa_Vars("")!Foo, V:foo, ArrPtr(foo), _
 "- Global Foo As Tfoo:"

Proc ShowVar(vGfaVar As Gfa_Var, vp%, ap%, comment$)
  Debug comment$

  Debug "Variable: "#39 & vGfaVar.Name & #39 & _
    ", TypeName: "#39 & vGfaVar.TypeName & #39 & _
    ", Sub: "#39 & vGfaVar.PName & #39
  Trace Hex(vGfaVar.Type)
  Trace vGfaVar.Addr
  Debug "ArrPtr(" & vGfaVar.Name & ") = " ap
  Debug "VarPtr(" & vGfaVar.Name & ") = " vp
  Trace vGfaVar.VarPtr
  Trace vGfaVar.Size
  Trace vGfaVar.Len
  Trace vGfaVar.IsTyped
  Debug
EndProc

31 March 2009

ByRef parameters are Pointers

Yes, that is right. A ByRef parameter is effectively a Pointer [To]. Let's see what this means. A pointer variable of some data type behaves exactly as a variable instance of that type. A variable pdbl declared As Pointer To Double behaves exactly as a Double. Not only is it used in the same way as a normal instance of a Double, but anything GFA-BASIC 32 allows to be done with a Double data type is allowed with pdbl (a pointer to double). Once a pointer has been initialized (given a memory address) the compiler interpretates the pdbl pointer variable as a variable of type Double. For the programmer the pdbl is the same as a normal Double variable. The compiler on the other hand accepts pdbl as a Double on each occasion it processes it, but it generates different code to perform operations on pdbl. The problem is that the compiler isn't aware of the exact location of pdbl's data location. Variables that are instantiated using Global, Local, Static, and of course Dim, are included in the program (exe). They have a reserved portion of memory that the compiler know about. All code generated by the compiler can operate on this memory location directly. The assembler code generated for accessing 'normal' variables is therefore quite different than assembler code generated for pointers. For pointers GFA-BASIC 32 generates C-like pointer code; it stores an address (data location) in a register and uses this value to indirectly access the data location. When the GFA-BASIC 32 compiler parses the code, it marks all un-addressed variables before generating code and when it comes to create assembler instructions it generates pointer code, assuming the actual address will be known at runtime. There are only two type of variables the memory address isn't known from at compile time: Pointer To and ByRef. Investigation showed that both types are marked the same way when they are encountered during compiling. A ByRef procedure argument is in essence a Pointer To variable. Initializing a pointer The pointer pdbl can be initialized at runtime only. The pointer pdbl initially points to address 0 (null). To be used practically, the pointer variable must be assigned a memory address. The compiler uses this memory address to operate on. Normally, the memory address of GFA-BASIC 32 variables is 'handled' through the VarPtr function (or its shortcut V:). Essentially, a pointer lacks a 'VarPtr' address. (It could have been an idea when GFA-BASIC supported a 'VarPtr(var)=addr' command to set the memory address. However, in case of variables that use a descriptor (String, arrays) there would also have to be an 'ArrPtr()= addr' to set the memory address for such a pointer.) To initialise a pointer a new keyword was introduced: Pointer(pvar)=. (Note - This still requires the programmer to be aware what memory to set with Pointer(). A Pointer To String will require a pointer to the descriptor of another string!) I discussed this command multiple times and won't go into that here. The question is how is the apllicable on ByRef arguments? A ByRef variable is a Pointer To variable and there is only one way to set the VarPtr address of a variable: the Pointer()= command. This command is implicitly invoked when a variable is passed to a procedure taking a ByRef argument. To get access to the passed argument the compiler generates code apropriate for the data type, but the memory address of the actual data isn't known at compile time. The ByRef variable is a local variable on the stack without a VarPtr address. The compiler than generates pointer-operation-code to process this ByRef variable, exactly the same code as generated for a Pointer To variable. This is in contrast with a ByVal variable. Here the compiler generates code to operate on the variable's memory directly, because its memory address is known in advance. (A local variable is located relative to the stack entry point (esp) of a procedure. The stack pointer is copied to ebx which is used by the compiler to locate the local variables. A local variable is recognizable in assembler instructions like mov eax, 112[ebx]. ). So, for the compiler the ByVal and ByRef keywords have two different meanings. It tells the compiler how to pass the argument to the subroutine and determines the type of code to generate. This is VERY important to realize when you are dealing with pointers in general. In case of low-level programming you must realize what exactly you are receiving in your subroutine. You need to ask yourself whether you need pointer code or normal code to be generated for that variable. Remember the ListView custom sort soutine I presented earlier? Windows passes the lParam member of the LV_ITEM structure to the compare function, which holds a pointer to a ListItem COM object. Do you remember to function's prototype? Here its is.
Function CompareDates(ByVal lngParam1 As ListItem,
  ByVal lngParam2 As ListItem, ByVal iCol As Long) As Long
Why does it need to be declared as ByVal, rather than as ByRef? Because it isn't all that simple (understatement). Some data types force GFA-BASIC 32 to generate pointer code by default, these include user-defined-types (Type) and Ocx/COM objects. GFA-BASIC 32 generates pointer-to code for the ListItem COM object by default. When the parameter would be declared ByRef, the value passed by Windows would force GFA-BASIC to generate code that uses lngParam as a pointer to a Listitem pointer. Hence Excpetion Errors! Ok enough for now, but its not end!

Pointers are pointers indeed!

I discussed the Pointer [To] data type in an article published at the GFA=BASIC 32 site: http://gfabasic32.googlepages.com/thepointertodatatype. It is actually quite accurate ;-). However, I needed to re-investigate the Pointer data type, because I got some unexpected 'Unexpected Exceptions'. I had to extend the investigations by studying disassemblies and the Gfa_Var object. I also had to reset my knowledge entirely and start from scratch all over again. In the article I published I focussed on comparing a Pointer To to a normal data type. I tried to proof that a Pointer data type isn't so different from a normal variable. Although, I am correct in this article I missed an important aspect of pointers. I simply didn't realize that GFA-BASIC 32 handles a Pointer data type differently, and I didn't realize it because I didn't inspect the resulting code generated by the compiler. Actually, the first lines of the first article signal the problem: "Pointer is a data type to declare variables as pointers.", and then the syntax is given as: Dim p As [Register] Pointer [To] type p: pointer variable type: any data type (Int, String, Double, user-defined-type) This declaration is complete but not accurate enough, because a pointer to an Ocx object is allowed too. In fact, you may declare a pointer to anything that GFA-BASIC 32 considers a data type. And this might proof to be very important, because GFA-BASIC 32 considers something to be a data type when it is an element of the internal TypeInfo hash table containing data types. How these data types are added to this hash table, GFA doesn't care! For instance, when you load a $Library, the data types from the lg32 are appended to this hash table, and the same is true when GFA-BASIC 32 starts and initializes all primary data types (Int, Bool, String, Hash, Variant, etc, etc.), they are simply added to the hash table. (Since I'm trying to implement the Class data type, this information is essential. GFA-BASIC doesn't care about a type as long as it is in the 'TypeInfo' hash table. We'll see where this will go.) Ok, back to the problem. In the declaration it is explicitly stated that a pointer can be located in a register, see the optional Register keyword. This actually indicates a different treatment of a pointer variable! A variable of type Double (8-bytes) cannot be located in a register, because a register is only 32-bits (4-bytes) wide. It is beyond this post how GFA stores (local) variables relative to the ebx register and reserves edi and esi for Register variables. Maybe in a later post; it isn't relevant to the topic at hand. What is important, is that GFA indeed handles a pointer type different, it handles a Pointer variable indeed as 32-bits pointer, otherwise you couldn't store a pointer (to any type) in a 32-bits register, would you? Wow. How did I miss this? Well, I'm only human too, you know. All I did was investigate the information GFA-BASIC 32 returned from a (pointer) variable using GFA functions like TypeName, VarPtr, and ArrPtr. I only wanted to know how the returned information differed form a normal variable compared to a pointer variable. As I pointed out in the article, the only difference seems to be the lack of a memory location for the data for a variable. Of course, this is true, but GFA-BASIC also generates different code to access the data of a pointer variable. Since I didn't inspect the disassembly (DisAsm Ocx object) I didn't see it. As it turned out, GFA-BASIC uses the C pointer-style to access a memory location through a pointer; the GFA-BASIC pointer type is compatible with the C-pointer. Since I will try to keep this post not too technical, I will limit the assembly code a minimum. Important to relaize is that a pointer can be kept in a 32-bit register, which doesn't apply for variables wider than 32-bits. Unfortunately, the compiler won't accept the statement:
Local p1 As Register Pointer To Double      ' double *p1;
The syntax control accepts it, but the compiler doesn't put p1 in a register. Schade (unfortunately). On the other hand the speed increase would be minimal, it is the difference of using a register directly: mov dpt [esi], value ; set first long pointed to in esi and of first copying the pointer to eax from the its (stack) position: mov eax, dpt 116[ebx] ; move pointer content mov dpt [eax], value ; set first long to value GFA also optimizes te code by keeping the pointer in eax when the pointer is accessed multiple times in a row (see for yourself). Now we are where I want it to be. The compiler generates assembler code to access the data of a variable declared with Pointer [To] through a pointer, like C. For instance the second long eax points to is accessed using mov dpt 4[eax], value ; set second long And this is completely different from the code used to access a non-pointer variable. As a conclusion I will summarize how to treat a pointer in GFA compared to C:
' Declare and initialize a double
Dim dbl As Double = 3.1         ' double dbl = 3.1;

' Declare an unitialized pointer to double
Dim p As Pointer To Double      ' double *p;

' Initialize the pointer
Pointer(p) = V:dbl                ' p = &dbl;

' Assign a value to dbl through p:
p = 7.2                           ' *p = 7.2
In the next post I discuss the ByRef and Pointer commands.

30 March 2009

Sort a ListView Ocx

To set the scene you might want to look at the knowledge base about sorting a ListView control in (Visual) BASIC http://support.microsoft.com/kb/170884. GFA-BASIC 32 supports only one method to sort a column, where VB uses three (!) properties to get a ListView control sorted. The .Sort method is defined as: ListView.Sort column%, compare% The .Sort method of the control only sorts the items alphabetically, either ascending or descending. The column% argument specifies the column to sort, but in contrast with the ColumnHeaders collection it starts counting at 0, rather than at 1. I have no idea why, but the column% parameter is passed to the LVM_SORT message directly. Ok, well so be it. The compare% argument is a bit more complex, because it is used as a bit flag. When the lowest bit of the high order word is set ($10000), the column is sorted descending (Z-A), otherwise ascending (A-Z). The low-word of the compare% argument specifies the compare mode GFA-BASIC 32 will use when comparing one item to another. The values are the same as for Mode Compare. For example, to sort the second column in a descending way using uppercase comparison (Mode Compare = -2), you would use: ListView.Sort 1, $10000 Or (-2) A bit complicated. Maybe the Sort method should have used the Mode Compare setting rather than letting it be specified in an argument. Anyway, a column may be sorted comparing using lowercase or using uppercase separately from the global setting. Custom Sort A column doesn't always consist of text string entries that have to sort alphabetically. A column may consist of dates or numbers (integers or floats). The .Sort method isn't prepared for sorting anything different than text. The link to the knowledge base opens an article that discusses how to create a custom sort for dates for a VB ListView control. Although, GFA-BASIC 32 tries to be VB compatible, the ListView Ocx control differs in many aspects. (The previous post discusses how the ListItems collection differs from VB.) GFA-BASIC 32 stores a pointer to the ListItem object in the lParam member of the LV_ITEM structure when it adds an item to the ListView Ocx. VB stores the ListView's item index. This difference is important because of the custom compare function to write for the custom sort. To initiate a custom sort you must send the LVM_SORT message to the ListView. Most often you will do this after a click in the column header. In GFA-BASIC 32 you might see the following code, ported from the code presented in the MS knowledge base article:
' GFA32 argument ByRef, not by value!
Sub ListView1_ColumnClick(ColumnHeader As ColumnHeader)
  Dim lngItem As Long
  ' Note:
  ' ColumnHeaders collection is 1-based
  ' ListItem.SubItems(iCol) is 0-based
  ' ListView.Sort iCol is 0-based

  Dim iSubItem As Long = ColumnHeader.Index - 1 ' 1-based

  'Handle User click on column header
  If ColumnHeader.Text = "Name" Then  'User clicked on Name header
    'ListView1.Sorted = True        'Use default sorting to sort the
    'ListView1.SortKey = 0          'items in the list
    ListView1.Sort iSubItem, 0          ' 0-based
  Else
    'ListView1.Sorted = False       'User clicked on the Date header
    'Use our sort routine to sort by date
    SendMessage ListView1.hWnd, LVM_SORTITEMS, iSubItem, ProcAddr(CompareDates)
  End If

  'Refresh the ListView before writing the data
  ListView1.Refresh

  ' MS/VB
  'Loop through the items in the List to print them out in sorted order.
  'NOTE: You are looping through the ListView control because when
  'sorting by date the ListItems collection won't be sorted.

  For lngItem = 1 To ListView1.ListItems.Count
    'ListView_GetListItem lngItem, ListView1.hWnd, strName, dDate
    'Print ListView1.ListItems(lngItem).AllText
  Next

  ' GFA32 - The ListItems collection is sorted as well.
  Dim li As ListItem
  For Each li In ListView1.ListItems
    Print li.AllText
  Next

End Sub
To show the differences with VB the code is heavily commented. The clue is located in the next code line:
SendMessage ListView1.hWnd, LVM_SORTITEMS, iSubItem, ProcAddr(CompareDates)
The .hWnd property returns the window handle of the ListView Ocx. The wParam argument specifies the corrected column number and the lParam argument holds the pointer to the function to compare two ListView items. The CompareDates function is declared as:
Function CompareDates(ByVal lngParam1 As ListItem, _
  ByVal lngParam2 As ListItem, ByVal iCol As Long) As Long
The first two long integer arguments receive the lParam member of the LV_ITEM structure, which is in GFA-BASIC 32 a pointer to a ListItem object. The compare function is a callback function. It is called from inside Windows and never from a GFA-BASIC 32 statement. GFA-BASIC 32 cannot check the function parameters against the data types passed when called. When the program is executing the lParam members are simply copied to the first arguments of the compare function. Because we know the value points to a ListItem object, we cast the 32-bits value to a Listitem. The GFA-BASIC 32 compare function is much simpler, convert the text of the ListItems to apropriate data type and compare:
Function CompareDates(ByVal lngParam1 As ListItem, _
  ByVal lngParam2 As ListItem, ByVal iCol As Long) As Long

  Dim dDate1 As Date, dDate2 As Date

  ' MS/VB way:
  'Obtain the item names and dates corresponding to the
  'input parameters
  °ListView_GetItemData lngParam1, hWnd, strName1, dDate1
  °ListView_GetItemData lngParam2, hWnd, strName2, dDate2

  ' GFA32 way. The LV_ITEM.lParam is passed to the compare
  ' function. The lParam contains the address of the ListItem
  ' object, which we intelligently casted to a ListItem object!
  dDate1 = ValDate(lngParam1.SubItems(iCol))
  dDate2 = ValDate(lngParam2.SubItems(iCol))

  'Compare the dates
  'Return 0 ==> Less Than
  '       1 ==> Equal
  '       2 ==> Greater Than

  If dDate1 < dDate2 Then
    CompareDates = 0
  ElseIf dDate1 = dDate2 Then
    CompareDates = 1
  Else
    CompareDates = 2
  End If

End Function