C# で Acme::x86::CPUID を作りました

C#のように実行環境が高度に抽象化された言語でプログラミングしているとき、実行マシンのCPUを判別してプログラムの処理を分岐したいときがよくでてくると思います。
そういうときに困ってしまわないように Acme::x86::CPUID みたいなのを作ってみました。

using System;
using System.Runtime.InteropServices;

class Acme_x86_CPUID
{
    [DllImport("user32")]
    private extern static UInt32 EnumWindows(UInt32 p, UInt32 lParam);
    [DllImport("kernel32")]
    private extern static UInt32 VirtualAlloc( IntPtr lpAddress, UInt32 dwSize, UInt32 flAllocationType, UInt32 flProtect );
    [DllImport("kernel32")]
    private extern static bool VirtualFree(UInt32 lpAddress, UInt32 dwSize, UInt32 dwFreeType);
    private const UInt32 MEM_COMMIT = 0x1000;
    private const UInt32 MEM_RELEASE = 0x8000;
    private const UInt32 PAGE_EXECUTE_READWRITE = 0x40;

    public static string ProcessorBrandString()
    {
        string Result;
        byte[] cpu = new byte[48];
        IntPtr pcpu = Marshal.AllocHGlobal(48);
        Marshal.Copy(new byte[48], 0, pcpu, 48);

        byte[] x86 = 
        {
            0x53, 0xbf, 0x00, 0x00, 0x00, 0x00, 
            0xb8, 0x02, 0x00, 0x00, 0x80, 
            0x50, 0x0f, 0xa2, 0x89, 0x07, 0x89, 
            0x5f, 0x04, 0x89, 0x4f, 0x08, 0x89, 
            0x57, 0x0c, 0x8d, 0x7f, 0x10, 0x58, 
            0x8d, 0x40, 0x01, 
            0x50, 0x0f, 0xa2, 0x89, 0x07, 0x89, 
            0x5f, 0x04, 0x89, 0x4f, 0x08, 0x89, 
            0x57, 0x0c, 0x8d, 0x7f, 0x10, 0x58, 
            0x8d, 0x40, 0x01, 
            0x50, 0x0f, 0xa2, 0x89, 0x07, 0x89, 
            0x5f, 0x04, 0x89, 0x4f, 0x08, 0x89, 
            0x57, 0x0c, 0x8d, 0x7f, 0x10, 0x58, 
            0x8d, 0x40, 0x01, 
            0x5b, 0x33, 0xc0, 0xc2, 0x08, 0x00, 
        };
        Marshal.WriteIntPtr(x86, 2, pcpu);

        UInt32 px86 = VirtualAlloc( IntPtr.Zero, (uint)x86.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        Marshal.Copy(x86, 0, (IntPtr)px86, x86.Length);
        try
        {
            EnumWindows(px86, 0);
            Marshal.Copy(pcpu, cpu, 0, cpu.Length);
        }
        finally
        {
            Result = System.Text.Encoding.ASCII.GetString( cpu );
            VirtualFree(px86, 0, MEM_RELEASE);
            Marshal.FreeHGlobal(pcpu);
        }
        return Result;
    }
}

[DllImport]はC#に標準でサポートされているとっても便利な構文です。
Acme_x86_CPUID は 100% Pure C# で書かれているため、別途Perlモジュールのインストールやunsafeコンテキストを使用する必要がありません。

■ 実行結果
以下、手元にある単一の環境で Acme_x86_CPUID::ProcessorBrandString の値を調べてみました。
Windows Vistax86環境で動作確認しましたが、それ以外の環境ではシステムがクラッシュする可能性がありますので実行はお勧めしません。
1. Windows Vista(32bit) - ブログを書いているノートPC

Intel(R) Core(TM)2 Duo CPU     T8100  @ 2.10GHz

■ まとめ
次回まっちゃ139で発表の機会があれば、この辺の DllImport を活用した基礎的なテクニックを簡単にお話ししようと思います。
Shibuya.pmよりも低レベルな内容ですので、アセンブラやDynaLoaderに詳しくない人でも安心して聞けると思います。どうぞご安心ください。