14 января 2010 г.

SystemParametersInfo with SPI_GETNONCLIENTMETRICS may fail

Оказывается, на версиях всеми любимой OS Windows ниже 6 (XP/2003) вызов функции SystemParametersInfo проваливается, если в поле cbSize структуры NONCLIENTMETRICS указан размер больше, чем нужно. Посмотрим на структуру NONCLIENTMETRICS:

typedef struct tagNONCLIENTMETRICSW
{
    UINT    cbSize;
    int     iBorderWidth;
    int     iScrollWidth;
    int     iScrollHeight;
    int     iCaptionWidth;
    int     iCaptionHeight;
    LOGFONTW lfCaptionFont;
    int     iSmCaptionWidth;
    int     iSmCaptionHeight;
    LOGFONTW lfSmCaptionFont;
    int     iMenuWidth;
    int     iMenuHeight;
    LOGFONTW lfMenuFont;
    LOGFONTW lfStatusFont;
    LOGFONTW lfMessageFont;
#if(WINVER >= 0x0600)
    int     iPaddedBorderWidth;
#endif /* WINVER >= 0x0600 */
}   NONCLIENTMETRICSW, *PNONCLIENTMETRICSW, FAR* LPNONCLIENTMETRICSW;

Правильный код:

NONCLIENTMETRICS ncm = { sizeof(NONCLIENTMETRICS), 0 };
#if (WINVER >= 0x0600)
OSVERSIONINFO osvi = { sizeof(OSVERSIONINFO), 0 };
VERIFY(GetVersionEx(&osvi));
if (osvi.dwMajorVersion < 6) {
    ncm.cbSize -= sizeof(int);
}
#endif
if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)) {
    _defaultLogFont = ncm.lfMessageFont;
}

6 комментариев:

  1. Низкий поклон и спасибо за пример

    ОтветитьУдалить
  2. You've done a great service. This has been bugging me for over a week. It was really crazy because GetLastError() was returning 0 when SystemParametersInfo() was returning 0.

    ОтветитьУдалить
  3. Обязательно схожу поставлю автору свечку в церковь. :)

    ОтветитьУдалить
  4. Спасибо! Очень помогло.

    ОтветитьУдалить
  5. Автору респект. Проблемма обозначилась при переходе с VS6 на VC 2010.

    ОтветитьУдалить