<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Trouble Ahead- Trouble Behind : C++</title><link>http://blogs.msdn.com/bobkjelgaard/archive/tags/C_2B002B00_/default.aspx</link><description>Tags: C++</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>The Case of the Unexpected Overload</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2009/08/03/9856270.aspx</link><pubDate>Mon, 03 Aug 2009 17:31:44 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9856270</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/9856270.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=9856270</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=9856270</wfw:comment><description>&lt;p&gt;So are you using C++ in a KMDF driver and scratching your head over some unexpectedly unresolved references?&lt;/p&gt;  &lt;p&gt;I recently engaged in a somewhat prolonged conversation with &lt;a href="http://blogs.msdn.com/doronh" target="_blank"&gt;Doron&lt;/a&gt; and a dev I won’t name [since I didn’t ask for permission] about C++ in KMDF driver.&amp;#160; This dev (a very good dev, by the way) had hit a stumbling point converting a driver from C to C++ and was wondering if we had ever tried this in QA.&lt;/p&gt;  &lt;p&gt;Yes, I know that means he/she doesn’t read this blog, since I’ve mentioned doing just that on more than one occasion.&amp;#160; But that’s OK, not many people do- and since I’ve got a tendency to write about whatever strikes my fancy at any moment, and I’m not the most dazzlingly brilliant human on the face of the planet, that’s not much of a surprise to me.&amp;#160; You are of course free to believe what you like about that statement.&lt;/p&gt;  &lt;p&gt;But in an attempt to be useful today- the problem was one of those that I guess I’ve hit so many times I don’t give it much thought.&amp;#160; But it gave our dev a bit of trouble, and not much gives this person that kind of trouble.&amp;#160; So perhaps a word to the wise will give the three or four of you still reading this a leg up the next time you use C++ in a KMDF driver.&lt;/p&gt;  &lt;h4&gt;The Lesson for Today Is…&lt;/h4&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;p&gt;It was just a simple conversion of a driver from C to C++ (to gauge my familiarity with the process, I did that with a half dozen or more drivers last week, and it was far from the only thing I did that week- in fact the big job was actually that I also made them W4 and PFD clean along with quite a few more drivers I’d already converted to C++- almost two dozen drivers total), but it ran afoul of this little bit of goodness:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;typedef
__drv_functionClass(EVT_WDF_OBJECT_CONTEXT_CLEANUP)
__drv_sameIRQL
__drv_maxIRQL(DISPATCH_LEVEL)
VOID
EVT_WDF_OBJECT_CONTEXT_CLEANUP(
    __in
    WDFOBJECT Object
    );

typedef EVT_WDF_OBJECT_CONTEXT_CLEANUP *PFN_WDF_OBJECT_CONTEXT_CLEANUP;&lt;/pre&gt;

&lt;p&gt;&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;

&lt;p&gt;That’s the “role typedef” for any WDF object’s context cleanup routine.&amp;#160; The SDV tool can use role typedefs to do a better job of statically verifying your driver code, so some special cleanup typedefs are defined to make it a better tool, and you can see them in this (by the way, everything I’m posting is from the WDK- no deep dark secrets here).&lt;/p&gt;

&lt;pre class="csharpcode"&gt;typedef EVT_WDF_OBJECT_CONTEXT_CLEANUP EVT_WDF_DEVICE_CONTEXT_CLEANUP;
typedef EVT_WDF_OBJECT_CONTEXT_DESTROY EVT_WDF_DEVICE_CONTEXT_DESTROY;
typedef EVT_WDF_OBJECT_CONTEXT_CLEANUP EVT_WDF_IO_QUEUE_CONTEXT_CLEANUP_CALLBACK;
typedef EVT_WDF_OBJECT_CONTEXT_DESTROY EVT_WDF_IO_QUEUE_CONTEXT_DESTROY_CALLBACK;
typedef EVT_WDF_OBJECT_CONTEXT_CLEANUP EVT_WDF_FILE_CONTEXT_CLEANUP_CALLBACK;
typedef EVT_WDF_OBJECT_CONTEXT_DESTROY EVT_WDF_FILE_CONTEXT_DESTROY_CALLBACK;&lt;/pre&gt;

&lt;p&gt;&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;

&lt;p&gt;So, what the original driver, being a good sample [because SDV suitability also matters], had was something like this (not exactly like this- nobody with my twisted sense of humor writes sample code, because humor never works globally- someone always takes offense- I’m just not inclined to care about that anymore, because I’m a callous old bastard with less than a dozen years to retirement age and not much “career” left to lose):&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// In the header file:&lt;/span&gt;

EVT_WDF_DEVICE_CONTEXT_CLEANUP HideTheBodies;

