كيفية الكشف عن حقيقة Windows الإصدار ؟
سؤال
وأنا أعلم أنني يمكن استدعاء 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).