Mike Schaeffer's Weblog
Fri, 27 Jan 2006
WMI and temperature probes...
I've spent a little more time spelunking around Win32's support for power and thermal management hardware. It seems like it should be possible to use Windows API calls to determine the presence of hardware temperature sensors and sample their current readings. As it turns out, with Windows Management Instrumentation (WMI), half of this is possible.

Quoting MSDN, "Windows Management Instrumentation (WMI) is a component of the Windows operating system that provides management information and control in an enterprise environment. Administrators can use WMI to query and set information on desktop systems, applications, networks, and other enterprise components. Developers can use WMI to create event monitoring applications that alert users when important incidents occur." Effectively, what that means is that there's a collection of COM objects that allow you to discover the hardware and software configuration of your local computer. With DCOM, it's possible to use this over the network to discover the same stuff on a remote machine. I'm guessing the intent is that the administrator of a server farm can use WMI services to aggregate statistics on her charges.

Reading the WMI documentation, one of the classes of information WMI makes available is Win32_TemperatureProbe, , which "represents the properties of a temperature sensor (electronic thermometer)." Had I read further, I would have also read the following and saved myself some time: "current implementations of WMI do not populate the CurrentReading property", but that's beside the point: this road gets more interesting before hitting that particular dead end. Doing some research on WMI and scripting led to a nice tutorial on WMI at the 4 Guys From Rolla website. From that, it was pretty easy to piece together this little piece of code that dumps data from arbitrary WMI classes:

wscript.echo "Temperature, version 0.1"

sub ShowServices(vClass)
  'Declare our needed variables...
  Dim objLocator, objService, objWEBMCol
  Dim objWEBM, objProp, propitem, objItem, str

  Set objLocator = _
  Set objService = _
     objLocator.ConnectServer() ' Connect to local PC

  Set objWEBM = objService.get(vclass) 
  Set objWEBMCol = objWEBM.Instances_ 
  Set objProp = objWebm.properties_ 

  For Each propItem in objProp
    str = propItem.Name

    For Each objItem in objWEBMCol 
       str = str & ", " & Eval("objItem." & propItem.Name)

    wscript.echo str
end sub

ShowServices "Win32_TemperatureProbe"
Dump that script into a .vbs file, run it with cscript, and it'll write out the state of the objects of the specified class. Since Windows doesn't report temperature readings, Win32_TemperatureProbe isn't all hat useful, but you ought to try it with something like Win32_Process or Win32_NetworkAdapter.

reddit this! Digg Me!

[/tech/win32] permanent link

Mon, 23 Jan 2006
Windows.h is wierd...
I've recently spent some time experimenting with the CallNtPowerInformation Win32 API call. If you are not familiar with this call, it's a Windows NT specific call that provides access to the power management related features of the OS. Among other things, it allows the current CPU frequency and battery charge to be retrieved. Like many other Win32 API's, CallNtPowerInformation has a very general prototype (notice the two LPVOID's for input and output):

NTSTATUS CallNtPowerInformation(
  PVOID lpInputBuffer,
  ULONG nInputBufferSize,
  PVOID lpOutputBuffer,
  ULONG nOutputBufferSize

To use CallNtPowerInformation, the InformationLevel argument specifies one of a number of different possible function codes. Some of these update power management settings, some retrieve current settings, and some retrieve system status values. Based on the function code, you provide input and output arguments via standard structures passed in via lpInputBuffer and lpOutputBuffer.

Where things might start to get odd is when you try to use the ProcessorInformation information level. This information level requires an output buffer of type PROCESSOR_POWER_INFORMATION. However, quoting from the MSDN documentation: "Note that this structure definition was accidentally omitted from Winnt.h. This error will be corrected in the future. In the meantime, to compile your application, include the structure definition contained in this topic in your source code." Peachy.

Being the dilligant programmer I know you are, you will, of course, want to check your return value when you call this function. Believe it or not, things are still wierd. To get the definition of the NTSTATUS typedef, you need to include winternl.h. To get the complete set of return codes, you need to include ntstatus.h. However, if you include both ntstatus.h and windows.h you get warnings about duplicate preprocessor definitions. This is because some of these constants are defined in both header files. To solve this little problem, you need to define WIN32_NO_STATUS before including windows.h and undefine it before including ntstatus.h. This tells windows.h not to define return codes and reenables return code definition for ntstatus.h.

The next problem you're likely to face is the fact that your program fails to link. This is because the powrprof.h does not explicitly specify C function linkage. If you include the header file unadorned in a C++ program, it'll assume C++ linkage, and try to call the API with a mangled name. This does not work, so you're forced to explicltly specify C linkage for the include file. The net result of all these complications might well end up looking like so:

#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS

#include <ntstatus.h>
#include <winnt.h>

extern "C" {
	#include <powrprof.h>

#include <winternl.h>

I'm not honestly sure why this had to be quite this complicated...

reddit this! Digg Me!

[/tech/win32] permanent link