今回は下のようなコモンダイアログを使って、ファイルの読み書きをします。
Windowsのバージョンによって、違ったコモンダイアログになります。
下記は、Windows 8の「名前を付けて保存」コモンダイアログは、下記のようになります。
Windows Vistaの「名前を付けて保存」コモンダイアログは、下記のようになります。
Windows XPの「ファイルを開く」コモンダイアログです。
ファイルの読み書き1 - インコのWindowsSDK で作成したソースを修正します。
流れ 〜ファイルを開く
1.EnableMenuItem()で、上書き保存のメニューを選択できないようにします。
EnableMenuItem()の引数にメニューのハンドルが必要なので、GetMenu()でメニューのハンドルを取得します。
HMENU GetMenu( // 戻り値:メニューのハンドル HWND hWnd // ウィンドウのハンドル );
BOOL EnableMenuItem( HMENU hMenu, // メニューのハンドル UINT uIDEnableItem, // メニューアイテムのID UINT uEnable // オプション(MF_ENABLED:選択不可、MF_ENABLED:選択可) );
●ファイルオープン時
2.GetOpenFileName()で、コモンダイアログの表示
BOOL GetOpenFileName( LPOPENFILENAME lpofn // OPENFILENAME構造体のアドレス );
3.SetWindowText()で、ウインドウタイトルをセット。 ここでは、ウインドウタイトルをファイル名にします。
BOOL SetWindowText( HWND hWnd, // ウィンドウまたはコントロールのハンドル LPCTSTR lpString // タイトルまたはテキスト );
hWnd | ウィンドウまたはコントロールのハンドル |
lpString | 新しいウィンドウタイトルまたはコントロールのテキストとして使われる文字列 |
※ファイル名の変数の型を、MAX_PATH(260)バイト確保した、TCHAR型に変えています。(LPCTSTR型はconst型なので、変数の書き換えができないためです。)
確保したサイズが足りないと、実行時に強制終了されます。
4.EnableMenuItem()で、上書き保存のメニューを選択できるようにします。
●名前を選択して保存するとき
5.OPENFILENAME構造体のサイズをセット
6.GetSaveFileName()で、コモンダイアログの表示
BOOL GetSaveFileName( LPOPENFILENAME lpofn // OPENFILENAME構造体のアドレス );
7.CreateFile()でファイルを開きます。
8.EDITSTREAM構造体をセット
9.EM_SETMODIFYで、リッチエディットコントロールの変更フラグを解除
10.CloseHandle()でハンドルをクローズ
ソースコードの入力
ソースコードは下記のように入れてください。
#include <windows.h> #include <richedit.h> #include "resource.h" #define TEXTMAX 10000 // グローバル変数: HINSTANCE hInst; // 現在のインターフェイス // リッチエディットの使用するために用いる変数宣言 TCHAR strPath[MAX_PATH + 1]; // DLLのパス HINSTANCE hRtLib; // インスタンスハンドル HWND hRichEdit; // ウィンドウハンドル // このコード モジュールに含まれる関数の宣言を転送します: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); DWORD CALLBACK MySaveProc(DWORD, LPBYTE, LONG, LONG *); DWORD CALLBACK MyReadProc(DWORD, LPBYTE, LONG, LONG *); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; MyRegisterClass(hInstance); // アプリケーションの初期化を実行します: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } // メイン メッセージ ループ: while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; } // // 関数: MyRegisterClass() // // 目的: ウィンドウ クラスを登録します。 // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL , IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_HP); wcex.lpszClassName = TEXT("HP"); wcex.hIconSm = LoadIcon(NULL , IDI_APPLICATION); return RegisterClassEx(&wcex); } // // 関数: InitInstance(HINSTANCE, int) // // 目的: メイン ウィンドウを作成します。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // グローバル変数にインスタンス処理を格納します。 hWnd = CreateWindow(TEXT("HP"), TEXT("HP"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // // 関数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目的: メイン ウィンドウのメッセージを処理します。 // // WM_CREATE - ウインドウ作成時の処理 // WM_SIZE - ウインドウサイズ変更時の処理 // WM_COMMAND - アプリケーション メニューの処理 // WM_DESTROY - 中止メッセージを表示して戻る // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; OPENFILENAME of; // OPENFILENAME構造体 TCHAR szText[TEXTMAX] = TEXT(""); static TCHAR szFile[MAX_PATH] = TEXT(""); HANDLE hFile; EDITSTREAM eds; // EDITSTREAM構造体 switch (message) { case WM_CREATE: // DLLのロード GetSystemDirectory(strPath , MAX_PATH + 1); wsprintf(strPath, TEXT("%s\\%s"), strPath, TEXT("RICHED20.DLL")); hRtLib = LoadLibrary((LPCTSTR)strPath); hRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE, // 拡張ウィンドウスタイル TEXT("RichEdit20A"), // 登録されているクラス名 TEXT(""), // ウィンドウ名 WS_CHILD // 子ウィンドウを作成 | WS_VISIBLE // 初期状態で可視のウィンドウを作成 | WS_BORDER // 境界を持つウィンドウを作成 | ES_MULTILINE // 複数行入力 | WS_HSCROLL // 水平スクロールバーを持つウィンドウ | WS_VSCROLL // 垂直スクロール バーを持つウィンドウ | ES_AUTOVSCROLL // 自動縦スクロール(ES_MULTILINE のときのみ有効) | ES_NOHIDESEL, // 選択されているテキストは、コントロールが... // フォーカス持っていない場合も反転表示 0, // ウィンドウの横方向の位置 0, // ウィンドウの縦方向の位置 0, // ウィンドウの幅 0, // ウィンドウの高さ hWnd, // 親ウィンドウまたはオーナーウィンドウのハンドル (HMENU)IDC_RICHEDIT, // メニューハンドルまたは子識別子 hInst, // アプリケーションインスタンスのハンドル NULL); // ウィンドウ作成データ break; case WM_SIZE: MoveWindow(hRichEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 選択されたメニューの解析: switch (wmId) { case IDM_OPEN: // OPENFILENAME構造体のサイズをセット memset(&of, 0, sizeof(OPENFILENAME)); of.lStructSize = sizeof(OPENFILENAME); // ダイアログボックスを所有するウィンドウへのハンドル of.hwndOwner = hRichEdit; of.lpstrFilter = TEXT("TEXT(*.txt)\0 *.txt\0RTF(*.rtf)\0 *.rtf\0\0"); // ファイル名を格納したバッファのアドレス of.lpstrFile = (LPTSTR)szFile; // lpstrFileメンバで指定されるバッファのサイズ of.nMaxFile = MAX_PATH; // ダイアログボックスの初期化に使用されるビットフラグ // OFN_PATHMUSTEXIST:ユーザーが有効なパス // およびファイル名のみを入力できるように指定 of.Flags = OFN_PATHMUSTEXIST; // デフォルトの拡張子を格納したバッファのアドレス of.lpstrDefExt = TEXT("txt"); // コモンダイアログの表示 GetOpenFileName( &of ); hFile = CreateFile(szFile, // ファイル名 GENERIC_READ, // アクセス指定 GENERIC_READ:読み取り 0, // 共有方法 0:共有しない NULL, // セキュリティ属性 0:デフォルト OPEN_EXISTING, // 動作指定 OPEN_EXISTING:ファイルをオープン。 // ファイルが存在していない場合、 // 関数が失敗 FILE_ATTRIBUTE_NORMAL, // フラグと属性 // FILE_ATTRIBUTE_NORMAL:属性設定なし NULL); // テンプレートファイル if (hFile != INVALID_HANDLE_VALUE) { eds.dwCookie = (DWORD)hFile; // ファイルハンドルを渡す eds.dwError = 0; // 読み込み操作の結果 0はエラーなし eds.pfnCallback = MyReadProc; // コールバック関数アドレス SendMessage(hRichEdit, EM_STREAMIN, // 読み込み SF_TEXT, // テキスト形式 (LPARAM)&eds); // EDITSTREAM 構造体のアドレス SendMessage(hRichEdit, EM_SETMODIFY, // エディットコントロールの変更フラグを設定または解除 (WPARAM)FALSE, // 解除 0); CloseHandle(hFile); // ウインドウタイトルをファイル名にする SetWindowText(hWnd, (LPCTSTR)szFile); // メニューの選択可 EnableMenuItem(GetMenu(hWnd), IDM_SAVE, MF_ENABLED); } break; case IDM_SAVE: hFile = CreateFile(szFile, // ファイル名 GENERIC_WRITE, // アクセス指定 GENERIC_WRITE:書き込み 0, // 共有方法 0:共有しない NULL, // セキュリティ属性 0:デフォルト OPEN_ALWAYS, // 動作指定 OPEN_ALWAYS:ファイルをオープン。 // ファイルが存在していない場合、 // 新しいファイルを作成 FILE_ATTRIBUTE_NORMAL // フラグと属性 // FILE_ATTRIBUTE_NORMAL:属性設定なし | FILE_FLAG_WRITE_THROUGH,// データをそのまま直接ディスクに書き込む NULL); // テンプレートファイル eds.dwCookie = (DWORD)hFile; // ファイルハンドルを渡す eds.dwError = 0; // 書き込み操作の結果 0はエラーなし eds.pfnCallback = MySaveProc; // コールバック関数アドレス SendMessage(hRichEdit, EM_STREAMOUT, // 書き込み (WPARAM)SF_TEXT, // テキスト形式 (LPARAM)&eds); // EDITSTREAM 構造体のアドレス SendMessage(hRichEdit, EM_SETMODIFY, // エディットコントロールの変更フラグを設定または解除 (WPARAM)FALSE, // 解除 0); CloseHandle(hFile); break; case IDM_SAVE2: // OPENFILENAME構造体のサイズをセット memset(&of, 0, sizeof(OPENFILENAME)); of.lStructSize = sizeof(OPENFILENAME); // ダイアログボックスを所有するウィンドウへのハンドル of.hwndOwner = hRichEdit; of.lpstrFilter = TEXT("TEXT(*.txt)\0 *.txt\0RTF(*.rtf)\0 *.rtf\0\0"); // ファイル名を格納したバッファのアドレス of.lpstrFile = (LPTSTR)szFile; // lpstrFileメンバで指定されるバッファのサイズ of.nMaxFile = MAX_PATH; of.Flags = OFN_OVERWRITEPROMPT; // デフォルトの拡張子を格納したバッファのアドレス of.lpstrDefExt = TEXT("txt"); // コモンダイアログの表示 GetSaveFileName( &of ); hFile = CreateFile(szFile, // ファイル名 GENERIC_WRITE, // アクセス指定 GENERIC_WRITE:書き込み 0, // 共有方法 0:共有しない NULL, // セキュリティ属性 0:デフォルト OPEN_ALWAYS, // 動作指定 OPEN_ALWAYS:ファイルをオープン。 // ファイルが存在していない場合、 // 新しいファイルを作成 FILE_ATTRIBUTE_NORMAL // フラグと属性 // FILE_ATTRIBUTE_NORMAL:属性設定なし | FILE_FLAG_WRITE_THROUGH,// データをそのまま直接ディスクに書き込む NULL); // テンプレートファイル eds.dwCookie = (DWORD)hFile; // ファイルハンドルを渡す eds.dwError = 0; // 書き込み操作の結果 0はエラーなし eds.pfnCallback = MySaveProc; // コールバック関数アドレス SendMessage(hRichEdit, EM_STREAMOUT, // 書き込み (WPARAM)SF_TEXT, // テキスト形式 (LPARAM)&eds); // EDITSTREAM 構造体のアドレス SendMessage(hRichEdit, EM_SETMODIFY, // エディットコントロールの変更フラグを設定または解除 (WPARAM)FALSE, // 解除 0); CloseHandle(hFile); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } DWORD CALLBACK MySaveProc(DWORD dwCookie, LPBYTE pbbuf, LONG cb, LONG *pcb) { if (WriteFile((HANDLE)dwCookie, pbbuf, cb, (LPDWORD)pcb, NULL)) { return FALSE; } else { return TRUE; } } DWORD CALLBACK MyReadProc(DWORD dwCookie, LPBYTE pbBuf, LONG cb, LONG *pcb) { ReadFile((HANDLE)dwCookie, pbBuf, cb, (LPDWORD)pcb, NULL); return(FALSE); }
上記の太線で示している箇所のみ追加です。
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDM_SAVE 110
#define IDM_SAVE2 112
#define IDM_OPEN 111
#define IDC_HP 109
#define IDC_RICHEDIT 101
上記の太線で示している箇所のみ追加です。
#include "resource.h"
/////////////////////////////////////////////////////////////////////////////
//
// メニュー
//
IDC_HP MENU
BEGIN
POPUP "ファイル(&F)"
BEGIN
MENUITEM "開く(&O)", IDM_OPEN
MENUITEM "上書き保存(&S)", IDM_SAVE
MENUITEM "名前を付けて保存(&A)", IDM_SAVE2
MENUITEM "アプリケーションの終了(&X)", IDM_EXIT
END
POPUP "ヘルプ(&H)"
BEGIN
MENUITEM "バージョン情報(&A)...", IDM_ABOUT
END
END
上記の太線で示している箇所のみ追加です。