Visual Objects 2.7A - What’s New


IDE and Repository Fixes

General IDE –

The Atom table size has been increased from 16Mb to 64Mb. This is now the minimum size and can be increased by making an entry into the Cavo27.Cfg file.

[Adam Options]


The above entry would increase the maximum size to 128Mb.

When the atom table is full an error message is now displayed.


Exception errors have been found and resolved. The ones below were the main problems but could sometimes lead to others who’s addresses are not listed.

The error causing this message has been resolved.

Version  : CA-Visual Objects 2.7 build 2716


Error    : An unhandled exception (0xC0000005) occurred inside module:

: C:\CAVO27\Bin\Cavoadam.dll at 0x10201148


The error causing this message has been resolved.

Version  : CA-Visual Objects 2.7 build 2716


Error    : An unhandled exception (0xC0000005) occurred inside module:

: C:\WINNT\system32\ntdll.dll at 0x77FCC455

The error causing this message has been resolved.

Version  : CA-Visual Objects 2.7 build 2716


Error    : An unhandled exception (0xC0000005) occurred inside module:

: C:\WINNT\system32\ntdll.dll at 0x77FCC641

The error causing this message has been resolved.

Version : CA-Visual Objects 2.7 build 2716

Error : An unhandled exception (0xC0000005) occurred inside module:
: C:\CAVO27\Bin\vo27gui.dll at 0x044F28A2

The error causing this message when closing VO has been resolved.

Version : CA-Visual Objects 2.7 build 2716

Error : An unhandled exception (0xC0000005) occurred inside module:
: C:\CAVO27\Bin\vo27gui.dll at 0x048128A2

The error causing this message when importing into the IDE has been resolved.

Version  : CA-Visual Objects 2.7 build 2716


Error    : An unhandled exception (0xC0000005) occurred inside module:

: C:\CAVO27\Bin\CAVOCOMP.dll at 0x109505FA


Located a memory corruption that could cause the repository to corrupt.


The problems that are associated with the “No Exported Method” have been addressed.


When selecting a project the Repository Explorer sometimes opened twice.


If Save Desktop was activated while a Source Code Editor was open, the next time the project was opened it was replaced by a second Repository Explorer.


Both %prgdir% and %mefdir% were resolving to %CavoBinDir% when they should have been independent.


The %projectdir% macro did include the trailing backslash where the other macros did Not.


Double-Clicking in the ListView while in “report mode” now works on the whole width of the listview and not just the text area of the first column.


There was a problem extracting external files during an import if the original location was on a non-existent drive.


There was a problem that external resource files could be deleted during import.


When Importing an application with external resources, the “Keep All” option would behave as though it was just keeping the current file instead of all files.


Unneeded refreshes of the Repository Explorer during the import of multiple Aef files has been suppressed.


The association of modules with prg files can now handle much larger numbers at the same time and the unneeded refreshes during this process have been suppressed.


The IDE Tree View was not refreshing when modules were added by Drag-And-Drop.


There was a problem when using Drag-And-Drop for several entities.


The system beep after compiling and linking has been restored.

This can be disabled by adding Silence=1 to the environment options.


Changing the size of the Icon in the explorer was not remembered, this has been addressed.


A problem when the Catalogue Directory was made ReadOnly has been addressed.


Opening a project from the desktop did not work as expected.


There was a refresh problem that affected the Menu Editor & several other entity operations.


Having more than one IDE open could cause one of them to crash.


When opening a VOPRJ file with the same project name as an existing project in another folder, VO will now rename the VOPRJ file and the project. It will add a numeric suffix. For example, adding a project "Ado" when a project "Ado" already exists will result in a rename to "Ado2"


The IDE Error tune can now be disabled in the Adam section of Cavo27.cfg





Compiler –

Resolved a memory leak with the VTable structures.


There was a problem with initializers for static local arrays.


When the compiler needs “temporary variables” it creates a stack entry for each of them. These stack entries were not being cleared. The compiler will now clear the reference to these variables. This will allow the garbage collector to remove the object when all other references are gone.


The numeric type for accessing an array and a DIM array were different. This has been addressed.


The compiler now enforces the strong typing of methods and functions. NIL is no longer an accepted value and passing NIL will result in a compiler error similar to this – “converting NIL <-> LONGINT :51423”

Passing a NIL to a method or function that is expecting a Usual is still permitted.


The compiler would sometimes give an “automatic conversion” warning even though the strong typed Method/Access/Assign was returning the correct type.


Typed methods returning a PSZ could generate a String/Psz conversion warning because a default return value of the incorrect type was generated.


The _VoDllMain( ) function no longer generates ProcName( ) information, regardless of the compiler settings.


When a typed method does not end with a return value the compiler automatically generates a RETURN SELF. This was a problem with typed methods that return a structure so it now generates a RETURN NULL_PTR for these methods.


There was a problem with incrementing typed pointers and Type inference.


There was a problem when more than one IDE was open. The Compiler Errors from one IDE could be displayed in the other.



Linker –

Exception errors have been found and resolved. The ones below were the main problems but could sometimes lead to others who’s addresses are not listed.

The error causing this message has been resolved.

Version  : CA-Visual Objects 2.7 build 2716


Error    : An unhandled exception (0xC0000005) occurred inside module:

         : C:\CAVO27\Bin\CAVOLINK.DLL at 0x10581749


It was possible for the linker to keep a 0 byte file open if linking failed. This has been addressed.


The linker had a 64Mb maximum to the size of file it could create. This has been increased to 256Mb. It is also possible to limit the size by putting an entry into the CAVO27.Cfg file.

For example –



This would bring it back to 64Mb.



This would set the maximum file size to 128Mb.


The Linker adds an Atom table for the generated EXE/DLL. This table by default has a maximum size of 0x1000000 (16Mb)

For apps that generated lots of symbols you can set the size in the Cavo27.Cfg or .VoPrj file:






Debugger –

When trying to set a break point in the debugger it sometimes tried to put the break on a different line.


A problem with the “Settings/Clear All” option in the debugger has been addressed.


The debugger sometimes became confused and did not process line by line. This was caused by code like this –

IF <expression>

// Nocode


  <do something>


This has now been resolved.


Fixed a GPF that could occur when displaying DIM-ed arrays in the View Locals window.




