第146章 RTFにD&Dする


今回は簡単です。RTFにファイルを落として、これを表示させよう というものです。D&Dについては 第105章ですでに解説しています。 どこが違うかというと、105章では親のクライアント領域に ファイルが落とされると、親のプロシージャにWM_DROPFILESが 来ました。しかし、リッチエディットコントロールに落とした場合は そのプロシージャに行ってしまいます。では、どうすれば良いかというと

1.通知メッセージを捕まえる
2.エディットコントロールをサブクラス化する

という2つの方法がありますね。 どちらも手間は同じくらいです。 今回はサブクラス化でやってみます。

その前に、通知メッセージでの処理方法を簡単に解説しておきます。

1.エディットコントロールのイベントマスクにENM_DROPFILESを加える 2.エディットコントロールができたらDragAcceptFiles関数を実行 3.EN_DROPFILESはWM_NOTIFYの形式でやってくるのでこれを捕まえる

イベントマスクを設定するのを忘れ勝ちですので注意して下さい。

次にサブクラス化での方法は

1.DragAcceptFiles関数の実行 2.リッチエディットコントロールをサブクラス化する 3.サブクラス化したプロシージャの中でWM_DROPFILESを捕まえる 4.終了前にサブクラス化の解除

と、これだけです。 では、早速プログラムを見てみましょう。

リソース・スクリプトに変更はありません。

// rich17.cpp ...省略... LRESULT CALLBACK MyEditProc(HWND, UINT, WPARAM, LPARAM); ...省略... char szClassName[] = "rich17"; //ウィンドウクラス ...省略... WNDPROC Org_EditProc;//リッチエディットコントロールのプロシージャ ...省略...

リッチエディットコントロールをサブクラス化するので そのプロシージャのプロトタイプ宣言をしておきます。 もともとのプロシージャを保存するためにグローバル変数に Org_EditProcを用意しておきます。

WinMain, InitApp, InitInstance,

