まず、Rich Edit 2.0の作り方ですが,
これだけで大丈夫です。1.LoadLibrary("RICHED20.DLL");でDLLをロードする 2.CreateWindowExのウィンドウクラスをRICHEDIT_CLASSにする
また、URL検出部分にマウスが来たり、マウスがクリックされた ことを親に通知させるには、イベントマスクにENM_LINKを加えます。EM_AUTOURLDETECT wParam = (WPARAM) bEnable; // TRUE , FALSE lParam = 0 ; //使いません
例によって親のプロシージャでWM_NOTIFYメッセージを処理します。
ENLINK構造体は次のように定義されています。EN_LINK idEditCtrl = (int) LOWORD(wParam); //エディットコントロールのID pEnlink = (ENLINK *) lParam; // ENLINK 構造体へのポインタ
32ビット版では_wPadXは無視して下さい。 これは、解説はあんまり必要ないですね。typedef struct _enlink { NMHDR nmhdr; UINT msg; _WPAD _wPad1; WPARAM wParam; _WPAD _wPad2; LPARAM lParam; CHARRANGE chrg; } ENLINK;
あと,構造体としてCHARFORMAT2とか PARAFORMAT2とかが出てきますがこれも仕様が変更になる 可能性がありますので、ここでは解説しません。 今回のサンプルでは単純にCHARFORMATをCHARFORMAT2に、 PARAFORMATをPARAFORMAT2に書き換えただけです。 (新しい構造体ではメンバがかなり増えて細かな設定ができる ようになりました)
URLとかmailto:などをみつけるとその部分の色が変わり下線が 引かれます。また,この部分をマウスが通過するとカーソルが 指型(?)に変わります。また、この部分をクリックすると指定の URLを呼び出したり、メールを出したりすることができます。 Rich Edit2.0では1.0の時はは,かなりめんどうだったことが比較的簡単に実現 できます。
では、プログラムを見てみましょう。リソース・スクリプトに変更はありません。
VC++6.0ではSTRICTは自動的に付加されるので#ifndefにしました。// rich20.cpp #ifndef STRICT #define STRICT #endif ...省略... #define SZMYVERSION "猫でもわかるRTF#猫でもわかるRTF Ver0.20" ...省略... char szClassName[] = "rich20"; //ウィンドウクラス ...省略... DWORD dwMyMask; //CHARFORMAT2で使うマスク値 ...省略...
の各関数に変更はありません。WinMain, InitApp, InitInstance
たったこれだけの改造で本文中からURLとかメールアドレスを検出して クリックすることにより実行することができるようになります。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { ...省略... ENLINK *penlk; char szURL[256]; ...省略... switch (msg) { case WM_CREATE: ...省略... hRtLib = LoadLibrary("RICHED20.DLL"); hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, RICHEDIT_CLASS, "", 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, hInst, NULL); //リッチエディットコントロールの最大文字数のセット SendMessage(hEdit, EM_EXLIMITTEXT, 0, (LPARAM)(1024*1024)); //親ウィンドウへデータ(hEdit)のアタッチ SetWindowLong(hWnd, GWL_USERDATA, (LONG)hEdit); DragAcceptFiles(hEdit, TRUE); //URL検出機能を組み込む SendMessage(hEdit, EM_AUTOURLDETECT, (WPARAM)TRUE, 0); ...省略... dwEvent |= ENM_MOUSEEVENTS | ENM_SELCHANGE | ENM_LINK; ...省略... case WM_NOTIFY: ...省略... if (wp == (WPARAM)ID_RICH) { lpN = (LPNMHDR)lp; switch (lpN->code ) { case EN_LINK: penlk = (ENLINK *)lp; if (penlk->msg == WM_LBUTTONDOWN) { SendMessage(hEdit, EM_EXSETSEL, 0, (LPARAM)(&(penlk->chrg))); SendMessage(hEdit, EM_GETSELTEXT, 0, (LPARAM)szURL); ShellExecute(hEdit, NULL, szURL, NULL, NULL, SW_SHOWNORMAL); } break; ...省略... }
初期状態のフォントをSystemにしました。この時フォントの高さも指定しておいて下さい。 そうしないとステータスバーに表示されるポイントが0になってしまいます。 この辺が1.0とはちょっと違うようです。BOOL SetInitialFont(HWND hEdit)//最初のフォントの設定 { CHARFORMAT2 cfm; memset(&cfm, 0, sizeof(CHARFORMAT2)); cfm.cbSize = sizeof(CHARFORMAT2); cfm.dwMask = CFM_BOLD | CFM_CHARSET | CFM_COLOR | CFM_FACE | CFM_ITALIC | CFM_SIZE | CFM_STRIKEOUT | CFM_UNDERLINE; dwMyMask = cfm.dwMask;//以後dwMyMaskの値を使う cfm.bCharSet = DEFAULT_CHARSET; cfm.yHeight = 14*20; strcpy(cfm.szFaceName, "System"); if (SendMessage(hEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfm) == 0) { MessageBox(hEdit, "EM_SETCHARFORMAT2失敗です", "Error", MB_OK); return FALSE; } return TRUE; }
単純にCHARFORMATをCHARFORMAT2に変えただけです。BOOL SetMyFont(HWND hEdit) { CHARFORMAT2 cfm; ...省略... cfm.cbSize = sizeof(CHARFORMAT2); ...省略... //フォント選択ダイアログを出して新しい設定を取得する if (ChooseFont(&cf)) { cfm.cbSize = sizeof(CHARFORMAT2); ...省略... }
これも構造体をPARAFORMAT2にしただけです。BOOL SetCenter(HWND hEdit) { PARAFORMAT2 pf; memset(&pf, 0, sizeof(PARAFORMAT2)); pf.cbSize = sizeof(PARAFORMAT2); SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); pf.dwMask |= PFM_ALIGNMENT; pf.wAlignment = PFA_CENTER; SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf); SetFocus(hEdit); return TRUE; }
これもPARAFORMAT2にしただけです。BOOL SetLeft(HWND hEdit) { PARAFORMAT2 pf; memset(&pf, 0, sizeof(PARAFORMAT2)); pf.cbSize = sizeof(PARAFORMAT2); ...省略... } BOOL SetRight(HWND hEdit) { PARAFORMAT2 pf; memset(&pf, 0, sizeof(PARAFORMAT2)); pf.cbSize = sizeof(PARAFORMAT2); ...省略... }
の各関数に変更はありません。ClearCheck, RTF_Save, RTF_SaveAs, MySaveProc, RTF_Open, MyReadProc
ここもPARAFORMAT2になっただけです。void RTF_CheckMenu(HWND hEdit, HMENU hMenu) { CHARRANGE cr; PARAFORMAT2 pf; ...省略... memset(&pf, 0, sizeof(PARAFORMAT2)); pf.cbSize = sizeof(PARAFORMAT2); ...省略... }
の各関数に変更はありません。RTF_Print, PrinterSet, GetPrintInfo, RTF_All, RTF_AddPageNo, RTF_SetWYSIWYG, RTF_New, RTF_Vertical, RTF_Horizontal, RTF_BackColor, MakeMyToolbar, InsertSep, MakeMyStatusbar
ここも単純な置き換えです。void SetStatusFontInfo(HWND hStatus, HWND hEdit) { CHARFORMAT2 cf; ...省略... memset(&cf, 0, sizeof(CHARFORMAT2)); cf.cbSize = sizeof(CHARFORMAT2); SendMessage(hEdit, EM_GETCHARFORMAT, (WPARAM)TRUE, (LPARAM)&cf); ...省略... }
の各関数に変更はありません。IsEditButtonAvailable, IsPasteButtonAvailable, SetStatusClock
ここも単純な置き換えです。// タブの設定 void RTF_SetTab(HWND hEdit, int unit) { PARAFORMAT2 pf; int i; memset(&pf, 0, sizeof(PARAFORMAT2)); pf.cbSize = sizeof(PARAFORMAT2); ...省略... } // 現在の段落の配置法(center, right, left)を調べてボタンに反映 void SetAlignmentButton(HWND hEdit, HWND hTool) { PARAFORMAT2 pf; memset(&pf, 0, sizeof(PARAFORMAT2)); pf.cbSize = sizeof(PARAFORMAT2); ...省略... }
の各関数に変更はありません。SetButtonHV, MyToolProc
置き換えです。void RTF_Num(HWND hEdit) { PARAFORMAT2 pf; memset(&pf, 0, sizeof(PARAFORMAT2)); pf.cbSize = sizeof(PARAFORMAT2); ...省略... }
この関数に変更はありません。MakeMyRuler
置きかえる場所は結構あちこちにあります。LRESULT CALLBACK MyStaticProc(HWND hStatic, UINT msg, WPARAM wp, LPARAM lp) { ...省略... PARAFORMAT2 pf; ...省略... Rectangle(hdc, 2, 6, w-2, 24); memset(&pf, 0, sizeof(PARAFORMAT2)); pf.cbSize = sizeof(PARAFORMAT2); SendMessage(hEdit, EM_GETPARAFORMAT,0, (LPARAM)&pf); if (pf.rgxTabs[0] > 0 && pf.cTabCount > 0) { ...省略... }
の各関数に変更はありません。MyEditProc, MyAboutProc, MyAboutStaticProc
さて、今回のプログラムで一番問題なのは縦書きが実現できない という点です。これは、どうしたらよいのでしょうか。
Update 15/Oct/1998 By Y.Kumei