&lt;span class="rem"&gt;// In the implementation&lt;/span&gt;
VOID
HideTheBodies(
    __in WDFDEVICE MortTheMortuaryTechnicianIsOnTheJob
    )
{
...&lt;/pre&gt;

&lt;p&gt;Of course, in C, that sort of works- but&lt;u&gt; &lt;strong&gt;in C++, that says you have two overloaded versions&lt;/strong&gt;&lt;/u&gt;&lt;strong&gt; &lt;/strong&gt;of &lt;strong&gt;&lt;em&gt;HideTheBodies&lt;/em&gt;&lt;/strong&gt;- one takes a WDFOBJECT as input, and isn’t defined, because nobody wrote it that way.&amp;#160; The one that is defined takes a WDFDEVICE as input.&amp;#160; More annoying, of course, is that from the typedef name, you’d expect it would take a WDFDEVICE as input, so it isn’t an error that’s glaringly obvious.&lt;/p&gt;

&lt;p&gt;As is- the code will compile fine, and PFD will be happy, too [they’re not the same function, remember].&amp;#160; But when you link it, you get an unresolved reference for &lt;em&gt;&lt;strong&gt;HideTheBodies&lt;/strong&gt;&lt;/em&gt;- decorated to indicate it has a WDFOBJECT parameter.&amp;#160; Now, unless you really look closely at such decorations (something my fine history of mistyping the simplest of code has taught me to do), you’re looking at a mystery.&amp;#160; It took my colleague digging through preprocessor output and object files and such to finally hit upon the error- a reasonably annoying circumstance!&lt;/p&gt;

&lt;p&gt;Another thing you can do (and this is what I usually do) is tie the callbacks to the context itself (with the context a class) as static member functions, as &lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2009/03/12/using-c-in-a-kmdf-driver-part-1-a-pattern-for-using-contexts-as-objects.aspx"&gt;I described earlier&lt;/a&gt; (effectively you do the cleanup by calling the context’s “delete” operator).&amp;#160; PFD currently doesn’t match the roletype if you do this, so I suppress those warnings (and there is no SDV for C++)- I think we’re trying to get that fixed…&amp;#160; But the compiler will catch the parameter type mismatch- a bit earlier than the linker.&lt;/p&gt;

&lt;p&gt;But I’ve hosed this both ways- so, until something on the subject gets posted by a recognized authority, this post can at least be found by the diligent searcher…&lt;/p&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9856270" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/customer+service/default.aspx">customer service</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/PFD/default.aspx">PFD</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/C_2B002B00_/default.aspx">C++</category></item><item><title>He’s Gone</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2009/06/25/he-s-gone.aspx</link><pubDate>Fri, 26 Jun 2009 05:15:16 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9804623</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/9804623.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=9804623</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=9804623</wfw:comment><description>&lt;p&gt;It has been a tough week, and a busy one.&amp;#160; I’m getting ready to leave on a vacation, and trying to get all those last-minute things done.&amp;#160; &lt;/p&gt;  &lt;p&gt;While &lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2009/06/18/crazy-is-as-crazy-does.aspx"&gt;my last post&lt;/a&gt; discussed the genesis of what I call the Configuration Agent and the WDF QA Universal Setup Job, this week’s focus has been entirely on another of my oddball notions- it started as a desire to build a &lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2008/11/12/adaptive-fault-injection.aspx"&gt;more precise fault injection engine&lt;/a&gt; for testing the KMDF loader.&amp;#160; With that California background, the project name was easy- Fault?&amp;#160; Why, San Andreas, of course!&amp;#160; &lt;/p&gt;  &lt;p&gt;At a high level it was a programming model built around IAT filtering of calls from a driver into the kernel.&amp;#160; I wanted precision, so I could specify behavior by thread and IRQL, program each DDI independently, allow a driver to do its own filtering [i.e. get a callback with context for a DDI call under given conditions]- and with enough flexibility and locking behavior that the behavior could be reprogrammed within such a callback. For instance, in one working application of mine a filter on calls to &lt;em&gt;IoCallDriver&lt;/em&gt; from the KMDF runtime were routed on specific threads to a callback in the test driver which then turned off all call logging, as it meant the call was leaving it’s stack location- I was using the logs from calls to various resource allocation DDI to make sure the framework did not allocate resources under conditions in which we contractually would not fail- so I wanted to stop logging before I called IoCallDriver and to restart it after it returned [I knew the driver handling it was synchronous- otherwise I would have to hook the completion side of things, of course].&lt;/p&gt;  &lt;p&gt;So the concept went well beyond fault injection, but it’s always been a side-line.&amp;#160; My initial tests wound up being very white box, and a refactoring of the loader code&amp;#160; meant a similar rewrite of the test was necessary, but there was no time to do that…&amp;#160; But with Windows 7 winding up [since we’ve announced dates, that can’t qualify as a secret anymore], I have time to go back and try to at least do a few new things beyond mere maintenance.&amp;#160; Such time is rare and fleeting, so I’ve been busily making the most of it.&lt;/p&gt;  &lt;p&gt;So today was busy- I worked a bit of overtime on a COM automation server (in process) exposing a scriptable interface to my engine for some of the other team members to use, and got it at least working well enough to demo.&amp;#160; Still have my packing to do, and dinner to make and so forth, so home I headed.&lt;/p&gt;  &lt;p&gt;Then I turned on the television, and immediately heard the news about Michael Jackson.&amp;#160; Whoa…&lt;/p&gt;  &lt;p&gt;On those old tapes I’ve been scraping &lt;a href="http://bobkjelgaard.members.winisp.net/bob-audio.htm"&gt;for my archives&lt;/a&gt; I’ve got many covers of his material from the time I was playing in bar bands: Billie Jean, Thriller, Beat It- and more.&amp;#160; I’ve not posted them because frankly I never thought I did any of them justice- a lot of my material from those days has rough edges [anyone who listens to what I have posted can hear that], but these were just not good enough.&amp;#160; But add me to the billions of fans, then and since, sure…&lt;/p&gt;  &lt;p&gt;The other thought that came early on was that in my previous post I mentioned having learned to keep some of my more controversial opinions to myself- one of those was intense skepticism about the molestation accusations.&amp;#160; I knew I wasn’t likely to sway anyone there- so why bother?&lt;/p&gt;  &lt;p&gt;He’s gone, and he was younger than I am- scary stuff.&amp;#160; Life is fleeting, and it was an unexpected reminder of that.&lt;/p&gt;  &lt;p&gt;But, it’s time to pack my CDs and games and controllers, write those last few checks for bills coming due during the vacation. eat that dinner, and get ready for a night’s rest prior to that final day of work, so another slapdash post, and back to work…&lt;/p&gt;  &lt;p&gt;There was some offsetting good news today- besides finding out I really do still remember enough about COM to roll out an in-process automation server on the QT- without using ATL of course, where would the challenge be in that [answer: in learning something new for a change- you old dog!]?&amp;#160; But of course it falls into that semi-confidential area where I’ll just have to sit on it for a while [not that it’s likely to shatter the world if revealed anyway, but circumspection is worthy of practice even for an old blowhard like myself].&lt;/p&gt;  &lt;p&gt;I’ll try to do something more substantial someday- these days I’ve just not got the time to really write anything too terribly technical.&amp;#160; My apologies to those diehards who still try to read this awful stuff I’m churning out of late…&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9804623" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/UMDF/default.aspx">UMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/test+development/default.aspx">test development</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/C_2B002B00_/default.aspx">C++</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/Life+at+Microsoft/default.aspx">Life at Microsoft</category></item><item><title>Exceptions rule!</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2009/04/18/exceptions-rule.aspx</link><pubDate>Sat, 18 Apr 2009 19:24:55 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9555103</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/9555103.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=9555103</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=9555103</wfw:comment><description>&lt;p&gt;I’ve decided to revert to storytelling mode today.&amp;#160; So sit right back and you’ll hear a tale, a tale of my fateful trip (or click something useful- you’re the one deciding, and I’m the one typing to satisfy whatever inner demon has driven me to do this today)…&lt;/p&gt;  &lt;p&gt;It began when someone found a bug in the static version of KMDF- the one almost nobody gets to use and which we have been trying to discontinue any support.&amp;#160; But people were still using it, and we had no clear migration path, and there was a bug.&amp;#160; So we decided to begin testing it.&amp;#160; Poor &lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2008/06/28/potential.aspx"&gt;Neslihan&lt;/a&gt; got that task (well at least it wasn’t me, this time).&amp;#160; Soon we had added a static KMDF driver to our list of test drivers used in our daily automated testing.&lt;/p&gt;  &lt;p&gt;Then, of course, we got the bugcheck.&amp;#160; As often happens, I played “Johnny-on-the-spot” and (virtually speaking) leapt onto the remote debug session accompanying the report.&amp;#160; Buffer overflow?&amp;#160; In FxDriverEntry?&amp;#160; But only on Itanium (I checked the other architectures that ran the same test, of course- no problems)?&amp;#160; What in blazes is this about?&lt;/p&gt;  &lt;p&gt;Well, the method is well documented, and not all that hard to understand- a “cookie&amp;quot; gets initialized, it gets stored to the local stack frame in such a way that code overflowing buffers in the stack frame will overwrite the stored copy.&amp;#160; On exit, code gets called that checks that value to see if that happened.&amp;#160; It’s a little more complicated than that, and I’m not going to be precise, because part of that complication is related to securing the method against the sort of people who like to exploit buffer overflows [so I’m not going to make the method clear for them- they can do their own research without my assistance].&amp;#160; The bugcheck analysis will even tell you the two values- expected and actual, making it easy for people who really think overflows are a bad idea to make a quick guess as to where the overflow came from.&lt;/p&gt;  &lt;p&gt;But the circumstances seemed suspicious, so I went and read the source code- H’mm- there’s a default value the cookie is initialized to…&amp;#160; Interesting- that’s the value we have- but it doesn’t match the expected value.&lt;/p&gt;  &lt;p&gt;At which time, something I’ve known for years hit me like the proverbial sledgehammer- our entry code calls GsDriverEntry (which supports the stack probes inserted by the GS compiler switch, hence its name) when it finishes.&amp;#160; GsDriverEntry &lt;em&gt;initializes&lt;/em&gt; the cookie, which means that that was why the values didn’t match.&amp;#160; Like the sword of Damocles, this had been hanging over our heads for years- the first time the compiler decided to do stack probes in our entry code, everything would break.&amp;#160; Ouch…&lt;/p&gt;  &lt;p&gt;I’ll leave a bunch of story out here- things got “interesting” at that point, but the problem eventually got solved, both for us and for other people facing similar issues, as well.&amp;#160; Short answer is that everyone now initializes the cookie right at the start, just as should happen…&lt;/p&gt;  &lt;p&gt;But a while back I had occasion to tweak the build process for the WdfVerifier WDK applet, and afterwards I ran it briefly to make sure I didn’t break anything in the process.&amp;#160; Oh, joy of joys- NONE of the 1.9 client drivers are being properly identified.&amp;#160; They are all identified as “Inbox”, which is what I do when &lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2008/11/11/determining-a-kmdf-driver-s-client-version.aspx"&gt;the client identification method I described last year&lt;/a&gt; fails on me.&lt;/p&gt;  &lt;p&gt;Already beginning to panic, I think- did someone change FxDriverEntry, and I didn’t even notice it?&amp;#160; So I go to our source control system, and look at the change history.&amp;#160; The most recent change is the fix for the problem with the stack probes (yes it occurred on static, but what scared me then was it could have happened to any version, because were weren't doing things properly).&amp;#160; But that just calls library routines to initialize said cookie… Oh, blazes, those routines must be calling an import I wasn’t accounting for!!!&amp;#160; Why???&amp;#160; Because I NULL the IAT to force access violations, and I handle the exception by giving up on getting the true version, and fall back to calling it “Inbox”- which is, after all, exactly what I am seeing.&amp;#160; Oh, well- so much for my having thoroughly considered all the test and product consequences of that change when it was made…&lt;/p&gt;  &lt;p&gt;Well, easy enough to find out what that import might be.&amp;#160; One nice trick &lt;a href="http://blogs.msdn.com/iliast"&gt;Ilias&lt;/a&gt; showed me is that you can open any binary in WinDbg as a crash dump, and happily resolve symbols and disassemble code.&amp;#160; So I pick a random driver on my dev box, and do so.&lt;/p&gt;  &lt;p&gt;What, no imports?&amp;#160; But, but--- hmm- it uses a fixed address (load of a 64-bit immediate value into RAX, since my dev box is an X64, thank you- you x86 dinosaurs can keep your wimpy processors).&amp;#160; What’s with this?&lt;/p&gt;  &lt;p&gt;The answer lies in wdm.h, of course- KeQueryTickCount turns out to always be a macro- on x86 and IA64, it accesses KeTickCount [which is an import, and if you followed my earlier tale, it’s clear adding an import to my existing hack-o-matic mechanism is a trivial task]- but on X64, it accesses an essentially hardcoded address in a “SharedUserData” area.&amp;#160; This snippet is from wdm.h, so you can see for yourself…&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="preproc"&gt;#define&lt;/span&gt; KI_USER_SHARED_DATA 0xFFFFF78000000000UI64

&lt;span class="preproc"&gt;#define&lt;/span&gt; SharedUserData ((KUSER_SHARED_DATA * &lt;span class="kwrd"&gt;const&lt;/span&gt;)KI_USER_SHARED_DATA)

&lt;span class="preproc"&gt;#define&lt;/span&gt; SharedInterruptTime (KI_USER_SHARED_DATA + 0x8)
&lt;span class="preproc"&gt;#define&lt;/span&gt; SharedSystemTime (KI_USER_SHARED_DATA + 0x14)
&lt;span class="preproc"&gt;#define&lt;/span&gt; SharedTickCount (KI_USER_SHARED_DATA + 0x320)

&lt;span class="preproc"&gt;#define&lt;/span&gt; KeQueryInterruptTime() *((&lt;span class="kwrd"&gt;volatile&lt;/span&gt; ULONG64 *)(SharedInterruptTime))

&lt;span class="preproc"&gt;#define&lt;/span&gt; KeQuerySystemTime(CurrentCount)                                     \
    *((PULONG64)(CurrentCount)) = *((&lt;span class="kwrd"&gt;volatile&lt;/span&gt; ULONG64 *)(SharedSystemTime))

&lt;span class="preproc"&gt;#define&lt;/span&gt; KeQueryTickCount(CurrentCount)                                      \
    *((PULONG64)(CurrentCount)) = *((&lt;span class="kwrd"&gt;volatile&lt;/span&gt; ULONG64 *)(SharedTickCount))&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;My. my. my- this is a problem- no import I can just tweak to point into my code.&amp;#160; For a plus, at least the value can’t change (if it did, existing drivers would, after all, cease to work)- well, at least not easily, so I’ll save any remaining paranoia about that for another time.&amp;#160; But I’m going to access violate trying to access that address in user mode (not to mention the reams of experimental evidence I had just accumulated by noticing the problem in the first place)…&lt;/p&gt;

&lt;p&gt;So in reading about exception handling, a phrase happens to catch my eye- putting it in my words, it says that when continuing an exception, you can alter the context record supplied to you with the exception (and I know this process well, but that’s perhaps a story for a different time).&amp;#160; Whoa- that must mean I can change the contents of the registers programmatically, and then tell it to repeat the failed instruction!&amp;#160; Now, I can’t find that illustrated in any of the samples the material I’m reading points me to [nor could I find it an an internet search, although the latter was by no means exhaustive].&amp;#160; But that HAS to be what it means, right?&lt;/p&gt;

&lt;p&gt;So I start coding- first the half dozen or so lines needed to handle the KeTickCount import.&amp;#160; Then an exception filter [only for AMD64, of course].&amp;#160; The logic is my usual bit of precise work: If it is an access violation, and if it is a read, and it is a read of that exact address, and one of the integer registers in the context record has that same address, then change that register’s entry in the context record to the address of the proxy I’ve decided to keep in WdfVerifier, and tell the OS to repeat the failed instruction.&amp;#160; I began with RAX, because after all, that’s what I had seen in my investigation, and it seemed the most likely place for a while, but I added the whole set since under the circumstances, it seemed unlikely to do any harm.&amp;#160; Anything that didn’t match that exact pattern, and I gave up- just execute the handler, which does nothing.&amp;#160; The attempt to run the driver entry code to extract the client version will fail, but WdfVerifier keeps running, and the machine itself is still quite safe from my hackery.&lt;/p&gt;

&lt;p&gt;Worked the first time, it did (not counting my usual compiles to get rid of typos).&amp;#160; Problem solved.&amp;#160; Total work time from start to finish- something like 5 or 6 hours- good enough- after all, I did have to do some research…&amp;#160; Of course, there’s always somebody who can do it better, faster, and quicker- and they usually jump out of the woodwork if I start talking about things in that fashion, but it’s my story, so I’ll brag now and regret it later…&lt;/p&gt;

&lt;p&gt;Exceptions do indeed rule!&amp;#160; I love it when a plan comes together…&lt;/p&gt;

&lt;p&gt;A glimpse now at handling the new import…&lt;/p&gt;

&lt;pre class="csharpcode"&gt;
    &lt;span class="rem"&gt;//  The descriptors are an array of entries per module, each terminated with an all-0 entry.&lt;/span&gt;
    &lt;span class="rem"&gt;//  Each entry has an RVA for the module image name, and a second for a 0-terminated list of RVAs to the structures used for&lt;/span&gt;
    &lt;span class="rem"&gt;//  resolving names of exported entries from the module (in loading these get resolved to real addresses and are plugged into&lt;/span&gt;
    &lt;span class="rem"&gt;//  the loaded image's import address table in the same order).  So we now know how to write an image loader if we need to...&lt;/span&gt;

    &lt;span class="rem"&gt;//  First, find the descriptor for the KMDF loader, and quit if it isn't there.&lt;/span&gt;
    DWORD   StringCopy = (DWORD) -1, WdfBind = (DWORD) -1, InitEvent = (DWORD) -1, TickCount = (DWORD) -1; 

    &lt;span class="rem"&gt;//  Then look for the Bind and Unbind entry points.  Case counts!&lt;/span&gt;

    &lt;span class="kwrd"&gt;enum&lt;/span&gt; {OutdatedTechnology, HasBind, HasUnbind, OneCoolDriver};
    
    BYTE        TargetIdentification = OutdatedTechnology;

....

            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;  (IsKernel)
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt;  (0 == strcmp(&lt;span class="str"&gt;&amp;quot;RtlCopyUnicodeString&amp;quot;&lt;/span&gt;, (PSTR) NameDescriptor.Name))
                    StringCopy = ImportsIndex;
                &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;  (0 == strcmp(&lt;span class="str"&gt;&amp;quot;KeInitializeEvent&amp;quot;&lt;/span&gt;, (PSTR) NameDescriptor.Name))
                    InitEvent = ImportsIndex;
                &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;  (0 == strcmp(&lt;span class="str"&gt;&amp;quot;KeTickCount&amp;quot;&lt;/span&gt;, (PSTR) NameDescriptor.Name))
                    TickCount = ImportsIndex;
                
                ImportsIndex++;
            }