Working With External Files -

When re-importing an existing application with external modules, the “Replace All Modules” option would remove the entities from the modules, but not replace them with the current entities in the prg file. This has been fixed.


Changes to external files were not recognised when pressing Shift+F8 to build the application. This has been addressed.


Code stored in external files could sometimes disappear from the IDE even though it was still in the file.

When changing a module linked to an external prg the repository did not refresh
itself. You had to manually "touch" the module for it to recognize the change.




Source Code Editor –

Exception errors have been found and resolved. The ones below were the main problems but could sometimes lead to others who’s addresses are not listed.

The error causing this message has been resolved.

Version : CA-Visual Objects 2.7 build 2716

Error : An unhandled exception (0xC0000005) occurred inside module:
: C:\CAVO27\Bin\Cavoedit.dll at 0x10D0E298

There was a large resource leak in the Source Code Editor which caused instability in the memory and screen corruption.


It was possible to get a binary entity being edited in the Source Code Editor. This has now been blocked.


When highlighting code in the Source Code Editor using the mouse and starting at the bottom. Moving up beyond the visible area did not work properly.


If the Method declaration line was broken over several lines, typing SELF: would not display the list of available variables and methods for that class. This list was also not displayed if one of the entries contained the text “class”.


When using “Find and Replace”, the text being found was not always highlighted.


The red Auto Complete box was not clearing properly from the screen when you continued to type.


The context menu did not always show the correct contents and would jump to unrelated places in the code.




Window Editor -

The maximum size of strings in the window editor has been increased to 256.




Menu Editor -

The maximum size of strings in the menu editor has been increased to 256.


The Editor now remembers the size and position of the properties window.


The code generated for the ToolBar:ButtonSize has been changed.




Server Editor -

The maximum size of strings in the server editors has been increased to 256.


The DBServer editor sometimes claimed that certain index files were corrupt and would not recognise the index expression. This was caused by the use of runtime functions like Deleted( ) in the expression. The most common functions have now been linked in to address this issue.


The Editor now remembers the size and position of the properties window.


The DBServer could cause a GPF if it was saving something created in an older version of VO.




Error Browser -

The Error Browser could crash the IDE if the Print Icon was pressed.


Sometimes modules were listed twice in the Error browser.



IDE Additions

Added some new compiler options:

Null Var Check - Enables/Disables checks for NULL_OBJECT and NULL_PTR when directly accessing Exported IVars or Structure Members.

ProcName & ProcLine - You can now set ProcName & ProcLine seperately. ProcLine requires Procname.



The build number can now be displayed at the root of the IDE tree view by placing an entry in the Cavo27.Cfg file.





We have done our best to avoid problems with compatibility with AEFS. You should have no problem reading older AEFs. The compiler options will probably be switched off when you read old AEFs and must be switched on manually.

You should also be able to read 2.7a AEFs in 2.6 but please check your compiler options and pay particular attention to the Procname/Procline flags!



Working With External Files -

Added the ability to cut the links between Modules and external files when multiple modules are selected.




Runtime Fixes

All Nation.Dll files have been checked for the correct collation sequence.


Several issues within the macro compiler have been addressed and the trace messages have been removed.


If a macro called Round() with a negative second parameter it would generate a runtime error.


The Symbol Table had a maximum size of 64Mb and could suffer from overflow.

This is now configurable. The size of the symbol table can be set in the linker section of the CAVO27.CFG file, and defaults to 0x1000000 (16Mb)


ExeAtomTabSize= 0x1000000

You can also set the Stacksize of your VO app in this file:



This size defaults to 0x100000, and can be increased when needed. If you have an application that uses a heavily linked class structure you may experience stack errors in the GC. Incrementing this size will help prevent problems


Using SetMaxDynSize( ) with large numbers caused dynamic memory errors and under certain situations had no effect at all on the amount of dynamic memory available.


If DynLock( ) is active SetMaxDynSize( ) will fail with a trappable error.


The return values of DiskSpace( ) and DiskFree( ) were incorrect in certain situations.


SetCollation( ) was returning #WINDOWS even when it had been set to #CLIPPER.


DynSize( ) now checks that the size passed to it will not exceed the maximum amount of available memory.


The Evaluate( ) and &( ) functions could cause Dynamic Memory errors.


The use of String2Psz( ) could sometimes leave a hidden local in memory.


The Str(), Str3() and _Str3() functions now return a string of all asterisks when the Decimals parameter is > 0 and the Decimals parameter is  > Length-2.

Also a string of all asterisks is returned when the number does NOT fit into the allocated space.


      ? Str(9,6,6)      => "******"

      ? Str(9,6,5)      => "******"

      ? Str(9,6,4)      => "9.0000"

      ? Str(9,6,3)      => " 9.000"

      ? Str(10,6,6)      => "******"

      ? Str(10,6,5)      => "******"

      ? Str(10,6,4)      => "******"

      ? Str(10,6,3)      => "10.000"


The error message “Dynamic memory Low” was displayed using the ‘Internal Error’ routine. When an app was running without a ‘User Interface’ (for example as a COM or DCOM app) this would cause it to die silently.

This message has now been changed to a regular error message so that it can be trapped in your code or by replacing the error handler.

The default implementation is that the runtime will call the error handler to display and log the message before terminating the application.

In this situation, because the dynamic memory is low, the runtime will transparently map dynamic memory allocations done from within the error handler to static memory allocations.

Be careful not to push the dynamic memory to the limit in your error handler because static memory may also be limited under these conditions.


If the AFill() "nStart" parameter was larger then the array length the LAST array element would  be replaced with the "uValue" parameter instead of throwing an error. It now gives a bound error as normal.


Both StretchBitmap( ) and ShowBitmap( ) functions would fail if the file was ReadOnly.


Both FOpen() and FCreate() would crash if they were called with an empty filename parameter.




Runtime Additions

The Runtime now has two new Functions that allow you to override the Locale ID used by the application.

