C# Programming/The .NET Framework/Marshalling

The .NET Framework currently supports calling unmanaged functions and using unmanaged data, a process called marshalling. This is often done to use Windows API functions and data structures, but can also be used with custom libraries.

GetSystemTimes

edit

A simple example to start with is the Windows API function GetSystemTimes. It is declared as:

BOOL WINAPI GetSystemTimes(
  __out_opt  LPFILETIME lpIdleTime,
  __out_opt  LPFILETIME lpKernelTime,
  __out_opt  LPFILETIME lpUserTime
);

LPFILETIME is a pointer to a FILETIME structure, which is simply a 64-bit integer. Since C# supports 64-bit numbers through the long type, we can use that. We can then import and use the function as follows:

using System;
using System.Runtime.InteropServices;

public class Program
{
    [DllImport("kernel32.dll")]
    static extern bool GetSystemTimes(out long idleTime, out long kernelTime, out long userTime);
    
    public static void Main()
    {
        long idleTime, kernelTime, userTime;
        
        GetSystemTimes(out idleTime, out kernelTime, out userTime);
        Console.WriteLine("Your CPU(s) have been idle for: " + (new TimeSpan(idleTime)).ToString());
        Console.ReadKey();
    }
}

Note that the use of out or ref in parameters automatically makes it a pointer to the unmanaged function.

GetProcessIoCounters

edit

To pass pointers to structs, we can use the out or ref keyword:

using System;
using System.Runtime.InteropServices;

public class Program
{
    struct IO_COUNTERS
    {
        public ulong ReadOperationCount;
        public ulong WriteOperationCount;
        public ulong OtherOperationCount;
        public ulong ReadTransferCount;
        public ulong WriteTransferCount;
        public ulong OtherTransferCount;
    }

    [DllImport("kernel32.dll")]
    static extern bool GetProcessIoCounters(IntPtr ProcessHandle, out IO_COUNTERS IoCounters);

    public static void Main()
    {
        IO_COUNTERS counters;

        GetProcessIoCounters(System.Diagnostics.Process.GetCurrentProcess().Handle, out counters);
        Console.WriteLine("This process has read " + counters.ReadTransferCount.ToString("N0") + 
            " bytes of data.");
        Console.ReadKey();
    }
}