GetSaveFileName is a Windows API call that displays a standard save file dialog. It has an option to specify a default file name extension that will be added if the user doesn't type one. (lpstrDefExt in the OPENFILENAME struct)
For some reason, this wasn't working. I wasted a bunch of time checking all my code and searching for known problems on the internet with no success.
Then I tried it again and suddenly it worked! But I hadn't changed anything!
Aha! I had changed something - I had typed a different file name. The problem is that if the name you type (with no extension) exists, then it doesn't add the extension. (e.g. I was typing "test" and I had an existing file called "test", with no extension) I guess it assumes that you are "picking" the existing file, even though I was typing it, not picking it from a list.
MSDN contains a huge amount of documentation, but all it takes is one little missing detail and you're in trouble.