The Locale controls the algorithms used for string comparison when running with SetCollation(#Windows), and also for functions such as Upper(), Lower(), IsUpper() etc.

In general, you should not try to compare binary information stored in strings. For example with the German Locale the following strings would be seen (and sorted) as equal: ‘Jaeger’ and ‘Jäger’! Further information on this is in the Programmers Notes section at the end of this document.

Having the possibility to control the locale helps prevent index corruption, that could occur in environments where users are accessing DBF files running different locales. The default behaviour of the Runtime has NOT been changed: it reads the Current Users locale ID using the GetUserDefaultLCID() function.


The new functions are:


FUNCTION SetAppLocaleID(DWORD uiNewLocale) as DWORD



This function sets the locale that the runtime uses for comparing strings when running in Windows collation mode (SetCollation(#Windows)), which is the default mode for Visual Objects. The string comparison is responsible for the sorting of DBF files, for comparing strings (including Asorting arrays of strings) and for the sort order within indexes. The default behaviour of the runtime is to read the locale id from the current user by calling the GetUserDefaultLCID() function. To avoid problem when different users using the same app have different Locales selected on their machines you can now control the Locale used by your app from within the code



uiNewLocale     must be a valid LocaleId and can be constructed using the MAKELCID() and MAKELANGID() functions



The previously installed Locale



// To use the standard German Language in Phone Book sorting mode:




// To use the Swiss German Language in Default sorting mode




// To use the Norwegian Bokmal language, default sorting mode




// To use language independent sorting





This function retrieves the current locale used by the runtime. This may be the default locale (GetUserDefaultLCID() ) or the locale previously set with the GetAppLocaleID() function.



The current installed App Locale



A new runtime function has been added for object handling.

FUNCTION FreeStaticObject( oObject )



The FreeStaticObject( ) function should be used to free objects that have been created using the CreateInstanceStatic( ) function.


Previously you would have had code like this –

o := CreateInstanceStatic(#MyClass)


MemFree(PTR(_CAST, o))


However, this code did not release the memory.


The code that you should be using is this –

o := CreateInstanceStatic(#MyClass)




A new runtime function has been added for loading DLLs that have been created with Visual Objects.


FUNCTION _VOLoadLibrary( )



To safely use a .Dll that was created in Visual Objects, it should be loaded using _VOLoadLibrary( ). This function will check to see that the old runtime (CavoRt20.Dll) is not being brought into memory and will generate an error if it is.

The runtime will first call the error handler and then terminate the application because having two runtimes in memory would cause all sorts of problems.




System Class Fixes

There was a problem with missing string table entries.


There was a problem in FieldSpec:PerformValidations() when the ADSATD driver was being used with long strings and a Field Type "M" because it only recognised the 9 characters.



System Library Fixes

The size of the static buffer that gets allocated in VO_SprintF has been increased to avoid memory corruption.


VO version defines have been added to be used by VO System DLLs




GUI Fixes

Additional Strong Typing has been implemented.


The TopAppWindow:Resize( ) method was not working as expected.


In previous versions, the DataBrowser was forced to use the same context menu as the DataWindow. This was sometimes inappropriate and has therefore been changed.

The default behaviour of both sharing the same context menu is retained so –

<oDataWindow>:ContextMenu := MyContextMenu{}

will still work in the normal way and both Form and Browse view will see the same context menu.

If you want the context menus to be different you can now use code like this –

<oDataWindow>:[ContextMenu,#FormView] := MyContextMenu{}

to just set the FormView context menu, and this –

<oDataWindow>:[ContextMenu,#BrowseView] := MyOtherContextMenu{}

to set the BrowseView context menu.


DataWindow:Show( ) has been changed so that focus is not pushed to the first edit field on the window. This allows the programmer to use SetFocus( ) in the PostInit( ) method.


DataBrowser:__BeginEditField( ) has been changed to match the behaviour of SingleLineEdit:FocusChange()


If Control:OwnerAlignment had not been assigned and
Window:SetAlignStartSize() was called, the wrong size would be used (that of
the window instead of the passed size). This has been fixed.


Owner alignment improvement for SubDataWindows and TabControls

Please see the end of this document for a complete list of constants and a discussion of the Owner Alignment topic.


A problem with Button control styles was identified and resolved.


Changed the TabControl:__FocusPage() method to resolve a tab key order problem.


Tab Orders were not being respected when a TabControl was being used.


Controls on the front TabPage were not being resized when the TabControl was resized until the tab was redisplayed/repainted.


A problem with FixedText controls and Win XP themes was identified and resolved.


The Disable() method of a FixedText showed no difference on the window even though the editor indicated that it should.


The Caption of a FixedText control used to expand a tab ( Chr(9) ) but in 2.7 this changed to displaying “|”. The style can be set using the –

FixedText:lUseDrawText := FALSE


FixedText:SetDrawStyle( DT_EXPANDTABS )

In 2.7a the default style of a FixedText has been changed to include DT_EXPANDTABS


Selection and typing in an SLE could cause the first character typed to be removed and the text would start with the second character typed.


The <oEdit>:SelectedText Access had a problem that could affect the SingleLineEdit and MultiLineEdit classes.


In the Window class, the PaintBackground() method has been addressed to resolve a problem of misalignment in tab pages.


A Memory leak in the Menu:Destroy() method has been located and addressed.


A problem with ImageLists in the ListBox and ComboBox classes has been addressed.


The ComboBox:__ControlTextValue Access has been removed and the functionality moved to an updated __GetText()


There was a problem in the ComboBox:__InitTextMetrics() which has been addressed.


The FixedText:Dispatch() method has been changed.


The Brush:__SetBrushOrg() method has been changed.


The PrintingDevice was registering an Axit in the Init() method but it was not un-registered in the Destroy().


The Print() method of the RichEdit control could put the application into an endless loop.


Corrected a flaw in the calculation of the RichEdit font point size.


The RichEdit:SelectedText Access had a memory handling problem.


To resolve some problems and also introduce some new features, the RichEdit class now uses the RichEdit20.Dll

See the Programmers Notes section at the end of this document for a list of versions and Operating Systems.


The Selection class and assignment to a control were not working properly unless there was a pause between the control gaining focus and the selection being applied. Code like this –


self:odcSLE1:Selection := Selection{ 1,2 }

would still result in the full text being highlighted. This has been resolved.


DataColumns were not being destroyed in the DataBrowser when they were manually created. They are now destroyed from inside of the DataBrowser:Destroy() method.


A problem with ListBox resizing was identified and resolved.


The ListBox:Clear() method has been changed so that, if the control has a FieldSpec attached, the blank item is of the correct data type.


The StandardFolderDialog had a memory problem when the Garbage Collector activated.


Dragging a ListView item worked as expected until the control or shift key was pressed at which point the movement was not shown on the screen.


The Size Access in the Icon class had a memory leak.


The ToolBar has been revised to support imagelists but compatibility with the old ToolBar class has been maintained. With the help of imagelists you can now implement all of the modern toolbar styles and you can build toolbars with 256 colors or even true colors. These additions will also remove the problems experienced with transparency of the toolbar buttons.


1.) The ToolBar:Create( ) method has additional functionality. If the ImageCount is zero when Toolbar:Create() is called (by assigning to window) only a Reabar Control is created. This is very useful if you want to use a rebar for bands that only have controls and not with the usual Toolbar buttons.

2.) Every subtoolbar now becomes registered with __WCRegisterControl()

3.) Now that all toolbars are registered with __WCRegisterControl() they are also unregistered in the Toolbar:Destroy() method.

4.) A new method has been added - SetImageList( ) See GUI Additions below.

5.) A new method has been added - GetImageList( ) See GUI Additions below.

6.) If you assign a bitmap it is automatically converted to a compatible imagelist.

In this situation you should not use SetImageList() (See TB_SETIMAGELIST in the Microsoft SDK documentation).

7.) The default background color for the toolbar bitmaps is Color{192,192,192}.

