So I’m working on some new drivers and I’ve implemented WMI methods for debug and testing uses. In theory, I should be able to make the method parameter take a variable size buffer at the end, but I just could not get it to work the way I wanted. Some Googling (do you capitalize Googling or not?) found others with the same issue, and some ugly VBScript code to work around the problem. I also found a Microsoft KB article (KB951242, about the RequestResponseEx method on WMI class Microsoft_IPMI) that seemed to suggest there was no workaround from .Net languages, and since I’m embracing powershell this was a problem.
I have a WMI methods defined (simplified for this post) like:
[WmiMethodId(6), Implemented, Description(“Send data to remote endpoint”) : amended]
void Send(
[in] uint32 BufferSize,
[in, WmiSizeIs(“BufferSize”)] uint8 Buffer,
[out,] uint32 Status
);
These compile with the mof compiler just fine, but if a try to run them from powershell (or VBScript) I get an “invalid parameter” error, and the driver never sees the WMI method call. The wmiprov.log files also gives messages about size was xx but expecting 1. I DID have a piece of VBScript code that does some ugly things along the lines of “instance.Methods_(“Send”).InParameters.Clone_” and some explanation that the issue was the parameter instance didn’t know about the WmiSizeIs qualifier, but the original WMI class does. I looked though chunks of .mof files and Microsoft even has a white paper on accessing Fibre Channel WMI data using VBScript, using the InParameters.Clone_ trick.
What I want is just to be able to type powershell that says:
$buffer = @(0xFF) * 64
$dev = gwmi -namespace root\wmi -class MyClassName
$result = $dev.Send($buffer.Count, $buffer)
What to do, I could just require fixed sized buffers, but that’s ugly. The VBScript samples seems to be saying the issues was the WmiSizeIs parameter qualifier was not getting set on instances of parameter objects, so the language runtime could not tell the relationship between the size field and the array size. Opening up wbemtest, I dug down though my class definition until I found the object that defined the method parameters, and the qualifiers. There was a little checkbox to propagate the parameter WmiSizeIs qualifier to instances, and it was false on the buffer parameter. I changed it to true, and saved the WMI class definition, and presto, WMI method calls with variable size buffers now work just like I want them to, no ugly hack required. I asked wbemtest to show me the mof for the modified class and wow, there was just this little “:ToInstance” syntax after the WmiSizeIs(“BufferSize”).
It seems likely all mof method definitions of variable length parameters should probably set the WmiSizeIs attribute with this “:ToInstance” qualifier, and as far as I could tell, none of the WDK sample code has it, not even the complex WMI mof’s from storage. The expectation seems to be everybody can just use ugly hacks in the clients. The problem is not in the language run-times or the WMI subsystem, it’s that everybody has been leaving out the ToInstance qualifier on our WMI definitions. I think it may only show up when you create a WMI record in an app, like a method in parameter record, and pass it down to the driver.
The correct MOF looks like:
[WmiMethodId(6), Implemented, Description(“Send data to remote endpoint”) : amended]
void Send(
[in] uint32 BufferSize,
[in, WmiSizeIs(“BufferSize”):ToInstance] uint8 Buffer,
[out,] uint32 Status
);