Printing various file version properties with PowerShell

Some files have version numbers. Some don’t. Some have more than one version number. Sometimes the version number is also a string. Sometimes the string matches the version number. Sometimes it doesn’t.

.NET comes with a System.Diagnostics.FileVersionInfo object that allows you to read all of these. I wrote up a quick fileversioninfo.ps1 PowerShell script to dump the object, given a filename. Let’s see what it shows:

>.\FileVersionInfo.ps1 -filename ${env:windir}\system32\ntdll.dll
-- File names and descriptions --
FileName: C:\WINDOWS\system32\ntdll.dll
InternalName: ntdll.dll
OriginalFilename: ntdll.dll.mui
FileDescription: NT Layer DLL
Comments: 

-- File version --
FileVersion: 10.0.21263.1000 (WinBuild.160101.0800)
File(Major.Minor.Build.Private)Part: 10.0.21263.1000

-- Product info --
ProductName: Microsoft® Windows® Operating System
ProductVersion: 10.0.21263.1000
Product(Major.Minor.Build.Private)Part: 10.0.21263.1000

-- Legal info --
Company Name: Microsoft Corporation
LegalCopyright: © Microsoft Corporation. All rights reserved.
LegalTrademarks:

-- Private build info --
IsPrivateBuild: False
PrivateBuild:

-- Special build info --
IsSpecialBuild: False
SpecialBuild:

-- Other info --
Language: English (United States)
IsDebug: False
IsPatched: False
IsPreRelease: False

Note that FileVersion is a string, while FileMajorPart, FileMinorPart, FileBuildPart, and FilePrivatePart are all numbers. If you make a file and you include file version information, make sure your FileVersion is consistent with your (FileMajorPart, FileMinorPart, FileBuildPart, FilePrivatePart).

Also note that ProductVersion is a string, while ProductMajorPart, ProductMinorPart, ProductBuildPart, and ProductPrivatePart are all numbers. If you make a file and you include product version information, make sure your ProductVersion is consistent with your (ProductMajorPart, ProductMinorPart, ProductBuildPart, ProductPrivatePart).

In the example case I showed, the file version is self-consistent; the product version is self-consistent; and the file version and product version are the same as each other. But this need not be the case. It’s fine for the file version and the product version to be different. But the both of them should be self-consistent.

Grabbing a dump file of another process via MiniDumpWriteDump

I was debugging a particular audio problem and I needed a process dump with full memory.

I used an internal gather-dumps tool and asked it to give me a bunch of dumps of the problem with full memory… and it gave me some dumps without full memory.

This told me that either the gather-dumps tool was broken, or MiniDumpWriteDump was broken, or perhaps both were working fine and my debugger was lying to me about the full-memory-ness of the dumps I was looking at.

To help narrow the problem down, I created a tool that is a very simple wrapper around MiniDumpWriteDump. This grabbed full memory dumps just fine, so I turned my attention toward the internal gather-dumps tool.

Usage:

>minidumpwritedump.exe
minidumpwritedump.exe [--help | -? | /?]
minidumpwritedump.exe --processId <processId> --dumpType <dumpType> --fileName <fileName>

See https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump

EDIT 2020-06-30: added a PowerShell script to translate a MINIDUMP_TYPE number into a human-readable set of values

Usage:

.\minidump_type.ps1 -minidump_type 482707
MiniDumpWithDataSegs, MiniDumpWithFullMemory, MiniDumpScanMemory, MiniDumpFilterModulePaths, MiniDumpWithProcessThreadData, MiniDumpWithoutOptionalData, MiniDumpWithFullMemoryInfo, MiniDumpWithThreadInfo, MiniDumpWithoutAuxiliaryState, MiniDumpWithPrivateWriteCopyMemory, MiniDumpIgnoreInaccessibleMemory, MiniDumpWithTokenInformation

How can my USB audio device tell the audio driver what kind of device it is?

Last time I blogged about how an audio device driver can tell Windows what kind of audio device it is. But how does the driver know? It depends on the driver.

In the case of a USB audio device, there is a hardware specification… or rather, three (so far:)