For your own Imagelist you can choose any color for the background. For example, a very popular choice is magenta Color{255,0,255}.


By supporting a Rebar with Toolbars it is possible to have Toolbars with different ButtonSizes or different ButtonStyles.
In the previous Toolbar implementation you could define only one ButtonSize and ButtonStyle for all of the Toolbars, because after the ToolBar was created you could not change ButtonSize or ButtonStyle and before the ToolBar was created only the  last assign to ButtonSize or ButtonStyle was valid.


In VO2.7 and 2.7 a toolbar which is not part of a Rebar has a divider.

In VO2.7a we can switch the divider On/Off with the EXPORT variable Divider.

The initialisation of this variable depends on the value of the EnableBands property.


The calculation of the ToolBar height has been changed to take into account any controls (SLE/ComboBox/Etc) that may be placed on the Toolbar.


There is a new sample in the Samples\Toolbar directory.


GUI Addition

You can now write a Window:DispatchUnknown( oEvent ) to handle messages that are not processed by the window. For Example –

METHOD DispatchUnknown(oEvent) CLASS Window

//Your code

//If you need the default window

//      procedure call SELF:Default(oEvent)

//Assign the event return value to SELF:EventReturnValue,

//      the default value is 0l.

     SELF:EventReturnValue := 1l


A new method can be written at the Window level to process menu commands. The window:PreMenuCommand( ) method will be called if it exists to process menu events before the normal MenuCommand( ) methods are called.

The method must return a logic –

TRUE – If you have processed the MenuCommand.

FALSE – If you want the normal MenuCommand to run as well.


A new Access/Assign has been added to the Window class to aid with Owner Alignment. The window:MinSize is provided to set the minimum size for a window.

Also added are a new callback method – MinMaxInfo() and the MinMaxInfoEvent class (documented below).


Window:MinMaxInfo() Method


Provide a method that is invoked when the size or position of a window is about to change (cf WM_GETMINMAXINFO in Win API). Receives a MinMaxInfoEvent.



oMinMaxInfoEvent   - The MinMaxInfoEvent object that describes the maximised width, height and position of the maximised window in addition to the minimum and maximum height and width of the window.


MinMaxInfoEvent Class


Provide information about a MinMaxInfoEvent, generated whenever the size or position of a window is about to change. The MinMaxInfoEvent object describes the maximised width, height and position of the maximised window in addition to the minimum and maximum height and width of the window.



CLASS MinMaxInfoEvent INHERIT Event


Important!  Visual Objects instantiates events.



MaxPosition Access/Assign

MaxSize Access/Assign

MaxTrackSize Access/Assign

MinTrackSize Access/Assign


Inherits From

Vobject, Event


Inherited By

(No descendants)



GUI Classes



The MinMaxInfoEvent event contains information about the size and placement of a window. It also allows these default values to be overridden by assigning new values.



MinMaxInfoEvent:MaxPosition Access/Assign


A point object. Specifies, in window coordinates, the position of the left side of the maximised window and the position of the top of the maximised window.



MinMaxInfoEvent:MaxSize Access/Assign


A dimension object. Specifies, in window coordinates, the maximised width and height of the window.



MinMaxInfoEvent:MaxTrackSize Access/Assign


A dimension object. Specifies, in window coordinates, the maximum width and height of the window.



MinMaxInfoEvent:MinTrackSize Access/Assign


A dimension object. Specifies, in window coordinates, the minimum width and height of the window.





The ImageList:Init method now has a fifth parameter, nGrow. This is the number of images by which the image list can grow when the system needs to make room for new images.


Method DialogWindow:ControlFocusChange()


If DialogWindow:ControlFocusChange() is used to validate a control (and also set the focus to another control), Control:SetFocus() should not be called until another control has received the focus.


In complex dialog windows that contain many edit controls, it makes sense to grab the edit control's text when the focus is changing so that other controls can be updated with it if necessary.


See the ButtonClick() method for an example of similar syntax to be used in this method.  Note that all controls are passed through this method, not only SingleLineEdit and MultiLineEdit controls.  If looking to control Combobox selections, then the ListBoxSelect() callback method should be reviewed.



oControlFocusChangeEvent            - The ControlFocusChangeEvent object that identifies which control generated the ControlFocusChangeEvent object and whether it has just gained or lost the keyboard focus.



Method DataWindow:ControlFocusChange()


If DataWindow:ControlFocusChange() is used to validate a control (and also set the focus to another control), Control:SetFocus() should not be called until another control has received the focus.


In complex dialog windows that contain many edit controls, it makes sense to grab the edit control's text when the focus is changing so that other controls can be updated with it if necessary.


See the ButtonClick() method for an example of similar syntax to be used in this method.  Note that all controls are passed through this method, not only SingleLineEdit and MultiLineEdit controls.  If looking to control Combobox selections, then the ListBoxSelect() callback method should be reviewed.



