سؤال

وأنا أعلم أنني يمكن استدعاء GetVersionEx الدالة Win32 API لاسترداد نسخة ويندوز.في معظم الحالات إرجاع قيمة يعكس الإصدار من Windows, ولكن في بعض الأحيان أنه ليس كذلك.

إذا كان المستخدم يعمل طلبي تحت طبقة توافق ، ثم GetVersionEx لن يكون الإبلاغ النسخة الحقيقية ولكن النسخة القسري من قبل "طبقة توافق".على سبيل المثال, إذا أنا التشغيل Vista و تنفيذ البرنامج في "نظام التشغيل Windows NT 4" وضع التوافق ، GetVersionEx لن يعود الإصدار 6.0 ولكن 4.0.

هل هناك طريقة لتجاوز هذا السلوك والحصول على صحيح Windows الإصدار ؟

هل كانت مفيدة؟

المحلول

أفضل نهج أعلم للتحقق مما إذا محددة API يتم تصديرها من DLL.كل نسخة ويندوز يضيف وظائف جديدة عن طريق التحقق من وجود هذه الوظائف يمكن معرفة نظام التشغيل الذي يعمل عليه التطبيق.على سبيل المثال, Vista الصادرات GetLocaleInfoEx من kernel32.dll في حين السابقة Windowses لم.

لخفض قصة قصيرة طويلة, هنا هو واحد من هذه القائمة تحتوي فقط من الصادرات 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  

كتابة وظيفة تحديد إصدار نظام التشغيل بسيط ؛ فقط المضي قدما من أحدث نظام التشغيل أن أقدم استخدام GetProcAddress للتحقق من تصدير واجهات برمجة التطبيقات.تنفيذ هذا في أي لغة يجب أن تكون تافهة.

التعليمة البرمجية التالية في دلفي كان يستخرج من الحر 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

