4

The current version of the Windows API documentation of the OPENFILENAME structure states (emphasis mine):

lpstrDefExt
Type: LPCTSTR

The default extension. GetOpenFileName and GetSaveFileName append this extension to the file name if the user fails to type an extension. This string can be any length, but only the first three characters are appended. The string should not contain a period (.). If this member is NULL and the user fails to type an extension, no extension is appended.

This is incorrect, as executing the following MVCE on Windows 10 (Build 17134.5) shows:

#include <stdio.h>
#include <Windows.h>

int main()
{
    wchar_t filename[256] = { 0 };

    OPENFILENAMEW ofn =
    {
        .lStructSize = sizeof(OPENFILENAMEW),
        .lpstrFilter = L"All Files\0*.*\0\0",
        .lpstrFile = filename,
        .nMaxFile = sizeof(filename),
        .lpstrDefExt = L"xlsx"
    };

    BOOL ret = GetSaveFileNameW(&ofn);

    if (ret != 0)
    { 
        wprintf(L"%s\r\n", filename);
    }
}

Entering test in the Save File dialog box yields C:\Users\...\Documents\test.xlsx, not C:\Users\...\Documents\test.xls, as the documentation claims.

When did this change, i.e., on which target systems can I rely on lpstrDefExt supporting more than three characters?

Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • 1
    [_"note this is stale documentation, possibly dating back to Windows 3.1 when names were limited to 8.3 format. At least since Vista, it accepted longer (just confirmed myself on Windows 10 too)"_](https://stackoverflow.com/questions/20310173/is-there-anyway-to-make-something-automatically-add-selected-file-extension-to-f#comment53538603_20310327). – CodeCaster May 02 '18 at 15:11
  • @CodeCaster: Thanks that's very relevant! *"at least since Vista..."* would be perfect, since I need to support Windows 7/Server 2008 and above. – Heinzi May 02 '18 at 15:13
  • 1
    On Vista and later, `Get(Open|Save)FileName()` are wrappers for the newer `IFile(Open|Save)Dialog` interfaces (unless you specify the `OFN_ENABLEHOOK` flag), which don't have many of the same limitations as the old APIs. – Remy Lebeau May 02 '18 at 15:21
  • Also, since Vista the recommendation is to use the [Common Item Dialog](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776913.aspx), rather than GetOpenFilename. – theB May 02 '18 at 15:23
  • This goes back 25 years, starting with the emulation of MS-Dos 8.3 filenames. A file named longfilename.xlsx has an extra directory entry that will resemble longfi~1.xls. Which matches a *.xls wildcard. This support is overdue to be turned off, especially so for x64 versions that can't support 16-bit code anymore, but today still enabled by default. All you can do about it is verify the names you get back. – Hans Passant May 02 '18 at 15:37
  • @RemyLebeau: Just for fun, I just tried to add a hook. It still supports the long file name extension, but, wow, the resulting dialog brought back 16-bit memories: https://imgur.com/a/bEPtMTL – Heinzi May 02 '18 at 15:46
  • @theB: That's good advice. In my case, that's not an option, since we call the dialog from VBA, and these dialogs [don't work well with VBA](https://stackoverflow.com/q/1907866/87698). I just created the C program as a MVCE. – Heinzi May 02 '18 at 15:49
  • @Heinzi You can get the Win95-XP dialog with a hook, you just have to include the Explorer flag, otherwise you get the Windows 3 style. – Anders May 02 '18 at 23:03

0 Answers0