문제

GetVersionEx Win32 API 함수를 호출하여 Windows 버전을 검색할 수 있다는 것을 알고 있습니다.대부분의 경우 반환된 값은 내 Windows 버전을 반영하지만 때로는 그렇지 않은 경우도 있습니다.

사용자가 호환성 계층에서 내 응용 프로그램을 실행하면 GetVersionEx는 실제 버전이 아니라 호환성 계층에서 적용되는 버전을 보고합니다.예를 들어, Vista를 실행 중이고 "Windows NT 4" 호환 모드에서 프로그램을 실행하면 GetVersionEx는 버전 6.0이 아닌 4.0을 반환합니다.

이 동작을 우회하고 실제 Windows 버전을 얻을 수 있는 방법이 있습니까?

도움이 되었습니까?

해결책

내가 아는 가장 좋은 접근 방식은 특정 API가 일부 DLL에서 내보내졌는지 확인하는 것입니다.각각의 새로운 Windows 버전에는 새로운 기능이 추가되며 해당 기능의 존재 여부를 확인하여 응용 프로그램이 어떤 OS에서 실행되고 있는지 알 수 있습니다.예를 들어 Vista는 다음을 내보냅니다. GetLocaleInfoEx 이전 Windows에서는 그렇지 않았지만 kernel32.dll에서.

간단히 말해서, kernel32.dll의 내보내기만 포함하는 목록이 있습니다.

> *function: implemented in*  
> GetLocaleInfoEx:       Vista  
> GetLargePageMinimum:   Vista, Server 2003  
GetDLLDirectory:         Vista, Server 2003, XP SP1  
GetNativeSystemInfo:     Vista, Server 2003, XP SP1, XP  
ReplaceFile:             Vista, Server 2003, XP SP1, XP, 2000  
OpenThread:              Vista, Server 2003, XP SP1, XP, 2000, ME  
GetThreadPriorityBoost:  Vista, Server 2003, XP SP1, XP, 2000,     NT 4  
IsDebuggerPresent:       Vista, Server 2003, XP SP1, XP, 2000, ME, NT 4, 98   
GetDiskFreeSpaceEx:      Vista, Server 2003, XP SP1, XP, 2000, ME, NT 4, 98, 95 OSR2  
ConnectNamedPipe:        Vista, Server 2003, XP SP1, XP, 2000,     NT 4,                 NT 3  
Beep:                    Vista, Server 2003, XP SP1, XP, 2000, ME,       98, 95 OSR2, 95  

실제 OS 버전을 확인하는 함수를 작성하는 것은 간단합니다.최신 OS에서 가장 오래된 OS로 진행하여 사용하세요. GetProc주소 내보낸 API를 확인합니다.어떤 언어로든 이것을 구현하는 것은 쉽지 않습니다.

Delphi의 다음 코드는 무료에서 추출되었습니다. DSiWin32 도서관):

TDSiWindowsVersion = (wvUnknown, wvWin31, wvWin95, wvWin95OSR2, wvWin98,
  wvWin98SE, wvWinME, wvWin9x, wvWinNT3, wvWinNT4, wvWin2000, wvWinXP,
  wvWinNT, wvWinServer2003, wvWinVista);

function DSiGetWindowsVersion: TDSiWindowsVersion;
var
  versionInfo: TOSVersionInfo;
begin
  versionInfo.dwOSVersionInfoSize := SizeOf(versionInfo);
  GetVersionEx(versionInfo);
  Result := wvUnknown;
  case versionInfo.dwPlatformID of
    VER_PLATFORM_WIN32s: Result := wvWin31;
    VER_PLATFORM_WIN32_WINDOWS:
      case versionInfo.dwMinorVersion of
        0:
          if Trim(versionInfo.szCSDVersion[1]) = 'B' then
            Result := wvWin95OSR2
          else
            Result := wvWin95;
        10:
          if Trim(versionInfo.szCSDVersion[1]) = 'A' then
            Result := wvWin98SE
          else
            Result := wvWin98;
        90:
          if (versionInfo.dwBuildNumber = 73010104) then
             Result := wvWinME;
           else
             Result := wvWin9x;
      end; //case versionInfo.dwMinorVersion
    VER_PLATFORM_WIN32_NT:
      case versionInfo.dwMajorVersion of
        3: Result := wvWinNT3;
        4: Result := wvWinNT4;
        5:
          case versionInfo.dwMinorVersion of
            0: Result := wvWin2000;
            1: Result := wvWinXP;
            2: Result := wvWinServer2003;
            else Result := wvWinNT
          end; //case versionInfo.dwMinorVersion
        6: Result := wvWinVista;
      end; //case versionInfo.dwMajorVersion
    end; //versionInfo.dwPlatformID
