PDA

View Full Version : Windows System Struct silent modified in Windows Vista



nicjedi
07-17-2008, 09:06 AM
Hi All, I'm new here.
I'm registered at forum because I've to modify stingray source code fixing some errors created with the new sdk for Vista.
I've used Visual Studio 2008 and Stingray Studio 10.
Compiling with NTDDI_VISTA, there was some problems using the software in OS different from Vista.
Debugging the code I found that the problem is the NONCLIENTMETRICS struct.

Looking in MSDN
http://msdn.microsoft.com/en-us/library/ms724506(VS.85).aspx
I found that if i Compile for Win Vista, the NONCLIENTMETRICS struct have one new member. For this reason if I use this struct in system older than Vista, the program create some errors.

Lurking the net I've found that also others struct are changed, but Microsoft don't have solved this problem for now!

I don't know why the OS don't manage these differences, but the only "patch" for now is to modify the Stingray code.
I've added code like this every time one sructure NONCILENTMETRICS is used


// ### DDx Nicola modified 2008/07/17 ###
OSVERSIONINFO osvi;
ZeroMemory( &osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx( &osvi) ;
if ( osvi.dwMajorVersion < 6)
ncm.cbSize -= 4;
// ### End modified ###


The structures modified are (founded looking the RunTimeHelper namespace of WTL)
REBARBANDINFO
LVGROUP
LVTILEINFO
MCHITTESTINFO
NONCLIENTMETRICS

I hope that this thread is useful for all. I think that for Stingray developer is better to create macros for manage these problems.

Thanks All ;)

Terry
07-18-2008, 07:31 AM
Nicola,

Thank you very much for this contribution to the forum.

As you have observed, this problem is caused by a change in the NONCLIENTMETRICS struct under Visual Studio 9.0. Vista adds a new element to this struct, 'int iPaddedBorderWidth'.

When you call ::SystemParametersInfo(), you pass in this struct with its cbSize member initialized to the size of the struct. If you initialize this to the size of this struct under Vista, then pass it to ::SystemParametersInfo() under an older version of Windows, the call will just fail and the struct will not be populated. If this failure is not handled, you will get unexpected results.

This problem has been fixed for the next release. The fix involves deriving a new struct from NONCLIENTMETRICS. This new struct (SEC_NONCLIENTMETRICS) has a constructor which initializes the cbSize member based upon the build and runtime platforms. Specifically, if the build platform is Vista, but the runtime platform is an earlier release, we deduct the size of iPaddedBorderWidth from the size of the NONCLIENTMETRICS struct.

This new struct can be added to the file ...\include\foundation\sflcommon.h. Here is the code:


struct SEC_NONCLIENTMETRICS : public NONCLIENTMETRICS
{
SEC_NONCLIENTMETRICS() {

cbSize = sizeof(NONCLIENTMETRICS);

// if we're targeted for Vista, the NONCLIENTMETRICS struct
// will be the wrong size for XP, so adjust if necessary.
#if(WINVER >= 0x0600)
OSVERSIONINFO versionInfo;
versionInfo.dwOSVersionInfoSize = sizeof( versionInfo );
GetVersionEx( &versionInfo );

// If we are running under XP, deduct the size of the
// iPaddedBorderWidth member added in Vista.
if ( versionInfo.dwMajorVersion < 6 ) {
cbSize -= sizeof(int);
}
#endif
}
};


Then use this struct instead of NONCLIENTMETRICS. This struct is self-initializing, so if you have code like this:


NONCLIENTMETRICS ncm;
memset(&ncm, 0, sizeof(ncm));
ncm.cbSize = sizeof(ncm);

You would replace it with this:


SEC_NONCLIENTMETRICS ncm;

This struct is used in 9 places in 5 files:



C:\Program Files\Rogue Wave\Stingray Studio 10.0\Src\Toolkit\docking\sbarautohide.cpp(172)
C:\Program Files\Rogue Wave\Stingray Studio 10.0\Src\Toolkit\docking\sbarautohide.cpp(684)
C:\Program Files\Rogue Wave\Stingray Studio 10.0\Src\Toolkit\mdi\swinfrm.cpp(1044)
C:\Program Files\Rogue Wave\Stingray Studio 10.0\Src\Toolkit\mdi\swinfrm.cpp(1056)
C:\Program Files\Rogue Wave\Stingray Studio 10.0\Src\Toolkit\mdi\swinmdi.cpp(1596)
C:\Program Files\Rogue Wave\Stingray Studio 10.0\Src\Toolkit\mdi\swinmdi.cpp(1608)
C:\Program Files\Rogue Wave\Stingray Studio 10.0\Src\Toolkit\ui\ctoolbar\TBMPMENU.cpp(324)
C:\Program Files\Rogue Wave\Stingray Studio 10.0\Src\Toolkit\ui\ctoolbar\TBMPMENU.cpp(336)
C:\Program Files\Rogue Wave\Stingray Studio 10.0 Src\Toolkit\ui\ctoolbar\TMenuFrm.cpp(116)

nicjedi
07-18-2008, 04:53 PM
Thank you for the code, I'm embrassed for the compliemnts :o

I will insert this code Monday morning!

Thanks a Lot to you

nicjedi
07-22-2008, 02:53 AM
Nicola,

Thank you very much for this contribution to the forum.

As you have observed, this problem is caused by a change in the NONCLIENTMETRICS struct under Visual Studio 9.0. Vista adds a new element to this struct, 'int iPaddedBorderWidth'.

When you call ::SystemParametersInfo(), you pass in this struct with its cbSize member initialized to the size of the struct. If you initialize this to the size of this struct under Vista, then pass it to ::SystemParametersInfo() under an older version of Windows, the call will just fail and the struct will not be populated. If this failure is not handled, you will get unexpected results.

This problem has been fixed for the next release. The fix involves deriving a new struct from NONCLIENTMETRICS. This new struct (SEC_NONCLIENTMETRICS) has a constructor which initializes the cbSize member based upon the build and runtime platforms. Specifically, if the build platform is Vista, but the runtime platform is an earlier release, we deduct the size of iPaddedBorderWidth from the size of the NONCLIENTMETRICS struct.

This new struct can be added to the file ...\include\foundation\sflcommon.h. Here is the code:


struct SEC_NONCLIENTMETRICS : public NONCLIENTMETRICS
{
SEC_NONCLIENTMETRICS() {

cbSize = sizeof(NONCLIENTMETRICS);

// if we're targeted for Vista, the NONCLIENTMETRICS struct
// will be the wrong size for XP, so adjust if necessary.
#if(WINVER >= 0x0600)
OSVERSIONINFO versionInfo;
versionInfo.dwOSVersionInfoSize = sizeof( versionInfo );
GetVersionEx( &versionInfo );

// If we are running under XP, deduct the size of the
// iPaddedBorderWidth member added in Vista.
if ( versionInfo.dwMajorVersion < 6 ) {
cbSize -= sizeof(int);
}
#endif
}
};


Tested with previous compilers I found that it return errors:
I think it's better to make the precompiler if like this:


#if(_MSC_VER >= 1500 && WINVER >= 0x0600)