[C#

这次是笔记电脑的内存容量资讯,首先,如果是一些基本的电脑资讯,如主机名称,网域,可以透过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 Architecture 与 WMI 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 function 与 GetPhysicallyInstalledSystemMemory 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));
            }
}

/// 
/// Windows 2000与XP适用GlobalMemoryStatusEx
/// 
/// 
/// 
[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;
}



/// 
/// NT适用GlobalMemoryStatus
/// 

/// 
[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() 函数行为


文章中的叙述如有观念不正确错误的部分,欢迎告知指正 谢谢 =)

另外要转载请附上出处 感谢