oControlFocusChangeEvent             - The ControlFocusChangeEvent object that identifies which control generated the ControlFocusChangeEvent object and whether it has just gained or lost the keyboard focus.


METHOD SetImageList(uImageList, symType, symTB) CLASS ToolBar


You can assign your own imagelist for every subtoolbar.

Additionally you could assign a separate HotImagelist and a DisabledImagelist for every subtoolbar.

If you assign a Bitmap instead, it is automatically converted into a compatible Imagelist. Bitmaps for a toolbar imagelist must be loaded with the parameter LR_CREATEDIBSECTION and not with the BMP_3DTRANSPARENT which is needed for Ribbons.

The Bitmap must have the default VO background color for Toolbar ribbons Color{192, 192, 192}.



uImageList - can be an Imagelist or a bitmap loaded with LR_CREATEDIBSECTION and the background Color{192, 192, 192}.

symType    - can be #IMAGELIST, #HOTIMAGELIST or #DISABLEDIMAGELIST - default value is #IMAGELIST

symTB       - is the name of the toolbar (subtoolbar) - default is #Maintoolbar



METHOD GetImageList(symType, symTB) CLASS ToolBar


This method is used to get the ImageList that is specified by the parameters passed.



symType    - can be #IMAGELIST, #HOTIMAGELIST or #DISABLEDIMAGELIST - default value is #IMAGELIST

symTB       - is the name of the toolbar (subtoolbar) - default is #Maintoolbar




METHOD AddSubToolBarBand(symToolBar, iPos, iMinWidth, lFlat_dwStyle) CLASS ToolBar

The parameter lFlat has been extended and is now named lFlat_dwStyle.

You are now able to pass a DWORD value to this parameter which allows you to create ToolBars with different styles inside a ReBar control. You can use any of these defines for this –

TBSTYLE_TOOLTIPS                    := 0x0100

TBSTYLE_WRAPABLE                    := 0x0200

TBSTYLE_ALTDRAG                     := 0x0400

TBSTYLE_FLAT                        := 0x0800

TBSTYLE_LIST                        := 0x1000

TBSTYLE_CUSTOMERASE                 := 0x2000

TBSTYLE_REGISTERDROP                := 0x4000

TBSTYLE_TRANSPARENT                 := 0x8000

The lFlat_dwStyle parameter still retains the acceptance of a logical value or NIL for backward compatibility.



For every control which sends WM_NOTIFY messages to its parent window, you can now implement your own notify handler in the control class.

The Owner window sends the message back to the control, if the window has no own notify handler for this message and if the control has a method named ParentNotify().


METHOD ParentNotify(nNotifyCode, lParam) CLASS ListView


nNotifyCode is the notify message

lParam   -     is the lParam value of the original WM_NOTIFY message. Generally it includes the address of a _winNMHDR structure or one of its control dependent sub structures.


The method must return a LONG and a value of 0l forces the call of the owner window Default() method.



A new method has been added to the Control class.


This method calls the default window procedure of the control and sets the EventReturnValue


A new method has been added to the Control class.


This is the same as Window:Repaint() but for controls.


Each control can now have its own PaintBackground method.

METHOD PaintBackground(hDC) CLASS MyControl


       hDC is the devicecontext which you can use for painting.


      Return TRUE, if you have painted the background.

      Return FALSE, if the default window procedure should paint the background.




A ToolBar can now have context menu assigned to it.

In the Menu:ShowAsPopUp() Method, the second parameter expects a Point{} object. If this is constructed as Point{-1,-1} the method has been changed so that it calculates a control dependent position for the context menu. This can be useful if you want to trigger the context menu from your code.


A ListBox:MultiSelection Access has been added so that you can see if it supports multiple selections.


The DataListView class now has an Owner Access to make it consistent with the ListView class.


The StatusBar class has been addressed to support Icons, ToolTips and Owner Draw.



DBServer Fixes

Total(), Average(), Count(), Sum(), DeleteAll() and RecallAll() methods fixed.


CopyStructure() method could fail if the names were not in the correct case.


The method Rlock() has been fixed to release all locks when a record number is not passed as documented it the help file.


When no records match the filter in the SetSelectiveRelation() method of 2.6, both BOF and EOF returned TRUE. This was different to 2.5 and in 2.7 it has been made to return the 2.5 values. This means that when no records match the filter BOF will return FALSE and EOF will return TRUE. This also matches the results of using the DBxxx functions.


Using servers from Timer methods or COM objects could cause the application to lock.


The :OrderBottomScope( ) and :OrderTopScope( ) were passing the wrong variable datatype in their call to the VODBOrderInfo( ) function.




SQL Class Fixes

Removed an unneeded call to Default() that was causing a runtime error from SQLSelect:__GetUpdateVal()


A problem with automatically converting dates to timestamps has been resolved.




Internet Classes

All of the Internet classes and the E-Mail sample have been revised.




OLE and OCX Fixes

A window that uses the ReportPro OCX can only be opened once. Attempting to open it a second time caused the application to crash.


Controls like the DHTMLEdit control could not be used because all keyboard input went to this control instead of the other SLE or MLE controls that were on the same window.


OLEAutoObject class method __InvokeMethod() did not handle the INVOKE_PROPERTYPUTREF type properly.


Passing parameters by reference has been addressed.


Further problems with the MapPoint control have been resolved.


Problems with events and the Flipper CAD Control have been addressed.



OLE and OCX Set-Up Changes

Two new fields have been added to both the OLE Control and Automation Server set-up dialogs. The “Remove Underscores” and “Prefix” fields are provided so as to allow you to remove possible name conflicts when generating included classes.

For example, if you were generating the wrapper classes for the Word automation server and you told it to include containing classes, VO would try to create classes like Font and Error. This would be a problem because these classes already exist in VO and the generation would fail.

By entering, for example, “Word” in the prefix field, all classes would have this prefix so the classes would be “WordFont” and “WordError” thus removing the conflict and allowing the OLE generation to complete properly.


The Enum values are now written to a module with the name

<Main Object> - Defines

This allows you to group multiple servers/controls in one library and still have their defines in separate modules.



Win32 API Fixes

In the structure _winNCCALCSIZE_PARAMS the member –


Should have been -


This has now been changed.


