程序检测系统是bios引导还是uefi引导
//百度很多资料都没有找到, 终于在谷歌上找到很多有用的资料了, 最后在微软的网站找到最有用的资料了.
//判断流程可以这样:
//1, 支持efi引导的//只有win7及以上, 所以xp, 03系统就只能够bios引导
//2, win7,8,8.1,10等系统, 可以用下面的代码, 本质上就是GetFirmwareEnvironmentVariableA, 或者GetFirmwareType这两个api的调用
#include <Windows.h>
#include <Winbase.h> //GetFirmwareEnvironmentVariableA 和 GetFirmwareType的头文件
#include <iostream>
using namespace std;
void main()
{
//For Windows 8/Server 2012 and above可用
/*
typedef enum _FIRMWARE_TYPE {
FirmwareTypeUnknown = 0,
FirmwareTypeBios = 1,
FirmwareTypeUefi = 2,
FirmwareTypeMax = 3
} FIRMWARE_TYPE, *PFIRMWARE_TYPE;
*/
FIRMWARE_TYPE a;
GetFirmwareType(&a);
switch (a)
{
case FirmwareTypeUnknown:
cout << "不知名引导" << endl; break;
case FirmwareTypeBios:
cout << "Bios引导" << endl; break;
case FirmwareTypeUefi:
cout << "Uefi引导" << endl; break;
case FirmwareTypeMax:
cout << "Not implemented" << endl; break;
}
//Windows 7/Server 2008R2 and above可用
GetFirmwareEnvironmentVariableA("", "{00000000-0000-0000-0000-000000000000}", NULL, 0);
if (GetLastError() == ERROR_INVALID_FUNCTION)
//API not supported; this is a legacy BIOS
cout << "Bios引导" << endl;
else
//API error (expected) but call is supported.This is UEFI.
cout << "Uefi引导" << endl;
system("pause");
}
/
下面贴上找到的最好的微软资料(三个办法判断bios和efi引导)
https://gallery.technet.microsoft.com/scriptcenter/Determine-UEFI-or-Legacy-7dc79488
http://www.upanok.com/jiaocheng/115.html
UEFI boot: how does that actually work, then?
https://www.happyassassin.net/2014/01/25/uefi-boot-how-does-that-actually-work-then/
BIOS Mode - See if Windows Boot in UEFI or Legacy Mode
http://www.eightforums.com/tutorials/29504-bios-mode-see-if-windows-boot-uefi-legacy-mode.html
<#
This script shows three methods to determine the underlying system firmware (BIOS) type - either UEFI or Legacy BIOS.
The first method relies on the fact that Windows setup detects the firmware type as a part of the Windows installation
routine and records its findings in the setupact.log file in the \Windows\Panther folder. It's a trivial task to use
Select-String to extract the relevent line from this file and to pick off the (U)EFI or BIOS keyword it contains.
To do a proper job there are two choices; both involve using Win32 APIs which we call from PowerShell through a compiled
(Add-Type) class using P/Invoke.
For Windows 7/Server 2008R2 and above, the GetFirmwareEnvironmentVariable Win32 API (designed to extract firmware environment
variables) can be used. This API is not supported on non-UEFI firmware and will fail in a predictable way when called - this
will identify a legacy BIOS. On UEFI firmware, the API can be called with dummy parameters, and while it will still fail
(probably!) the resulting error code will be different from the legacy BIOS case.
For Windows 8/Server 2012 and above there's a more elegant solution in the form of the GetFirmwareType() API. This
returns an enum (integer) indicating the underlying firmware type.
Chris Warwick, @cjwarwickps, September 2013
chrisjwarwick.wordpress.com
#>
# First method, one-liner, extract answer from setupact.log using Select-String and tidy-up with -replace
# Look in the setup logfile to see what bios type was detected (EFI or BIOS)
(Select-String 'Detected boot environment' C:\Windows\Panther\setupact.log -AllMatches ).line -replace '.*:\s+'
<#
Second method, use the GetFirmwareEnvironmentVariable Win32 API.
From MSDN (http://msdn.microsoft.com/en-ca/library/windows/desktop/ms724325%28v=vs.85%29.aspx):
"Firmware variables are not supported on a legacy BIOS-based system. The GetFirmwareEnvironmentVariable function will
always fail on a legacy BIOS-based system, or if Windows was installed using legacy BIOS on a system that supports both
legacy BIOS and UEFI.
"To identify these conditions, call the function with a dummy firmware environment name such as an empty string ("") for
the lpName parameter and a dummy GUID such as "{00000000-0000-0000-0000-000000000000}" for the lpGuid parameter.
On a legacy BIOS-based system, or on a system that supports both legacy BIOS and UEFI where Windows was installed using
legacy BIOS, the function will fail with ERROR_INVALID_FUNCTION. On a UEFI-based system, the function will fail with
an error specific to the firmware, such as ERROR_NOACCESS, to indicate that the dummy GUID namespace does not exist."
From PowerShell, we can call the API via P/Invoke from a compiled C# class using Add-Type. In Win32 any resulting
API error is retrieved using GetLastError(), however, this is not reliable in .Net (see
blogs.msdn.com/b/adam_nathan/archive/2003/04/25/56643.aspx), instead we mark the pInvoke signature for
GetFirmwareEnvironmentVariableA with SetLastError=true and use Marshal.GetLastWin32Error()
Note: The GetFirmwareEnvironmentVariable API requires the SE_SYSTEM_ENVIRONMENT_NAME privilege. In the Security
Policy editor this equates to "User Rights Assignment": "Modify firmware environment values" and is granted to
Administrators by default. Because we don't actually read any variables this permission appears to be optional.
#>
Function IsUEFI {
<#
.Synopsis
Determines underlying firmware (BIOS) type and returns True for UEFI or False for legacy BIOS.
.DESCRIPTION
This function uses a complied Win32 API call to determine the underlying system firmware type.
.EXAMPLE
If (IsUEFI) { # System is running UEFI firmware... }
.OUTPUTS
[Bool] True = UEFI Firmware; False = Legacy BIOS
.FUNCTIONALITY
Determines underlying system firmware type
#>
[OutputType([Bool])]
Param ()
Add-Type -Language CSharp -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
public class CheckUEFI
{
[DllImport("kernel32.dll", SetLastError=true)]
static extern UInt32
GetFirmwareEnvironmentVariableA(string lpName, string lpGuid, IntPtr pBuffer, UInt32 nSize);
const int ERROR_INVALID_FUNCTION = 1;
public static bool IsUEFI()
{
// Try to call the GetFirmwareEnvironmentVariable API. This is invalid on legacy BIOS.
GetFirmwareEnvironmentVariableA("","{00000000-0000-0000-0000-000000000000}",IntPtr.Zero,0);
if (Marshal.GetLastWin32Error() == ERROR_INVALID_FUNCTION)
return false; // API not supported; this is a legacy BIOS
else
return true; // API error (expected) but call is supported. This is UEFI.
}
}
'@
[CheckUEFI]::IsUEFI()
}
<#
Third method, use GetFirmwareTtype() Win32 API.
In Windows 8/Server 2012 and above there's an API that directly returns the firmware type and doesn't rely on a hack.
GetFirmwareType() in kernel32.dll (http://msdn.microsoft.com/en-us/windows/desktop/hh848321%28v=vs.85%29.aspx) returns
a pointer to a FirmwareType enum that defines the following:
typedef enum _FIRMWARE_TYPE {
FirmwareTypeUnknown = 0,
FirmwareTypeBios = 1,
FirmwareTypeUefi = 2,
FirmwareTypeMax = 3
} FIRMWARE_TYPE, *PFIRMWARE_TYPE;
Once again, this API call can be called in .Net via P/Invoke. Rather than defining an enum the function below
just returns an unsigned int.
#>
# Windows 8/Server 2012 or above:
Function Get-BiosType {
<#
.Synopsis
Determines underlying firmware (BIOS) type and returns an integer indicating UEFI, Legacy BIOS or Unknown.
Supported on Windows 8/Server 2012 or later
.DESCRIPTION
This function uses a complied Win32 API call to determine the underlying system firmware type.
.EXAMPLE
If (Get-BiosType -eq 1) { # System is running UEFI firmware... }
.EXAMPLE
Switch (Get-BiosType) {
1 {"Legacy BIOS"}
2 {"UEFI"}
Default {"Unknown"}
}
.OUTPUTS
Integer indicating firmware type (1 = Legacy BIOS, 2 = UEFI, Other = Unknown)
.FUNCTIONALITY
Determines underlying system firmware type
#>
[OutputType([UInt32])]
Param()
Add-Type -Language CSharp -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
public class FirmwareType
{
[DllImport("kernel32.dll")]
static extern bool GetFirmwareType(ref uint FirmwareType);
public static uint GetFirmwareType()
{
uint firmwaretype = 0;
if (GetFirmwareType(ref firmwaretype))
return firmwaretype;
else
return 0; // API call failed, just return 'unknown'
}
}
'@
[FirmwareType]::GetFirmwareType()
}
# An electron is pulled-up for speeding. The policeman says, “Sir, do you realise you were travelling at 130mph?” The electron says, “Oh great, now I’m lost.”