.....


        DWORD       IATSize, RelocationsSize;
        LONGLONG    OurFakeTickCount = 0x8badf00ddeadbeefI64;   &lt;span class="rem"&gt;//  ersatz Tick count &lt;/span&gt;        
        PVOID*  ImportAddresses = (PVOID*) 
            ImageDirectoryEntryToDataEx(DriverImage, TRUE, IMAGE_DIRECTORY_ENTRY_IAT, &amp;amp;IATSize, &amp;amp;Unused);
        
        PIMAGE_BASE_RELOCATION  Relocations = (PIMAGE_BASE_RELOCATION)
            ImageDirectoryEntryToDataEx(DriverImage, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &amp;amp;RelocationsSize, &amp;amp;Unused);

        &lt;span class="kwrd"&gt;if&lt;/span&gt;  (NULL == ImportAddresses)
        {
            FreeLibrary((HMODULE) DriverImage);
            &lt;span class="kwrd"&gt;return&lt;/span&gt;  &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }

        &lt;span class="rem"&gt;//  Plug them in here, and we are good to go!&lt;/span&gt;

        DWORD   OldProtect;

        &lt;span class="kwrd"&gt;if&lt;/span&gt;  (!VirtualProtect(ImportAddresses, IATSize, PAGE_READWRITE, &amp;amp;OldProtect))
        {
            FreeLibrary((HMODULE) DriverImage);
            &lt;span class="kwrd"&gt;return&lt;/span&gt;  &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }

        memset(ImportAddresses, 0, IATSize);

        ImportAddresses[StringCopy] = FakeOutStringCopy;
        ImportAddresses[WdfBind] = CollectVersion;
        &lt;span class="kwrd"&gt;if&lt;/span&gt;  (InitEvent != (DWORD) -1)
            ImportAddresses[InitEvent] = FakeEventInit;
        &lt;span class="kwrd"&gt;if&lt;/span&gt;  (TickCount != (DWORD) -1)
            ImportAddresses[TickCount] = &amp;amp;OurFakeTickCount;

        VirtualProtect(ImportAddresses, IATSize, OldProtect, &amp;amp;OldProtect);&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;So for some other glimpses, this is one part of the other hackery (complete with my elementary-level annotations):&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; AllKMDFDrivers
{
    MachineKey&amp;amp;             Owner;
    KMDFDriverList&amp;amp;         InstalledKMDFDrivers;
    LoadedDrivers&amp;amp;          CurrentlyLoadedDrivers;
    LoaderDiagnosticsFlag   LoaderFlag;
    String                  RuntimeVersion;
    DWORD                   Major, Minor, Build;

    &lt;span class="kwrd"&gt;bool&lt;/span&gt;            ServiceUsesKMDFLoader(__in PCWSTR ServiceName, __in RegistryKey&amp;amp; Service, __out MyBindInfoAlias&amp;amp; Binding);
    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt;     FakeOutStringCopy(__in PVOID, __in PVOID);  &lt;span class="rem"&gt;//  Fake RtlCopyUnicodeString entry&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt;     FakeEventInit(__in PVOID, __in ULONG, __in ULONG);  &lt;span class="rem"&gt;//  Fake KeInitializeEvent entry&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; ULONG    CollectVersion(__out MyBindInfoAlias&amp;amp; BindingOut, __in PVOID, __in MyBindInfoAlias&amp;amp; BindingIn, __in PVOID);
&lt;span class="preproc"&gt;#if&lt;/span&gt; defined(_AMD64_)
    &lt;span class="kwrd"&gt;static&lt;/span&gt; LONG     Filterx64Exception(__in EXCEPTION_POINTERS* ExceptionInfo, __in LONGLONG&amp;amp; FakeTickCount);
&lt;span class="preproc"&gt;#endif&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;While the rest of it looks like this (and again, this is partial)- yes, feel free to hate my stylistic indifference to the herd- perhaps I’ll get fired for this, and all can breathe a vast sigh of relief…&lt;/p&gt;

&lt;p&gt;First, the code that calls the filter&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        MangledDriverEntry  CrashAndBurn = (MangledDriverEntry) ((PBYTE) DriverImage + EntryRva);

        __try
        {
            CrashAndBurn(Binding, &amp;amp;Binding);
        }
&lt;span class="preproc"&gt;#if&lt;/span&gt; !defined(_AMD64_)
        __except(EXCEPTION_EXECUTE_HANDLER)
&lt;span class="preproc"&gt;#else&lt;/span&gt;     
        __except(Filterx64Exception(GetExceptionInformation(), OurFakeTickCount))
&lt;span class="preproc"&gt;#endif&lt;/span&gt;
        {
        }&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;and now our filter:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="preproc"&gt;#if&lt;/span&gt; defined(_AMD64_)
&lt;span class="rem"&gt;/**********************************************************************************************************************************&lt;/span&gt;
&lt;span class="rem"&gt;&lt;/span&gt;
&lt;span class="rem"&gt;LONG    AllKMDFDrivers::Filterx64Exception(__in EXCEPTION_POINTERS* ExceptionInfo, __in LONGLONG&amp;amp; FakeTickCount)&lt;/span&gt;
&lt;span class="rem"&gt;&lt;/span&gt;
&lt;span class="rem"&gt;Ahh, the joys of low-level intervention by the truly incorrigible!  On AMD64, we will get an exception when the code tries to get&lt;/span&gt;
&lt;span class="rem"&gt;the tick count.  This value resides at a known address (which cannot change because if it did, all existing drivers would then fail&lt;/span&gt;
&lt;span class="rem"&gt;to work- although I suppose someone could resort to what I am about to do- bring it on, I'll see if I can keep up with the absurd&lt;/span&gt;
&lt;span class="rem"&gt;arms race).&lt;/span&gt;
&lt;span class="rem"&gt;&lt;/span&gt;
&lt;span class="rem"&gt;So, first, verify from the exception record that we are getting an access violation of some sort reading that known address.  Then&lt;/span&gt;
&lt;span class="rem"&gt;see if one of the integer registers has that address (start with RAX, since that's where it currently is, and I bet it doesn't&lt;/span&gt;
&lt;span class="rem"&gt;change much).  If it does, change it to point to the value given to this function (which resides in WdfVerifier, since I made it&lt;/span&gt;
&lt;span class="rem"&gt;a reference, and will let the compiler play enforcer), and then continue execution.&lt;/span&gt;
&lt;span class="rem"&gt;&lt;/span&gt;
&lt;span class="rem"&gt;In all other cases, execute the handler, which will do nothing (meaning the version will continue to be unknown).&lt;/span&gt;
&lt;span class="rem"&gt;&lt;/span&gt;
&lt;span class="rem"&gt;**********************************************************************************************************************************/&lt;/span&gt;

LONG    AllKMDFDrivers::Filterx64Exception(__in EXCEPTION_POINTERS* ExceptionInfo, __in LONGLONG&amp;amp; FakeTickCount)
{

    &lt;span class="rem"&gt;//  cf definition of SharedTickCount in wdm.h&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; DWORD64    KnownTickCountAddress = 0xFFFFF78000000320UI64;

    &lt;span class="kwrd"&gt;if&lt;/span&gt;  (NULL == ExceptionInfo || NULL == ExceptionInfo-&amp;gt;ExceptionRecord || NULL == ExceptionInfo-&amp;gt;ContextRecord)
        &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_EXECUTE_HANDLER;

    &lt;span class="kwrd"&gt;switch&lt;/span&gt;  (ExceptionInfo-&amp;gt;ExceptionRecord-&amp;gt;ExceptionCode)
    {
    &lt;span class="kwrd"&gt;case&lt;/span&gt;    EXCEPTION_ACCESS_VIOLATION:
    &lt;span class="kwrd"&gt;case&lt;/span&gt;    EXCEPTION_IN_PAGE_ERROR:    &lt;span class="rem"&gt;//  Unlikely, but what the heck...&lt;/span&gt;
        &lt;span class="kwrd"&gt;if&lt;/span&gt;  (2 &amp;gt; ExceptionInfo-&amp;gt;ExceptionRecord-&amp;gt;NumberParameters)
            &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_EXECUTE_HANDLER;
        &lt;span class="kwrd"&gt;break&lt;/span&gt;;

    &lt;span class="kwrd"&gt;default&lt;/span&gt;:
        &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_EXECUTE_HANDLER;
    }

    &lt;span class="kwrd"&gt;if&lt;/span&gt;  (EXCEPTION_NONCONTINUABLE == ExceptionInfo-&amp;gt;ExceptionRecord-&amp;gt;ExceptionFlags)
        &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_EXECUTE_HANDLER;

    &lt;span class="kwrd"&gt;if&lt;/span&gt;  (EXCEPTION_READ_FAULT != ExceptionInfo-&amp;gt;ExceptionRecord-&amp;gt;ExceptionInformation[0] ||
        KnownTickCountAddress != ExceptionInfo-&amp;gt;ExceptionRecord-&amp;gt;ExceptionInformation[1])
        &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_EXECUTE_HANDLER;

    &lt;span class="kwrd"&gt;if&lt;/span&gt;  (KnownTickCountAddress == ExceptionInfo-&amp;gt;ContextRecord-&amp;gt;Rax)
    {
        ExceptionInfo-&amp;gt;ContextRecord-&amp;gt;Rax = (DWORD64) &amp;amp;FakeTickCount;
            &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_CONTINUE_EXECUTION;
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;  (KnownTickCountAddress == ExceptionInfo-&amp;gt;ContextRecord-&amp;gt;Rbx)
 &lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The rest I leave as an exercise to the reader, having already put all 0.378 of you through the treadmill today…&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9555103" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/WdfVerifier/default.aspx">WdfVerifier</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/test+development/default.aspx">test development</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/C_2B002B00_/default.aspx">C++</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/Life+at+Microsoft/default.aspx">Life at Microsoft</category></item><item><title>Using C++ in a KMDF driver part 1- a pattern for using contexts as objects</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2009/03/12/using-c-in-a-kmdf-driver-part-1-a-pattern-for-using-contexts-as-objects.aspx</link><pubDate>Thu, 12 Mar 2009 16:36:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9471696</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/9471696.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=9471696</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=9471696</wfw:comment><description>&lt;p&gt;This is an article I’ve started probably close to a dozen times since I started this blog, but never published.&amp;#160; In part because of all the heat the topic of using C++ in the kernel generates, and the rest perhaps because of my reaction to that heat.&lt;/p&gt;  &lt;p&gt;So I’ll get one thing off my chest at the start and perhaps that will be enough to let me proceed.&lt;/p&gt;  &lt;p&gt;I’ve been writing drivers with C++ in the kernel (or the Win 3.1/9x/ME VMM) pretty much since I began using the language (in the very early 90’s).&amp;#160; I routinely use paged code (paged data not so much- I’ve never had designs where there seemed to be any benefit to it).&amp;#160; That spans more than a decade- in fact, its close to two decades now.&lt;/p&gt;  &lt;p&gt;I’ve NEVER had a problem with the issues raised in the paper.&amp;#160; I’m not even going to link to it.&amp;#160; If you want to find it- it isn’t hard to find.&amp;#160; On top of that, in a determined effort to find people who had, I didn’t find many- and the one clear case I did find was cured with a #pragma that would have made sense if you were a C programmer and had a basic understanding of where VTABLES and such get emitted to.&amp;#160; So I personally have a sense of mismatch between my own experience and the strongly worded severity there.&lt;/p&gt;  &lt;p&gt;I’ve been told that if I persist, I’ll deserve all the paging problems I get [and that nobody will help me with them].&amp;#160; Well, I do get them (always have), and I’ve been developing long enough in this environment that I don’t really need anybody’s help to find the root cause of a bug like that.&amp;#160; The causes are always the ones I remember- acquiring a spin lock in pagable code- making a routine pagable that can be called at elevated IRQL- all the usual ways to screw up in that other language that is the hallmark of a true first-class kernel developer.&amp;#160; But none of them had anything to do with my choice of programming language.&amp;#160; Not once.&amp;#160; Not saying that it never happened across all those years, because in the early ones, the ability to catch a bug like that was severely limited- there was no Driver Verifier, no static analysis tools.&amp;#160; So it may not have been noticed early on.&amp;#160; But now that I have them, it’s still not happening…&lt;/p&gt;  &lt;p&gt;Now there can be plenty of reasons for that- but I look at what people take away from the paper, and I do a lot of the things they think aren’t safe.&amp;#160; I use polymorphism and inheritance freely.&amp;#160; I don’t use multiple inheritance a lot, but I have used it and have not observed problems arising from its use.&amp;#160; On the other hand, there are common features that I don’t use as a matter of personal preference or style that may bear on this.&amp;#160; I don’t expose the implementation of functions in header files (meaning the compiler is not going to start out by inlining them and then give up later, dumping them in some unintended segment) with the exception of trivial accessor functions.&amp;#160; I don’t use templates (I’m not sure they were a language feature when I started, but at any rate, during my learning curve I never needed them, so while I can handle code with templates, I don’t use them myself).&amp;#160; I almost always code my own constructors, destructors, copy constructors and assignment operators (I usually have to- I prefer references to pointers and if you have reference members, the compiler can’t generate default code for most of those routines).&lt;/p&gt;  &lt;p&gt;So now that its clear I’m not going to walk the company line on that topic [the opinions I expressed ought obviously to be clearly my own], I’ll proceed to something more useful…&lt;/p&gt;  &lt;h2&gt;Leveraging the KMDF Object Model&lt;/h2&gt;  &lt;p&gt;KMDF provides a nice object model, with managed lifetimes and one of the most delightful observations I had in my first KMDF driver was that it was easy for me to blend this with my usual coding patterns.&lt;/p&gt;  &lt;p&gt;As an aside, I’ll note that I never use sample code to learn anything.&amp;#160; I take the reference materials and code to them.&amp;#160; If there are samples, I treat them as the last resort- and I will deliberately change as much as I can of them [in part to see what knowledge of things that can go wrong wasn’t explicitly represented in the sample].&amp;#160; I judge the quality of the reference material by how rarely I have to look at a sample to figure something out [yes, I don’t find much reference material i would call “good”].&lt;/p&gt;  &lt;p&gt;So my first KMDF driver was a software bus driver, and I didn’t go near toaster in writing it.&amp;#160; In fact it was one of those “ActiveX” (OLE automation) test drivers I mentioned in our DDC presentation.&amp;#160; Now we had some samples for them, too- and not surprisingly, virtually no reference material.&amp;#160; The samples were fastidious about one thing- all the COM parts were in C++ (not a lot of choice there)- but all the parts using KMDF were in C- precisely because of said paper.&amp;#160; I might add that this was even though no attempt was made to mark any of the code or data pagable in those samples.&amp;#160; Well, I’m a stubborn &amp;lt;expletive of your choice here&amp;gt;, so I decided then and there I was going to write the whole driver in C++ in spite of the objections I received.&amp;#160; I was still in my “trial period” so they could always fire me if they wanted to, but the job market was good enough at that time that I was pretty sure I could find something…&lt;/p&gt;  &lt;p&gt;Back to the proper topic- one fine thing is that most of the KMDF macros are agnostic enough they can handle at least straightforward C++.&amp;#160; That was one of the happiest discoveries of that time.&lt;/p&gt;  &lt;p&gt;So the basic pattern as I use it:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Declare a static function in your class that takes a WDFOBJECT as input and returns a pointer to an object of your class. &lt;/li&gt;    &lt;li&gt;Declare a class-specific placement form new operator that takes as its additional input the type of handle you expect your object to live in the context of (that is, it can be more precise than the preceding function can and you can benefit from stronger typing in C++) &lt;/li&gt;    &lt;li&gt;Declare a class-specific delete operator that basically does nothing if you need to have your destructor invoked. &lt;/li&gt;    &lt;li&gt;If you have such a delete operator, also declare a static member with a void return that takes a WDFOBJECT as input. &lt;/li&gt;    &lt;li&gt;Use the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro to get the compiler to write that first function for you. &lt;/li&gt;    &lt;li&gt;Have your new operator implementation use the first function to return the address of the underlying context (you basically ignore or validate the size parameter) from the passed-in handle. &lt;/li&gt;    &lt;li&gt;When creating the context, and you need your destructor called, use a WDF_OBJECT_ATTRIBUTES structure with the EvtCleanupCallback set to the routine in item 4. &lt;/li&gt;    &lt;li&gt;Code that routine to use the routine in item 1 to get the context address out of the object handle- and delete that pointer.&amp;#160; This causes your destructor to be called at cleanup time (which is much more sensible than destroy time) and your do-nothing delete operator will also be invoked (or inlined out of existence if your compiler is any good).&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;There- you “create” your object when the KMDF object is created (or via a WdfObjectAllocateContext call if you add your object later), and “delete” it when the object dies.&amp;#160; But KMDF manages the memory and most of the object lifetime for you.&amp;#160; Sure works for me (a lot).&lt;/p&gt;  &lt;p&gt;The following snippet is from that first driver (I’ve since dropped the usage of “C” on class definitions in my general drive toward anarchic style).&amp;#160; This is slightly convoluted because I have logic allowing only one instance of a device with this driver- so I’ve deliberately intermingled driver-level and device-level usages (always pushing those boundaries- but I think that’s a good way for an SDET to think).&amp;#160; I’ll admit this is slightly doctored (I removed some things related to the COM technology as that I can’t disclose, plus I tried to include support for the standard bus interface and that just complicates things without illustrating this method), but it should show I practiced what I am preaching…&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; CTargetTestBus
{
    &lt;span class="kwrd"&gt;static&lt;/span&gt; WDFDEVICE                Owner;              &lt;span class="rem"&gt;//  WDF device that &amp;quot;owns&amp;quot; this bus object&lt;/span&gt;

    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt;*    &lt;span class="kwrd"&gt;operator&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt;(size_t size, WDFDEVICE OwningDevice);
    CTargetTestBus(WDFDEVICE OwningDevice);
    ~CTargetTestBus() {}

    &lt;span class="rem"&gt;//  Private callbacks (ie, accessed from within this class' code)&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; EVT_WDF_IO_QUEUE_IO_DEFAULT      OnIoDispatchDefault;

    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; delete(&lt;span class="kwrd"&gt;void&lt;/span&gt;*) {}
&lt;span class="kwrd"&gt;public&lt;/span&gt;:

    NTSTATUS    NewChild(LPCWSTR Name, &lt;span class="kwrd"&gt;int&lt;/span&gt; InstanceID);
    NTSTATUS    RemoveChild(LPCWSTR Name, &lt;span class="kwrd"&gt;int&lt;/span&gt; InstanceID);
    &lt;span class="kwrd"&gt;void&lt;/span&gt;        DoneWithBus();

    &lt;span class="kwrd"&gt;static&lt;/span&gt; CTargetTestBus*  GetThisTargetTestBus(__in WDFOBJECT Object);    &lt;span class="rem"&gt;//  WDF macro writes this code&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; CTargetTestBus&amp;amp;  GetTheBus(&lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;amp; BusPresent);
    
    &lt;span class="rem"&gt;//  Driver callbacks (public, because used in DriverEntry)&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; EVT_WDF_DRIVER_DEVICE_ADD        OnDriverDeviceAdd;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt;             OnDriverUnload(IN WDFDRIVER Driver);

    &lt;span class="rem"&gt;//  This one is accessed from a member in CChildInfo&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; EVT_WDF_CHILD_LIST_CREATE_DEVICE OnAddNewChild;
};


&lt;span class="rem"&gt;// Macros to get the context&lt;/span&gt;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CTargetTestBus, CTargetTestBus::GetThisTargetTestBus);&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;em&gt;Now playing:&amp;#160; Me (that old recording of Johnny B Goode again)!&lt;/em&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9471696" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/test+development/default.aspx">test development</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/C_2B002B00_/default.aspx">C++</category></item><item><title>Why You'll Never See a Sample From Me...</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2008/02/08/why-you-ll-never-see-a-sample-from-me.aspx</link><pubDate>Fri, 08 Feb 2008 23:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7545594</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/7545594.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=7545594</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=7545594</wfw:comment><description>&lt;P&gt;I noticed yesterday that &lt;A href="http://blogs.msdn.com/peterwie" target=_blank mce_href="http://blogs.msdn.com/peterwie"&gt;Peter&lt;/A&gt; and &lt;A href="http://blogs.msdn.com/888_umdf_4_you" target=_blank mce_href="http://blogs.msdn.com/888_umdf_4_you"&gt;Patrick&lt;/A&gt; are &lt;A href="http://blogs.msdn.com/888_umdf_4_you/archive/2008/02/06/7496771.aspx" target=_blank mce_href="http://blogs.msdn.com/888_umdf_4_you/archive/2008/02/06/7496771.aspx"&gt;trading comments and thoughts on coding styles&lt;/A&gt;.&amp;nbsp; So I'll come out of my cage and admit I am the consummate iconoclast on most issues of style.&amp;nbsp; When I review code, I make comments about logic, out-and-out errors, and (generally adding that I don't regard it as important) typos in comments.&amp;nbsp; Beyond that, I don't bother.&amp;nbsp; When I read the &lt;A href="http://www.osronline.com/showThread.cfm?link=124310" target=_blank mce_href="http://www.osronline.com/showThread.cfm?link=124310"&gt;occasional forum thread on coding&lt;/A&gt;, I just sort of sit and shake my head as I read how much people hate the way I like to think and loathe the things I find useful to do.&lt;/P&gt;
&lt;P&gt;But that's nothing new- I learned a long time ago that my ideas were different.&amp;nbsp; But I've spent my years in maintenance and other activities and still have them.&lt;/P&gt;
&lt;P&gt;Most standards are fueled by someone's personal tastes being enforced by fiat on a team, usually backed up by anecdotal assertions about how useful they are in maintenance.&amp;nbsp; You take liberal amounts of those add a dash of geopolitical correctness or "professional presentation" reviews and a nice heaping of endless semantic analysis of names and what I once found to be enjoyable (writing code to make a computer solve a problem) becomes one of the most tedious tasks on earth.&lt;/P&gt;
&lt;P&gt;I loathe standards.&amp;nbsp; I deliberately flout them at times just to get the pent-up frustrations off my chest.&amp;nbsp; I usually revert to using them [pragmatism again], but occasionally get caught when I write some toy that someone later decides should be kept but they don't want to rewrite it [hard to understand, because for the life of me, most devs secretly want to rewrite every line of code they see so it fits their personal style- usually they have to wait unitl they have a senior position, at which point they have learned to call it "refactoring", which makes it sound more worthwhile than "making it pretty because currently it iz teh suk".&lt;/P&gt;
&lt;P&gt;Of late, I like this set of rules:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;132 columns: 80 columns- that was punched cards.&amp;nbsp; I used them, they sucked.&amp;nbsp; Character mode displays- same limit because they had to display what was on punched cards.&amp;nbsp; They were better, but I like my hi-res displays much better, thank you.&amp;nbsp; Printers- I wrote and tested printer drivers for over a decade.&amp;nbsp; I've personally destroyed enough trees I should rot in hell for several eternities.&amp;nbsp; I only print when I must, and then I use both sides, N-up and whatever else I can do to keep my repentant attitude.&amp;nbsp; And if some line gets longer than that, I'll fix it if I feel like it. &lt;/LI&gt;
&lt;LI&gt;Mnemonic names are good.&amp;nbsp; CamelCasingRules.&amp;nbsp; Elaborate and contrived jokes are best, as long as you don't waste too much time on them. &lt;/LI&gt;
&lt;LI&gt;Putting each parameter in a function call on a separate line is a waste of good screen real estate.&amp;nbsp; I learned how to read more than one word at a time years ago.&amp;nbsp; If I care what the parameters are, I'll look closer- I can even pop up a nice API description from MSDN or wherever if I need to (or use a class browser, etc).&amp;nbsp; If I don't care what they are, I like being able to ignore one or two lines of code instead of a dozen. &lt;/LI&gt;
&lt;LI&gt;C++ overloading is useful.&amp;nbsp; That goes for functions, operators and even casts.&amp;nbsp; If a line of code looks confusing, I use a browser to tell me which if any of those are in play.&amp;nbsp; I then use intuition to tell me where the problems are likely to be. &lt;/LI&gt;
&lt;LI&gt;My sole old-fashioned item is I adhere to &lt;A href="http://en.wikipedia.org/wiki/Edsger_Dijkstra" target=_blank mce_href="http://en.wikipedia.org/wiki/Edsger_Dijkstra"&gt;Djikstra&lt;/A&gt;'s seminal laws.&amp;nbsp; Gotos are unnecessary.&amp;nbsp; I could care if they look pretty- I still see more screwups today from their use than anything else.&amp;nbsp; But I also am pragmatist and observer of the human condition enough to know a pointless battle when I see it.&amp;nbsp; Each generation of programmers is smart enough to never do it wrong, and knows better than some dead Dutch guy how to write good code.&amp;nbsp; Just ask them, they'll tell you.&amp;nbsp; Global variables is the other one [at least, that's how I remember it]. &lt;/LI&gt;
&lt;LI&gt;C is a good language for dinosaurs.&amp;nbsp; Plod along, ye denizens of the past! &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Next week, maybe I'll adopt a different set of attitudes, just to be ornery.&amp;nbsp; But I can only observe hours of discussion about a name or a standard like "do it this way because then when I use a proportional font I like the way it looks" or "all function names will begin with the camel-cased path to the source file from the base of the build tree [that's not a joke, BTW- I really worked where that was the standard- geez, use a PDB]".&lt;/P&gt;
&lt;P&gt;SDETs aren't totally immune from such standards, but things are a bit more lax, and people maybe don't watch me as much as they should to keep me from misbehaving.&amp;nbsp; I think my most recent misdeed was creating a quick off-the cuff C++ class to wrap a buffer pointer so it wouldn't leak (similar to the &lt;A href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization" target=_blank mce_href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization"&gt;RAII pattern&lt;/A&gt;).&amp;nbsp; Being in a hurry, I named the class the first thing that came to mind: leak free buffer = &lt;A href="http://en.wikipedia.org/wiki/Pampers" target=_blank mce_href="http://en.wikipedia.org/wiki/Pampers"&gt;Pampers&lt;/A&gt;.&amp;nbsp; Ordinarily I would have gone back and changed it, but I got in a hurry and checked it in anyway.&amp;nbsp; I'm sure I'll get a diaperful about doing that at some point...&lt;/P&gt;
&lt;P&gt;So just for fun, here are concrete examples of why you'll not be seeing samples from me:&lt;/P&gt;
&lt;P&gt;From WdfVerifier:&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=rem&gt;/**********************************************************************************************************************************&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;void    ExplainHowTheCommandLineWorksInMindNumbingDetail()&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;Does as it says, says what it does.&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;**********************************************************************************************************************************/&lt;/SPAN&gt;

&lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt;    ExplainHowTheCommandLineWorksInMindNumbingDetail()
{
    &lt;SPAN class=rem&gt;//  Like a good localizable application, the text for the message box is now in the resources.&lt;/SPAN&gt;
    String  Explanation(IDS_Explanation);

    MessageBox(NULL, Explanation, ApplicationName, MB_ICONINFORMATION | MB_OK);
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;That happens to get called from here:&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=rem&gt;/**********************************************************************************************************************************&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;extern "C" int __cdecl main(int, __in char**)&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;Yes, I cheated- even though this is a Windows program, it still uses main- it uses the Windows API to get a unicode command line.&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;Seriously, this works fine, and it isn't any danger at all.  Used to do it all the time in the early days of NT (those halcyon days&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;when you had to start Windows from the command line after the system booted).&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;**********************************************************************************************************************************/&lt;/SPAN&gt;

&lt;SPAN class=kwrd&gt;extern&lt;/SPAN&gt; &lt;SPAN class=str&gt;"C"&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; __cdecl main(&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt;, __in &lt;SPAN class=kwrd&gt;char&lt;/SPAN&gt;**)
{
    &lt;SPAN class=rem&gt;//  Check the command line- it will tell us if we need to display a UI or just function as a console app.&lt;/SPAN&gt;

    &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt;     ParameterCount = 0, ServiceCount = 0;
    &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt;    ExplainYourself = &lt;SPAN class=kwrd&gt;false&lt;/SPAN&gt;;
    &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt;    RemoteAccessRequired;
    PWSTR   MachineName = NULL;
    PWSTR*  Parameters = CommandLineToArgvW(GetCommandLineW(), &amp;amp;ParameterCount);
    
    &lt;SPAN class=rem&gt;//  Parameter 0 is the program name, and it isn't important here...&lt;/SPAN&gt;

    &lt;SPAN class=kwrd&gt;switch&lt;/SPAN&gt;  (ParameterCount)
    {
    &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt;    1:
        &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

    &lt;SPAN class=kwrd&gt;default&lt;/SPAN&gt;:
        ExplainYourself = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;;
        &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;

    &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt;    3:
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;  (CompareString(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, 
            Parameters[1], -1, L&lt;SPAN class=str&gt;"-machine"&lt;/SPAN&gt;, -1) == CSTR_EQUAL)
            MachineName = Parameters[2];
        &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
            ExplainYourself = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;;
    }

    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;  (ExplainYourself)
    {
        ExplainHowTheCommandLineWorksInMindNumbingDetail();
        &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt;  98052;
    }&lt;/PRE&gt;
&lt;P&gt;
&lt;STYLE type=text/css&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;
&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas color=#000000 size=2&gt;The comment about starting as UI or console is an artifact I missed (and will thus shortly disappear).&amp;nbsp; You can look up 98052 (hint- it's a US postal code, aka ZIP code).&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas color=#000000 size=2&gt;This will upset all those who loathe overloads- it is from a stress test I wrote early on for thrashing KMDF request processing, pnp and power in a random fashion- this snippet does all the up front configuration stuff (there are built-in defaults which you can override from a file specified on the command line- you can optionally display a huge property sheet-based configuration UI and save it all back to a file- settings are also saved to registry and those settings override defaults (but not from file or UI, of course):&lt;/FONT&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=rem&gt;/**********************************************************************************************************************************&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;main&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;Establishes the stress run settings, possibly with user interaction, then starts the initial mix and loops forever interfering with&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;the setup until it gets stopped, the machine reboots, the debugger breaks, or you bugcheck.&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;**********************************************************************************************************************************/&lt;/SPAN&gt;

&lt;SPAN class=kwrd&gt;extern&lt;/SPAN&gt; &lt;SPAN class=str&gt;"C"&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; __cdecl main(&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt;, __in &lt;SPAN class=kwrd&gt;char&lt;/SPAN&gt;**)
{
    &lt;SPAN class=rem&gt;//  Record the global instance handle, so all are copacetic with Win32.&lt;/SPAN&gt;
    PropertyPage::InstanceIs((HINSTANCE)GetModuleHandle(NULL));

    &lt;SPAN class=rem&gt;//  Seed the PRNG&lt;/SPAN&gt;
    FILETIME    Now;
    GetSystemTimeAsFileTime(&amp;amp;Now);
    srand(Now.dwHighDateTime + Now.dwLowDateTime);

    &lt;SPAN class=kwrd&gt;try&lt;/SPAN&gt;
    {
        UsingCom                ButThenWhoDoesNot;

        &lt;SPAN class=rem&gt;//  We need to get access to the global configuration.  We must pay toll to the gatekeper to do so.&lt;/SPAN&gt;

        ControlHolder           WhatMakesUsTick;

        &lt;SPAN class=rem&gt;//  Define objects that make up the stress configuration control (and UI)&lt;/SPAN&gt;
        ThreadConfiguration&amp;amp;    ThreadControl = WhatMakesUsTick;
        TargetDelays&amp;amp;           TargetDelayControl = WhatMakesUsTick;
        HunterTimeouts&amp;amp;         HunterTimeoutControl = WhatMakesUsTick;
        HunterSectoring&amp;amp;        HunterSectorControl = WhatMakesUsTick;
        TargetLifetimes&amp;amp;        TargetLifetimeControl = WhatMakesUsTick;
        TargetStatus&amp;amp;           TargetReportingControl = WhatMakesUsTick;
        TargetToggler&amp;amp;          TargetToggleCentral = WhatMakesUsTick;
        HunterIdleTimes&amp;amp;        HunterIdling = WhatMakesUsTick;
        HunterPowerUpDelays&amp;amp;    HunterPowerUp = WhatMakesUsTick;
        HunterPowerDownDelays&amp;amp;  HunterPowerDown = WhatMakesUsTick;
        TargetIdleTimes&amp;amp;        TargetIdling = WhatMakesUsTick;
        TargetPowerUpDelays&amp;amp;    TargetPowerUp = WhatMakesUsTick;
        TargetPowerDownDelays&amp;amp;  TargetPowerDown = WhatMakesUsTick;

        &lt;SPAN class=rem&gt;//  Now, define the object that represents our operating situation&lt;/SPAN&gt;
        MemoryStorage           Configuration;

        &lt;SPAN class=rem&gt;//  Size the parameter store, then populate it.&lt;/SPAN&gt;
        SizeCalculator  Sizer;

        Sizer &amp;lt;&amp;lt; ThreadControl &amp;lt;&amp;lt; TargetDelayControl &amp;lt;&amp;lt; TargetReportingControl &amp;lt;&amp;lt; HunterTimeoutControl &amp;lt;&amp;lt;
            HunterSectorControl &amp;lt;&amp;lt; TargetLifetimeControl &amp;lt;&amp;lt; TargetToggleCentral &amp;lt;&amp;lt; HunterIdling &amp;lt;&amp;lt; HunterPowerUp &amp;lt;&amp;lt;
            HunterPowerDown &amp;lt;&amp;lt; TargetIdling &amp;lt;&amp;lt; TargetPowerUp &amp;lt;&amp;lt; TargetPowerDown;

        Configuration &amp;lt;&amp;lt; Sizer;

        &lt;SPAN class=rem&gt;//  First, set it to the defaults defined by each participating object.&lt;/SPAN&gt;
        Configuration &amp;lt;&amp;lt; ThreadControl &amp;lt;&amp;lt; TargetDelayControl &amp;lt;&amp;lt; TargetReportingControl &amp;lt;&amp;lt; HunterTimeoutControl &amp;lt;&amp;lt;
            HunterSectorControl &amp;lt;&amp;lt; TargetLifetimeControl &amp;lt;&amp;lt; TargetToggleCentral &amp;lt;&amp;lt; HunterIdling &amp;lt;&amp;lt; HunterPowerUp &amp;lt;&amp;lt;
            HunterPowerDown &amp;lt;&amp;lt; TargetIdling &amp;lt;&amp;lt; TargetPowerUp &amp;lt;&amp;lt; TargetPowerDown;

        &lt;SPAN class=rem&gt;//  Then, initialize from the registry if there's anything there (settings from last run)&lt;/SPAN&gt;

        Registry    LastRun(HKEY_LOCAL_MACHINE, L&lt;SPAN class=str&gt;"Software\\Microsoft\\KMDF QA\\IoTargetStress"&lt;/SPAN&gt;);

        Configuration &amp;lt;&amp;lt; LastRun;

        &lt;SPAN class=rem&gt;//  Now check the command line- it will tell us if we need to display a UI or initialize from some file.&lt;/SPAN&gt;

        &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; ParameterCount = 0;
        &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt;    DisplayUI = &lt;SPAN class=kwrd&gt;false&lt;/SPAN&gt;;
        PWSTR   FileName = NULL;
        PWSTR*  Parameters = CommandLineToArgvW(GetCommandLineW(), &amp;amp;ParameterCount);

        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;  (1 &amp;lt; ParameterCount)
        {
            &lt;SPAN class=rem&gt;//  Unfortunately LOCALE_INVARIANT is an XP invention, and this has to run on Win2K&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;  (CompareString(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, Parameters[1],
                -1, L&lt;SPAN class=str&gt;"-configure"&lt;/SPAN&gt;, -1) == CSTR_EQUAL)
            {
                DisplayUI = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;;
                &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;  (2 &amp;lt; ParameterCount )
                    FileName = Parameters[2];
            }
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
                FileName = Parameters[1];
        }

        &lt;SPAN class=rem&gt;//  If we've got a file to initialize from, so be it.&lt;/SPAN&gt;

        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;  (NULL != FileName)
        {
            FileStorage TreasuredValues(FileName);

            Configuration &amp;lt;&amp;lt; TreasuredValues;
        }

        LocalFree(Parameters);

        &lt;SPAN class=rem&gt;//  Populate everything with our cool new settings (or perhaps the defaults they gave us in the first place)...&lt;/SPAN&gt;
        Configuration &amp;gt;&amp;gt; ThreadControl &amp;gt;&amp;gt; TargetDelayControl &amp;gt;&amp;gt; TargetReportingControl &amp;gt;&amp;gt; HunterTimeoutControl &amp;gt;&amp;gt;
            HunterSectorControl &amp;gt;&amp;gt; TargetLifetimeControl &amp;gt;&amp;gt; TargetToggleCentral &amp;gt;&amp;gt; HunterIdling &amp;gt;&amp;gt; HunterPowerUp &amp;gt;&amp;gt;
            HunterPowerDown &amp;gt;&amp;gt; TargetIdling &amp;gt;&amp;gt; TargetPowerUp &amp;gt;&amp;gt; TargetPowerDown;

        &lt;SPAN class=rem&gt;//  If the command line says to display the Configuration UI, then do it.&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;  (DisplayUI)
        {
            Properties          ConfigurationManager;

            &lt;SPAN class=rem&gt;//  Populate the property sheet with its pages.&lt;/SPAN&gt;
            ConfigurationManager &amp;lt;&amp;lt; ThreadControl &amp;lt;&amp;lt; TargetDelayControl &amp;lt;&amp;lt; TargetReportingControl &amp;lt;&amp;lt; HunterTimeoutControl &amp;lt;&amp;lt;
                HunterSectorControl &amp;lt;&amp;lt; TargetLifetimeControl &amp;lt;&amp;lt; TargetToggleCentral &amp;lt;&amp;lt; HunterIdling &amp;lt;&amp;lt; HunterPowerUp &amp;lt;&amp;lt;
                HunterPowerDown &amp;lt;&amp;lt; TargetIdling &amp;lt;&amp;lt; TargetPowerUp &amp;lt;&amp;lt; TargetPowerDown;

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;  (ConfigurationManager.Interact() == IDOK)
            {
                &lt;SPAN class=rem&gt;//  Pull the updated configuration out of the objects&lt;/SPAN&gt;
                Configuration &amp;lt;&amp;lt; ThreadControl &amp;lt;&amp;lt; TargetDelayControl &amp;lt;&amp;lt; TargetReportingControl &amp;lt;&amp;lt; HunterTimeoutControl &amp;lt;&amp;lt;
                    HunterSectorControl &amp;lt;&amp;lt; TargetLifetimeControl &amp;lt;&amp;lt; TargetToggleCentral &amp;lt;&amp;lt; HunterIdling &amp;lt;&amp;lt; HunterPowerUp &amp;lt;&amp;lt;
                    HunterPowerDown &amp;lt;&amp;lt; TargetIdling &amp;lt;&amp;lt; TargetPowerUp &amp;lt;&amp;lt; TargetPowerDown;

                &lt;SPAN class=rem&gt;//  Now, store it off to a file.&lt;/SPAN&gt;
                FileStorage Payload;

                Configuration &amp;gt;&amp;gt; Payload;
            }
        }

        &lt;SPAN class=rem&gt;//  Save this run's settings off to the registry&lt;/SPAN&gt;
        Configuration &amp;gt;&amp;gt; LastRun;

        &lt;SPAN class=rem&gt;//  Time to actually start doing the REAL work&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;&lt;FONT face=Consolas color=#000000 size=2&gt;Yup, those are cast operators for object references [BTW, they are polymorphic, to boot], overloaded (multiple ways, depending upon the target object) shift operators (iostream-style) and a host of sins that will leave me burning in many folks' idea of programmer Hades for many lifetimes.&amp;nbsp; Yes, there are "hunters" that fire requests at "targets"- they can even acquire them at will.&amp;nbsp; I'd show you THAT code, but this is long enough [a static KMDF device context accessor named Hunter::HidingInBushes and some variables named "Nimrod" might give you a general idea, though- and yes, I did write all those KMDF Drivers in C++].&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas color=#000000 size=2&gt;And like all true sinners, I am pretty much unrepentant.&amp;nbsp; But I do promise never to author a WDK or SDK sample.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas color=#000000 size=2&gt;&lt;/FONT&gt;
&lt;STYLE type=text/css&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;
&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7545594" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/WdfVerifier/default.aspx">WdfVerifier</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/test+development/default.aspx">test development</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/C_2B002B00_/default.aspx">C++</category></item></channel></rss>