今回はリッチエディットでファイルの読み書きをします。
リッチエディット1 - インコのWindowsSDK で作成したソースを修正します。
流れ 〜ファイルを開く
1.OPENFILENAME構造体をセット
OPENFILENAME構造体はコモンダイアログボックスを初期化するために使う情報が入っています。
typedef struct tagOFN { DWORD lStructSize; // 構造体サイズ(=76) HWND hwndOwner; // ダイアログボックスのオーナーウィンドウのハンドル HINSTANCE hInstance; LPCTSTR lpstrFilter; // ファイル名を格納したバッファのアドレス LPTSTR lpstrCustomFilter; DWORD nMaxCustFilter; DWORD nFilterIndex; LPTSTR lpstrFile; DWORD nMaxFile; // lpstrFileメンバで指定されるバッファのサイズ LPTSTR lpstrFileTitle; DWORD nMaxFileTitle; LPCTSTR lpstrInitialDir; LPCTSTR lpstrTitle; DWORD Flags; // ダイアログボックスの初期化に使用されるビットフラグ WORD nFileOffset; WORD nFileExtension; LPCTSTR lpstrDefExt; // デフォルトの拡張子を格納したバッファのアドレス LPARAM lCustData; LPOFNHOOKPROC lpfnHook; LPCTSTR lpTemplateName; void * pvReserved; DWORD dwReserved; DWORD FlagsEx; } OPENFILENAME, *LPOPENFILENAME;
lStructSize | OPENFILENAME構造体のサイズ | |
hwndOwner | ダイアログボックスを所有するウィンドウのハンドル | |
hInstance | ・FlagsメンバでOFN_ENABLETEMPLATEHANDLEフラグが設定されている場合・・・ ダイアログボックステンプレートが格納されているメモリオブジェクトのハンドル ・FlagsメンバでOFN_ENABLETEMPLATEフラグが設定されている場合・・・ lpTemplateNameメンバによって指定されたダイアログテンプレートが格納されているモジュールへのハンドル ・FlagsメンバでOFN_EXPLORERフラグが設定されている場合・・・ システムはエクスプローラスタイルのダイアログを作成するために、指定されたテンプレートを使用 | |
lpstrFilter | 「ファイルの種類」コンボボックスに表示される、ファイルのフィルタ 例: "*.txt;*.doc;*.bak" 「種類の説明1 \0 拡張子1 \0 種類の説明2 \0 拡張子2 \0 \0」の形式で記載します。(最後に\0が2つ続きます) |
|
lpstrCustomFilter | フィルタパターン文字列を保存するためのバッファ | |
nMaxCustFilter | lpstrCustomFilterメンバで指定されるバッファのサイズ | |
lpstrFile | ファイル名の初期値 | |
nMaxFile | lpstrFileメンバで指定されるファイル名の最大文字数 | |
lpstrFileTitle | (パス情報を除く)ファイル名および拡張子を格納するための、バッファ この情報が不要の場合には、このメンバに0(NULL)を指定 |
|
nMaxFileTitle | lpstrFileTitleメンバで示されるバッファのサイズ | |
lpstrTitle | ダイアログボックスのタイトルバーに表示される文字列 このメンバに0(NULL)を指定すると、デフォルトのタイトル(『開く』および『名前を付けて保存』) |
|
Flags | ダイアログボックスの初期化に使用されるビットフラグを設定 | |
OFN_READONLY | 「書込み禁止」チェックボックスを、初期状態からチェックがついた状態にする | |
OFN_OVERWRITEPROMPT | 「名前をつけて保存」ダイアログボックスで、選択されたファイルがすでに存在する場合にはメッセージボックスを表示 | |
OFN_HIDEREADONLY | 「書込み禁止」チェックボックスを無効 | |
OFN_ENABLETEMPLATE | hInstanceメンバの機能切り替え | |
OFN_ENABLETEMPLATEHANDLE | hInstanceメンバの機能切り替え | |
OFN_ALLOWMULTISELECT | 「ファイル名」リストボックスで複数の選択ができるようにする | |
OFN_PATHMUSTEXIST | ユーザーが有効なパスとディレクトリしか入力できないようになる。無効なパスやファイル名を入力すると 警告のメッセージボックスが出るようになる。 | |
OFN_CREATEPROMPT | 存在しないファイルをユーザーが指定した場合、ファイルを作成するかどうかの確認ダイアログを表示。 | |
OFN_FORCESHOWHIDDEN | システムファイルまたは隠し属性ファイルを表示。ただし、システム属性・隠し属性の両方の属性を持つファイルは表示しない。 | |
lpstrDefExt | デフォルトの拡張子をセット 拡張子に.(ピリオド)は不要 |
|
lpTemplateName | ダイアログテンプレートリソースのポインタ FlagsメンバにOFN_ENABLETEMPLATEが設定されているときのみ有効 |
|
pvReserved | 0(NULL)固定 | |
dwReserved | 0固定 |
2.CreateFile()でファイルを開く
HANDLE CreateFile( LPCTSTR lpFileName, // ファイル名 DWORD dwDesiredAccess, // アクセス指定 DWORD dwShareMode, // 共有方法 LPSECURITY_ATTRIBUTES lpSecurityAttributes, // セキュリティ属性 DWORD dwCreationDisposition, // 動作指定 DWORD dwFlagsAndAttributes, // フラグと属性 HANDLE hTemplateFile // テンプレートファイルのハンドル );
lpFileName | ファイル名 | |
dwDesiredAccess | アクセス指定 | |
0 | ファイルの読み書きをしない 属性を取得する際に使用 |
|
GENERIC_WRITE | 書き込み | |
GENERIC_READ | 読み取り | |
dwShareMode | 共有方法 | |
0 | 共有しない | |
FILE_SHARE_READ | これ以降、オープン操作で読み取りアクセスが要求された場合、そのオープンを許可 | |
FILE_SHARE_WRITE | これ以降、オープン操作で書き込みアクセスが要求された場合、そのオープンを許可 | |
FILE_SHARE_DELETE | これ以降、オープン操作で削除アクセスが要求された場合、そのオープンを許可 | |
lpSecurityAttributes | セキュリティ属性 | |
0(NULL) | デフォルトのセキュリティ | |
dwCreationDisposition | 動作指定 | |
CREATE_NEW | 新しいファイルを作成 指定したファイルが既に存在している場合、この関数は失敗。 |
|
CREATE_ALWAYS | 新しいファイルを作成 そのファイルを上書きし、既存の属性を消去。 |
|
OPEN_EXISTING | ファイルを開きます 指定したファイルが存在していない場合、この関数は失敗。 |
|
OPEN_ALWAYS | ファイルを開きます 指定したファイルが存在していない場合、新しいファイルを作成。 |
|
TRUNCATE_EXISTING | ファイルを開き、ファイルのサイズを 0 バイトにします 指定したファイルが存在していない場合、この関数は失敗。 |
|
dwFlagsAndAttributes | ファイルの属性とフラグ | |
FILE_ATTRIBUTE_READONLY | 読み取り専用 | |
FILE_ATTRIBUTE_HIDDEN | 隠しファイル | |
FILE_ATTRIBUTE_SYSTEM | システムファイル | |
FILE_ATTRIBUTE_NORMAL | 属性なし | |
hTemplateFile | テンプレートファイルのハンドル |
3.EDITSTREAM構造体をセット
typedef struct _editstream { DWORD_PTR dwCookie; // アプリケーション定義値 DWORD dwError; // エラーコード EDITSTREAMCALLBACK pfnCallback; // コールバック関数アドレス } EDITSTREAM;
3.1.dwCookieにファイルハンドルを渡す
3.2.dwErrorは、コールバック関数の戻り値が入りますが、
初期値0をセットします。
3.3.pfnCallbackにコールバック関数のアドレスをセット
コールバック関数・・・
プログラム中で、呼び出し先の関数の実行中に実行されるように、あらかじめ指定しておく関数。
4.EM_STREAMINで、リッチエディットにEDITSTREAM構造体をセット
lResult = SendMessage( (HWND) hWndControl, // ウィンドウハンドル (UINT) EM_STREAMIN, (WPARAM) wParam, // データフォーマットと置きかえオプションを示すフラグ (LPARAM) lParam // EDITSTREAM構造体のアドレス );
・wParamは、データフォーマットと置きかえオプションを示すフラグを指定。
SF_TEXTは、データフォーマットが、テキスト形式
5.EM_SETMODIFYで、リッチエディットコントロールの変更フラグを解除
lResult = SendMessage( (HWND) hWndControl, // ウィンドウハンドル (UINT) EM_SETMODIFY, (WPARAM) FALSE, 0 );
6.CloseHandle()でハンドルをクローズ
BOOL CloseHandle( HANDLE hObject // オブジェクトのハンドル );
● コールバック関数
DWORD CALLBACK ******(DWORD, LPBYTE, LONG, LONG)
7.ReadFile()でデータの読み込み
BOOL ReadFile( HANDLE hFile, // ファイルのハンドル LPVOID lpBuffer, // ファイルから読み取ったデータを格納するためのバッファアドレス DWORD nNumberOfBytesToRead, // 読み取り対象のバイト数 LPDWORD lpNumberOfBytesRead, // 実際に読み取られたバイト数を格納するための変数 LPOVERLAPPED lpOverlapped // OVERLAPPED構造体またはNULL );
流れ 〜ファイルに書き込む
1.CreateFile()でファイルを開く
2.EDITSTREAM構造体をセット
3.EM_SETMODIFYで、リッチエディットコントロールの変更フラグを解除
4.CloseHandle()でハンドルをクローズ
● コールバック関数
DWORD CALLBACK ******(DWORD, LPBYTE, LONG, LONG)
5.WriteFile()でデータの書き込み
BOOL WriteFile( HANDLE hFile, // ファイルのハンドル LPCVOID lpBuffer, // 書き込むデータが入ったバッファアドレス DWORD nNumberOfBytesToWrite, // 書き込み対象のバイト数 LPDWORD lpNumberOfBytesWritten, // 実際に書き込まれたバイト数を格納するための変数 LPOVERLAPPED lpOverlapped // OVERLAPPED構造体またはNULL );
ソースコードの入力
ソースコードは下記のように入れてください。
#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(""); LPCTSTR szFile = TEXT("sample.txt"); 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"); hFile = CreateFile(szFile, // ファイル名 GENERIC_READ, // アクセス指定 GENERIC_READ:読み取り 0, // 共有方法 0:共有しない NULL, // セキュリティ属性 0:デフォルト OPEN_ALWAYS, // 動作指定 OPEN_ALWAYS:ファイルをオープン。 // ファイルが存在していない場合、 // 新しいファイルを作成 FILE_ATTRIBUTE_NORMAL, // フラグと属性 // FILE_ATTRIBUTE_NORMAL:属性設定なし NULL); // テンプレートファイル if (hFile == INVALID_HANDLE_VALUE) { MessageBox(hRichEdit, TEXT("ファイルがありません"), TEXT("Error"), MB_OK); break; } 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); 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_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_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 "アプリケーションの終了(&X)", IDM_EXIT
END
POPUP "ヘルプ(&H)"
BEGIN
MENUITEM "バージョン情報(&A)...", IDM_ABOUT
END
END
上記の太線で示している箇所のみ追加です。