Prev: Automatically identifying a directory
Next: How to extract the x-axis and y-axis current ticks of a plot from AbsoluteOptions?
From: Alexey Popkov on 16 Mar 2010 05:47 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?
From: Todd Gayley on 18 Mar 2010 05:32 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(a)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(a)ullTotalPhys Out[62]== 3218776064 Todd Gayley Wolfram Research
From: Àëåêñåé Ïîïêîâ on 20 Mar 2010 03:47 Todd , Many thanks for the detailed response. Both methods are shown by you, very interesting. And thanks for sending a separate copy of the message directly to me: message appeared in the newsgroup is damaged, and part of the code from it does not work even after the correction of obvious damage. I have a question on the first method. As I understand, the function mo["FreePhysicalMemory"] will return the value corresponding to the time of creation of the first NETObject ('query'). Thus, it is not suitable for periodic calls on a regular basis. How can I get the actual value corresponding to the time of the call? Or how can I force updating of the values? Alexey Popkov ----- Original Message ----- From: "Todd Gayley" <tgayley(a)wolfram.com> To: "Alexey Popkov" <lehin.p(a)gmail.com>; <mathgroup(a)smc.vnet.net> Sent: Thursday, March 18, 2010 2:22 AM Subject: Re: Calling kernel.dll from Mathematica 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(a)Get[] Out[53]= �NETObject[System.Management.ManagementObjectCollection]� 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]= �NETObject[System.Management.ManagementObject]� 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(a)ullTotalPhys Out[62]= 3218776064 Todd Gayley Wolfram Research
From: Alexey Popkov on 24 Mar 2010 05:33 Todd, Interesting that I seem to have found a way to update the values. For this I call the method Get[]: freePhysicalMemoryFromWMI := (mo(a)Get[]; mo["FreePhysicalMemory"]); I have no idea where this is documented but observations have shown that it like works correctly. And it allows me to compare the effectiveness of two methods in terms of CPU load (I have a dual-core processor) by AbsoluteTiming. The following code compares the time required to obtain 10000 of actual values in two ways. Amazingly, the first method is 60 times slower than the second! It seems that in terms of performance with the frequent call working with the DLL is preferred. In[1]:= Needs["NETLink`"] query=NETNew["System.Management.ManagementObjectSearcher","SELECT * FROM Win32_OperatingSystem"]; resultCollection=query(a)Get[]; mo=First[NETObjectToExpression[resultCollection]]; freePhysicalMemoryFromWMI:=(mo(a)Get[];mo["FreePhysicalMemory"]); 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);"]; struct=NETNew["Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1+MEMORYSTATUSEX"]; freePhysicalMemoryFromDLL:=(globalMemoryStatusEx[struct];struct(a)ullAvailPhys ); Table[freePhysicalMemoryFromWMI,{10000}];//AbsoluteTiming Table[freePhysicalMemoryFromDLL,{10000}];//AbsoluteTiming Out[9]= {141.5937500,Null} Out[10]= {2.3750000,Null} Alexey Popkov 2010/3/24 Todd Gayley <tgayley(a)wolfram.com> > At 02:46 AM 3/20/2010, Alexey Popkov wrote: > >> Todd , >> >> Many thanks for the detailed response. Both methods are shown by you, very >> interesting. >> >> And thanks for sending a separate copy of the message directly to me: >> message appeared in the newsgroup is damaged, and part of the code from it >> does not work even after the correction of obvious damage. >> >> I have a question on the first method. As I understand, the function >> mo["FreePhysicalMemory"] >> will return the value corresponding to the time of creation of the first >> NETObject ('query'). Thus, it is not suitable for periodic calls on a >> regular basis. >> How can I get the actual value corresponding to the time of the call? Or >> how >> can I force updating of the values? >> > > > Alexey, > > Just re-do the entire call when you need the current values. Here is the > code packaged as a function: > > GetMemoryData[] := > NETBlock[ > Module[{query, mo}, > > query = NETNew["System.Management.ManagementObjectSearcher", > "SELECT * FROM Win32_OperatingSystem"]; > mo = First[NETObjectToExpression[query(a)Get[]]]; > (# -> mo[#])& /@ {"TotalVisibleMemorySize", "FreePhysicalMemory", > "TotalVirtualMemorySize"} > ] > ] > > > In[10]:= GetMemoryData[] > > Out[10]= {TotalVisibleMemorySize -> 3143336, FreePhysicalMemory -> 1124652, > TotalVirtualMemorySize -> 4444440} > > > > Todd Gayley > Wolfram Research > >
From: Alexey Popkov on 28 Mar 2010 05:08
Todd, Is there a straightforward way to determine which of the loaded NETTypes corresponds to a function returned by DefineDLLFunction? Or the only way is to use Definition[]? Alexey Popkov ----- Original Message ----- From: "Todd Gayley" <tgayley(a)wolfram.com> To: "Alexey Popkov" <lehin.p(a)gmail.com>; <mathgroup(a)smc.vnet.net> Sent: Thursday, March 18, 2010 2:22 AM Subject: Re: Calling kernel.dll from Mathematica <...> 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]} <...> Todd Gayley Wolfram Research |