end; { DSiGetWindowsVersion }

function DSiGetTrueWindowsVersion: TDSiWindowsVersion;

  function ExportsAPI(module: HMODULE; const apiName: string): boolean;
  begin
    Result := GetProcAddress(module, PChar(apiName)) <> nil;
  end; { ExportsAPI }

var
  hKernel32: HMODULE;

begin { DSiGetTrueWindowsVersion }
  hKernel32 := GetModuleHandle('kernel32');
  Win32Check(hKernel32 <> 0);
  if ExportsAPI(hKernel32, 'GetLocaleInfoEx') then
    Result := wvWinVista
  else if ExportsAPI(hKernel32, 'GetLargePageMinimum') then
    Result := wvWinServer2003
  else if ExportsAPI(hKernel32, 'GetNativeSystemInfo') then
    Result := wvWinXP
  else if ExportsAPI(hKernel32, 'ReplaceFile') then
    Result := wvWin2000
  else if ExportsAPI(hKernel32, 'OpenThread') then
    Result := wvWinME
  else if ExportsAPI(hKernel32, 'GetThreadPriorityBoost') then
    Result := wvWinNT4
  else if ExportsAPI(hKernel32, 'IsDebuggerPresent') then  //is also in NT4!
    Result := wvWin98
  else if ExportsAPI(hKernel32, 'GetDiskFreeSpaceEx') then  //is also in NT4!
    Result := wvWin95OSR2
  else if ExportsAPI(hKernel32, 'ConnectNamedPipe') then
    Result := wvWinNT3
  else if ExportsAPI(hKernel32, 'Beep') then
    Result := wvWin95
  else // we have no idea
    Result := DSiGetWindowsVersion;
end; { DSiGetTrueWindowsVersion }

--- 업데이트 날짜: 2009-10-09

