I admit it: I regularly find things in WDF that I had no idea existed. This either speaks to the overall richness of the API, or to my resolute dedication to doing things “the way I’ve always done them.” I’m really not sure which. Shall we vote? No, let’s not.
Anyhow, I’m working on a driver that needs to read some string data during initialization from the Registry. I want to read this from the Parameters subkey of my driver’s service entry in HLKM/System/CCS/Services. I seemed to recall that WDF had all these cool functions to “easily” read things from the Registry, and sure enough, there’s a function that does exactly what I want:
status = WdfDriverOpenParametersRegistryKey(Driver, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, ®KeyHandle);
So, that’s convenient. And there’s also a similarly convenient WdfRegistryQueryString function that you can use to retrieve string data from the Registry given a value name. But I noticed that WdfRegistryQueryString took as an argument something called a WDFSTRING. “Here we go again”, I thought to myself, “another unnecessary and cumbersome abstraction.” I was thinking of WDFMEMORY here (Don’t write me… I know it has its place and all… but does anybody really call WdfMemoryCreate when instead of ExAllocatePool? I don’t think so).
But hmmmmm… When you have string data to read and store, from anywhere really, there is always the annoyance of allocating the buffers to store the data and then returning those buffers at the right time before you exit. It turns out that this is where WDFSTRINGs becomes handy.
To read a string value from the Registry, you create a WDFSTRING object and pass it to the WDF function that reads registry values. You can then get the UNICODE_STRING that holds the value you read from the Registry and store that away someplace convenient. I stored it in my WDFDRIVER context. Here:
// // Read a configuration string value from the Registry // status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &stringHoldingValue); if (NT_SUCCESS(status)) { status = WdfRegistryQueryString(regKeyHandle, &StringKeyValueName, stringHoldingValue); if (NT_SUCCESS(status)) { WdfStringGetUnicodeString(stringHoldingValue, &DriverContext->ConfigValue); #if DBG DbgPrint("ReadRegistryValues ConfigValue: %wZ \n", &DriverContext->ConfigValue); #endif } }
Because the WDFSTRING is parented by the WDFDRIVER Object by default, the Framework will deallocate it for you before your driver exits. You can, of course, parent the WDFSTRING on any other appropriate object.
Not at all cumbersome, and in fact pretty useful! You never know what you’re going to find when you read the documentation.