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.