The SetAbortProc prototype was pointing to " gdi32" (note the leading space) which has now been removed.


The function GetDlgItemText( ) was defined “AS WORD PASCAL” this has been changed to “AS DWORD PASCAL”.




Visual Objects and Visual Source Safe

There is now a new CheckBox on both the Project Properties and the New Project dialogs which allows the developer to enable/disable source code control at the project level.


Source Code Control can be totally disabled in the Cavo27.Cfg file.




A new option has been added to disconnect a module or application from source code control. This can be used, for example, when you want to work off-site. Using this will cause VO to stop checking the source code control properties and make the modules Read/Write, regardless of their state in the source code control.

When you reconnect to the source code control the following will happen:

-         Modules that were Checked Out will remain unchanged.

-         Changes to modules that were NOT Checked Out will be discarded.


The source code control Icon meanings have changed:
  - No Icon: Not under source code control
  - Blue Closed Lock: Not checked out and can be checked out
  - Red Closed Lock: Not checked out and can NOT be checked out because it is in use by another user.
  - Green Open Lock: Checked out in Current Project
  - Gray Lock: Disconnected


All modules are now inserted into source code control as both a Prg and as an Mef. When you choose the Compare option in the menu, it is the Prg that is used.


It is now possible to Check In/Out multiple files in one go.


You can now Check In/Out with comments or you can use the Check In/Out Now which does not have comments.


VO now has a smarter Check In/Out and only replaces modules that have actually changed. This should make working in large projects easier.


An issue with modules being removed from VSS has been addressed.


It was possible for the “Lock Icons” to stop being displayed in the IDE. This has been addressed.


An issue with re-indexing the repository and source code control was identified and resolved.


The menu option, “Get Latest Version” was not working and has been addressed


There was an error when logging on to VSS if the userid and/or pathname variables were long.


When synchronizing modules in the Repository with modules in VSS, new modules in VSS were not imported in the Repository.


Moved VSS menus onto the right mouse menu.


Added two options to the VSS menus: Disconnect & Connect. These will allow you to work with an app when the VSS database is not available


The menu option Refresh was not working properly.


There was a problem checking in an application that was already checked in or checking out an application that was already checked out.


There was a problem if the local folder could not be found.


Removed 'Synchronize Modules' and 'Import Modules'. These two were not working properly.


The ListView does NOT show the grey Lock icons anymore for entries that are not under VSS. This icon will be used for entries that are under VSS control but are disconnect.


Added a “Refresh Icons” option to the context menu.


Programmer Notes

This section is given to things that have been reported which are not considered to be bugs but could do with an explanation.


Data Type Conversions

Should the compiler give an error?

Int:=( int * Dword) the compiler returns Dword!

Int:=( Dword* int) the compiler returns an int.


MemSet(ptr, 0, wCount )

Where  wCount is set as "2L", or, INT(_cast, dwVar)


By default the compiler does NOT warn about this, but adds overflow checking code to the generated output (unless you switch off overflow checking)

If you want warnings for these, you need to enable the numeric warnings, by changing the entry W51422=0 in the [Compiler] section of your Cavo27.cfg (or your VOPRJ file) to W51422=1.


This will tell the compiler to give a warning for this kind of 'silent numeric conversions'.



Strong Typing

Init( ) methods must not be strong typed and can not use default values.

Code like this -




METHOD Init(symName AS SYMBOL, cCaption := "" AS STRING) AS Foo PASCAL CLASS Foo


Will not work and in a future version it will give a compiler error.



GroupBox and Owner Alignment

The problem is, that a groupbox is a great button which is lying over your controls and the background and the transparent style effects only to the caption of the groupbox control.


In practice you have to experiment with the following:


1.) The control style WS_CLIPSIBLINGS - Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of a child window, to draw within the client area of a neighbouring child window.


2.) The control order of the groupbox control


3.) The position of control with has the WS_GROUP style, if needed.



In most cases the following rules work.


1.) If you have a Groupbox with Transparent = false.

Groupbox should be the first control in the zorder before the first control placed on the groupbox. The Clipsiblings style must be false for the groupbox and for all controls placed on the groupbox.


2.) You have a Groupbox with Transparent = true.

Groupbox should be the last control in the zorder after the last control placed on the groupbox. The Clipsiblings style must be true for the groupbox and for the controls placed on the groupbox it can be true too, but this is not a must.

If the WS_GROUP style is important for you, set WS_GROUP of the groupbox to false and set WS_GROUP of the first control inside the groupbox to true.



Now you may ask, why earlier versions of VO had no problems with this?

The reason is, that VO 2.7 has changed the autorefresh class styles of all window classes to avoid annoying flicker of VO apps during resizing or moving windows.


As a result of this you have to deal with some window styles like WS_CLIPSIBLING, WS_CLIPCHILDREN or with the z-Order in some cases.

But it is normal Windows GUI developing using these styles.


If you don't know how to change the z-order (control order) in your program use the following simple function.


FUNCTION SetZOrder(oControl AS Control, oControlInsertAfter AS Control) AS VOID PASCAL

 SetWindowPos(oControl:handle(), oControlInsertAfter:handle(), 0, 0, 0, 0, SWP_NOMOVE + SWP_NOSIZE)



But may be, flicker is no problem for you or others.

In this case you could simply add the following method to your window


METHOD Resize(oResizeEvent) CLASS YourWindow


 //Put your changes here






Using a manifest on Win XP causes the application to crash!

A situation has been seen where an application runs as expected on Win XP without the manifest included but crashes if it is included. The problem was traced to an old version of the SHLWAPI.DLL in the Windows\System32 directory. The current version is 6.0.2800.1400 and this is known to be working. The correct version can be obtained by making sure that all service packs for Internet Explorer have been applied.



Strong Typed Methods and Functions

Strong typed methods and functions are expected to return a value.

If the return value is missed from a function you will see an error –

“strong typed function does not return explicit value :51351”

If the return value is missed from a method you will not see an error because VO will automatically return the correct data type with its default value.



Default Settings and Project Settings

The default settings are those that will be acquired by a new project when it is set-up.

The projects settings are specific to that project and can be changed without upsetting any other project. Once a project is set-up, amending the default settings will have no affect on the project. The developer will need to change the properties in the project settings if an alteration is needed.  This gives the developer the flexibility required when working for multiple clients who each have their own standards for their set-up.


