I am a Software Development Engineer in Test working for the Windows Sound team. You can contact me via email: mateer at microsoft dot com
Friend key: 28904932216450_59cd9d55374be03d8167d37c8ff4196b
There are a handful of Problems (with a capital P) which occur over and over again in programming. One of them is Logging.
It is incredibly convenient to use the variadic printf function to log strings with values of common types embedded in them:
// spot the bugLOG(L"Measurement shows %lg% deviation", 100.0 * abs(expected - actual) / expected);
However, printf is very error prone. It is very easy to use the wrong format specifier like %d instead of %Id, or to forget to escape a special character like % or \. In particular, the above line contains a bug.
Static code analysis tools like PREfast are quite good at catching these kinds of errors. If my LOG macro was something like this, PREfast would catch the bug:
#define LOG(fmt, ...) wprintf(fmt L"\n", __VA_ARGS__)
This works because PREfast knows that the first argument to wprintf is a format string, and can match up the format specifiers with the trailing arguments and verify that they match.
If you implement your own variadic logger function, though, PREfast doesn't necessarily know that the last explicit argument is a format specifier - you have to tell it. For example, PREfast will NOT catch format specifier issues if the LOG macro is defined like this:
// PREfast doesn't know Format is a format string interface IMyLogger { virtual void Log(LPCWSTR Format, ...) = 0; }; extern IMyLogger *g_Logger; #define LOG(fmt, ...) g_Logger->Log(fmt, __VA_ARGS__)
How do you tell it? Well, let's look at the declaration of wprintf. It's in (SDK)\inc\crt\stdio.h:
_CRTIMP __checkReturn_opt int __cdecl wprintf(__in_z __format_string const wchar_t * _Format, ...);
The relevant part here is __format_string. So the fixed IMyLogger declaration looks like this:
// Now PREfast can catch format specifier issues interface IMyLogger { virtual void Log(__format_string LPCWSTR Format, ...) = 0; }; extern IMyLogger *g_Logger; #define LOG(fmt, ...) g_Logger->Log(fmt, __VA_ARGS__)
Most device drivers these days have signatures which allow the operating system to validate that the driver files have not been tampered with since the author sent them out into the world.
It is still possible to run into an unsigned driver. If you try to install an unsigned driver, Windows will warn you at install time:
IMPORTANT: if you see this warning, ask yourself this question - DO I TRUST THE SOURCE OF THIS DRIVER? If the answer is anything but a resounding YES, you should click "Don't install this software."
Windows XP was, by and large, a 32-bit operating system. A 64-bit version of Windows XP was developed but it was not broadly released. At that time it was still fairly common to have unsigned drivers.
Windows Vista was the first client release of Windows to have a widely deployed 64-bit release. This gave an opportunity to be more strict about enforcing driver signatures. For backwards compatibility, it was still possible to run unsigned drivers on the 32-bit version of Windows Vista (so the XP drivers would still work) but there was no such burden on Windows Vista 64-bit; so Windows Vista 64-bit was the first time that there was really a strong incentive to run with only signed drivers.
Even so, there are still workarounds provided:
The most reliable method, however, and the one with the fewest side effects, is to... well... sign the driver!
To sign a driver:
At this point you can see who says this driver is OK. Double-click the .cat file | View Signature | View Certificate | Certification Path and note the highest certificate in the chain:
If you're a professional driver developer and you want your driver to ship on Windows systems, your next step would very likely be to use the Windows Logo Kit to run the Microsoft logo tests, and get an official "Microsoft says this driver has passed the logo tests" signature for your .cat file. (The difference is that the top certificate in the chain will be "Microsoft Root Authority" rather than "Microsoft Test Root Authority.") A full description of this process lies outside the scope of this blog post.
But if you're just developing a driver for your personal use, you would probably skip this step. Instead of getting a "Microsoft says this driver is OK" signature, you can add the root certificate for your signing certificate to the "trusted root certificates" certificate store on the machine you want to load the driver on.
If the root certificate in question is the "Microsoft Test Root Authority", you can run "bcdedit -set testsigning on" and reboot.
If it's some other certificate (for example, if you generated a self-signed certificate) then you need to add it to the trusted certificate store by using certmgr.exe or by going to Internet Explorer | Internet Options | Content | Certificates.
If you have everything right, then installing the driver should not pop up the "driver is unsigned" warning. If you still get the warning, looking at C:\windows\inf \setupapi.dev.log can give some clues as to what is wrong... whether there is a driver file that is not listed in the catalog file, or the catalog file's signature does not lead back to a trusted root certificate, or something else.
1 In Windows 8 Developer Preview, the F8 experience has been reworked. Hit Shift-F8 instead.2 2 Some BIOSes have an issue where Shift is not sent to Windows this early. If you have Windows 8 Developer Preview installed one of these machines there's another way - hit F10 during boot to get to the "Edit Boot Options" screen. Add /DISABLE_INTEGRITY_CHECKS to the boot flags.
Last time I wrote about how to query audio endpoint properties.
This time, a few words about WAVEFORMATEX structures. WAVEFORMATEX is a variable-sized structure - it can be as small as a PCMWAVEFORMAT or larger than a WAVEFORMATEXTENSIBLE.
If the wFormatTag member (the first field) is WAVE_FORMAT_PCM, then you should assume that it is a PCMWAVEFORMAT. In particular you should not touch the cbSize field since that may not be memory you own!
If wFormatTag is anything else, you can look at the cbSize to see how much bigger than a WAVEFORMATEX the structure is. For example, if the wFormatTag is WAVE_FORMAT_EXTENSIBLE, you have the right to expect that cbSize be at least sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX).
I updated the attachment to the post linked above. Here's the new output:
PKEY_AudioEngine_DeviceFormat VT_BLOB of size 40 WAVEFORMATEXTENSIBLE Format ( wFormatTag: 65534 (WAVE_FORMAT_EXTENSIBLE) nChannels: 4 nSamplesPerSec: 16000 nAvgBytesPerSec: 128000 nBlockAlign: 8 wBitsPerSample: 16 cbSize: 22 ) Samples ( wValidBitsPerSample / wSamplesPerBlock / wReserved: 16 ) dwChannelMask: 0x0 SubFormat: {00000001-0000-0010-8000-00AA00389B71} (KSDATAFORMAT_SUBTYPE_PCM)
And here's the code that produces it:
HRESULT LogWaveFormat(LPCWAVEFORMATEX pWfx, UINT nBytes) { if (NULL == pWfx) { ERR(L"LogWaveFormat called with a NULL pointer"); return E_POINTER; } if (nBytes < sizeof(PCMWAVEFORMAT)) { ERR(L"Wave format is only %u bytes, smaller even than a PCMWAVEFORMAT (%Iu bytes)", nBytes, sizeof(PCMWAVEFORMAT)); return E_INVALIDARG; } else if (nBytes == sizeof(PCMWAVEFORMAT)) { const PCMWAVEFORMAT *pPcm = reinterpret_cast<const PCMWAVEFORMAT *>(pWfx); // PCMWAVEFORMAT must have a wFormatTag of WAVE_FORMAT_PCM if (WAVE_FORMAT_PCM != pPcm->wf.wFormatTag) { ERR(L"PCMWAVEFORMAT has invalid format tag %u (expected %u)", pPcm->wf.wFormatTag, WAVE_FORMAT_PCM); return E_INVALIDARG; } LOG( L" PCMWAVEFORMAT\n" L" wf.wFormatTag: %u (%s)\n" L" wf.nChannels: %u\n" L" wf.nSamplesPerSec: %u\n" L" wf.nAvgBytesPerSec: %u\n" L" wf.nBlockAlign: %u\n" L" wBitsPerSample: %u", pPcm->wf.wFormatTag, StringFromWaveFormatTag(pPcm->wf.wFormatTag), pPcm->wf.nChannels, pPcm->wf.nSamplesPerSec, pPcm->wf.nAvgBytesPerSec, pPcm->wf.nBlockAlign, pPcm->wBitsPerSample ); return S_OK; } else if (nBytes < sizeof(WAVEFORMATEX)) { ERR( L"Wave format is %u bytes, " L"bigger than a PCMWAVEFORMAT (%Iu bytes) " L"but smaller than a WAVEFORMATEX (%Iu bytes)", nBytes, sizeof(PCMWAVEFORMAT), sizeof(WAVEFORMATEX) ); return E_INVALIDARG; } else if (nBytes != sizeof(WAVEFORMATEX) + pWfx->cbSize) { ERR( L"Wave format takes up %u bytes " L"but sizeof(WAVEFORMATEX) + pWfx->cbSize is %Iu bytes", nBytes, sizeof(WAVEFORMATEX) + pWfx->cbSize ); return E_INVALIDARG; } else { // nBytes matches cbSize switch (pWfx->wFormatTag) { case WAVE_FORMAT_EXTENSIBLE: { if (pWfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { ERR( L"cbSize for a WAVE_FORMAT_EXTENSIBLE format must be at least " L"sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) (%Iu), " L"not %u", sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX), pWfx->cbSize ); return E_INVALIDARG; } const WAVEFORMATEXTENSIBLE *pWfxExt = reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(pWfx); LOG( L" WAVEFORMATEXTENSIBLE\n" L" Format (\n" L" wFormatTag: %u (%s)\n" L" nChannels: %u\n" L" nSamplesPerSec: %u\n" L" nAvgBytesPerSec: %u\n" L" nBlockAlign: %u\n" L" wBitsPerSample: %u\n" L" cbSize: %u\n" L" )\n" L" Samples (\n" L" wValidBitsPerSample / wSamplesPerBlock / wReserved: %u\n" L" )\n" L" dwChannelMask: 0x%x\n" L" SubFormat: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X} (%s)", pWfxExt->Format.wFormatTag, StringFromWaveFormatTag(pWfxExt->Format.wFormatTag), pWfxExt->Format.nChannels, pWfxExt->Format.nSamplesPerSec, pWfxExt->Format.nAvgBytesPerSec, pWfxExt->Format.nBlockAlign, pWfxExt->Format.wBitsPerSample, pWfxExt->Format.cbSize, pWfxExt->Samples.wValidBitsPerSample, pWfxExt->dwChannelMask, pWfxExt->SubFormat.Data1, pWfxExt->SubFormat.Data2, pWfxExt->SubFormat.Data3, pWfxExt->SubFormat.Data4[0], pWfxExt->SubFormat.Data4[1], pWfxExt->SubFormat.Data4[2], pWfxExt->SubFormat.Data4[3], pWfxExt->SubFormat.Data4[4], pWfxExt->SubFormat.Data4[5], pWfxExt->SubFormat.Data4[6], pWfxExt->SubFormat.Data4[7], StringFromSubFormat(pWfxExt->SubFormat) ); if (pWfx->cbSize > sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { LOG(L" Trailing bytes:\n"); return LogBytes( reinterpret_cast<const BYTE *>(pWfx) + sizeof(WAVEFORMATEXTENSIBLE), pWfx->cbSize - (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) ); } return S_OK; } case WAVE_FORMAT_PCM: if (pWfx->cbSize > 0) { ERR(L"cbSize for a WAVE_FORMAT_PCM format must be 0, not %u", pWfx->cbSize); return E_INVALIDARG; } // intentionally fall through default: LOG( L" WAVEFORMATEX\n" L" wFormatTag: %u (%s)\n" L" nChannels: %u\n" L" nSamplesPerSec: %u\n" L" nAvgBytesPerSec: %u\n" L" nBlockAlign: %u\n" L" wBitsPerSample: %u\n" L" cbSize: %u", pWfx->wFormatTag, StringFromWaveFormatTag(pWfx->wFormatTag), pWfx->nChannels, pWfx->nSamplesPerSec, pWfx->nAvgBytesPerSec, pWfx->nBlockAlign, pWfx->wBitsPerSample, pWfx->cbSize ); if (pWfx->cbSize > 0) { LOG(L" Trailing bytes:"); return LogBytes(reinterpret_cast<const BYTE *>(pWfx) + sizeof(WAVEFORMATEX), pWfx->cbSize); } return S_OK; } }}
In 2012, World Chess Champion Viswanathan Anand will attempt to defend his title aqainst challenger Boris Gelfand. This is a very unusual match in that both players are fairly old by World Chess Champion contender standards. I decided to see just how unusual it was, and do so with some degree of rigor.
One tricky bit is that chess championships (usually) have (at least) two players, so we have to define an age metric for pairs of people. Creating a well-ordering on tuples is sometimes controversial. I chose to have the comparison routine be: age(contenders) = min(age(contender) : contender ∈ contenders) which is to say, the age of the youngest contender.
Another tricky bit was deciding which matches were definitively "world chess championship matches." I pulled the list of world chess championship matches from chessgames.com. For time periods where the organizational ownership of the title is in question, this includes matches sponsored by all contending organizations.
As a naïve first pass, I looked up the birth years for all the contenders and subtracted that from the year of the championship to get an estimated age. This could be off by a year if the youngest contender's birthday comes after (or during?) the match. Nevertheless, this was accurate enough to give me a short list of matches to investigate further:.
Closer investigation of each of the highlighted matches revealed that, astonishingly, in every case the youngest contender's birthday came after the match:
We conclude that Anand vs. Gelfand (2012) features the oldest contenders since the very first World Chess Championship Steinitz vs. Zukertort (1886) - and is within a year of even that! If the 2014 championship is a rematch, it will set the record.
1 Topalov was the clear winner of the 2005 FIDE World Championship Tournament so there was no need for a runoff.