Получение Windows версии из препроцессора (C ++ Win32) - PullRequest
1 голос
/ 11 февраля 2020

Я работаю над приложением Win32 и в настоящее время пытаюсь реализовать функции мультидисплея. Для этого я хочу использовать EnumDisplayMonitors, функцию, которая присутствует только в Windows 2000 и выше. До сих пор я старался поддерживать обратную совместимость вплоть до Windows 95.

Поэтому я хочу игнорировать этот связанный раздел кода, когда программа работает на более старых версиях Windows. Однако его простое присутствие в коде, даже если оно не выполняется, приводит к сбою программы. Я хочу использовать #ifdef, чтобы игнорировать этот раздел кода, однако я не могу найти способ получить текущую Windows версию из препроцессора. Я видел предложения использовать WINVER или _WIN32_WINNT, но оба должны быть установлены мной, насколько я понимаю, в ущерб всей сути. Любые попытки использовать их предсказуемо не работали как задумано.

Есть ли способ получить текущую версию Windows от препроцессора? Если нет, есть ли другой способ полностью отключить эту функцию в зависимости от ОС? Опять же, независимо от того, используется ли оно, его простое присутствие падает на Windows 95.

Ответы [ 2 ]

7 голосов
/ 11 февраля 2020

Правильный способ справиться с этим совсем не с препроцессором. Вместо этого вам нужно использовать функцию Win32 API GetProcAddress() во время выполнения, например:

typedef BOOL (WINAPI *LPFN_EDM)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
LPFN_EDM lpEnumDisplayMonitors = (LPFN_EDM) GetProcAddress(GetModuleHandle("user32.dll"), "EnumDisplayMonitors");
if (lpEnumDisplayMonitors)
{
    // use lpEnumDisplayMonitors as needed... 
}
else
{
    // use something else...
}

Это даже описано в документации Microsoft:

Эксплуатация Версия системы

Идентификация текущей операционной системы обычно не лучший способ определить, присутствует ли конкретная функция операционной системы. Это связано с тем, что в операционной системе могут быть добавлены новые функции в распространяемой DLL. Вместо использования функций Помощника по API Версии для определения платформы или номера версии операционной системы, проверьте наличие самой функции.

Чтобы определить лучший способ проверки функции, обратитесь к документации для Интересная особенность. В следующем списке обсуждаются некоторые распространенные методы обнаружения объектов:

  • Вы можете проверить наличие функций, связанных с функцией. Чтобы проверить наличие функции в системной DLL, вызовите функцию LoadLibrary для загрузки DLL. Затем вызовите функцию GetProcAddress, чтобы определить, присутствует ли интересующая функция в DLL. Используйте указатель, возвращаемый GetProcAddress для вызова функции. Обратите внимание, что даже если функция присутствует, это может быть заглушка, которая просто возвращает код ошибки, такой как ERROR_CALL_NOT_IMPLEMENTED.

  • Вы можете определить наличие некоторых функций с помощью GetSystemMetrics функция. Например, вы можете обнаружить несколько мониторов, набрав GetSystemMetrics(SM_CMONITORS). Существует несколько версий распространяемых библиотек DLL, которые реализуют функции оболочки и общие элементы управления. Информацию о том, какие версии присутствуют в системе, в которой работает ваше приложение, см. В разделе Версии оболочки и общих элементов управления .

Если ваш компилятор toolchain поддерживает Delay Loading , тогда вы можете использовать это вместо вызова GetProcAddress() вручную. Установите для своего проекта задержку загрузки user32.dll, а затем, как правило, после EnumDisplayMonitors() вызывайте *1043*, как обычно, после проверки ОС поддерживает то, что вам нужно, например, проверяет, является ли Windows Win2K или более поздней, через GetVersionEx() или проверка установки нескольких мониторов, например:

OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionEx(&osvi);

if (osvi.dwMajorVersion >= 5) // Win2K = 5.0
{
    // use EnumDisplayMonitors as needed... 
}
else
{
    // use something else...
}
if (GetSystemMetrics(SM_CMONITORS) > 1)
{
    // use EnumDisplayMonitors as needed... 
}
else
{
    // use something else...
}
1 голос
/ 11 февраля 2020

Скомпилируйте таргетинг на самое низкое значение Windows, которое вы поддерживаете, с помощью WINVER / _WIN32_WINNT (независимо от того, что поддерживает ваш SDK), затем загрузите все нужные вам функции динамически во время выполнения (LoadLibrary et c.), Зная, где вы на самом деле работает.

...