In USB Audio-speak, the “kind of device” in question is called a “terminal type.” Each of the USB Audio specifications includes the USB Audio Terminal Types specification by reference. for example:

  • USB Audio 1.0 section 5.3.3.1.4 Headphone Input Terminal ID10 Descriptor says Allowed values for the wTerminalType field can be found in the Audio 1.0 Terminal Types Specification.
  • USB Audio 2.0 section 4.7.2.5 Output Terminal Descriptor and
    USB Audio 3.0 section 4.5.2.2 OUTPUT TERMINAL DESCRIPTOR both say A complete list of Terminal Type codes is provided in a separate document, USB Audio Terminal Types that is considered part of this specification.

Terminals can be input, or output, or bi-directional, or… well, a couple other things. Each version of the terminal types specification has a list for each of these. For example, here’s the list of bi-directional terminal types from the USB Audio Terminal Types 3.0 spec:

  • Bi-directional Undefined – 0x0400
  • Handset – 0x0401
  • Headset – 0x0402
  • Speakerphone, no echo reduction – 0x0403
  • Echo-suppressing speakerphone – 0x0404
  • Echo-canceling speakerphone – 0x0405

Microsoft provides a USBView tool which can show you the USB descriptor for any USB device. Here’s a screenshot showing the USB audio terminal types for the USB audio device on my desk:

USBView showing wTerminalType values for a USB audio device

Windows’ USB Audio class driver reads the terminal type from the descriptor, converts it to a Kernel Streaming pin category GUID as listed in ksmedia.h, and reports it to Windows via the KSPIN_DESCRIPTOR for the pin factory corresponding to the terminal.

How can my audio device driver tell Windows what kind of audio device it is?

Last time I blogged about how an application can ask Windows what kind of audio device it is using. But how does Windows know?

Windows has a common Device Driver Interface (DDI) for audio drivers (sound cards) and video capture drivers (webcams) called Kernel Streaming (KS.)

An audio output (like a speaker) or input (like a microphone) or video capture input (like a webcam) is called a “Kernel Streaming pin factory.” The audio device driver or video capture device driver fills out a descriptor for each pin factory, which is a KSPIN_DESCRIPTOR structure.

One of the fields in this structure is Category. To quote from the documentation:

Specifies a pointer to a KS pin category GUID. The KS pin category GUID identifies the general category of functionality that the pin provides. Examples of KS pin category GUIDs are KSNODETYPE_SPEAKER, KSNODETYPE_HEADPHONES, and KSNODETYPE_MICROPHONE, which are all defined in Ksmedia.h. Also see Pin Category Property.

KSPIN_DESCRIPTOR.Category

The Windows Driver Kit comes with ksmedia.h, which has a long list of KSNODETYPE_ values. If you’re writing a driver, this is a good place to see what your options are.

It also comes with a useful utility called Kernel Streaming Studio (KSStudio.exe). This will allow you to see (among other things) the KSPIN_DESCRIPTOR settings for every audio device and video capture device on your system which supports Kernel Streaming. Here’s a screenshot showing that the USB Audio device on my desk advertises KSNODETYPE_SPEAKER and KSNODETYPE_MICROPHONE:

Kernel Streaming Studio (KSStudio.exe) showing KSPIN_DESCRIPTOR.Category

But how does the driver know? It depends on the driver. See:

How can my application tell what kind of audio device it’s using?

There are many kinds of audio devices – speakers, microphones, headsets, cars, TVs, etc.

If you’re writing an app and you want to ask Windows what kind of audio device you’re dealing with, you can use the Windows.Devices.Enumeration APIs on Windows 8 and later. There’s a sample here that shows how to enumerate devices and their properties generically:
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing

Since you’re interested in audio devices specifically, you would use one of the selectors from the Windows.Media.Devices.MediaDevice namespace, e.g. GetDefaultAudioRenderId.

If you are running on Windows 7, that API does not exist, and you have to use the IMMDeviceEnumerator API instead. I have a sample for that here:
https://matthewvaneerde.wordpress.com/2011/06/13/how-to-enumerate-audio-endpoint-immdevice-properties-on-your-system/