の各関数に変更はありません。

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { ...省略... switch (msg) { case WM_CREATE: InitCommonControls(); hTool = MakeMyToolbar(hWnd); InsertSep(hTool); hStatus = MakeMyStatusbar(hWnd); hRuler = MakeMyRuler(hWnd, hTool); hRtLib = LoadLibrary("RICHED32.DLL"); hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "RICHEDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE | WS_HSCROLL | WS_VSCROLL | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_NOHIDESEL, 0, 0, 0, 0, //とりあえず幅、高さ0のウィンドウを作る hWnd, (HMENU)ID_RICH,//統一性を図るためIDを変えました hInst, NULL); //リッチエディットコントロールの最大文字数のセット SendMessage(hEdit, EM_EXLIMITTEXT, 0, (LPARAM)(1024*1024)); //親ウィンドウへデータ(hEdit)のアタッチ SetWindowLong(hWnd, GWL_USERDATA, (LONG)hEdit); DragAcceptFiles(hEdit, TRUE); dwEvent = SendMessage(hEdit, EM_GETEVENTMASK, 0, 0); dwEvent |= ENM_MOUSEEVENTS | ENM_SELCHANGE; SendMessage(hEdit, EM_SETEVENTMASK, 0, (LPARAM)dwEvent); SetInitialFont(hEdit); //リッチエディットコントロールをWYSIWYGの幅にする //要するにプリンタにセットしてある用紙の幅に合わせる RTF_SetWYSIWYG(hEdit); tbs.hkr = HKEY_CURRENT_USER; tbs.pszSubKey = "Software\\Kumei\\rich13"; tbs.pszValueName = "Setting"; SendMessage(hTool, TB_SAVERESTORE, FALSE, (LPARAM)&tbs); SetStatusFontInfo(hStatus, hEdit); //ボタンを復元してから次の4つの関数を呼んでボタン状態を設定 IsEditButtonAvailable(hEdit, hTool); IsPasteButtonAvailable(hEdit, hTool); SetButtonHV(hEdit, hTool); SetAlignmentButton(hEdit, hTool); SetTimer(hWnd, ID_MYTIMER, 500, NULL); Org_ToolProc = (WNDPROC)GetWindowLong(hTool, GWL_WNDPROC); SetWindowLong(hTool, GWL_WNDPROC, (LONG)MyToolProc); Org_StaticProc = (WNDPROC)GetWindowLong(hRuler, GWL_WNDPROC); SetWindowLong(hRuler, GWL_WNDPROC, (LONG)MyStaticProc); Org_EditProc = (WNDPROC)GetWindowLong(hEdit, GWL_WNDPROC); SetWindowLong(hEdit, GWL_WNDPROC, (LONG)MyEditProc); break; ...省略... case WM_CLOSE: if (SendMessage(hEdit, EM_GETMODIFY, 0, 0)) { id = MessageBox(hWnd, "文書が変更されています。保存しますか。", "注意!", MB_YESNO); if (id == IDYES) RTF_Save(hEdit); } id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if (SetWindowLong(hEdit, GWL_WNDPROC, (LONG)Org_EditProc) == 0) MessageBox(NULL, "サブクラス化解除失敗(hEdit)", "失敗", MB_OK); DestroyWindow(hEdit); DestroyWindow(hWnd); } else SetFocus(hEdit); break; ...省略...

WM_CREATEのところでDragAcceptFiles関数を呼んだり エディットコントロールのサブクラス化をしています。

WM_CLOSEのところでサブクラス化の解除をしています。

LRESULT CALLBACK MyEditProc(HWND hMyEdit, UINT msg, WPARAM wp, LPARAM lp) { BOOL bRTF; //ファイル拡張子がrtfかどうか UINT uNo_of_file; HDROP hDrop; char szFileName[MAX_PATH]; HANDLE hFile; EDITSTREAM eds; int c; switch (msg) { case WM_DROPFILES: hDrop = (HDROP)wp; uNo_of_file = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); if (uNo_of_file > 1) { MessageBox(hMyEdit, "1回にドロップできるファイルはひとつです", "Error", MB_OK | MB_ICONHAND); DragFinish(hDrop); return (CallWindowProc(Org_EditProc, hMyEdit, msg, wp, lp)); } DragQueryFile(hDrop, 0, szFileName, sizeof(szFileName)); c = strlen(szFileName); if (szFileName[c-3] == 'r' && szFileName[c-2] == 't' && szFileName[c-1] == 'f') bRTF = TRUE; else bRTF = FALSE; hFile = CreateFile(szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE){ MessageBox(NULL, "無効なファイルハンドル", "Error", MB_OK); return 0; } eds.dwCookie = (DWORD)hFile; eds.dwError = 0; eds.pfnCallback = MyReadProc; if (strcmp(szFName, "") == 0) { char szTitle[MAX_PATH]; strcpy(szFName, szFileName); strcpy(szTitle, szAppTitle); strcat(szTitle, " [ "); strcat(szTitle, szFName); strcat(szTitle, " ]"); SetWindowText(GetParent(hMyEdit), szTitle); } if (bRTF) SendMessage(hMyEdit, EM_STREAMIN, SF_RTF |SFF_SELECTION, (LPARAM)&eds); else SendMessage(hMyEdit, EM_STREAMIN, SF_TEXT | SFF_SELECTION, (LPARAM)&eds); CloseHandle(hFile); DragFinish(hDrop); return 0; } return (CallWindowProc(Org_EditProc, hMyEdit, msg, wp, lp)); }


サブクラス化されたエディットコントロールのプロシージャです。 メニューの「ファイル」「開く」ではすでにコントロールに 文字列がある場合はそれを保存するかどうか聞いてきて 新規にファイルが開かれます。しかし、このプログラムではD&Dした 場合、開いたファイルの内容を挿入することができます。 すこし、便利になりましたね。

また、このプログラムではリッチエディットコントロールにきた いろいろなメッセージを通知メッセージと、サブクラス化という別々の 方法で取得している点に注意して下さい。


[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 26/Sep/1998 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。