坊間流傳的代碼都有些問題,比如不能正常擷取win7以上的版本資訊,不能擷取諸如專業版,旗艦版等的資訊,不能正常擷取作業系統位的資訊。
使用代碼,寫了一個簡單的庫來實現效果。用法大概如下:
StringBuilder sb = new StringBuilder(String.Empty);sb.AppendLine("Operation System Information");sb.AppendLine("----------------------------");sb.AppendLine(String.Format("Name = {0}", OSVersionInfo.Name));sb.AppendLine(String.Format("Edition = {0}", OSVersionInfo.Edition));if (OSVersionInfo.ServicePack!=string.Empty)sb.AppendLine(String.Format("Service Pack = {0}", OSVersionInfo.ServicePack));elsesb.AppendLine("Service Pack = None");sb.AppendLine(String.Format("Version = {0}", OSVersionInfo.VersionString));sb.AppendLine(String.Format("ProcessorBits = {0}", OSVersionInfo.ProcessorBits));sb.AppendLine(String.Format("OSBits = {0}", OSVersionInfo.OSBits));sb.AppendLine(String.Format("ProgramBits = {0}", OSVersionInfo.ProgramBits));textBox1.Text = sb.ToString();
對比一下坊間的幾種不足:
總的來說。最大的問題就是不能正確檢測你的作業系統到底是32位還是64位。幾種方法大致如下:
1.使用IntPtr指標的大小
最關鍵的一句代碼是:
return IntPtr.Size * 8;
但是事實上,這個返回的不是作業系統的位元,返回的是啟動並執行程式的位元,如果在64位的windows上以32位的模式運行了這個程式,那麼就會返回32.
2.使用PROCESSOR_ARCHITECTURE 環境變數
string pa = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");return ((String.IsNullOrEmpty(pa) || String.Compare(pa, 0,"x86", 0, 3, true) == 0) ? 32 : 64);
這就是純粹的誤導了,因為和1的情況一樣。不能返回處理器的位元而是返回了運行程式的位元,如果在64位的windows上以32位的模式運行了這個程式,那麼就會返回32.
3. 使用PInvoke 和 GetSystemInfo
注意:為了保持文章不要太長。。我沒有包括PInvoke API的聲明,(譯者註:C#的互通性嘛),但你可能在我提供的原始碼裡找到。
ProcessorArchitecture pbits = ProcessorArchitecture.Unknown;try{SYSTEM_INFO l_System_Info = new SYSTEM_INFO();GetSystemInfo(ref l_System_Info);switch (l_System_Info.uProcessorInfo.wProcessorArchitecture){case 9: // PROCESSOR_ARCHITECTURE_AMD64pbits = ProcessorArchitecture.Bit64;break;case 6: // PROCESSOR_ARCHITECTURE_IA64pbits = ProcessorArchitecture.Itanium64;break;case 0: // PROCESSOR_ARCHITECTURE_INTELpbits = ProcessorArchitecture.Bit32;break;default: // PROCESSOR_ARCHITECTURE_UNKNOWNpbits = ProcessorArchitecture.Unknown;break;}}catch{Ignore }return pbits;
老問題,還是會返回運行程式的位元,而不是作業系統/處理器的位元。
4.使用PInvoke和GetNativeSystemInfo
我看到過有人說上面的都不可信。可以使用GetNativeSystemInfo代替,代碼和上面一樣,只是把GetSystemInfo換成GetNativeSystemInfo就好。
結果不一樣了。但是。。。這個API返回了處理器本身的位元,而我對作業系統的位元感興趣。。畢竟64位的處理器上也可以輕鬆運行32位的作業系統
5.組合 IntPtr.Size 和 IsWow64Process
static public SoftwareArchitecture OSBits{get{SoftwareArchitecture osbits = SoftwareArchitecture.Unknown;switch (IntPtr.Size * 8){case 64:osbits = SoftwareArchitecture.Bit64;break;case 32:if (Is32BitProcessOn64BitProcessor())osbits = SoftwareArchitecture.Bit64;elseosbits = SoftwareArchitecture.Bit32;break;default:osbits = SoftwareArchitecture.Unknown;break;}return osbits;}}private static IsWow64ProcessDelegate GetIsWow64ProcessDelegate(){IntPtr handle = LoadLibrary("kernel32");if (handle != IntPtr.Zero){IntPtr fnPtr = GetProcAddress(handle, "IsWow64Process");if (fnPtr != IntPtr.Zero){return (IsWow64ProcessDelegate)Marshal.GetDelegateForFunctionPointer((IntPtr)fnPtr,typeof(IsWow64ProcessDelegate));}}return null;}private static bool Is32BitProcessOn64BitProcessor(){IsWow64ProcessDelegate fnDelegate = GetIsWow64ProcessDelegate();if (fnDelegate == null){return false;}bool isWow64;bool retVal = fnDelegate.Invoke(Process.GetCurrentProcess().Handle, out isWow64);if (retVal == false){return false;}return isWow64;}
如果IntPtr是64.作業系統必然也是64位,因為你不能在32位的作業系統上運行64位的程式
如果程式在32位元模式下運行,代碼會檢測是否是64位的處理器,而程式在32位元模式下運行來判斷是32位還是64位。
如果返回的是64,那麼作業系統是64位,但是程式以32位的模式運行,如果是32,那麼作業系統也是32.
最後,我在lib裡還加入了一些方法。以便區分程式/作業系統/處理器的位元。
譯自http://www.codeproject.com/Articles/73000/Getting-Operating-System-Version-Info-Even-for-Win,有刪減。