[C# | Net1.1]回到.Net1.1與NT-取得電腦實體記憶體容量-WMI查詢與使用Win32 API

這次是筆記電腦的記憶體容量資訊,首先,如果是一些基本的電腦資訊,如主機名稱,網域,可以透過System.Enviroment取得。

但是電腦的記憶體,CPU型號等資訊,則需要透過別的類別提供,而基本上,.Net1.1有提供WMI的方式去調用到Win32API的方法,來取得,但是若是沒有WMI的話,如Windows NT作業系統,則需要透過Interop的方式取得,而以下分別來介紹。

前言

 


 

這次是筆記電腦的記憶體容量資訊,首先,如果是一些基本的電腦資訊,如主機名稱,網域,可以透過System.Enviroment取得。

但是電腦的記憶體,CPU型號等資訊,則需要透過別的類別提供,而基本上,.Net1.1有提供WMI的方式去調用到Win32API的方法,來取得,但是若是沒有WMI的話,如Windows NT作業系統,則需要透過Interop的方式取得,而以下分別來介紹。

 

第一種方式通用方法-透過WMI去Query

 


 

基本上在.Net1.1的時候就有提供一個功能,是透過Windows的服務-WMI這支程式去做Query取得如作業系統資訊或是裝置資訊等等,甚至更多。

WMI Services

 

而在程式中也能使用,像是VBScript,C++,VB.Net與C#都可以調用此服務,並且在.Net1.1就支援。

而在.Net1.1中,是透過使用System.Managemnet 這個Namespace下的元件來做調用,可以看參考WMI .NET ArchitectureWMI Queries

而使用System.Managemnet ,其時便是去查詢Win32 API的類別,如這邊我們要取得的電腦上所插的記憶體,便可以使用 Win32_PhysicalMemory class 來查詢,範例如下:

ObjectQuery winQuery = new ObjectQuery("SELECT * FROM Win32_PhysicalMemory ");

ManagementObjectSearcher searcher = new ManagementObjectSearcher(winQuery);

foreach (ManagementObject item in searcher.Get())
{

        Console.WriteLine("Total Physical Memory = " + Convert.ToInt32(item["Capacity"])/1024/1024); //取得的是Bytes單位,所以換算成MB
}

因此,透過WMI這個服務,是可以做到許多事情的,不過因為是調用外部的服務,所以在介面的溝通上,會有效能的影響。

 

 

第二種方式-使用ComputerInfo類別

 


 

這個類別是在.Net 2.0的時後推出的,其中所在的Namespace是 Microsoft.VisualBasic.Devices ,因此如果C#要使用,需要參考 Mircosoft.VisualBasic,如下:

Console.WriteLine(ComputerInfo.TotalPhysicalMemory);

 

 

第三種方式-調用Win32 API (沒有WMI服務的情況下)

 


 

第三種方式也是我使用的方式,因為我會在NT的作業系統上執行程式,所以需要考慮到,Windows NT沒有WMI這個服務的狀況,事實上,WMI是從Windows 2000好像才出來的產生,雖然NT可以從官網上下載軟體安裝,彈事也有其額外需求,如下:

For Windows 98 and Windows NT 4.0, WMI is available as an Internet download from http://www.microsoft.com/downloads. Search for the download “Windows Management Instrumentation (WMI) CORE 1.5 (Windows 95/98/NT 4.0).”

Note that Windows NT 4.0 requires Service Pack 4 or later before you can install and run WMI.

Additional software requirements for WMI include:

  1. Microsoft® Internet Explorer version 5.0 or later.

  2. Windows Script Host (WSH). WSH ships with Windows 2000, Windows XP, Windows Server 2003, and Windows Me, but not with Windows NT4 or Windows 98. You can download WSH from http://www.microsoft.com/downloads. The latest version -- which ships with Windows XP and Windows Server 2003 -- is WSH 5.6.

 

所以NT要上到sp4 而且要IE5以上,而且還需安裝WSH,此種條件無法保證真實的機器上會有,而且再來重點是,此軟體的載點貌似已經死掉…所以要下載再上上去也有難度QQ

因此,不如使用Win32 API調用,就不會有上述問題了,那麼開始正題吧!

 

在Win32 API中有兩個方法可以取得記憶體的資訊,分別是GlobalMemoryStatusEx functionGetPhysicallyInstalledSystemMemory function ,其中 GetPhysicallyInstalledSystemMemory 比較簡易,是直接回傳,但是本人因為需要其他資訊,所以改採用 GlobalMemoryStatusEx,因為此方法取回的資訊是一個名為 MEMORYSTATUSEX 的結構,裡面可以得到虛擬記憶體、分頁等資訊,而非只有安插的記憶體大小。

 

但是,如果有注意到,便會發現文件中還有一個方法是叫 GlobalMemoryStatus function ! 而且也有一個類似的結構,叫做 MEMORYSTATUS ,結構中的資訊也一樣,所以換句話說拿到的應該是一樣的資訊才對?

 

GlobalMemoryStatusEx 與 GlobalMemoryStatus 的差異

 

這兩個方法的差異,可以參考這篇官網文章 ,其差異也是早期作業系統的一些硬體狀況與後來的差異,使的資料會溢位所導致錯誤,因此如果是NT以前的系統是使用GlobalMemoryStatus 方法,而2000以後的系統則是使用GlobalMemoryStatusEx  方法。

 

所以程式分成兩個方法。

首先是GlobalMemoryStatusEx 調用,如下:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MEMORYSTATUSEX
{
            public uint dwLength;
            public uint dwMemoryLoad;
            public ulong ullTotalPhys;
            public ulong ullAvailPhys;
            public ulong ullTotalPageFile;
            public ulong ullAvailPageFile;
            public ulong ullTotalVirtual;
            public ulong ullAvailVirtual;
            public ulong ullAvailExtendedVirtual;
            public MEMORYSTATUSEX()
            {
                this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
            }
}

/// <summary>
/// Windows 2000與XP適用GlobalMemoryStatusEx
/// </summary>
/// <param name="lpBuffer"></param>
/// <returns></returns>
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);

 

而GlobalMemoryStatus 則是:

public struct MEMORYSTATUS
{
            public uint dwLength;
            public uint dwMemoryLoad;
            public uint dwTotalPhys;
            public uint dwAvailPhys;
            public uint dwTotalPageFile;
            public uint dwAvailPageFile;
            public uint dwTotalVirtual;
            public uint dwAvailVirtual;
}



/// <summary>
/// NT適用GlobalMemoryStatus
/// </summary>

/// <param name="lpBuffer"></param>
[DllImport("kernel32.dll", SetLastError=true)]
public static extern void GlobalMemoryStatus (ref MEMORYSTATUS lpBuffer);

 

真的要感謝Net1.1就有Interop

 

 

參考資料

GlobalMemoryStatusEx (kernel32)

ComputerInfo.TotalPhysicalMemory Property

Using WMI

WMI .NET Architecture

WMI Queries

WMI Tasks: Computer Hardware

Win32_PhysicalMemory class

How to get the size of available system memory?

GlobalMemoryStatus function

GlobalMemoryStatusEx function

GetPhysicallyInstalledSystemMemory function

GlobalMemoryStatus Reference in C#, VB.NET and VB6

在一個以上的 2 GB RAM 的系統上的資訊: GlobalMemoryStatus() 函式行為

 


 

文章中的敘述如有觀念不正確錯誤的部分,歡迎告知指正 謝謝 =)

另外要轉載請附上出處 感謝