CheckBox Styles

It should be remembered that the CheckBox has three states, “Checked”, “Not Checked” and “Un-Set”. A DBF has only two states TRUE and FALSE which are represented by “Checked” and “Not Checked”. The “Un-Set” state is required for SQL databases where the field may not have had a value put into it and this state is represented by the control turning grey. This is the meaning of the Style “3 State”.


Tab Controls, Painting and control order
There is a problem in that the z-order of controls influences two things, painting and key tab order.

If you set the z-order for correct key tab order handling, the tabcontrol must be positioned above the page-window and as a result of this painting will not work.

If you set the z-order for the correct painting, the key tab order is not as most users would expect.

What's the result of this?

1.) The correct painting must have higher priority than the expected key tab order. Therefore the z-order of the tab page window has to be higher than the z-order of the tabcontrol.

2.) A good compromise for the tab key order was the solution in VO 2.6, but with this implementation it was impossible to get the optimal tab key order, however most VO developers could live with this.

How can we get the optimal tab key order?

We need to satisfy both conditions:

a) z-order of the tab page window has to be higher than the z-order of the tabcontrol for correct painting.

b) The z-order of the tab page window must be the next one after the z-order of the tabcontrol.

Previously there was only one way that both conditions could be satisfied, if the tab page window is the first window in the z-order and the tabcontrol is the last window in the z-order.

Because in this case the tab page window is always the first one in the z-order the first focused control is the next control in z-order. Therefore you must implement your own focus handling if the dialog gets the focus.

This method works perfectly, but it is a little bit tricky because you have to deal with an unnatural control order (z-order) and your own focus management.


Now VO 2.7a tests to see if the tabcontrol is last in the control order. In all other cases VO 2.7a is compatible with the VO 2.6 behaviour.



Early-Bound, Late-Bound and the ONLYEARLY pragma

In VO there are two ways to call methods for an object (Methods include Access & Assign methods in this case):
 - Late-Bound (the default)
 - Early-Bound

Late-bound calls are used for all methods that are NOT strongly typed (and not declared). For each late-bound method the VO compiler generates code that gets executed at startup of your app and that builds a class description in memory at runtime. It uses the (undocumented) DeclareMethod() function to declare the method.

Late-bound methods are always called using the Clipper calling convention, they can have a variable number of parameters and always return a USUAL. This allows you to subclass a method and to add extra parameters or change the meaning of the parameters. Inside a method you can use PCount() to retrieve the actual number of parameters.

Late-bound calls always go through the Send(), IVarget() & IVarPut() functions in the VO Runtime. These functions do a lookup in the MethodTable for the objects to find the proper method. The MethodTable is build by the runtime based on the information from the DeclareMethod() function.

Early-bound calls are used for methods that are strongly typed and declared. They use the VTable, which is a table of function pointers.

Every object in VO has a reference to the VTable of its class. An early-bound method call uses the method address that it finds in the VTable. Early-bound calls are always of type Strict or Pascal, never of type Clipper. With the Pascal calling convention the number of parameters is fixed. Strict methods may have a variable number of parameters, but only when they use the special syntax using the "..." (ellipses) as the last parameter

The confusing part in VO is that you can also do late-bound calls into typed methods. To enable this, VO also generates the DeclareMethod() code and generates an EXTRA (So-called Stub) method. For late-bound calls the VO Runtime will lookup the method name, using the MethodTable build by the DeclareMethod() function, and will find the address of the Stub. This stub method will then call the actual code through the VTable.

An example -

CLASS Robert
PROTECT cName := "MrData" as String

ACCESS Name as String PASCAL ClASS Robert
    RETURN cName

 LOCAL oPerson as Robert
 LOCAL oPerson2 as OBJECT
 oPerson := Robert{}
 oPerson2 := oPerson
 ? oPerson:Name               // This is an early bound call
 ? oPerson2:Name              // This is a late bound call

With oPerson:Name the compiler can figure out that it needs to call the first method in the VTable of the class.
With oPerson2:Name the compiler has no idea what to call. So it will generate an IVarGet() for the object with a #Name argument. The runtime will then try to find the Name Access (or an exported Name Ivar).

The former developers were asked for an option to remove the extra stub method.

The ~"ONLYEARLY" pragma does that, when used in a class declaration: it suppresses the generation of the DeclareMethod and suppresses the generation of the Stub methods.

The ~"ONLYEARLY" can also be used in the body of a function/method. Within
that context it makes sure you are not accidentally calling methods late bound.

So in the above example -

CLASS Robert
 PROTECT cName := "MrData" as String

This will suppress the generation of the DeclareMethod for the Name access and suppress the stub method. This will cause the oPerson2:Name to fail because Name can't be called late-bound any more

 LOCAL oPerson as Robert
 LOCAL oPerson2 as OBJECT
 oPerson := Robert{}
 oPerson2 := oPerson
 ? oPerson:Name               // This is an early bound call
 ? oPerson2:Name              // This is a late bound call

This will generate a compiler error, telling you that the call to oPerson2:Name is not early bound.


Owner Alignment

There are two assigns that aid owner alignment –

Control:OwnerAlignment  for controls
Window:OwnerAlignment   for windows


Whenever one of these assigns is called, the current size and position of the control or window is saved to an internal array. The assign can be called as often as is required without any difficulty and it will simply overright the old values.


Window:SetAlignStartSize( oSize) – Sets the start size of the form window. In general, this size is set with the first assign to OwnerAlignment but it can be useful when trying to control the sizes for yourself.


In 2.7A the values of the Owner Alignment constants follow logical rules.

  1. They all start with OA_
  2. X or Y means the alignment of the X position or the Y position.
  3. WIDTH or HEIGHT refers to the alignment of the width or height.
  4. P is the prefix to show that the alignment is proportional to its own size and the size of the owner window. Without the P prefix it becomes linear aligned to the size of the window.


There are eight different commands:

OA_X        The x-positions follows linear
OA_PX       The x-positions follows proportional
OA_Y        The y-positions follows linear
OA_PY       The y-positions follows proportional
OA_WIDTH      The width follows linear
OA_PWIDTH      The width follows proportional
OA_HEIGHT      The height follows linear
OA_PHEIGHT      The height follows proportional

