If you want to check if you are running on a Server Core edition of Windows you can use the GetProductInfo API.

GetProductInfo takes 4 input parameters that can be obtained using GetVersionEx and the OSVERSIONINFOEX structure:

objectpascal Download
var
  osvi: OSVERSIONINFOEX;
begin
  ZeroMemory(@osvi, SizeOf(osvi));
  osvi.dwOSVersionInfoSize := SizeOf(osvi);
  Win32Check(GetVersionEx(osvi));

No we call GetProductInfo:

objectpascal Download
var
  dwProdType: DWORD;
begin
  Win32Check(GetProductInfo(osvi.dwMajorVersion, osvi.dwMinorVersion,
    osvi.wServicePackMajor, osvi.wServicePackMinor, dwProdType));

 

 

The value returned in dwProdType can be checked against one of the constants for the Server Core editions:

objectpascal Download
    PRODUCT_DATACENTER_SERVER_CORE,
    PRODUCT_STANDARD_SERVER_CORE,
    PRODUCT_ENTERPRISE_SERVER_CORE,
    PRODUCT_WEB_SERVER_CORE,
    PRODUCT_DATACENTER_SERVER_CORE_V,
    PRODUCT_STANDARD_SERVER_CORE_V,
    PRODUCT_ENTERPRISE_SERVER_CORE_V,
    PRODUCT_STORAGE_EXPRESS_SERVER_CORE,
    PRODUCT_STORAGE_STANDARD_SERVER_CORE,
    PRODUCT_STORAGE_WORKGROUP_SERVER_CORE,
    PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE,
    PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE,
    PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE,
    PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE

So if put this all together we can write a function for it:

objectpascal Download
function IsServerCore: Boolean;
var
  osvi: OSVERSIONINFOEX;
  dwProdType: DWORD;
begin
  ZeroMemory(@osvi, SizeOf(osvi));
  osvi.dwOSVersionInfoSize := SizeOf(osvi);
  Win32Check(GetVersionEx(osvi));

  Win32Check(GetProductInfo(osvi.dwMajorVersion, osvi.dwMinorVersion,
    osvi.wServicePackMajor, osvi.wServicePackMinor, dwProdType));

  case dwProdType of
    PRODUCT_DATACENTER_SERVER_CORE,
    PRODUCT_STANDARD_SERVER_CORE,
    PRODUCT_ENTERPRISE_SERVER_CORE,
    PRODUCT_WEB_SERVER_CORE,
    PRODUCT_DATACENTER_SERVER_CORE_V,
    PRODUCT_STANDARD_SERVER_CORE_V,
    PRODUCT_ENTERPRISE_SERVER_CORE_V,
    PRODUCT_STORAGE_EXPRESS_SERVER_CORE,
    PRODUCT_STORAGE_STANDARD_SERVER_CORE,
    PRODUCT_STORAGE_WORKGROUP_SERVER_CORE,
    PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE,
    PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE,
    PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE,
    PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE: Result := True
  else
    Result := False;
  end;
end;

But where do these values come from?

GetProductInfo is exported by Kernel32.dll, this function is a stub to RtlGetProductInfo which is exported by ntdll.dll

RtlGetProductInfo performs a few checks on the input parameters and then calls the undocumented NtQueryLicenseValue API which has this signature:

objectpascal Download
function NtQueryLicenseValue(Name: PUNICODE_STRING; ulType: ULONG;
  Buffer: Pointer; Length: ULONG; var DataLength: ULONG): NTSTATUS; stdcall;

The value of the Name parameter on my Windows 7 machine is Kernel-ProductInfo, the ulType parameter is SL_DATA_DWORD (4), the buffer is a PDWORD with Length being SizeOf(DWORD).

If the call to NtQueryLicenseValue fails, a special value of 0xABCDABCDu is returned which equals PRODUCT_UNLICENSED.

You can directly check this value with the Licensing Demo from my Having fun with Windows Licensing article:

SNAGHTML6063f2