<?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>16.7ms in the life : Coding</title><link>http://blogs.msdn.com/peterrosser/archive/tags/Coding/default.aspx</link><description>Tags: Coding</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Thoughts on software complexity</title><link>http://blogs.msdn.com/peterrosser/archive/2006/06/02/SoftwareComplexity.aspx</link><pubDate>Sat, 03 Jun 2006 07:06:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:615591</guid><dc:creator>Peter Rosser</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/peterrosser/comments/615591.aspx</comments><wfw:commentRss>http://blogs.msdn.com/peterrosser/commentrss.aspx?PostID=615591</wfw:commentRss><wfw:comment>http://blogs.msdn.com/peterrosser/rsscomments.aspx?PostID=615591</wfw:comment><description>&lt;P&gt;If you've ever tried to create a software application of any decent size, you have probably realized that what works with small tools more often than not does not scale well to larger sizes.&amp;nbsp; There are whole books written about how to scale up and out, new languages and technologies invented to help manage it, and millions of dollars in educational budgets spent every year to achieve that elusive goal.&lt;/P&gt;
&lt;P&gt;And yet, the landscape is still rife with examples of poorly designed software.&lt;/P&gt;
&lt;P&gt;A significant part of the&amp;nbsp;problem is not that engineers are not smart enough--it's that we outsmart ourselves.&amp;nbsp; The conventional wisdom is that humans can store 7 ± 2 primitives (e.g. numbers) on the top stack of short-term memory.&amp;nbsp; The number skews higher for strongly associative items, and vice versa.&amp;nbsp; We can store fewer abstract items, often only 2 or 3 at a time.&amp;nbsp; The issue is not one of comprehension, it's one of focused retension.&amp;nbsp; When the number of data items in a class exceeds our capacity to retain them at once, the brain tends to move the perceived "less important" fields/properties into peripheral storage.&amp;nbsp; This, I think, leads to not fully comprehending the interactions in the class.&amp;nbsp; We engineers like to think of ourselves as intelligent, and that we can understand very complex ideas.&amp;nbsp; This may be true, but it misses the point; the point of software engineering is to create&amp;nbsp;reliable, performant, maintainable software.&amp;nbsp; It is &lt;EM&gt;not&lt;/EM&gt; to create complex applications.&lt;/P&gt;
&lt;P&gt;Well, there's the problem, isn't it?&amp;nbsp; In order to create the really cool applications, you must have complexity.&amp;nbsp; It's simply unavoidable, especially given the advanced competition for consumer dollars.&amp;nbsp; You can't very well create a next generation RPG that has realistic physics, with a "real" economy, kickass graphics and brutally smart AI without complexity.&lt;/P&gt;
&lt;P&gt;Or can you?&lt;/P&gt;
&lt;P&gt;Actually, I believe the answer is that you can, at least the bad kind of complexity that causes the pain.&amp;nbsp;The key is differentiating between behavioral complexity and system complexity.&amp;nbsp; Behavioral complexity is the aforementioned features like smart AI, or realistic physics.&amp;nbsp; Those sorts of things are monstrously difficult to get right, but that's not what holds back the very large application development projects.&amp;nbsp; The major cause for schedule slips, regressions, out-and-out bugs, and general angst is system complexity.&lt;/P&gt;
&lt;P&gt;Before I go on, I'd like to define what I mean (yes, I do get to hijack words like this) by&amp;nbsp;system complexity: &lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #f5f5dc"&gt;System complexity a property of a system that&amp;nbsp;is directly proportional to the difficulty one has&amp;nbsp;in&amp;nbsp;comprehending&amp;nbsp;the system&amp;nbsp;at the level and detail necessary to make changes to the system without introducing instability or functional regressions. &lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;In other words, the higher the system complexity, the harder it is to upgrade, maintain, and&amp;nbsp;develop the system.&amp;nbsp;Whether the system is a single class, an object library, an inheritance heirarchy, or an entire application, someone "schooled in the art" of software engineering should be able to understand it, given a reasonable time to examine the system.&amp;nbsp; This ability should &lt;EM&gt;scale through the system.&lt;/EM&gt;&amp;nbsp; When one examines a particular object, it should be apparent without examining the private implementation details how to use it.&amp;nbsp; From top to bottom, from bottom to top; the entire system should be accessible to the non-super-geniuses out there.&amp;nbsp; What goes for good UI design also goes for good C++, C# and COM design: your target audience should be able to use it without extensive systems training.&lt;/P&gt;
&lt;P&gt;System Complexity is what makes the Mythical Man Month true.&amp;nbsp; It's what keeps that guy who wrote the accounting system from scratch in 1986 employed.&amp;nbsp; It's what causes games, productivity applications, and even (some might say especially) large operating system projects to slip their schedules.&lt;/P&gt;
&lt;P&gt;So what can you do about it?&amp;nbsp; The first step to recovery is admitting you have a problem.&amp;nbsp; Pedantic, but true.&amp;nbsp; Getting back to the point I tried to make earlier about engineers--we like to think we are smart.&amp;nbsp; Egos loom large in the software industry, and often with good reason.&amp;nbsp; One of the smartest developers I have come across worked on a critical piece of the code for several years, and guarded his territory jealously.&amp;nbsp; Make no mistake, this guy was brilliant--and he knew it.&amp;nbsp; To make a long story short, when he left, the code he left behind was an engineering marvel [he says wryly] that no one else understood.&amp;nbsp; Oh, we know what it does, but there's a crucial difference in understanding what something does, and grokking fully how it does it.&amp;nbsp; Tracing execution paths through this code is difficult, and 1200-line methods named "Run" are common.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;The author understood it all, or said he did, but my opinion is that he was fooling himself, too.&amp;nbsp;Once you get a piece of the system working, after all, you don't need to touch that piece again unless the design changes, a bug is found, or something like that.&amp;nbsp;Over time, though, people started to notice that even small fixes in this particular area would touch a dozen or more files, and churn lots of code.&amp;nbsp; That's a symptom of high system complexity; he would go in to make the fix, then discover that 100 variables influenced the behavior, or the implementation in one area was strongly dependent on the implementation in another, or most often, both.&amp;nbsp; But since the author had traveled this area so much, he was able to turn around the fixes in an acceptable timeframe, so he "got away" with it.&lt;/P&gt;
&lt;P&gt;It's no surprise that when the author decided to move on to other things, as employees often do, that we had a tough decision to make.&amp;nbsp; Do we maintain this code that's &lt;EM&gt;working&lt;/EM&gt;?&amp;nbsp; Do we refactor?&amp;nbsp; In the end it came down to pragmatism and schedule: the problem was recognized, and we chose to refactor the system in measured stages, minimizing the risk to the product and getting back to a good, maintainable state.&lt;/P&gt;
&lt;P&gt;That's all I have time for today... my build is done, so back to work I go.&amp;nbsp;Windows Vista waits for no man!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=615591" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Coding/default.aspx">Coding</category><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Musing/default.aspx">Musing</category></item><item><title>Using exported DLL functions</title><link>http://blogs.msdn.com/peterrosser/archive/2006/02/22/ExportedDllFunctions.aspx</link><pubDate>Thu, 23 Feb 2006 01:11:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:537396</guid><dc:creator>Peter Rosser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/peterrosser/comments/537396.aspx</comments><wfw:commentRss>http://blogs.msdn.com/peterrosser/commentrss.aspx?PostID=537396</wfw:commentRss><wfw:comment>http://blogs.msdn.com/peterrosser/rsscomments.aspx?PostID=537396</wfw:comment><description>&lt;P&gt;Now and then it's necessary to use "private" or "internal-only" functions in DLLs that you did not write, don't have the source for, and/or cannot get public interfaces for.&amp;nbsp; I recently had to do this again for a utility application, so I thought it would be nice to document the process a little more clearly for others.&lt;/P&gt;
&lt;P&gt;A starting assumption is that the reader is familiar with GetProcAddress() in its "main" form, which is when you know the full signature of the function you need to call.&amp;nbsp; For example, if you have a copy of foo.dll that exports Bar(LPWSTR, DWORD*):&lt;/P&gt;&lt;FONT color=#008000 size=2&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;// library function is: Bar(LPWSTR lpParam, DWORD *pdwParam)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;typedef&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;void&lt;/FONT&gt;&lt;FONT size=2&gt; (&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;__stdcall&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt; *BAR_PROC)(LPWSTR, DWORD*);&lt;BR&gt;&lt;BR&gt;HANDLE hFoo = LoadLibrary(&lt;/FONT&gt;&lt;FONT color=#800000 size=2&gt;"foo.dll"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;);&lt;BR&gt;BAR_PROC proc = (BAR_PROC)GetProcAddress(hFoo, &lt;/FONT&gt;&lt;FONT color=#800000 size=2&gt;"Bar"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;);&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;// call the library function&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;DWORD dwParam = 0x4;&lt;BR&gt;(proc)(L&lt;/FONT&gt;&lt;FONT color=#800000 size=2&gt;"string"&lt;/FONT&gt;&lt;FONT size=2&gt;, &amp;amp;dwParam);&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;But what if you need to access a function that is not included in the named exports of the library?&amp;nbsp; 90% of the time the functions will be exported with a name, but sometimes not, and for various reasons.&amp;nbsp; The most common reason is for "security through obscurity", because using the function is supposed to be something that you, the user, "should never have to do".&amp;nbsp; Unfortunately, there are scenarios when you need to do just that, for reasons the original publisher never considered, such as if you need to tweak the way something behaves in your mission-critical server process, and the company that made the original custom component has gone out of business.&lt;/P&gt;
&lt;P&gt;Enter the "ordinal" function access method.&amp;nbsp; If you look at the MSDN docs, they even allude to using a function's ordinal with GetProcAddress, but it's a bit of a mystery how to a) get the ordinal, and b) how to use it even if you get it.&amp;nbsp; Once you know the ordinal and prototype of a function, it's simple to use it--getting the function prototypes is the fun part.&lt;/P&gt;
&lt;P&gt;Say you got your hands on a .DEF file that lists the function ordinals, or have used link.exe and&amp;nbsp;through sufficiently wizardly use of a hex editor have examined the [NONAME] functions and determined what their prototypes are.&amp;nbsp; Let's pretend that the Bar function above was actually a [NONAME] function, and you got a listing like this from link.exe /dump /exports foo.dll:&lt;/P&gt;&lt;PRE&gt;Microsoft (R) COFF/PE Dumper Version 7.10.4035 
Copyright (C) Microsoft Corporation. All rights reserved. 


