Why does GetFirmwareEnvironmentVariable exist on a BIOS-based PC?

Norman Diamond 101 Reputation points
2021-11-20T15:54:55.653+00:00

https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfirmwareenvironmentvariablew

"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."

But GetFirmwareEnvironmentVariable DIDN'T fail with ERROR_INVALID_FUNCTION. It failed with ERROR_PRIVILEGE_NOT_HELD. This made my program think the PC is UEFI-based. How can I detect that the PC is BIOS-based?

I think the MSDN document used to be correct in the past but a Windows Update broke it. How can I detect that the PC is BIOS-based?

Windows development | Windows API - Win32
{count} votes

Accepted answer
  1. Norman Diamond 101 Reputation points
    2021-11-22T11:42:15.897+00:00

    One PC has both Windows 7 and Windows 10 1703 installed (selectable by Windows 10's boot manager). In both, when running elevated as Administrator but not enabling SE_SYSTEM_ENVIRONMENT_NAME, MSDN's suggested attempt to call GetFirmwareEnvironmentVariable returns ERROR_INVALID_FUNCTION so I detect that the PC is BIOS-based.

    (On that PC, Windows 10 repeatedly downloaded and failed to install newer versions of Windows 10 because of the display adapter, so I hid those updates.)

    Some time after that, a Windows Update broke MSDN's code.

    Yes the fix was to enable SE_SYSTEM_ENVIRONMENT_NAME. My program works now in Windows 7 (BIOS), Windows 10 1703 (BIOS), Windows 10 21H1 (BIOS), and Windows 10 21H1 (UEFI). I get ERROR_INVALID_FUNCTION on BIOS-based PCs. I didn't inspect what error is set in Windows 10 21H1 (UEFI) since the dummy firmware variable doesn't exist, but it wasn't ERROR_INVALID_FUNCTION so I detect that the PC is UEFI-based.

    I still wonder why.

    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. RLWA32 49,551 Reputation points
    2021-11-21T10:36:30.023+00:00

    The documentation for the function indicates that "To read a firmware environment variable, the user account that the app is running under must have the SE_SYSTEM_ENVIRONMENT_NAME privilege."

    In my quick tests the process calling the function must have the privilege (e.g., running as Administrator) AND the privilege must be enabled in the token before the function is called. If this is not done the function returns ERROR_PRIVILEGE_NOT_HELD. When the privilege is present and enabled then the function returns ERROR_INVALID_FUNCTION.

    0 comments No comments

  2. Norman Diamond 101 Reputation points
    2021-11-21T11:21:21.387+00:00

    'The documentation for the function indicates that "To read a firmware environment variable [...]"'

    On a BIOS-based PC there are no firmware environment variables. Meanwhile according to MSDN the function GetFirmwareEnvironmentVariable doesn't even exist if Windows was installed on a legacy BIOS. I don't actually need to read the value of a non-existent dummy variable when attempting the call that MSDN says to do; I just need to find out if the function exists or not the way MSDN says to do.

    Furthermore MSDN's suggested code used to work. Why did MSDN's code stop working? Why did a Windows Update add a function on BIOS-based Windows installations that isn't supposed to exist on BIOS-based Windows installations?


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.