Navigation:  Tutorial >

Extending gwst structure members

Previous pageReturn to chapter overviewNext page

Like the storage of a C++ class can be extended in subsequent inheritances, gwst structures also allow to extend its storage by inheritance. This allow to reuse the previous functionality.

 

See the following example:

 

// Tut08.prg

BEGIN STRUCTURE OSVERSIONINFO

   MEMBER DWORD dwOSVersionInfoSize

   MEMBER DWORD dwMajorVersion

   MEMBER DWORD dwMinorVersion

   MEMBER DWORD dwBuildNumber

   MEMBER DWORD dwPlatformId

   MEMBER SZSTR szCSDVersion SIZE 128

 

First as usual, we have declared all the members of our structure, and now we will add some properties to make easy the interpretation of the values.

 

   DYNAMIC PROPERTY lIs9x READ ( (::dwMajorVersion == 4 ) .and. ;

                                 (::dwPlatformId   == 1 )  )

   // ---------------

   DYNAMIC PROPERTY lIsXp READ ( (::dwMajorVersion == 5 ) .and. ;

                                 (::dwMinorVersion  > 0 )  )

   // ---------------

   DYNAMIC PROPERTY lIsVista READ (::dwMajorVersion == 6 )

 

We will also add the method GetVersionEx() that will fill our structure with the info provided by the Windows API.

 

   DYNAMIC METHOD GetVersionEx BLOCK {|Self| ::_zeromemory_() ,;

                  ::dwOSVersionInfoSize := OSVERSIONINFO():_mc__size_ ,;

                  (@kernel32:GetVersionExA( Self ) != 0)}

END STRUCTURE

 

The gwst class var _mc__size_  contain the default size for every gwst class, usually we will use the instance method ::_sizeof_(), but in this case we need that the member dwOSVersionInfoSize contain always the size of the OSVERSIONINFO() structure, even in subclasses.

 

We have now a fully functional structure with some extra properties and a method for automatically fill its members from the info provided by the Windows API.

 

Since Windows NT 4. SP6 we can use an extended version of this structure that provides some extra info. This time instead of rewrite all the code to manage our extended structure, we will write our new class reusing the previous code.

 

BEGIN STRUCTURE OSVERSIONINFOEX EXTENDING OSVERSIONINFO

 

We add the clause EXTENDING that allow us to add new members to the base structure class, so we just will add the new members to our structure.

 

   MEMBER WORD wServicePackMajor

   MEMBER WORD wServicePackMinor

   MEMBER WORD wSuiteMask

   MEMBER BYTE wProductType

   MEMBER BYTE wReserved   

 

Now we will add some properties for easy interpretation of the bit flags stored inside the WORD value wSuiteMask

 

   DYNAMIC PROPERTY lBackOffice              IS MASK 0x0004  ;

                                             OF wSuiteMask READONLY

   DYNAMIC PROPERTY lWebEdition              IS MASK 0x0400  ;

                                             OF wSuiteMask READONLY

   DYNAMIC PROPERTY lDataCenter              IS MASK 0x0080  ;

                                             OF wSuiteMask READONLY

   DYNAMIC PROPERTY lEnterprise              IS MASK 0x0002  ;

                                             OF wSuiteMask READONLY

   DYNAMIC PROPERTY lEmbeddedNT              IS MASK 0x0040  ;

                                             OF wSuiteMask READONLY

   DYNAMIC PROPERTY lPersonal                IS MASK 0x0200  ;

                                             OF wSuiteMask READONLY

   DYNAMIC PROPERTY lSingleUserTS            IS MASK 0x0100  ;

                                             OF wSuiteMask READONLY

   DYNAMIC PROPERTY lSmallBusiness           IS MASK 0x0001  ;

                                             OF wSuiteMask READONLY

   DYNAMIC PROPERTY lSmallBusinessRestricted IS MASK 0x0020  ;

                                             OF wSuiteMask READONLY

   DYNAMIC PROPERTY lTerminal                IS MASK 0x0010  ;

                                             OF wSuiteMask READONLY

 

And now we will add also more properties to help us interpreting the value wProductType.

 

   DYNAMIC PROPERTY lDomainController  READ ( ::wProductType == 0x02 )

   DYNAMIC PROPERTY lNtServer          READ ( ::wProductType == 0x03 )

   DYNAMIC PROPERTY lNtWorstation      READ ( ::wProductType == 0x01 )

 

When we was defined the GetVersionEx() method in our base class I was explain that the common way to get the size of a gwst structure is using the instance method ::_sizeof_(). If we was used this instance method we will not need to overload the ::GetVersionInfoEx()  method now, because ::_sizeof_() will report the current size of our new structure.

 

As you will see in the next block of code the reason to hardcode the size of the structure is because the call of the WINAPI function GetVersionExA() can fail under some older Windows platforms if we specify the size of our new extended structure.

 

   DYNAMIC METHOD GetVersionEx BLOCK {|Self| ::_zeromemory_() ,;

                  ::dwOSVersionInfoSize := OSVERSIONINFOEX():_mc__size_ ,;

                  iif( @kernel32:GetVersionExA( Self ) == 0 ,;

                       ::OSVERSIONINFO:GetVersionEx() ,;

                       .T.)}

END STRUCTURE

 

So if GetVersionExA() fail using  the extended size, we will call the same method from the parent object, that will meet the OS requirements for this API call.