Calling the __cpuid MSVC function via C# a DLL Pinvoke (C++, C#)

Here is the latest piece of code I wish to share with everyone since I run into this myself, I am sure others will be interested also.

The C++ Part

Firstly you will need to create a new DLL project in Visual Studio. You will also need to add this line into the cpp file for your project:

[cc lang=”c++”]#include [/cc]

This will allow you to access the intrinsic __cpuid call.

Next, I use a custom structure to hold the data returned by the function call. I do this mainly for readability since it helps when referencing. The code for the structure is as follows and should be added to the header file.

[cc lang=”c++”]struct CPUInfo
{
int EAX;
int EBX;
int ECX;
int EDX;
};[/cc]

Simple enough eh? Good. Now we need to construct a function call that will wrap the results from a __cpuid call into the structure above. Again, this is quite simple:

[cc lang=”c++”]extern “C” __declspec(dllexport) CPUInfo cpuID(int infoType)
{
CPUInfo i;
int results[4] = { 0, 0, 0, 0 };
__try
{
__cpuid(results, infoType);
}
__except (EXCEPTION_EXECUTE_HANDLER) {}

i.EAX = results[0];
i.EBX = results[1];
i.ECX = results[2];
i.EDX = results[3];

return i;
}[/cc]

Finally you will need the following function definition for the header file:

[cc lang=”c++”]extern “C” __declspec(dllexport) CPUInfo cpuID(int infoType);[/cc]

As you can see. The above function also checks for any exceptions – it needs this as some older CPUs do not support the cpuid call. In these cases it will simply return a CPUInfo structure filled with 0’s so that the code doesn’t break anything.

Now. You will need to compile the DLL and then you can use it in your C# project using the following method.

The C# Part

First. Create an analogue of the C++ CPUInfo class in C#. This is really simple to do and the following is what is needed, for those who do not wish to try themselves:

[cc lang=”c#”][StructLayout(LayoutKind.Sequential)]
struct CPUInfo
{
public int EAX;
public int EBX;
public int ECX;
public int EDX;
}[/cc]

Finally you will need the pinvoke definition. Depending on the name of the DLL (I called mine HardwareInfo.dll) the following code will be slightly different:

[cc lang=”c#”]///

/// This pinvoke method will return the result from a __cpuid call, if supported.
///

/// A code that indicates what information this instruction retrieves. /// A CPUInfo structure giving the result from the query, or an empty structure if not supported.
[DllImport(“HardwareInfo.dll”, CallingConvention = CallingConvention.Cdecl)]
public static extern CPUInfo _cpuid(uint infoType);[/cc]

Hopefully that wasn’t too bad. Here is an example of how you would use the above code:

[cc lang=”c#”]CPUInfo example = cpuID(0x00000000);
uint maxSupportedStandardLevels = (uint)(example.EAX & 0xffff);[/cc]

The above code will tell you the maximum supported level of call that is supported on the current processor.

Notes:

Just remember that you will need to add a reference to the System.Runtime.InteropServices namespace if you are going to use this code.

As always, comments, improvements and suggestions are welcome.

Leave a comment

Your email address will not be published. Required fields are marked *