اتضح أنه يحصل من الصعب جدا أن تفعل "غير الشرعيين" الكشف عن نظام التشغيل على ويندوز فيستا SP1 أو أعلى.نظرة على التغييرات API يدل على أن جميع ويندوز 2008 المهام التي تم تنفيذها في ويندوز فيستا SP1 و أن جميع ويندوز 7 المهام التي تم تنفيذها في ويندوز 2008 R2.سيء جدا :(

--- نهاية التحديث

FWIW, هذه مشكلة واجهت في الممارسة.نحن (الشركة التي أعمل) بأن لم يكن حقا فيستا جاهزة عندما Vista صدر (وبعض أسابيع بعد ذلك ...).كان لا يعمل تحت طبقة توافق أيضا.(بعض المشاكل DirectX.لا تسأل.)

نحن لا نريد أيضا-الذكية-عن-على-الخاصة-جيد للمستخدمين تشغيل هذا التطبيق على ويندوز فيستا في كل وضع التوافق أو لا - لذلك كان علي أن أجد حلا (الرجل أذكى مني أشار لي في الحق الاتجاه ؛ الاشياء المذكورة أعلاه ليست من بنات أفكاري).الآن أنا نشر هذا لمتعتك ومساعدة جميع النفوس الفقيرة التي سوف تضطر إلى حل هذه المشكلة في المستقبل.جوجل ، يرجى مؤشر هذا المقال!

إذا كان لديك حل أفضل (أو ترقية و/أو إصلاح الألغام), الرجاء نشر الإجابة هنا ...

نصائح أخرى

استعلام WMI:

"Select * from Win32_OperatingSystem"

تحرير:في الواقع سيكون أفضل:

"Select Version from Win32_OperatingSystem"

هل يمكن تطبيق هذا في دلفي مثل ذلك:

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;

حول كيفية الحصول على نسخة من نظام الملف ؟

أفضل أن يكون هذا الملف kernel32.dll يقع في %WINDIR%\System32\kernel32.dll.

هناك واجهات برمجة التطبيقات للحصول على إصدار الملف.على سبيل المثال:أنا أستخدم ويندوز XP -> "5.1.2600.5512 (xpsp.080413-2111)"

حل آخر:

قراءة إدخال التسجيل التالي:

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

أو مفاتيح أخرى من

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion

النسخة الحقيقية متجر على PEB كتلة من معالجة المعلومات.

عينة Win32 التطبيق (دلفي رمز)

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.

التالية يعمل معي في ويندوز 10 بدون ويندوز 10 GUID المدرجة في التطبيق البيان:

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()`, ولكن لم تجربها بعد.

ملاحظة: جبر يسأل عن النهج الذي يمكن تجاوز قيود GetVersionEx.JCL رمز يستخدم GetVersionEx, وتخضع بالتالي طبقة توافق.هذه المعلومات للأشخاص الذين لا تحتاج إلى تجاوز "طبقة توافق" فقط.

باستخدام جدي JCL, يمكنك إضافة وحدة JclSysInfo و استدعاء دالة GetWindowsVersion.تقوم بإرجاع نوع المذكورة TWindowsVersion.

حاليا JCL يحتوي على جميع شحنها إصدارات ويندوز ، يحصل تغيير في كل مرة Microsoft السفن نسخة جديدة من ويندوز في مربع:

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

إذا كنت تريد أن تعرف إذا كنت تقوم بتشغيل إصدار 64 بت ويندوز 7 بدلا من 32 بت ، ثم اتصل JclSysInfo.IsWindows64.

علما بأن JCL السريع مقابض طبعات ، مثل الموالية ، في نهاية المطاف ، إلخ.مكالمة 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);

على الأهمية التاريخية ، يمكنك التحقق NT-المستوى الطبعة جدا مع NtProductType وظيفة ، فإنه يعود:

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

علما أن "ن طبعات" يتم الكشف عنها أعلاه.أن الاتحاد الأوروبي (أوروبا) نسخة من ويندوز ، التي أنشئت بسبب الأوروبي لمكافحة الثقة اللوائح.هذا جيد جدا تدرج الكشف داخل JCL.

هنا عينة الوظيفة التي سوف تساعدك على الكشف عن ويندوز فيستا و لا شيء خاص عندما على ويندوز فيستا.

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

ملاحظة أنه إذا كنت تريد أن تفعل "أكبر من" التدقيق ، ثم يجب عليك فقط استخدام تقنيات أخرى.نلاحظ أيضا أن التحقق من الإصدار كثير من الأحيان يمكن أن تكون مصدرا المستقبل الكسر.لدي عادة اختيار لتحذير المستخدمين والاستمرار ، بحيث بلدي رمز ثنائي لا تصبح المصدر الفعلي الكسر في المستقبل.

في الآونة الأخيرة حاولت تثبيت التطبيق ، والمثبت فحص محرك الأقراص مساحة حرة ، ولن تثبيت, لأنه كان أكثر من 2 غيغا بايت من المساحة الحرة.32 بت عدد صحيح التوقيع قيمة في المثبت أصبحت سلبية ، وكسر المثبت.اضطررت إلى تثبيته في VM الحصول على عمل.مضيفا "التعليمات البرمجية الذكية" في كثير من الأحيان يجعل التطبيق الخاص بك "أغبى".أن نكون حذرين.

بالمناسبة, لقد وجدت أن من سطر الأوامر, يمكنك تشغيل WMIC.exe ثم اكتب path Win32_OperatingSystem ("Select * from Win32_OperatingSystem" لم يكن العمل بالنسبة لي).في المستقبل ربما JCL يمكن أن تمتد إلى استخدام WMI المعلومات.

أساسا إلى إجابة مكررة Q: الحصول على نظام التشغيل الكبرى والصغرى ، وبناء إصدارات ويندوز 8.1 و في دلفي 2007

بدءا 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;

ملاحظة واحدة حول استخدام NetServerGetInfo () ، الذي يعمل على Windows 10 (10240.th1_st1)...

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

sv101_version_major

رقم الإصدار الرئيسي و نوع الملقم.

الرئيسية الافراج عن رقم إصدار نظام التشغيل المحدد في الأقل أهمية 4 بت.نوع الملقم المحدد في أهم 4 بت.على MAJOR_VERSION_MASK بت المحددة في Lmserver.ح رأس {0x0F} يجب أن يكون استخدامها من قبل تطبيق للحصول على رقم الإصدار الرئيسي من هذه الأعضاء.

وبعبارة أخرى, (sv101_version_major & MAJOR_VERSION_MASK).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top