Dump of file c:\myprojects\foo.dll 

File Type: DLL

  Section contains the following exports for foo.dll

    00000000 characteristics 
    41107692 time date stamp Tue Aug 03 22:39:30 2005 
        0.00 version 
           1 ordinal base 
           6 number of functions 
           4 number of names 

    ordinal hint RVA      name 
          3    0 00006948 Connect 
          4    1 00007798 Close 
          5    2 00012000 GetFoo 
          6    3 00014D12 SetFoo 
          1      0000F3A0 [NONAME] 
          2      0000D20A [NONAME]

  Summary

        6000 .data
        2000 .reloc
        9000 .rsrc
       18000 .text
&lt;/PRE&gt;
&lt;P&gt;The depends.exe tool provides similar data in a GUI fashion.&amp;nbsp;You can examine the binary at offsets F3A0 and D20A to determine what the function signature is (well, what the base pointer sig is), and match them up to the expected signature of Bar(LPWSTR, DWORD*) manually to get the proper ordinal.&amp;nbsp; Or more easily, if you know that one of the methods is the droid you are looking for, you can just code up a quick test app and poke at the method as if it were the one you wanted.&amp;nbsp; If it works without throwing an exception... ;-)&lt;/P&gt;
&lt;P&gt;Getting back to the main point, to load the exported-by-ordinal function, there's a handy macro pre-defined in the Visual Studio (v6 or later, IIRC) build environment&amp;nbsp;that can package up that ordinal into the "expected" LPSTR for GetProcAddress.&amp;nbsp; In my example, assuming Bar was actually at ordinal 1, you would do this:&lt;/P&gt;&lt;FONT color=#008000 size=2&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;// library function is: Bar(LPWSTR lpParam, DWORD *pdwParam)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;typedef&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;void&lt;/FONT&gt;&lt;FONT size=2&gt; (&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;__stdcall&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt; *BAR_PROC)(LPWSTR, DWORD*);&lt;BR&gt;&lt;BR&gt;HANDLE hFoo = LoadLibrary(&lt;/FONT&gt;&lt;FONT color=#800000 size=2&gt;"foo.dll"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;);&lt;BR&gt;BAR_PROC proc = (BAR_PROC)GetProcAddress(hFoo, MAKEINTRESOURCEA(1));&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;// call the library function&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;DWORD dwParam = 0x4;&lt;BR&gt;(proc)(L&lt;/FONT&gt;&lt;FONT color=#800000 size=2&gt;"string"&lt;/FONT&gt;&lt;FONT size=2&gt;, &amp;amp;dwParam);&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;The only difference is that you use the MAKEINTRESOURCEA macro to convert that ordinal into something that GetProcAddress can understand, rather than the string name of the function.&lt;/P&gt;
&lt;P&gt;If you really want to get tricky, you don't actually need GetProcAddress at all to do this magic.&amp;nbsp; If you can guarantee that the DLL won't change underneath you, or you don't mind breaking if it does, or you have smart scanning code that can "find" the offsets again, you can plug the RVA directly into the FARPROC variable.&amp;nbsp; It's all just numbers under the hood, after all.&amp;nbsp; Using the example output of link.exe from above, you can do this:&lt;/P&gt;&lt;FONT color=#008000 size=2&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;// library function is: Bar(LPWSTR lpParam, DWORD *pdwParam)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;typedef&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;void&lt;/FONT&gt;&lt;FONT size=2&gt; (&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;__stdcall&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt; *BAR_PROC)(LPWSTR, DWORD*);&lt;BR&gt;&lt;FONT color=#0000ff&gt;#define&lt;/FONT&gt;&lt;FONT color=#000000&gt; PROC_OFFSET 0x0000F3A0&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;HANDLE hFoo = LoadLibrary(&lt;/FONT&gt;&lt;FONT color=#800000 size=2&gt;"foo.dll"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;);&lt;BR&gt;BAR_PROC proc = (BAR_PROC)(hFoo + PROC_OFFSET)&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;;&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;// call the library function&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;DWORD dwParam = 0x4;&lt;BR&gt;(proc)(L&lt;/FONT&gt;&lt;FONT color=#800000 size=2&gt;"string"&lt;/FONT&gt;&lt;FONT size=2&gt;, &amp;amp;dwParam);&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;Why does this work?&amp;nbsp; LoadLibrary(dll) loads the specified library into the process' address space, and returns a HANDLE value.&amp;nbsp; This HANDLE is the starting address of the library, and since the RVA values for a DLL are offsets from the starting address, you can perform simple addition to the base to get a function's entry point.&amp;nbsp; Pretty cool, huh?&amp;nbsp; All GetProcAddress does is read the DLL's export table into a struct and performs the math for you, returning the result.&amp;nbsp; I'm a big fan of not reinventing the wheel, so I use GetProcAddress when there's an exports entry for what I need.&lt;/P&gt;
&lt;P&gt;What do you do if the function you need is not exported at all?&amp;nbsp; Nine times out of ten it's much easier to just get it exported, but if that's not possible, well, that's a topic for another day.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=537396" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Coding/default.aspx">Coding</category><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Windows/default.aspx">Windows</category></item><item><title>DVB Radio "No TV Signal" Workaround</title><link>http://blogs.msdn.com/peterrosser/archive/2006/01/22/DvbRadioWorkaroundForNoSignalError.aspx</link><pubDate>Mon, 23 Jan 2006 07:50:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:516080</guid><dc:creator>Peter Rosser</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/peterrosser/comments/516080.aspx</comments><wfw:commentRss>http://blogs.msdn.com/peterrosser/commentrss.aspx?PostID=516080</wfw:commentRss><wfw:comment>http://blogs.msdn.com/peterrosser/rsscomments.aspx?PostID=516080</wfw:comment><description>&lt;P&gt;I&amp;nbsp;am currently investigating a fix for two DVB Radio issues identified a workaround for those affected.&amp;nbsp; If you are getting a "No TV Signal" blue overlay when tuning to a DVB Radio station, particularly&amp;nbsp;a low-bitrate station like BBC World Service, or you are seeing 15+ second channel change times for changing between DVB Radio and DVB Video channels, this workaround may apply to you.&lt;/P&gt;
&lt;P&gt;This involves editing your registry, so if you are not comfortable doing that, please wait for the binary fix to be released.&lt;/P&gt;
&lt;P&gt;The key is:&lt;/P&gt;
&lt;P&gt;HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Media Center\Service\Video\Tuners\DVR&lt;/P&gt;
&lt;P&gt;Set &lt;STRONG&gt;NearUnderflowCheckMillis=4000 (0x00000fa0)&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;If you are not experiencing problems with DVB Radio, do not change this value.&amp;nbsp; If you are in the U.S., for example, it can cause instability with ATSC tuning.&amp;nbsp; Once the binary fix is released, you should return this value to its original value of 2000 (decimal).&lt;/P&gt;
&lt;P&gt;This is a non-supported, non-official&amp;nbsp;workaround and is provided AS-IS, with no warranty.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=516080" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Coding/default.aspx">Coding</category><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Media+Center/default.aspx">Media Center</category></item><item><title>Windows Insomnia: Why Won't My Computer Go To Sleep?</title><link>http://blogs.msdn.com/peterrosser/archive/2006/01/04/WindowsInsomnia.aspx</link><pubDate>Thu, 05 Jan 2006 08:18:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:509518</guid><dc:creator>Peter Rosser</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/peterrosser/comments/509518.aspx</comments><wfw:commentRss>http://blogs.msdn.com/peterrosser/commentrss.aspx?PostID=509518</wfw:commentRss><wfw:comment>http://blogs.msdn.com/peterrosser/rsscomments.aspx?PostID=509518</wfw:comment><description>&lt;P&gt;One of the issues I am investigating for a fix relates to the auto-suspend feature in Windows.&amp;nbsp; The way it's supposed to work is you set a time in the Power control panel (Control Panel --&amp;gt; Performance and Maintenance --&amp;gt; Power Options) that controls how long the computer waits until it goes into "standby" or "suspend".&amp;nbsp; Whether that is S2 or S3 depends on your BIOS settings.&amp;nbsp; What's going on with the bug I'm looking at is sometimes Windows will not suspend when it should, or indeed, ever, unless you close Media Center or manually select Standby.&lt;/P&gt;
&lt;P&gt;This is pretty annoying, especially since my Media Center consumes about 200W while fully active (250-275W if engaged in HDTV playback), and only about 15W in S3 suspend.&amp;nbsp; With electricity around $0.084 / kWh, that works out to $0.40 each day left unchecked.&amp;nbsp; If I let it go all month, that's another $12, just because of this stupid bug (well, and because I'm lazy and forget to manually suspend... but I should not &lt;EM&gt;have&lt;/EM&gt; to).&amp;nbsp; Lame, lame, lame.&amp;nbsp; Extrapolating to all of the customers affected by this issue, I can see it adding up to a big problem.&amp;nbsp; Say only 250,000 users hit this (a low figure, I bet), that's $3,000,000 per month in wasted energy costs, based on the rates I pay.&amp;nbsp; Yikes!&lt;/P&gt;
&lt;P&gt;While I can fix this problem, I cannot fix all of the things that prevent computers from going into standby automatically, because they should really not be fixed, or because Windows software is not causing the problem in the first place.&amp;nbsp; Several things can cause a computer to fail to go into standby, and figuring out exactly what is causing the problem can be very difficult.&lt;/P&gt;
&lt;P&gt;So, what are the most common causes of Windows insomnia?&amp;nbsp; In rough order of likelihood, here is my &lt;A href="http://en.wikipedia.org/wiki/SWAG"&gt;SWAG&lt;/A&gt;:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;There is user activity.&amp;nbsp; This usually means keyboard or mouse activity, but can be "simulated" by applications via SendKeys(), etc. 
&lt;LI&gt;Windows is not configured to go into Standby automatically.&amp;nbsp; Since it's not the default for most computers, this&amp;nbsp;makes the list.&amp;nbsp; Easy to fix. 
&lt;LI&gt;An application tells Windows not to go into Standby automatically.&amp;nbsp; Different from user activity simulation because this is what applications are &lt;EM&gt;supposed&lt;/EM&gt; to do to prevent Standby. [ &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/power/base/setthreadexecutionstate.asp"&gt;SetThreadExecutionState(&lt;EM&gt;state&lt;/EM&gt;)&lt;/A&gt;&amp;nbsp;] 
&lt;LI&gt;An application generates enough system activity (e.g. disk access, network access, CPU usage) that Windows does not consider the machine to be "idle" enough. 
&lt;LI&gt;A hardware device driver prevents it.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Case 1 is very unlikely, since really the only applications that do this sort of thing are hacks/trainers/evil programs (and testing programs, if you want a legitimate example).&amp;nbsp; Unless your computer is infected by malware, this is probably not the cause.&amp;nbsp; Run a quality scanner to tell.&amp;nbsp; For case 2, just set Control Panel setting.&lt;/P&gt;
&lt;P&gt;For cases 3 and 4, troubleshooting gets trickier.&amp;nbsp; For the average end-user who does not know how to use a Kernel Debugger like &lt;A href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx"&gt;WinDbg&lt;/A&gt; or &lt;A href="http://www.compuware.com/products/driverstudio/softice.htm"&gt;SoftICE&lt;/A&gt;, and does not have &lt;A href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx"&gt;easy access to kernel symbols&lt;/A&gt;, figuring out who is keeping the computer up all night takes a little wanton process termination.&amp;nbsp;Before you open up taskmgr and start gunning processes, though, there are a couple of things you can check:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Are you sharing any folders on the network?&amp;nbsp; If a remote computer is connected to your machine and refreshes the connection (i.e. sends a command), the Server service will call KeInhibitSystemShutdown(), which does exactly what it sounds like it does: resets the system's idle timer.&amp;nbsp; How do you tell if this is happening? An easy way is to pull up a command window (Start --&amp;gt; Run --&amp;gt; cmd) and type:&lt;BR&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;nbtstat -s&lt;BR&gt;&lt;/FONT&gt;&lt;BR&gt;If you see any "IN" connections, they can keep you awake.&amp;nbsp; Most well-behaved Windows applications will not needlessly refresh connections over the network, but others don't play that nicely.&amp;nbsp; A ubiquitous example would be WMP or iTunes--both will scan network folders for changes if you add the path to your "watched folders" list.&amp;nbsp; The best way to solve this problem is to fix the client side (the other computer), but if that's not possible, you can just deny access to that computer/user.&amp;nbsp; In the worst case, you can stop the Server service (&lt;FONT face="Courier New"&gt;net stop server&lt;/FONT&gt;), but that prevents sharing altogether. 
&lt;LI&gt;Check your Application and System event logs for errors or warnings.&amp;nbsp; Often, exceptional situations will be reported there and can provide a clue to why Windows is not going into Standby. 
&lt;LI&gt;Hardware (or more appropriately, drivers for hardware) can prevent Windows from entering standby, too.&amp;nbsp; If you used to be able to go into standby, but cannot now, have you added or replaced hardware, or updated drivers?&amp;nbsp; This can be tricky, too, since most people set their Standby timers for longer than is convenient to sit around and wait on, so failure to go into Standby can be missed for days or weeks. 
&lt;LI&gt;To eliminate any remote networking cause, isolate your computer from the network (unplug the network cable!).&amp;nbsp; Low-tech, but effective.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;If you have eliminated network shares, suspicious event log entries, and hardware from causing the problem, the next thing to do is start killing processes and see which one (or if you're unlucky, which ones) are doing it.&amp;nbsp; You need to first exclude those processes that are part of Windows itself, since terminating them is not very wise.&amp;nbsp; An easy way to get a fairly complete list of the Windows processes is to boot into Safe Mode, press Start --&amp;gt; Run, and type:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;tasklist &amp;gt;"%SystemDrive%\SysProcesses.txt"&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;A new file will be created on your system drive (usually C:) that contains the list of processes you shouldn't touch.&amp;nbsp; Reboot back into normal Windows mode, log in, and:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Open the SysProcesses.txt file 
&lt;LI&gt;Start taskmgr (right click on the taskbar and select &lt;STRONG&gt;Task Manager&lt;/STRONG&gt;) and click the Processes tab. 
&lt;LI&gt;Set your Standby timer to 1 minute (in the Power Options control panel) 
&lt;LI&gt;Let&amp;nbsp;1 minute elapse.&amp;nbsp; If the computer does not suspend, proceed to the next step. 
&lt;LI&gt;Select a process not listed in the SysProcesses.txt file in taskmgr and kill it. 
&lt;LI&gt;Go to step 4.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;If you run out of processes to kill and the computer still won't go into Standby, it's time to start shutting down services in the Services console (Start --&amp;gt; Run --&amp;gt; &lt;FONT face="Courier New"&gt;services.msc&lt;/FONT&gt;).&amp;nbsp; If you have stopped all of the services you possibly can, it's either a piece of hardware or one of the core Windows processes, and things are a bit tougher.&amp;nbsp; To troubleshoot those, you need the help of a kernel-mode debugger.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=509518" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Coding/default.aspx">Coding</category><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Musing/default.aspx">Musing</category><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Windows/default.aspx">Windows</category></item><item><title>Visual Studio 2005 Shipping on my Birthday</title><link>http://blogs.msdn.com/peterrosser/archive/2005/10/31/487569.aspx</link><pubDate>Tue, 01 Nov 2005 08:14:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:487569</guid><dc:creator>Peter Rosser</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/peterrosser/comments/487569.aspx</comments><wfw:commentRss>http://blogs.msdn.com/peterrosser/commentrss.aspx?PostID=487569</wfw:commentRss><wfw:comment>http://blogs.msdn.com/peterrosser/rsscomments.aspx?PostID=487569</wfw:comment><description>&lt;P&gt;You know I'm a geek when something like that gives me even a little bit of a thrill.&amp;nbsp; November 7th... not just an election day or my birthday, but also the VS2005 public ship day. ^_^.&amp;nbsp; I'm installing it now on my primary and backup dev boxes at work now... sometimes the perks of working here are pretty nice.&amp;nbsp;Mmm... generics.&lt;/P&gt;
&lt;P&gt;One of my coworkers suggested I take another look at Managed C++ (during our conversation I expressed my "dismay" at the prior version's foibles), so I'll take a peek at that as soon as I have a spare cycle or two.&amp;nbsp; It's pretty hard to get any free time with the painting at home and the heavy influx of&amp;nbsp;QFE issues we always get post release, but I'm sure I'll manage.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=487569" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Coding/default.aspx">Coding</category><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Musing/default.aspx">Musing</category><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Tools/default.aspx">Tools</category></item><item><title>Getting a QWORD from the registry using C# and P/Invoke</title><link>http://blogs.msdn.com/peterrosser/archive/2005/10/20/483333.aspx</link><pubDate>Fri, 21 Oct 2005 07:43:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:483333</guid><dc:creator>Peter Rosser</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/peterrosser/comments/483333.aspx</comments><wfw:commentRss>http://blogs.msdn.com/peterrosser/commentrss.aspx?PostID=483333</wfw:commentRss><wfw:comment>http://blogs.msdn.com/peterrosser/rsscomments.aspx?PostID=483333</wfw:comment><description>&lt;P&gt;From time to time you need to use really, really big numbers, like when describing, say, the time of day you need to download a certain set of data from remote servers.&amp;nbsp; Well, you probably don't&amp;nbsp;&lt;EM&gt;need&lt;/EM&gt; that much granularity in the time, but that's what MCE uses to schedule EPG downloads. &amp;lt;g&amp;gt;&lt;/P&gt;
&lt;P&gt;So, we store this thing off in the registry at in a value named dlRegTime.&amp;nbsp; I can see why the dev did this: it's easy to convert a DateTime to an Int64 by way of DateTime.ToFileTime(), which makes for a clean, unambiguous value to write.&amp;nbsp; I'd almost bet that he was patting himself on the back... until he had to actually write the value to the registry.&lt;/P&gt;
&lt;P&gt;The problem comes when you need that value from C# (or, I guess, VB.NET).&amp;nbsp; The 1.1 Framework designers apparently did not think that anyone could ever possibly need a 64-bit value from the registry, and if they did, they could P/Invoke.&amp;nbsp; That's exactly what you have to do.&amp;nbsp; Here's an example where I convert the &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/filetime_str.asp"&gt;FILETIME&lt;/A&gt; stored as a QWORD into a DateTime:&lt;/P&gt;
&lt;DIV style="BACKGROUND-COLOR: #f5f5dc"&gt;&lt;PRE&gt;[DllImport("Advapi32.dll")]
static extern uint RegOpenKeyEx(UIntPtr hKey,
    string lpSubKey,
    uint ulOptions,
    int samDesired,
    out IntPtr phkResult);

[DllImport("Advapi32.dll", EntryPoint="RegQueryValueEx")]
static extern uint RegQueryValueEx_QWORD(
    IntPtr hKey,
    string lpValueName,
    uint lpReserved,
    ref uint lpType,
    ref long lpData,
    ref int lpcbData
    );

[DllImport("Advapi32.dll")]
static extern uint RegCloseKey(IntPtr hKey);

const int KEY_QUERY_VALUE = 0x1;
const string EPG_REGKEY = 
    @"SOFTWARE\Microsoft\Windows\CurrentVersion\Media Center\Service\EPG";
const string DLTIME_REGVALUE = "dlRegTime";

DateTime GetNextDownloadTime()
{
    UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
    IntPtr hkey = IntPtr.Zero;
    DateTime date = DateTime.MinValue;

    try
    {
        uint lResult = RegOpenKeyEx(
            HKEY_LOCAL_MACHINE, 
            EPG_REGKEY,
            0, KEY_QUERY_VALUE, out hkey);

        if (0 == lResult)
        {
            long qword = 0;
            uint uType = 0;
            int cbData = 8;
            
            lResult = RegQueryValueEx_QWORD(hkey, 
                                            "dlRegTime", 
                                            0, 
                                            ref uType, 
                                            ref qword, 
                                            ref cbData);

            date = DateTime.FromFileTime(qword);
        }
        else
        {
            throw new ApplicationException("The registry key " + 
                EPG_REGKEY + 
                " could not be opened for reading.  The error code was 0x" + 
                lResult.ToString("x"));
        }
    }
    finally
    {
        if (IntPtr.Zero != hkey)
        {
            RegCloseKey(hkey);
        }
    }

    return date;
}
&lt;/PRE&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=483333" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/peterrosser/archive/tags/Coding/default.aspx">Coding</category></item></channel></rss>