Borland C++ 5.5 トラブル

Last Updated: Feb.3,2007
Borland C++ 5.5.1 でファイルオープンダイアログが表示されないトラブルについて。

1. どんなトラブルか

まず、この現象が確認できる Windows GUI アプリのソースを示します。環境は、Windows 98 Second Edition。

// test1.cpp

#include <windows.h>

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE /* hPrevInstance */,
                     LPSTR     /* lpCmdLine */,
                     int       /* nCmdShow */ )
{
    OPENFILENAME ofn;
    TCHAR szFile[MAX_PATH] = "";
    
    ZeroMemory(&ofn, sizeof(OPENFILENAME));
    ofn.lStructSize     = sizeof(OPENFILENAME);
    ofn.hInstance       = hInstance;
    ofn.lpstrFile       = szFile;
    ofn.nMaxFile        = MAX_PATH;
    ofn.Flags           = OFN_FILEMUSTEXIST;
    
    if (!GetOpenFileName(&ofn))
    {
        wsprintf(szFile, "Error: %lu", CommDlgExtendedError());
        MessageBox(NULL, szFile, NULL, MB_OK);
    }
    else
        MessageBox(NULL, szFile, "取得したファイル名", MB_OK);

    return 0;
}

最初は非常に悩みました。VC++ 6.0 では、問題なくコンパイル・実行出来るのですが、BC++ 5.5.1 では、コンパイルは通っても実行が正常に出来ないのです。エラー番号が 1 と表示されていますので、MSDN ライブラリで調べてみると、

CDERR_STRUCTSIZE The lStructSize member of the initialization structure for the corresponding common dialog box is invalid.

つまり、OPENFILENAME 構造体の lStructSize メンバの値が無効だと言っているのです。はて、これはどうしたわけか?

2. 調査してみた

次に、commdlg.h を開いて OPENFILENAME 構造体がどのように定義されているかを確認してみることにしました。

typedef struct tagOFNA {
   DWORD        lStructSize;
   HWND         hwndOwner;
   HINSTANCE    hInstance;
   LPCSTR       lpstrFilter;
   LPSTR        lpstrCustomFilter;
   DWORD        nMaxCustFilter;
   DWORD        nFilterIndex;
   LPSTR        lpstrFile;
   DWORD        nMaxFile;
   LPSTR        lpstrFileTitle;
   DWORD        nMaxFileTitle;
   LPCSTR       lpstrInitialDir;
   LPCSTR       lpstrTitle;
   DWORD        Flags;
   WORD         nFileOffset;
   WORD         nFileExtension;
   LPCSTR       lpstrDefExt;
   LPARAM       lCustData;
   LPOFNHOOKPROC lpfnHook;
   LPCSTR       lpTemplateName;
#ifdef _MAC
   LPEDITMENU   lpEditInfo;
   LPCSTR       lpstrPrompt;
#endif
#if (_WIN32_WINNT >= 0x0500)
   void *       pvReserved;
   DWORD        dwReserved;
   DWORD        FlagsEx;
#endif // (_WIN32_WINNT >= 0x0500)
} OPENFILENAMEA, *LPOPENFILENAMEA;

(中略)

#if (_WIN32_WINNT >= 0x0500)
#define OPENFILENAME_SIZE_VERSION_400A  CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName)
#define OPENFILENAME_SIZE_VERSION_400W  CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName)
#ifdef UNICODE
#define OPENFILENAME_SIZE_VERSION_400  OPENFILENAME_SIZE_VERSION_400W
#else
#define OPENFILENAME_SIZE_VERSION_400  OPENFILENAME_SIZE_VERSION_400A
#endif // !UNICODE
#endif // (_WIN32_WINNT >= 0x0500)

これを見ると一目瞭然なのですが、_WIN32_WINNT の値が 0x0500 以上かそうでないかによって、構造体のサイズがちがうのです。それでは、この値の正体が一体何なのか?が問題となります。調べてみましたが、ややこしいので(英語が苦手)、簡単に解釈すると、Windows 2000 以上が 0x0500 以上と言うことらしく、Windows NT4 は、0x0400 で、Windows 98 もこの仲間に入るみたいです。

であれば、解決法は 3 通りあります。

3. 解決法

1. コンパイルオプションに -D_WIN32_WINNT=0x0400 を指定してコンパイルする。

COMMAND.COM /C BCC32.EXE -W -D_WIN32_WINNT=0x0400 test1.cpp

2. OPENFILENAME 構造体の lStructSize メンバの値に OPENFILENAME_SIZE_VERSION_400 を指定する。

    ZeroMemory(&ofn, sizeof(OPENFILENAME));
    ofn.lStructSize     = OPENFILENAME_SIZE_VERSION_400;
    ofn.hInstance       = hInstance;
    ofn.lpstrFile       = szFile;
    ofn.nMaxFile        = MAX_PATH;
    ofn.Flags           = OFN_FILEMUSTEXIST;
    
    if (!GetOpenFileName(&ofn))
    {

3. ソースファイルの先頭で、_WIN32_WINNT の値を 0x0400 に定義する。

// test1.cpp
#define _WIN32_WINNT    0x0400

#include <windows.h>

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE /* hPrevInstance */,
                     LPSTR     /* lpCmdLine */,
                     int       /* nCmdShow */ )
{

これで、問題は解決しました。

4. 参考

最後に OS の互換性について、この他のマクロ定義の値も含めて表にしておきます。

プラットフォーム マクロ定義
Windows Vista _WIN32_WINNT>=0x0600 WINVER>=0x0600
Windows Server 2003 _WIN32_WINNT>=0x0502 WINVER>=0x0502
Windows XP _WIN32_WINNT>=0x0501 WINVER>=0x0501
Windows 2000 _WIN32_WINNT>=0x0500 WINVER>=0x0500
Windows NT 4.0 _WIN32_WINNT>=0x0400 WINVER>=0x0400
Windows Me _WIN32_WINDOWS=0x0500 WINVER>=0x0500
Windows 98 _WIN32_WINDOWS>=0x0410 WINVER>=0x0410
Windows 95 _WIN32_WINDOWS>=0x0400 WINVER>=0x0400

Internet Explorer のバージョンによってもいろいろあるようです。

ブラウザ マクロ定義 バンドル
Internet Explorer 7.0 _WIN32_IE>=0x0700 Vista
Internet Explorer 6.0 SP2 _WIN32_IE>=0x0603 XP SP2
Internet Explorer 6.0 SP1 _WIN32_IE>=0x0601 -
Internet Explorer 6.0 _WIN32_IE>=0x0600 XP
Internet Explorer 5.5 _WIN32_IE>=0x0550 Me
Internet Explorer 5.01 _WIN32_IE>=0x0501 2000
Internet Explorer 5.0, 5.0a, 5.0b _WIN32_IE>=0x0500 98SE
Internet Explorer 4.01 _WIN32_IE>=0x0401 -
Internet Explorer 4.0 _WIN32_IE>=0x0400 98, 95 OSR2.5
Internet Explorer 3.0, 3.01, 3.02 _WIN32_IE>=0x0300 95 OSR2
 

Back Copyright (c) 2002, 2007 AOK. All Rights Reserved.