Either way, there are two properties of interest to you, depending on the level of granularity you want. (There are also other general properties which may be of interest, e.g. you can use the container ID property to tell whether the audio device is internal or external to the system. This blog post limits itself to the following two audio-specific properties.)

  1. PKEY_AudioEndpoint_FormFactor = “{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E} 0”. This is a PROPVARIANT with vt = VT_UI4 and ulVal = some member of the EndpointFormFactor enumerated type.
  2. PKEY_AudioEndpoint_JackSubType = “{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 8”. Not every audio device has this property, only ones that are backed by Kernel Streaming audio drivers. For such devices, the property is a PROPVARIANT with vt = VT_LPWSTR and pwszVal = one of various GUIDs defined in ksmedia.h, in string form. The GUID names begin with KSNODETYPE_, for example KSNODETYPE_DISPLAYPORT_INTERFACE = {E47E4031-3EA6-418d-8F9B-B73843CCBA97} means that the audio device is connected via a DisplayPort jack, which in turn probably means that the audio device is either a TV or an audio receiver.

But how does Windows know? See How can my audio device driver tell Windows what kind of audio device it is?

Tracking down calls to AvSetMmThreadCharacteristics

Boring introductory stuff first:

Windows Vista introduced a feature called the “Multimedia Class Scheduler Service” (MMCSS). This is designed to give audio and video threads regular, short, bursts of very high priority, so that audio and video can stream without glitching. The bursts are regular so that audio and video packets don’t get delayed, and they are short so that non-multimedia activity doesn’t get starved.

It’s very important to note that apps which called into high-level audio and video APIs (e.g., the <audio> and <video> HTML tags) don’t have to worry about this kind of thing; the implementation of the high-level API takes care of registering the right pieces of its code with MMCSS.

For apps which (for one reason or another) choose not to use the high-level APIs, and instead want to hook into low-level APIs directly, the original design was for the app to call AvSetMmThreadCharacteristics function from its streaming thread when streaming begins, and AvRevertMmThreadCharacteristics when streaming ends.

In Windows 8.1, the Real-Time Work Queue API was created. This is the preferred approach for apps which want to use low-level APIs.

(whew)

Now the good stuff. I got an email from a pro audio application developer who said that AvSetMmThreadCharacteristics was giving an ERROR_TOO_MANY_THREADS error in his app… even though he only registered a single thread with MMCSS! Surely one thread is not too many…

At this point you should pause and read the excellent book One Kitten is Not Too Many. I’ll wait.

Welcome back! A bunch of different theories started popping up in my head, like “maybe some other process on the system is consuming all the MMCSS slots”, or “maybe a plugin for the application is registering threads without the application developer’s knowledge”, or “maybe the call to AvRevertMmThreadCharacteristics isn’t happening”, or “maybe the task handle is being overwritten between Set and Revert”.

But then I remembered Raymond Chen’s advice: Theorize if you want, but if the problem is right there in front of you, why not go for the facts?

MMCSS has “Event Tracing for Windows” (ETW) logging. In particular, when a task is created, the Microsoft-Windows-MMCSS provider logs a Thread_Join event. This will shed light on what processes and threads are registering with MMCSS.

Also, ETW supports grabbing a stack at the point of an event being logged! This will shed light on whether the registration is happening from app code directly, or a plugin, or whatever.

So I sent the developer these instructions:

  1. Download mmcss.wprp (right-click the link and save)
  2. Open an elevated Command Prompt or PowerShell window
  3. Run wpr.exe -start mmcss.wprp
  4. Launch the app
  5. Create some audio objects and let them run for one second or so
  6. Close the app
  7. Run wpr.exe -stop mmcss.etl (you can change the output file name if you like)
  8. Inspect the resulting mmcss.etl file

In my local testing (I just used echo ^G from a command prompt) I was able to see a Microsoft-Windows-MMCSS/Thread_Join/ event with this stack (only the bold part is interesting)

[Root]
  ntdll.dll!RtlUserThreadStart
  kernel32.dll!BaseThreadInitThunk
  wdmaud.drv!CWorker::_StaticThreadProc
  wdmaud.drv!CWorker::_ThreadProc
  wdmaud.drv!`CWaveHandle::Open’::`2′::COpenJob::Work
  wdmaud.drv!CWaveOutHandle::_Open
  wdmaud.drv!CWaveHandle::_Open
  avrt.dll!AvSetMmThreadCharacteristicsA
avrt.dll!AiThreadConnect
avrt.dll!AiCreateMmcssTaskIndexOrThreadClient
ntdll.dll!ZwCreateFile
ntoskrnl.exe!KiSystemServiceCopyEnd
ntoskrnl.exe!NtCreateFile
ntoskrnl.exe!IopCreateFile
ntoskrnl.exe!ObOpenObjectByNameEx
ntoskrnl.exe!ObpLookupObjectName
ntoskrnl.exe!IopParseDevice
ntoskrnl.exe!IoCallDriverWithTracing
ntoskrnl.exe!IofCallDriver
mmcss.sys!CiDispatchCreate
mmcss.sys!CiDispatchCreateMmThreadClient
mmcss.sys!CiThreadCreate
mmcss.sys!CiLogThreadJoin
ntoskrnl.exe!EtwWrite

How to negotiate an audio format for a Windows Audio Session API (WASAPI) client

The Windows Audio Session API (WASAPI) provides a family of interfaces for playing or recording audio.

Chief among these are the IAudioClient, IAudioClient2, and IAudioClient3 interfaces.

There is a Windows audio session (WASAPI) sample on GitHub, but in this blog post I want to dive into the nitty-gritty of one particular question:

How do I decide what WAVEFORMATEX to pass to IAudioClient::Initialize*?
*Or equivalent

Before I answer this question, let’s take a look at some of the relevant methods on these interfaces.

  1. IAudioClient2::SetClientProperties is a way for you to tell Windows some things about the audio stream before actually creating it (by passing an AudioClientProperties structure.)
    The client properties you specify can affect the answers to some of the questions you ask Windows, so be sure to set this BEFORE calling any of the other methods.
  2. IAudioClient::GetMixFormat gives you the audio format that the audio engine will use for this client (with its given AudioClientProperties) to mix all the similar playback streams together, or to split all the similar recording streams apart.
    This format is guaranteed to work*, but sometimes there is a better format that also works.
    * Unless you use AUDCLNT_SHAREMODE_EXCLUSIVE, or AudioClientProperties.bIsOffload = TRUE.
  3. PKEY_AudioEngine_DeviceFormat gives you the audio format that the audio engine uses after the playback mix to talk to the audio driver for the speaker, or to talk to the audio driver for the microphone before splitting the recording streams apart.
    This format is guaranteed to work with AUDCLNT_SHAREMODE_EXCLUSIVE.
    If the audio device has not been used with AUDCLNT_SHAREMODE_SHARED yet, the format may not have been calculated, and the property will be empty.
    You can force the format to be calculated by calling IAudioClient::GetMixFormat.
  4. IAudioClient::IsFormatSupported lets you ask Windows whether the client (with its given AudioClientProperties) supports a given format in a given share mode.
    In certain cases (e.g., AUDCLNT_SHAREMODE_SHARED), if the client does not support the format in question, Windows may suggest a format which (Windows thinks) is close.
  5. IAudioClient::Initialize considers the previously given AudioClientProperties; takes the WAVEFORMATEX you have decided on; and takes a set of flags, including AUDCLNT_STREAMFLAGS_XXX flags.
    The two interesting flags for format negotiation are AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM and AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY, which tell Windows that you want the WASAPI audio engine to do any necessary conversions between the client format you are giving it and the playback mix format or recording split format.
    This will work for uncompressed integer PCM and uncompressed floating-point client formats, but will not work for compressed formats like AAC.

OK, with all that background out of the way, let’s try to answer the question. There are several approaches which will work.

  1. Use a higher level audio API instead of WASAPI
    This is the preferred approach. WASAPI is complicated. And even with all that complication, it’s a very underpowered API – for example, it doesn’t even do MP3 decoding.
    No matter what your application is, there is almost always a higher-level audio API which is better suited for you. If you are not sure what it is, send me an email and ask me; I might be able to recommend one for you, or I may be able to put you in touch with someone else who can.
    A few examples of higher-level audio APIs: MediaElement, MediaCapture, AudioGraph, XAudio2.
    If you’ve tried a higher-level API, but you’ve run into some problem or other and now you’re resorting to WASAPI, email me and tell me about the problem; I want to fix it so we can get you back on the right API for you.
  2. If you don’t care what format is used
    IAudioClient::SetClientProperties(…);
    use IAudioClient::GetMixFormat // no need to call IsFormatSupported here
  3. If you have a format in hand
    Maybe you’re playing audio from a file, or maybe you need to record from the microphone and hand off to a DSP library that insists on a particular input format.
    If that is the case, use the following pattern:

    IAudioClient::SetClientProperties(…);
    if (IAudioClient::IsFormatSupported(formatInHand)) { use that }
    else { use IAudioClient::GetMixFormat, or the suggested closest supported format, and convert between that and formatInHand in the app code }

    Another option which will work, but which is less preferred, is to use this pattern:

    IAudioClient::SetClientProperties(…);
    IAudioClient::Initialize(formatInHand, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY)

    Since you’re using WASAPI directly (see point 1 above!) you will need to compress/decompress the audio in app code.

Or in tabular form (because people like tables)

AUDCLNT_SHAREMODE_SHARED AUDCLNT_SHAREMODE_EXCLUSIVE
Any format is fine
IAudioClient2::SetClientProperties(…);
use IAudioClient::GetMixFormat()
IAudioClient2::SetClientProperties(…);
use PKEY_AudioEngine_DeviceFormat
I have a particular format I want to use
IAudioClient2::SetClientProperties(…);
if (IAudioClient::IsFormatSupported(yourFormat)) { use it }
else { use the suggested closest-supported-format and convert between it and yourFormat in app code }

or

IAudioClient2::SetClientProperties(…);
IAudioClient::Initialize(yourFormat, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY)
IAudioClient2::SetClientProperties(…);
if (IAudioClient::IsFormatSupported(yourFormat)) { use it }
else { use PKEY_AudioEngine_DeviceFormat and convert between it and yourFormat in app code }

Regardless of which approach you use, you should always have some assurance that the format will work before calling IAudioClient::Initialize.

You could get this assurance in various ways – IAudioClient::GetMixFormat, IAudioClient::IsFormatSupported, or AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY.

It is an application bug to call IAudioClient::Initialize blind.

Getting the schema for Windows Performance Recorder profiles

I was having some trouble authoring a Windows Performance Recorder profile by hand-editing the XML, and I wanted to check it against the schema.

This MSDN page says “you can get the WPRControlProfiles.xsd file in %ProgramFiles(x86)%\Windows Kits\8.1\Windows Performance Toolkit“. That appears to no longer be true.

I dug around a little and eventually found it. It’s a resource in %ProgramFiles(x86)%\Windows Kits\8.1\Windows Performance Toolkit\windowsperformancerecordercontrol.dll – the rest of the instructions seem to work fine.

wpr-schema

You can extract it by opening the .dll in Visual Studio, expanding to the right node (highlighted above), then right-click and choose “Export”.

Pulling ClickOnce applications from the client using a script

I have a bunch of internal Microsoft ClickOnce applications that I use all the time.

But every time I clean install my machine I need to go look up all the application entry points and reinstall them.

This got boring, so I wrote an executable that takes a URL on the command line, and then uses the System.Deployment.Application.InPlaceHostingManager API to pull the ClickOnce application to the machine.

Browse source

Download binary

Riffing on Raymond – incrementing the reference count on a smart pointer

Last Friday, Raymond Chen blogged about how to use a function that released one of its inputs with various smart pointer classes.

He made two suggestions, and I offered a third:

  1. (Raymond) tell the smart pointer class to release ownership to the function
  2. (Raymond) use a different function that doesn’t release the input
  3. (Me) take an explicit reference on the function’s behalf

Raymond suggested that I should actually try my suggestion. So I did.

For each of the four smart pointer types, I tried four different ways to add a reference. Here are the results:

Smart pointer type .AddRef() ->AddRef() Cast to IUnknown * Get underlying pointer
Microsoft::WRL::ComPtr Compile error Compile error Compile error .Get()
ATL::CComPtr Compile error Compile error OK .p
_com_ptr_t OK OK OK .GetInterfacePtr()
std::unique_ptr Compile error OK Compile error .get()

Here’s the code I used.