09 March 2009

The Collection Ocx (part 2)

In the previous post I introduced the Collection Ocx object and discussed its implementation. The Collection COM object is nothing more than a COM wrapper to the Hash object. To be more precise, the Collection Ocx maintains a Hash Variant data object. The following two statements both result in the creation of a Hash data structure: Dim col As New Collection Dim hs As Hash Variant The Hash commands (and its many operators []) provide the functionality to the underlying hash table. The hash table is the data structure GFA-BASIC 32 uses in almost any case some kind of collection is to be made. GFA-BASIC 32 uses the hash table at the base of the Ocx collections like Panels, ListImages, ColumnHeaders, etc. But it also uses the hash table intensively at the heart of the compiler. All data types, variables, constants, anythings that has to be collected during compiling is stored in a hash table. This prooves the outstanding performance of the Hash data structure, because the compiler is one of the fastest around. Not all Ocx collections use the hash table though; the ListItems Ocx is a COM wrapper around the ListView control's LVM_GETITEM message. The ListItem object, the element from a ListItems collection, is stored in the lParam member of the LVITEM structure used with LVM_GETITEM and LVM_SETITEM messages (see your SDK/MSDN). This brings me to the heart of my post, all so called Ocx/COM collections use the same interface. They use the same properties and methods to access a collection element. These properties and methods I discussed in the previous post. For most of Ocx collection objects these properties and methods directly translate in Hash commands. As said, some Ocx collections implement the methods (and properties) Add, Item, Remove, Clear, and Count in some other way. For instance, the ToolBar's collection Buttons is rather buggy, because the Buttons collection isn't a wrapper for a Hash table, but for a set of functions that maintain the buttons in another way. The Buttons collections is not build on proven mechanism of the hash table. Because most GFA-BASIC 32 Ocx collections are based on the Hash data structure, accessing an item is very fast. An item is either accessed using the default Item() method or obtained with the iteration command For Each...Next. The argument of the Item method of a collection always takes a Variant, which contains
  • a numberic value specifying the index
  • or a string specifying the key used to store the item
Collection elements are accessible by their index value, although the lower bound of a collection object’s index is always 1, and can’t be set otherwise in code. In VB, however, the performance is poor if items are to be accessed by index. This is in contrast with GFA-BASIC 32, which has a very fast implementation of accessing a collection object by index, due to its fast performance Hash structure! (And this isn't the only optimization GFA-BASIC 32 features with Collections.) Often the default method .Item() is invoked using a literal string key, rather than a string variable. For instance, look at these statements that access the element by a literal string key: v =c("a") v = c.Item("a") In the case the string literal starts with an alphabetic character (a-z, A-Z) and for the rest contains digits and/or an underscore (_), GFA-BASIC 32 uses a non-OLE compatible function to access the item. Rather than converting the "a" to COM string, GFA-BASIC 32 passes a pointer to the ANSI version of the key-string. This might need some more explanation. Every call to a COM function, whether it is a property or method, that takes a string (either in a Variant or as string parameter) uses a special COM BSTR data type. To facilitate the COM requirement GFA-BASIC will convert each(!) string you assign to a COM property or use in a method call to a BSTR, a wide UNICODE string. GFA-BASIC 32 consequently uses this ANSI to UNICODE conversion, because this is required by the COM rules. GFA-BASIC 32 must perform these conversions when you use the CreateObject() function to obtain an external COM automation object that require COM compatibility, which is the use of UNICODE. Internally, GFA-BASIC 32 objects stores the BSTRs as ANSI strings. Now you might notice the strange fact, that a string passed to an Ocx object is conerted twice, form ANSI to COM-compatible UNICODE, and back from UNICODE to ANSI. This IS EXACTLY what is happening, for instance when you pass a (large) string to aTextBox ocx, the string is first converted to UNICODE and then passed to the underlying EDITTEXT control using SetWindowTextA(). Before the string is passed to the ANSI version the SetWindowText() API it has to reconverted to ANSI. Fortunately, GFA-BASIC uses its own highly optimized Ansi-to-Unicode and Unicode-to-Ansi functions. The !-operator is used to provide an optimization for the literal strings used as keys used in methods to access an item of a GFA-BASIC 32 collection (Collection, ListImages, ListItems, Buttons, etc), the literal strings are passed in ANSI format rather than in UNICODE when you use the ! operator to specify the key. This alternative syntax results in 'v!a' for the example mentioned, and in general: Collection!StringIndex. So v =c!a <=> v =c("a") Next time I discuss the gain in performance.


  1. How i can support from gfawin23.ocx to unicode? so that my database can use letters from unicode? For example: Its not a problem to write in my database (latin letters) with ascii-code, but if i want to write letters from unicode, my database didnt accept it! He didnt shows the letters from unicode....What i have to do, that my database shows me the unicode-letteers like Ð, ý, Þ, ð, etc.
    as original letters like Ğ, ı, ş, ğ, etc.???

    Thank you for your answers.
    Franz Baldas

  2. I need help for ocx-elements......

    I will furnish the ocx-elements with unicode basically.(it takes 2 bytes for one character basically)What I lack is , that the textbox know, that she get unicode and that the textbox shows that correct and that the textbox gives unicode back basically.

    Maybe someone will have a idea, and i will be happy ;-)

    Thanks for the answers.

  3. if you enter in a textbox for example Chinese the text string returns only ASCII code, no UNICODE and the textbox shows only trash. If I received a pure UNICODE, which means two byte per character, I would be able to fill an IBL-OCX or a list box.

    But all OCX elements only understand ASCII and they ignore the first byte. I get and I’m allowed to send only ASCII, one character one byte.

    I want to send UNICODE ----- > hex 00 65 = A in UNICODE, 65 = A in ASCII or 00 32 is space in UNICODE and 32 = space in ASCII.

    How can I manage to make the OCX’s to understand that?

    I want to be able to handle the whole screen management of the OCX’s in UNICODE like WINDOWS does so that I can, for example enter in a textbox mixed Chinese and English. This is only possible in UNICODE.

    I hope that helps you to understand this problem better and you can tell me how to manage that.

  4. There is an increasingly amount of questions on support of UNICODE controls. One of these days I will get into that. First let me describe what is happening in the background.

    Whenever you use an Ocx command, GFA-BASIC 32 creates the ANSI version of the control. Then the properties and methods take UNICODE strings (COM derictive) as a parameter. Before passing the UNICODE string GFA-BASIC converts the ANSI string datatype to UNICODE to pass it on to the runtime DLL. Then the runtime function convert the string back to ANSI to call the Windows API function for that particular property or method. Than, o irony, Windows converts it back to UNICODE ...

    To allow the user to enter UNICODE text, all you need to do is to create a the wide-variant of the control, rather than the ANSI version. Than, automatically, Windows accept UNICODE characters. What we need to do is to get the UNICODE out of the control. This can be done the API way ofcourse. For the moment I suggest, you use UNICODE on your own, without the properties and methods that make the Ocx controls so easy to use.

    To get advantage from the Ocx events you can wrap the control into a COM interface using the WrapXXX commands. You can use the event subs, but not the properties and methods that take a string data type. Most other properties taking a Bool or Integer may still work. Just test!

  5. I allready understand the API-Functions, but i think, just a idea, that the possibility must be given to manage that with GetA or GetW and same with PutA and PutW.
    If someone have an idea how to manage the problem, off course he must not do that just for fun, i will pay for his work and his time.
    Therefore please read my posting from 22.09.2009 If you have a idea, let me know how i can contact you.