C#으로 Windows의 VT / Hyper-V 활성화 여부 조회하기
처음에는 기존 네이티브 DLL에 COM(Component Object Model) 라이브러리를 추가해 VirtualizationFirmwareEnabled와 HypervisorPresent를 가져오려 했다. 아래 이유로 C#에서 처리하기로 했다.
- COM 초기화: 같은 스레드에서 여러 번 초기화되거나 STA/MTA 모델이 뒤섞일 수 있다.
- COM 보안: 보안 설정이 중복으로 초기화될 수 있다.
- 스레드 관리: Unity의 기본 스레드 모델 때문에 문제가 생길 수 있다.
- P/Invoke와 C++/CLI: DLL을 올바르게 호출하고 데이터를 마샬링하기가 복잡하다.
wmic로 조회
섹션 제목: “wmic로 조회”VT 활성화 조회:
wmic cpu get VirtualizationFirmwareEnabledHyper-V 활성화 조회:
wmic computersystem get HypervisorPresentC# 코드 전문:
// C# 코드 전문
private bool OpenCMDtoGetVirtualizationFirmwareEnabled(){ var process = new Process { StartInfo = new ProcessStartInfo { FileName = "cmd.exe", Arguments = "/c wmic cpu get VirtualizationFirmwareEnabled", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true, Verb = "runas" // 관리자 권한으로 실행 } };
process.Start(); string output = process.StandardOutput.ReadToEnd().Trim(); process.WaitForExit();
Debug.LogWarning($"VirtualizationFirmwareEnabled: {output}"); // 출력 결과 확인
// "VirtualizationFirmwareEnabled"이라는 단어가 포함된 첫 번째 행을 제거 var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (lines.Length > 1) { return lines[1].Equals("TRUE", StringComparison.OrdinalIgnoreCase); }
return false;}
private bool OpenCMDtoGetHypervisorPresent(){ var process = new Process { StartInfo = new ProcessStartInfo { FileName = "cmd.exe", Arguments = "/c wmic computersystem get HypervisorPresent", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true, Verb = "runas" // 관리자 권한으로 실행 } };
process.Start(); string output = process.StandardOutput.ReadToEnd().Trim(); process.WaitForExit();
Debug.LogWarning($"VirtualizationFirmwareEnabled: {output}"); // 출력 결과 확인
// "VirtualizationFirmwareEnabled"이라는 단어가 포함된 첫 번째 행을 제거 var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (lines.Length > 1) { return lines[1].Equals("TRUE", StringComparison.OrdinalIgnoreCase); }
return false;}Windows 버전별 분기
섹션 제목: “Windows 버전별 분기” // Win OS 조회 및 분기
public string IsVirtualizationEnabled(){
OperatingSystem os = Environment.OSVersion; Version version = os.Version;
Debug.LogWarning($"Operating System: {os.Platform}"); Debug.LogWarning($"Version: {version.Major}.{version.Minor}"); Debug.LogWarning($"Service Pack: {os.ServicePack}");
// 운영체제 버전에 따라 분기 처리 if (os.Platform == PlatformID.Win32NT) { switch (version.Major) { case 6 when version.Minor == 1: // Windows 7 { Debug.LogWarning("Operating System: Windows 7"); return IsVirtualizationEnabledByDll(); } case 6 when version.Minor == 2: // Windows 8 { Debug.LogWarning("Operating System: Windows 8"); if (OpenCMDtoGetVirtualizationFirmwareEnabled()) return "On"; return "Off"; } case 6 when version.Minor == 3: // Windows 8.1 { Debug.LogWarning("Operating System: Windows 8.1"); if (OpenCMDtoGetVirtualizationFirmwareEnabled()) return "On"; return "Off"; } case 10 when version.Build >= 22000: // Windows 11 { Debug.LogWarning("Operating System: Windows 11"); if (OpenCMDtoGetVirtualizationFirmwareEnabled()) return "On"; return "Off"; } case 10: Debug.LogWarning("Operating System: Windows 10"); // Windows 10 { if (OpenCMDtoGetVirtualizationFirmwareEnabled()) return "On"; return "Off"; } default: // Unknown Windows Debug.LogWarning("Operating System: Unknown Windows Version"); return "NA"; } }
Debug.LogWarning("Operating System: Non-Windows or Unsupported Version"); // Not Windows return "NA";}Windows 7
섹션 제목: “Windows 7”Windows 7은 버전이 낮아 wmi로 이 값을 조회할 수 없다. 그래서 __cpuid로 직접 조회한다(Intel/AMD).
또한 Windows 7에서는 Hyper-V를 쓸 수 없다. COM 초기화가 필요 없으므로 DLL로 C++ 코드를 호출한다.
bool VirtualizationChecker::IsCpuSupportVirtualization(){ uint32_t signature_reg[3] = { 0 }; if (!cpuid_ex(0, signature_reg, 1)) { return false; }
uint32_t features[4] = { 0 }; cpuid_ex(1, features, 2, 4);
if (signature_reg[0] == 0x756e6547 && signature_reg[1] == 0x6c65746e && signature_reg[2] == 0x49656e69) return features[2] & (1 << 5);
if (signature_reg[0] == 0x68747541 && signature_reg[1] == 0x69746e65 && signature_reg[2] == 0x444d4163) return features[2] & (1 << 2);
return false;}
bool VirtualizationChecker::cpuid_ex(unsigned int leaf, uint32_t* regs, size_t start, size_t end){#if (!defined(__x86_64__) && ! defined(__i386__) && ! defined(_M_IX86) && ! defined(_M_X64)) return false;#elif defined(_MSC_VER) || defined(__INTEL_COMPILER) int x[4]; __cpuid((int*)x, leaf);#elif defined(__clang__) || defined(__GNUC__) unsigned int x[4]; __cpuid(leaf, x[0], x[1], x[2], x[3]);#else static_assert(false, "cpuid_ex: compiler is not supported");#endif
for (; start < end; start++) { *regs++ = static_cast<uint32_t>(x[start]); } return true;}