c#如何使用新的版本助手API
本文关键字:API 版本 何使用 | 更新日期: 2023-09-27 18:04:06
由于OSVersion现在不可靠,因为Windows 10已经发布(这个函数报告Windows 8 for Windows 10),我试图在我的c#应用程序中使用新的版本助手API函数。
如果这只是我的DLL导入的问题,我很抱歉,但这里是我尝试拉入这些新方法来正确检测操作系统。
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindows7OrGreater();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindows8OrGreater();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindows8Point1OrGreater();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindows10OrGreater();
当我调用这些方法时,我得到:
异常是:EntryPointNotFoundException -无法在DLL 'kernel32.dll'中找到名为'IsWindows7OrGreater'的入口点。
我做错了什么吗?有人有什么想法吗?谢谢你的帮助!
EDIT:请参阅接受的答案,并查看此代码项目,以将这些方法移植到c#。
你的代码必须有一个包含
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of all Windows versions that this application is designed to work with. Windows will automatically select the most compatible environment.-->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node-->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>-->
</application>
</compatibility>
告诉操作系统你的代码支持更新的操作系统
使用以下类
using System;
using System.Runtime.InteropServices;
namespace VersionHelper
{
public static class VersionHelper
{
const byte VER_EQUAL = 1;
const byte VER_GREATER = 2;
const byte VER_GREATER_EQUAL = 3;
const byte VER_LESS = 4;
const byte VER_LESS_EQUAL = 5;
const byte VER_AND = 6;
const byte VER_OR = 7;
const byte VER_CONDITION_MASK = 7;
const byte VER_NUM_BITS_PER_CONDITION_MASK = 3;
//
// RtlVerifyVersionInfo() type mask bits
//
const uint VER_MINORVERSION = 0x0000001;
const uint VER_MAJORVERSION = 0x0000002;
const uint VER_BUILDNUMBER = 0x0000004;
const uint VER_PLATFORMID = 0x0000008;
const uint VER_SERVICEPACKMINOR = 0x0000010;
const uint VER_SERVICEPACKMAJOR = 0x0000020;
const uint VER_SUITENAME = 0x0000040;
const uint VER_PRODUCT_TYPE = 0x0000080;
// wProductType
// Any additional information about the system.This member can be one of the following values.
const byte VER_NT_DOMAIN_CONTROLLER = 0x0000002;
const byte VER_NT_SERVER = 0x0000003;
const byte VER_NT_WORKSTATION = 0x0000001;
//
// _WIN32_WINNT version constants
//
const ushort _WIN32_WINNT_NT4 = 0x0400;
const ushort _WIN32_WINNT_WIN2K = 0x0500;
const ushort _WIN32_WINNT_WINXP = 0x0501;
const ushort _WIN32_WINNT_WS03 = 0x0502;
const ushort _WIN32_WINNT_WIN6 = 0x0600;
const ushort _WIN32_WINNT_VISTA = 0x0600;
const ushort _WIN32_WINNT_WS08 = 0x0600;
const ushort _WIN32_WINNT_LONGHORN = 0x0600;
const ushort _WIN32_WINNT_WIN7 = 0x0601;
const ushort _WIN32_WINNT_WIN8 = 0x0602;
const ushort _WIN32_WINNT_WINBLUE = 0x0603;
const ushort _WIN32_WINNT_WINTHRESHOLD = 0x0A00; /* ABRACADABRA_THRESHOLD*/
const ushort _WIN32_WINNT_WIN10 = 0x0A00; /* ABRACADABRA_THRESHOLD*/
const bool FALSE = false;
static byte LOBYTE(ushort w)
{
return ((byte)(w & 0xff));
}
static byte HIBYTE(ushort w)
{
return ((byte)(w >> 8 & 0xff));
}
[DllImport("kernel32.dll")]
static extern ulong VerSetConditionMask(ulong ConditionMask, uint TypeMask, byte Condition );
[DllImport("kernel32.dll")]
static extern bool VerifyVersionInfoW(ref OSVERSIONINFOEXW lpVersionInformation, uint dwTypeMask, ulong dwlConditionMask);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct OSVERSIONINFOEXW
{
public int dwOSVersionInfoSize;
public int dwMajorVersion;
public int dwMinorVersion;
public int dwBuildNumber;
public int dwPlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szCSDVersion;
public UInt16 wServicePackMajor;
public UInt16 wServicePackMinor;
public UInt16 wSuiteMask;
public byte wProductType;
public byte wReserved;
}
public static bool
IsWindowsVersionOrGreater(ushort wMajorVersion, ushort wMinorVersion, ushort wServicePackMajor)
{
var osvi = new OSVERSIONINFOEXW
{
dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEXW))
};
var dwlConditionMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
osvi.dwMajorVersion = wMajorVersion;
osvi.dwMinorVersion = wMinorVersion;
osvi.wServicePackMajor = wServicePackMajor;
return VerifyVersionInfoW(ref osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}
public static bool
IsWindowsXPOrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0);
}
public static bool
IsWindowsXPSP1OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1);
}
public static bool
IsWindowsXPSP2OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2);
}
public static bool
IsWindowsXPSP3OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3);
}
public static bool
IsWindowsVistaOrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
}
public static bool
IsWindowsVistaSP1OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1);
}
public static bool
IsWindowsVistaSP2OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2);
}
public static bool
IsWindows7OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
}
public static bool
IsWindows7SP1OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1);
}
public static bool
IsWindows8OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
}
public static bool
IsWindows8Point1OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0);
}
public static bool
IsWindowsThresholdOrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0);
}
public static bool
IsWindows10OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0);
}
public static bool
IsWindowsServer()
{
var osvi = new OSVERSIONINFOEXW
{
dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEXW)),
wProductType = VER_NT_WORKSTATION
};
var dwlConditionMask = VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL);
return !VerifyVersionInfoW( ref osvi, VER_PRODUCT_TYPE, dwlConditionMask);
}
}
}
不幸的是,它比这更复杂一些。这些"函数"实际上是在VersionHelpers.h
中定义的宏。
如果你想一下,这是唯一的办法——他们不能在旧的Windows版本中添加功能。
你必须把宏移植到c#。
VersionHelpers函数没有导出到任何dll中,而是定义在VersionHelpers.h文件中。为了在c#代码中使用该功能,您可以从头文件
中复制该功能。导入这两个函数:
[DllImport("kernel32.dll")]
static extern ulong VerSetConditionMask(ulong dwlConditionMask, uint dwTypeBitMask, byte dwConditionMask);
[DllImport("kernel32.dll")]
static extern bool VerifyVersionInfo([In] ref OsVersionInfoEx lpVersionInfo, uint dwTypeMask, ulong dwlConditionMask);
定义以下结构:
[StructLayout(LayoutKind.Sequential)]
struct OsVersionInfoEx
{
public uint OSVersionInfoSize;
public uint MajorVersion;
public uint MinorVersion;
public uint BuildNumber;
public uint PlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string CSDVersion;
public ushort ServicePackMajor;
public ushort ServicePackMinor;
public ushort SuiteMask;
public byte ProductType;
public byte Reserved;
}
然后使用以下函数:
static bool IsWindowsVersionOrGreater(uint majorVersion, uint minorVersion, ushort servicePackMajor)
{
OsVersionInfoEx osvi = new OsVersionInfoEx();
osvi.OSVersionInfoSize = (uint)Marshal.SizeOf(osvi);
osvi.MajorVersion = majorVersion;
osvi.MinorVersion = minorVersion;
osvi.ServicePackMajor = servicePackMajor;
// These constants initialized with corresponding definitions in
// winnt.h (part of Windows SDK)
const uint VER_MINORVERSION = 0x0000001;
const uint VER_MAJORVERSION = 0x0000002;
const uint VER_SERVICEPACKMAJOR = 0x0000020;
const byte VER_GREATER_EQUAL = 3;
ulong versionOrGreaterMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
uint versionOrGreaterTypeMask = VER_MAJORVERSION |VER_MINORVERSION | VER_SERVICEPACKMAJOR;
return VerifyVersionInfo(ref osvi, versionOrGreaterTypeMask, versionOrGreaterMask);
}
不需要使用互操作/非托管代码或添加目标清单。
使用WMI获取Windows操作系统版本
就像前面提到的GetVersionEx和Environment一样。OSVersion文档,GetVersionEx行为/可用性与Windows 8.1改变。(对于。net <5.0环境。OSVersion反映了这一点)VerifyVersionInfo函数也是如此。如果你使用。net 5或Core,你可以直接使用Environment。OSVersion再次,顺便说一下,我的同事在我们的核心项目上工作,排除了使用带有指令的管理对象搜索器查询WMI的代码,因为它没有为核心编译)
另一种方法是使用来自其他答案的PInvoke与这些函数的Windows SDK对应物(来自ntdll.dll)
- RtlGetVersion(可以使用osversioninfo或OSVERSIONINFOEXW结构,它们是非sdk对应的别名。只是要确保在调用它之前设置dwOSVersionInfoSize,以便它知道您引用的是哪个。)
- RtlVerifyVersionInfo
它们使用与kernel23.dll中的函数相同的结构体,并且可以以相同的方式使用(也使用VerSetConditionMask函数作为文档VER_SET_CONDITION宏的替代品,但只有Unicode版本可用,所以一定要用StructLayoutAttribute注释结构体,Charset设置为Charset。Unicode (c#默认为ANSI)
因此,如果使用以下导入,已经发布的代码应该会给出可靠的结果:
(如果你不能或不想使用WMI或注册表)
[DllImport("kernel32.dll")]
private static extern ulong VerSetConditionMask(ulong dwlConditionMask, uint dwTypeBitMask, byte dwConditionMask);
[DllImport("ntdll.dll")]
private static extern uint RtlGetVersion(ref OSVERSIONINFOW lpVersionInformation);
[DllImport("ntdll.dll")]
private static extern uint RtlGetVersion(ref OSVERSIONINFOEXW lpVersionInformation);
[DllImport("ntdll.dll")]
private static extern bool RtlVerifyVersionInfo([In] ref OSVERSIONINFOEXW lpVersionInformation, uint dwTypeMask, ulong dwlConditionMask);