However, any number of these can be combined using the _Or() function.

For example - Control:OwnerAlignment := _Or(OA_X, OA_Y)

But it should be remembered that -

Combining OA_X with OA_PX is equal to OA_PX
Combining OA_Y with OA_PY is equal to OA_PY
Combining OA_WIDTH with OA_PWIDTH is equal to OA_PWIDTH
Combining OA_HEIGHT with OA_PHEIGHT is equal to OA_PHEIGHT


Because you can only put one constant into the Window Editor, combination constants have been defined for this purpose.


The naming convention follows this convention –

OA_ + _X or _PX + _Y or _PY + _WIDTH or _PWIDTH + _HEIGHT or _PHEIGHT

So for example –



Here is a full list of Owner Alignment defines:

DEFINE OA_BOTTOM                     := 4


DEFINE OA_CENTER                     := 9

DEFINE OA_FULL_SIZE                  := 10

DEFINE OA_HEIGHT                     := 0b0000000110000000

DEFINE OA_LEFT                       := 1

DEFINE OA_LEFT_AUTOSIZE              := 5

DEFINE OA_NO                        := 0

DEFINE OA_PHEIGHT                    := 0b0000001110000000

DEFINE OA_PWIDTH                     := 0b0000110010000000

DEFINE OA_PWIDTH_HEIGHT              := 0b0000110110000000

DEFINE OA_PWIDTH_PHEIGHT             := 0b0000111110000000

DEFINE OA_PX                         := 0b1100000010000000

DEFINE OA_PX_HEIGHT                  := 0b1100000110000000

DEFINE OA_PX_PHEIGHT                 := 0b1100001110000000

DEFINE OA_PX_PWIDTH                  := 0b1100110010000000

DEFINE OA_PX_PWIDTH_HEIGHT           := 0b1100110110000000

DEFINE OA_PX_PWIDTH_PHEIGHT          := 0b1100111110000000

DEFINE OA_PX_PY_PHEIGHT              := 0b1111001110000000

DEFINE OA_PX_PY_PWIDTH_PHEIGHT       := 0b1111111110000000

DEFINE OA_PX_Y                       := 0b1101000010000000

DEFINE OA_PX_Y_PWIDTH                := 0b1101110010000000

DEFINE OA_PY                         := 0b0011000010000000

DEFINE OA_PY_PHEIGHT                 := 0b0011001110000000

DEFINE OA_PY_PWIDTH_PYHEIGHT         := 0b0011111110000000

DEFINE OA_PY_WIDTH_PHEIGHT           := 0b0011011110000000

DEFINE OA_RIGHT                      := 3


DEFINE OA_TOP                        := 2

DEFINE OA_TOP_AUTOSIZE               := 6

DEFINE OA_WIDTH                      := 0b0000010010000000

DEFINE OA_WIDTH_HEIGHT               := 0b0000010110000000

DEFINE OA_WIDTH_PHEIGHT              := 0b0000011110000000

DEFINE OA_X                          := 0b0100000010000000

DEFINE OA_X_HEIGHT                   := 0b0100000110000000

DEFINE OA_X_PHEIGHT                  := 0b0100001110000000

DEFINE OA_X_PY_PHEIGHT               := 0b0111001110000000

DEFINE OA_X_Y                        := 0b0101000010000000

DEFINE OA_Y                          := 0b0001000010000000

DEFINE OA_Y_PWIDTH                   := 0b0001110010000000

DEFINE OA_Y_WIDTH                    := 0b0001010010000000



RichEdit Versions

To resolve some issues and to introduce some new functionality, the RichEdit class is now based on the RichEdit20.Dll


There are four revisions of the RichEdit standard and these are their Dll names.

1.0 - Riched32.dll

2.0 - Riched20.dll

3.0 - Riched20.dll

4.1 - Msftedit.dll


The following list describes which versions of Rich Edit are included in which releases of Microsoft Windows®.


Windows XP SP1 - Includes Rich Edit 4.1, Rich Edit 3.0, and a Rich Edit 1.0 emulator.

Windows XP - Includes Rich Edit 3.0 with a Rich Edit 1.0 emulator.

Windows Me - Includes Rich Edit 1.0 and 3.0.

Windows 2000 - Includes Rich Edit 3.0 with a Rich Edit 1.0 emulator.

Windows NT 4.0 - Includes Rich Edit 1.0 and 2.0.

Windows 98 - Includes Rich Edit 1.0 and 2.0.

Windows 95 - Includes only Rich Edit 1.0. However, Riched20.dll is compatible and may be installed by an application that requires it.


For a full description of the differences, please see the MSDN at this address –





String Comparisons

Take the following examples:

s1 := W2Bin(1) + W2Bin(9002) + W2Bin( 310 )
s2 := W2Bin(1) + W2Bin(9002) + W2Bin( 9011 )

 ? AsString(s1 == s2)
 ? AsString(s1 > s2)
 ? AsString(s1 < s2)



 ? AsString(s1 == s2)
 ? AsString(s1 > s2)
 ? AsString(s1 < s2)

Different people reported different results when running these samples on
their machines.

Most people are NOT aware of the fact that the results of these comparisons
may differ depending on the nation Module they have loaded (when running
with SetCollation(#Clipper) or depending on the LocaleId they have selected
on their machine (when running with SetCollation(#Windows)).

For example with the German Collation Module strings are ordered like this:
"AÄB" and with the US collation module: "ABÄ"

Comparing strings with embedded NULL characters will almost always fail
when SetCollation(#Windows) is active, because windows will treat the NULL
characters as an End-Of-String.




SetCueBanner() Does Not Show Anything

On some configurations of WinXP, there is a known problem with SetCueBanner().

The situation can arise that even though the EM_SETCUEBANNER is set, no cue banner is shown.


There are two known things that may help and one or both may be the answer to your situation.

In the Control Panel/Regional and Language Options.

On the Languages tab

  1. The removal of Operating System support for Complex Scripts
  2. The removal of Operating System support for East Asian languages.

Both of these will require a reboot.


This problem is not unique to Visual Objects and our implementation of this feature is correct. Several other development languages have reported the same problem to Microsoft and we are now waiting for them to resolve this issue.