MathGroup Archive 2010

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Calling kernel.dll from Mathematica

  • To: mathgroup at smc.vnet.net
  • Subject: [mg108446] Re: Calling kernel.dll from Mathematica
  • From: Todd Gayley <tgayley at wolfram.com>
  • Date: Thu, 18 Mar 2010 04:32:01 -0500 (EST)

At 04:46 AM 3/16/2010, Alexey Popkov wrote:
>Hello,
>There are nice examples in the Documentstion on calling simple functions
>defined in the Windows's kernel.dll from Mathematica. For example, it is
>easy to call GetTickCount function:
>
>Needs["NETLink`"]
>getTickCount == DefineDLLFunction["GetTickCount", "kernel32.dll", "int", {}]
>
>But I have not found any example on calling a function that returns a
>structure. I am interested in use GlobalMemoryStatusEx function that
>"retrieves information about the system's current usage of both physical and
>virtual memory." In C# it is easy to get this information in numerical form:
>
>http://msdn.microsoft.com/en-us/library/aa366589%28VS.85%29.aspx
>
>But how can this be done in Mathematica?


Alexey,

There are several ways to get this memory
information via .NET/Link, including calling the
GlobalMemoryStatusEx function directly from Mathematica.

The first approach I would recommend is to see if
the information is available via a managed API
(that is, in .NET itself), so you can avoid the
hassles of calling a complex DLL function. A
little googling reveals that you can get memory
info from the Windows Management Interface. The
relevant class is Win32_OperatingSystem
(http://msdn.microsoft.com/en-us/library/aa394239(VS.85).aspx).
Translating a little WMI sample code directly into Mathematica gives:

    In[52]:== query ==
NETNew["System.Management.ManagementObjectSearcher",
"SELECT * FROM Win32_OperatingSystem"];

    In[53]:== resultCollection == query@Get[]

    Out[53]== =ABNETObject[System.Management.ManagementObjectCollection]=BB

The NETObjectToExpression function conveniently
turns IEnumerable objects like collections into
Mathematica lists. This collection will only have one item in it:

    In[54]== mo == First[NETObjectToExpression[resultCollection]]

    Out[54]== =ABNETObject[System.Management.ManagementObject]=BB

The URL page above gives the various properties
you can extract from this object, including
TotalVisibleMemorySize, FreePhysicalMemory,
TotalVirtualMemorySize, and
FreeVirtualMemorySize. For example (note that the values are in Kb):

    In[55]:== mo["TotalVisibleMemorySize"]

    Out[56]== 3143336


If that isn't to your liking, or you just want to
know how to call a DLL function that takes a struct, read on.

One approach that is often overlooked when using
.NET/Link in complex scenarios is to simply write
a little C# or VB code that encapsulates the task
and call it from Mathematica. The spirit of
.NET/Link (and J/Link) is that you can do
virtually anything directly from Mathematica
without dipping into any other languages, but in
some cases it's easier to write some code of your
own, especially since you can often find example
code out there that does almost exactly what you
want. I won't demonstrate this because we can do
what we need here without ever leaving
Mathematica, but it's an important option to keep in mind.


Here's how to call the GlobalMemoryStatusEx
function from Mathematica. The first thing to do
is to find some C# code that demonstrates how to
do it. A great reference for calling Windows DLL
functions from .NET is www.pinvoke.net, and
that's where you can find a C# example for
GlobalMemoryStatusEx
(http://www.pinvoke.net/default.aspx/kernel32.GlobalMemoryStatusEx).
Here's the C# declaration, copied from that site:

    [StructLayout(LayoutKind.Sequential, CharSet==CharSet.Auto)]
    private 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 ));
        }
    }

    [return: MarshalAs(UnmanagedType.Bool)]
    [DllImport("kernel32.dll", CharSet == CharSet.Auto, SetLastError == true)]
    static extern bool GlobalMemoryStatusEx( [In,
Out] MEMORYSTATUSEX lpBuffer);

As you can see, you need to define a custom
struct that the GlobalMemoryStatusEx function
fills in. DefineDLLFunction provides some options
for handling complex function declarations, but
nothing that can handle this level of complexity.
For situations like this, DefineDLLFunction
provides a fallback mode where you can just
supply a string of C# code that represents an
external function declaration in all its complexity:

     In[57]:== globalMemoryStatusEx == DefineDLLFunction[
                "[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 ));
                    }
                 }

                 [return: MarshalAs(UnmanagedType.Bool)]
                 [DllImport(\"kernel32.dll\",
CharSet == CharSet.Auto, SetLastError == true)]
                 public static extern bool
GlobalMemoryStatusEx( [In, Out] MEMORYSTATUSEX lpBuffer);"
              ];

     Out[57]== Function[Null,
If[NETLink`DLL`Private`checkArgCount[GlobalMemoryStatusEx,{##1},1],
                Wolfram`NETLink`DynamicDLLNamespace`DLLWrapper1`GlobalMemoryStatusEx[##1],
$Failed], {HoldAll}]

Note that I had to make one change to the
declaration from the website--the MEMORYSTATUSEX
struct was declared private, but it needs to be public.

So far, that was easy--find an example C#
declaration for the function and paste it
directly into Mathematica. There is one
complication, though, which is that we need to
instantiate the MEMORYSTATUSEX structure to pass
it in as the argument to globalMemoryStatusEx.
That struct was defined when the C# compiler was
called by .NET/Link to compile the external
function declaration. But what is its type name?
The answer to that can be found by looking at the
function definition returned by
DefineDLLFunction. You can see that the
GlobalMemoryStatusEx function is in the context
Wolfram`NETLink`DynamicDLLNamespace`DLLWrapper1`,
which corresponds to a .NET class name of
Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1.
That is the class that was automatically created
to hold the GlobalMemoryStatusEx function. You
can also see that this is the created class name
by looking at LoadedNETTypes[]:

     In[58]:== LoadedNETTypes[]

     Out[58]== {NETType[Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1,1]}

That class is the class in which the
MEMORYSTATUSEX class definition is nested, and if
you know how nested class names in .NET work,
this means that it will have the .NET name of
Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1+MEMORYSTATUSEX.
If you don't know this, you can see the class
name by asking for information about the
definition of the GloalMemoryStatusEx function:

     In[59]:==
NETTypeInfo["Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1",
"Methods", "GlobalMemoryStatusEx"]

         (prints: )
              \[FilledCircle] Methods (matching
string pattern GlobalMemoryStatusEx)

              static bool
GlobalMemoryStatusEx(Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1+MEMORYSTATUSEX
lpBuffer)

You can see the type name in the line above.

Now we are ready to call the function. First
create a new instance of the struct:

     In[60]:== struct ==
NETNew["Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1+MEMORYSTATUSEX"];

Call the function:

     In[61]:== globalMemoryStatusEx[struct];

     In[62]:== struct@ullTotalPhys

     Out[62]== 3218776064



Todd Gayley
Wolfram Research 


  • Prev by Date: Re: Pi day
  • Next by Date: Re: Bug in NMinimize?
  • Previous by thread: Re: Calling kernel.dll from Mathematica
  • Next by thread: Re: Calling kernel.dll from Mathematica