Vista SP1 이상에서는 "문서화되지 않은" OS 감지를 수행하는 것이 매우 어려워지는 것으로 나타났습니다.살펴보기 API 변경 Windows 2008의 모든 기능은 Vista SP1에도 구현되어 있고, Windows 7의 모든 기능은 Windows 2008 R2에도 구현되어 있음을 보여줍니다.안타깝네요 :(

--- 업데이트 종료

FWIW, 이것은 제가 실제로 직면한 문제입니다.우리(제가 일하는 회사)에는 Vista가 출시되었을 때(그리고 그로부터 몇 주 후...) 실제로 Vista에 준비되지 않은 프로그램이 있습니다.호환성 레이어에서도 작동하지 않았습니다.(일부 DirectX 문제.묻지 마세요.)

우리는 너무 똑똑해서 좋은 사용자가 Vista에서 이 앱을 실행하는 것을 전혀 원하지 않았습니다(호환 모드이든 아니든). 그래서 해결책을 찾아야 했습니다(나보다 똑똑한 사람이 나에게 올바른 방향을 알려줬습니다.위의 내용은 내 생각이 아닙니다).이제 나는 여러분의 즐거움을 위해 그리고 앞으로 이 문제를 해결해야 할 모든 불쌍한 영혼들을 돕기 위해 이 글을 게시합니다.구글, 이 기사의 색인을 생성해주세요!

더 나은 솔루션(또는 업그레이드 및/또는 수정 사항)이 있는 경우 여기에 답변을 게시해 주세요...

다른 팁

WMI 쿼리:

"Select * from Win32_OperatingSystem"

편집하다:실제로 더 나은 것은 다음과 같습니다.

"Select Version from Win32_OperatingSystem"

Delphi에서는 다음과 같이 구현할 수 있습니다.

function OperatingSystemDisplayName: string;

  function GetWMIObject(const objectName: string): IDispatch;
  var
    chEaten: Integer;
    BindCtx: IBindCtx;
    Moniker: IMoniker;
  begin
    OleCheck(CreateBindCtx(0, bindCtx));
    OleCheck(MkParseDisplayName(BindCtx, PChar(objectName), chEaten, Moniker));
    OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
  end;

  function VarToString(const Value: OleVariant): string;
  begin
    if VarIsStr(Value) then begin
      Result := Trim(Value);
    end else begin
      Result := '';
    end;
  end;

  function FullVersionString(const Item: OleVariant): string;
  var
    Caption, ServicePack, Version, Architecture: string;
  begin
    Caption := VarToString(Item.Caption);
    ServicePack := VarToString(Item.CSDVersion);
    Version := VarToString(Item.Version);
    Architecture := ArchitectureDisplayName(SystemArchitecture);
    Result := Caption;
    if ServicePack <> '' then begin
      Result := Result + ' ' + ServicePack;
    end;
    Result := Result + ', version ' + Version + ', ' + Architecture;
  end;

var
  objWMIService: OleVariant;
  colItems: OleVariant;
  Item: OleVariant;
  oEnum: IEnumvariant;
  iValue: LongWord;

begin
  Try
    objWMIService := GetWMIObject('winmgmts:\\localhost\root\cimv2');
    colItems := objWMIService.ExecQuery('SELECT Caption, CSDVersion, Version FROM Win32_OperatingSystem', 'WQL', 0);
    oEnum := IUnknown(colItems._NewEnum) as IEnumVariant;
    if oEnum.Next(1, Item, iValue)=0 then begin
      Result := FullVersionString(Item);
      exit;
    end;
  Except
    // yes, I know this is nasty, but come what may I want to use the fallback code below should the WMI code fail
  End;

  (* Fallback, relies on the deprecated function GetVersionEx, reports erroneous values
     when manifest does not contain supportedOS matching the executing system *)
  Result := TOSVersion.ToString;
end;

시스템 파일의 버전을 구하는 것은 어떻습니까?

가장 좋은 파일은 %WINDIR%\System32\kernel32.dll에 있는 kernel32.dll입니다.

파일 버전을 얻는 API가 있습니다.예:Windows XP를 사용하고 있습니다 -> "5.1.2600.5512 (xpsp.080413-2111)"

또 다른 해결책:

다음 레지스트리 항목을 읽으십시오.

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName

또는 다른 키

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion

실제 버전은 프로세스 정보의 PEB 블록에 저장됩니다.

Win32 앱용 샘플(Delphi 코드)

unit RealWindowsVerUnit;

interface

uses
  Windows;

var
  //Real version Windows
  Win32MajorVersionReal: Integer;
  Win32MinorVersionReal: Integer;

implementation

type
  PPEB=^PEB;
  PEB = record
    InheritedAddressSpace: Boolean;
    ReadImageFileExecOptions: Boolean;
    BeingDebugged: Boolean;
    Spare: Boolean;
    Mutant: Cardinal;
    ImageBaseAddress: Pointer;
    LoaderData: Pointer;
    ProcessParameters: Pointer; //PRTL_USER_PROCESS_PARAMETERS;
    SubSystemData: Pointer;
    ProcessHeap: Pointer;
    FastPebLock: Pointer;
    FastPebLockRoutine: Pointer;
    FastPebUnlockRoutine: Pointer;
    EnvironmentUpdateCount: Cardinal;
    KernelCallbackTable: PPointer;
    EventLogSection: Pointer;
    EventLog: Pointer;
    FreeList: Pointer; //PPEB_FREE_BLOCK;
    TlsExpansionCounter: Cardinal;
    TlsBitmap: Pointer;
    TlsBitmapBits: array[0..1] of Cardinal;
    ReadOnlySharedMemoryBase: Pointer;
    ReadOnlySharedMemoryHeap: Pointer;
    ReadOnlyStaticServerData: PPointer;
    AnsiCodePageData: Pointer;
    OemCodePageData: Pointer;
    UnicodeCaseTableData: Pointer;
    NumberOfProcessors: Cardinal;
    NtGlobalFlag: Cardinal;
    Spare2: array[0..3] of Byte;
    CriticalSectionTimeout: LARGE_INTEGER;
    HeapSegmentReserve: Cardinal;
    HeapSegmentCommit: Cardinal;
    HeapDeCommitTotalFreeThreshold: Cardinal;
    HeapDeCommitFreeBlockThreshold: Cardinal;
    NumberOfHeaps: Cardinal;
    MaximumNumberOfHeaps: Cardinal;
    ProcessHeaps: Pointer;
    GdiSharedHandleTable: Pointer;
    ProcessStarterHelper: Pointer;
    GdiDCAttributeList: Pointer;
    LoaderLock: Pointer;
    OSMajorVersion: Cardinal;
    OSMinorVersion: Cardinal;
    OSBuildNumber: Cardinal;
    OSPlatformId: Cardinal;
    ImageSubSystem: Cardinal;
    ImageSubSystemMajorVersion: Cardinal;
    ImageSubSystemMinorVersion: Cardinal;
    GdiHandleBuffer: array [0..33] of Cardinal;
    PostProcessInitRoutine: Cardinal;
    TlsExpansionBitmap: Cardinal;
    TlsExpansionBitmapBits: array [0..127] of Byte;
    SessionId: Cardinal;
  end;

//Get PEB block current win32 process
function GetPDB: PPEB; stdcall;
asm
  MOV EAX, DWORD PTR FS:[30h]
end;

initialization
  //Detect true windows wersion
  Win32MajorVersionReal := GetPDB^.OSMajorVersion;
  Win32MinorVersionReal := GetPDB^.OSMinorVersion;
end.

다음은 응용 프로그램 매니페스트에 Windows 10 GUID가 나열되지 않은 Windows 10에서 작동합니다.

uses
  System.SysUtils, Winapi.Windows;

type
  NET_API_STATUS = DWORD;

  _SERVER_INFO_101 = record
    sv101_platform_id: DWORD;
    sv101_name: LPWSTR;
    sv101_version_major: DWORD;
    sv101_version_minor: DWORD;
    sv101_type: DWORD;
    sv101_comment: LPWSTR;
  end;
  SERVER_INFO_101 = _SERVER_INFO_101;
  PSERVER_INFO_101 = ^SERVER_INFO_101;
  LPSERVER_INFO_101 = PSERVER_INFO_101;

const
  MAJOR_VERSION_MASK = $0F;

function NetServerGetInfo(servername: LPWSTR; level: DWORD; var bufptr): NET_API_STATUS; stdcall; external 'Netapi32.dll';
function NetApiBufferFree(Buffer: LPVOID): NET_API_STATUS; stdcall; external 'Netapi32.dll';

type
  pfnRtlGetVersion = function(var RTL_OSVERSIONINFOEXW): LONG; stdcall;
var
  Buffer: PSERVER_INFO_101;
  ver: RTL_OSVERSIONINFOEXW;
  RtlGetVersion: pfnRtlGetVersion;
begin
  Buffer := nil;

  // Win32MajorVersion and Win32MinorVersion are populated from GetVersionEx()...
  ShowMessage(Format('GetVersionEx: %d.%d', [Win32MajorVersion, Win32MinorVersion])); // shows 6.2, as expected per GetVersionEx() documentation

  @RtlGetVersion := GetProcAddress(GetModuleHandle('ntdll.dll'), 'RtlGetVersion');
  if Assigned(RtlGetVersion) then
  begin
    ZeroMemory(@ver, SizeOf(ver));
    ver.dwOSVersionInfoSize := SizeOf(ver);

    if RtlGetVersion(ver) = 0 then
      ShowMessage(Format('RtlGetVersion: %d.%d', [ver.dwMajorVersion, ver.dwMinorVersion])); // shows 10.0
  end;

  if NetServerGetInfo(nil, 101, Buffer) = NO_ERROR then
  try
    ShowMessage(Format('NetServerGetInfo: %d.%d', [Buffer.sv101_version_major and MAJOR_VERSION_MASK, Buffer.sv101_version_minor])); // shows 10.0
  finally
    NetApiBufferFree(Buffer);
  end;
end.

업데이트: NetWkstaGetInfo() 아마도 'NetServerGetInfo()'와 유사하게 작동할 수도 있지만 아직 시도하지는 않았습니다.

메모: Gabr은 다음의 한계를 우회할 수 있는 접근 방식에 대해 묻고 있습니다. GetVersionEx.JCL 코드는 GetVersionEx를 사용하므로 호환성 계층의 적용을 받습니다.이 정보는 호환성 레이어를 우회할 필요가 없는 사람들만을 위한 것입니다.

Jedi JCL을 사용하면 JclSysInfo 유닛을 추가하고 함수를 호출할 수 있습니다. GetWindowsVersion.열거형 TWindowsVersion을 반환합니다.

현재 JCL에는 배송된 모든 Windows 버전이 포함되어 있으며 Microsoft가 새 버전의 Windows를 한 상자에 배송할 때마다 변경됩니다.

  TWindowsVersion =
   (wvUnknown, wvWin95, wvWin95OSR2, wvWin98, wvWin98SE, wvWinME,
    wvWinNT31, wvWinNT35, wvWinNT351, wvWinNT4, wvWin2000, wvWinXP,
    wvWin2003, wvWinXP64, wvWin2003R2, wvWinVista, wvWinServer2008,
    wvWin7, wvWinServer2008R2);

32비트 대신 64비트 Windows 7을 실행하고 있는지 알고 싶다면 다음을 호출하세요. JclSysInfo.IsWindows64.

JCL은 Pro, Ultimate 등과 같은 Edition도 처리합니다.GetWindowsEdition을 호출하면 다음 중 하나가 반환됩니다.

TWindowsEdition =
   (weUnknown, weWinXPHome, weWinXPPro, weWinXPHomeN, weWinXPProN, weWinXPHomeK,
    weWinXPProK, weWinXPHomeKN, weWinXPProKN, weWinXPStarter, weWinXPMediaCenter,
    weWinXPTablet, weWinVistaStarter, weWinVistaHomeBasic, weWinVistaHomeBasicN,
    weWinVistaHomePremium, weWinVistaBusiness, weWinVistaBusinessN,
    weWinVistaEnterprise, weWinVistaUltimate, weWin7Starter, weWin7HomeBasic,
    weWin7HomePremium, weWin7Professional, weWin7Enterprise, weWin7Ultimate);

역사적 관심을 위해 NtProductType 함수를 사용하여 NT 수준 버전도 확인할 수 있으며 다음을 반환합니다.

 TNtProductType =       (ptUnknown, ptWorkStation, ptServer, ptAdvancedServer,        
        ptPersonal, ptProfessional, ptDatacenterServer, 
        ptEnterprise, ptWebEdition);

위에서는 "N 에디션"이 감지되었습니다.이는 EU 독점금지 규정에 따라 만들어진 EU(유럽) 버전의 Windows입니다.이는 JCL 내부 감지의 매우 미세한 그라데이션입니다.

다음은 Vista를 감지하고 Vista에서 특별한 작업을 수행하는 데 도움이 되는 샘플 기능입니다.

function IsSupported:Boolean;
begin
  case GetWindowsVersion of
     wvVista:  result := false; 
    else
      result := true;
  end;
end;

"보다 큼" 검사를 수행하려면 다른 기술을 사용해야 합니다.또한 버전 확인은 종종 향후 손상의 원인이 될 수 있습니다.나는 일반적으로 사용자에게 경고하고 계속 진행하여 내 바이너리 코드가 미래에 실제 손상 소스가 되지 않도록 선택했습니다.

최근에 앱을 설치하려고 했는데 설치 프로그램이 내 드라이브 여유 공간을 확인했지만 여유 공간이 2GB가 넘었기 때문에 설치되지 않았습니다.설치 프로그램의 32비트 정수 부호 값이 음수가 되어 설치 프로그램이 중단되었습니다.작동하려면 VM에 설치해야했습니다."스마트 코드"를 추가하면 앱이 "어리석게" 되는 경우가 많습니다.조심하세요.

그런데 명령줄에서 WMIC.exe를 실행하고 다음을 입력할 수 있다는 것을 알았습니다. path Win32_OperatingSystem ("Win32_OperatingSystem에서 * 선택"이 작동하지 않았습니다.)앞으로는 WMI 정보를 사용하도록 JCL을 확장할 수도 있습니다.

본질적으로 중복된 질문에 대답하려면: Delphi 2007에서 Windows 8.1 이상의 OS 메이저, 마이너 및 빌드 버전 얻기

W2K부터 사용할 수 있습니다 NetServerGetInfo.NetServerGetInfo는 W7 및 W8.1에 대한 올바른 정보를 반환하지만 W10에서는 테스트할 수 없습니다.

function GetWinVersion: string;
var
  Buffer: PServerInfo101;
begin
  Buffer := nil;
  if NetServerGetInfo(nil, 101, Pointer(Buffer)) = NO_ERROR then
  try
     Result := <Build You Version String here>(
      Buffer.sv101_version_major,
      Buffer.sv101_version_minor,
      VER_PLATFORM_WIN32_NT // Save since minimum support begins in W2K
      );
  finally
    NetApiBufferFree(Buffer);
  end;
end;

Windows 10(10240.th1_st1)에서도 여전히 작동하는 NetServerGetInfo() 사용에 대한 참고 사항...

https://msdn.microsoft.com/en-us/library/windows/desktop/aa370903%28v=vs.85%29.aspx

sv101_version_major

주 버전 번호 및 서버 유형.

운영 체제의 주요 릴리스 버전 번호는 최소 4 비트로 지정됩니다.서버 유형은 가장 중요한 4 비트로 지정됩니다.lmserver.h 헤더 {0x0f}에 정의 된 major_version_mask 비트 마스크는 응용 프로그램 에서이 멤버로부터 주요 버전 번호를 얻기 위해 사용해야합니다.

즉, (sv101_version_major & MAJOR_VERSION_MASK)입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top