第139章 RTFの背景色を変える


リッチエディットコントロールでは背景色を変えることができます。 今回は,「色の設定」コモンダイアログを使って背景色を ユーザーの好みの色に変えるプログラムを作ってみます。

メニューの「表示」「背景色の変更」で背景の色を変える事ができます。



メニューの「背景色の変更」を選択すると左のようなコモンダイアログボックスが 表示されます。「基本色」の中から好きな色を選択します。気に食わないときは 「色の作成」ボタンを押して自分で好みの色を作ることができます。 この時作った色は「作成した色」のところに記憶しておくと便利です。 上の図の背景色は自分で作って「作成した色」のところにおいてあります。

今回のプログラムではいろいろな設定はiniファイルとかレジストリに 記憶させていないので新しい色を作っておいても次回起動時には 反映されません。



「色の設定」コモンダイアログはChooseColor関数で呼びます。

BOOL ChooseColor( LPCHOOSECOLOR lpcc //初期化データを持った構造体へのポインタ

lpccはCHOOSECOLOR構造体へのポインタです。
ユーザーが色を選んで「OK」ボタンを押すと0以外の数値が 「キャンセル」ボタンを押すと0が返されます。

CHOOSECOLOR構造体は次のように定義されています。

typedef struct { // cc DWORD lStructSize; HWND hwndOwner; HWND hInstance; COLORREF rgbResult; COLORREF* lpCustColors; DWORD Flags; LPARAM lCustData; LPCCHOOKPROC lpfnHook; LPCTSTR lpTemplateName; } CHOOSECOLOR;

lStructSizeはこの構造体の大きさを指定します。

hwndOwner「色の設定」ダイアログボックスのオーナーウィンドウを指定します。

hInstanceダイアログテンプレートを使うときにインスタンスハンドルを指定します。

rgbResultダイアログボックスを開く前にこの値を指定しておくとその色が選択されます。 (この場合FlagsをCC_RGBINITにしておく必要あり)ダイアログボックスが閉じられるときには ユーザーが指定した色が入ります。

lpCustColorsはカスタムカラーボックス(「色の作成」ボタンを押すと 右側に出てくる)の設定が格納されます。COLORREF変数の配列で要素は16個です。

Flagsは次の値の組み合わせを指定します。
CC_ENABLEHOOKはフック関数を有効にします。フックについては 第40章を参照してください。
CC_ENABLETEMPLATEはテンプレートを使ってダイアログボックスを作ります。 (hInstanceとlpTemplateNameメンバが有効な時)
CC_ENABLETEMPLATEHANDLEが指定されているとlpTemplateNameメンバは無視されます。
CC_FULLOPENはダイアログが出てくるときにカスタムカラーを作成する 部分も一度に現れます。
CC_PREVENTFULLOPENは「色の作成」ボタンを無効にします。
CC_RGNINITを指定すると、rgbResultメンバで指定した色を選択したダイアログボックスが 出現します。
CC_SHOWHELPを指定すると「ヘルプ」ボタンが表示されます。(「キャンセル」の右側)

lCustDataはシステムがlpfnHookメンバで指定されたフック関数にデータを渡します。これによって フック関数はlCustDataの値を知ることができます。

lpfnHookにはフック関数のポインタを指定します。

lpstrTemplateNameにはダイアログテンプレートの名前を指定します。

これで、ユーザーが指定した色を取得することができるようになりました。 では、背景色をこの色にするにはどうしたら良いのでしょうか。
これは簡単です。EM_SETBKGNDCOLORメッセージを使います。

EM_SETBKGNDCOLOR wParam = (WPARAM) (BOOL) fUseSysColor; lParam = (LPARAM) (COLORREF) clr;

fUseSysColorを0以外に設定するとシステムの背景色が使われます。 0を指定するとclrの値が使われます。

clrは背景色を指定します。

これでリッチエディットコントロールの背景色を自由に変更する ことができるようになりました。

さて、前回までのプログラムを使ってみて次のような不満がありました。 すなわちプログラムのソースファイルのように拡張子が「txt」以外の 普通のテキストファイルが開けない、というものです。 これは、ファイルのオープンと名前をつけて保存する部分を少し 改良すれば解決します。今回はこの部分にも手を入れてみます。
では、プログラムを見てみましょう。

// rich10.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "新規作成(&N)", IDM_NEW MENUITEM "開く(&O)", IDM_OPEN MENUITEM SEPARATOR MENUITEM "上書き保存(&S)", IDM_SAVE MENUITEM "名前をつけて保存(&A)", IDM_SAVEAS MENUITEM SEPARATOR MENUITEM "プリンターの設定(&U)", IDM_PRNSET MENUITEM "印刷(&P)", IDM_PRINT MENUITEM SEPARATOR MENUITEM "終了(&X)", IDM_END END POPUP "編集(&E)" BEGIN MENUITEM "元に戻す(&U)", IDM_UNDO MENUITEM SEPARATOR MENUITEM "横書き(&H)", IDM_HORIZONTAL MENUITEM "縦書き(&V)", IDM_VERTICAL MENUITEM SEPARATOR MENUITEM "フォントの変更(&F)", IDM_FONT POPUP "段落書式" BEGIN MENUITEM "中央揃え(&C)", IDM_CENTER MENUITEM "左揃え(&L)", IDM_LEFT MENUITEM "右揃え(&R)", IDM_RIGHT END MENUITEM SEPARATOR MENUITEM "コピー(&C)", IDM_COPY MENUITEM "切り取り(&T)", IDM_CUT MENUITEM "貼り付け(&P)", IDM_PASTE MENUITEM SEPARATOR MENUITEM "すべて選択(&L)", IDM_ALL END POPUP "表示(&V)" BEGIN MENUITEM "背景色の変更(&B)", IDM_BACKCOLOR END END MYPOPUP MENU DISCARDABLE BEGIN POPUP "ダミーです" BEGIN MENUITEM "新規作成", IDM_NEW MENUITEM "開く", IDM_OPEN MENUITEM SEPARATOR MENUITEM "上書き保存", IDM_SAVE MENUITEM "名前をつけて保存", IDM_SAVEAS MENUITEM SEPARATOR MENUITEM "横書き", IDM_HORIZONTAL MENUITEM "縦書き", IDM_VERTICAL MENUITEM SEPARATOR MENUITEM "フォントの変更", IDM_FONT MENUITEM SEPARATOR MENUITEM "左揃え", IDM_LEFT MENUITEM "右揃え", IDM_RIGHT MENUITEM "中央揃え", IDM_CENTER MENUITEM SEPARATOR MENUITEM "終了", IDM_END MENUITEM SEPARATOR MENUITEM "コピー", IDM_COPY MENUITEM "切り取り", IDM_CUT MENUITEM "貼り付け", IDM_PASTE MENUITEM "元に戻す", IDM_UNDO MENUITEM SEPARATOR MENUITEM "印刷", IDM_PRINT MENUITEM "プリンタの設定", IDM_PRNSET MENUITEM SEPARATOR MENUITEM "すべて選択", IDM_ALL MENUITEM SEPARATOR MENUITEM "背景色の変更", IDM_BACKCOLOR END END

「背景色の変更」(IDM_BACKCOLOR)が増えました。

// rich10.cpp #define STRICT #include <windows.h> #include <richedit.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); DWORD CALLBACK MySaveProc(DWORD, LPBYTE, LONG, LONG *); DWORD CALLBACK MyReadProc(DWORD, LPBYTE, LONG, LONG *); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL SetInitialFont(HWND hWnd); BOOL SetMyFont(HWND); BOOL SetCenter(HWND); BOOL SetLeft(HWND); BOOL SetRight(HWND); void ClearCheck(HMENU);//段落書式のチェックをはずす void RTF_Save(HWND); void RTF_SaveAs(HWND); void RTF_Open(HWND); void RTF_CheckMenu(HWND, HMENU); void RTF_Print(HWND); void RTF_All(HWND); HDC GetPrintInfo(void); int PrinterSet(HWND); int RTF_AddPageNo(HDC, int); void RTF_SetWYSIWYG(HWND); void RTF_New(HWND); void RTF_Vertical(HWND); void RTF_Horizontal(HWND); void RTF_BackColor(HWND); char szClassName[] = "rich10"; //ウィンドウクラス HINSTANCE hInst; DWORD dwMyMask; //CHARFORMATで使うマスク値 char szFName[MAX_PATH]; int nFileType = 1; //1:RTF 2:TXT 3:All char *szAppTitle = "猫でもわかるRTF"; PRINTER_INFO_5 prninfo[3];

今回は背景色を変えるRTF_BackColor関数が新たに増えました。
また、nFileTypeが3ならすべて(*.*)という意味を持たせました。

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 BOOL InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; hWnd = CreateWindow(szClassName, szAppTitle, //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW,//ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInstance, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

親ウィンドウ(メイン・ウィンドウ)を作るところまではいつも同じです。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HINSTANCE hRtLib; static HWND hEdit; DWORD dwEvent; MSGFILTER *pmf; HMENU hMenu, hSub; int x, y; POINT pt; switch (msg) { case WM_CREATE: 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)1, hInst, NULL); dwEvent = SendMessage(hEdit, EM_GETEVENTMASK, 0, 0); dwEvent |= ENM_MOUSEEVENTS; SendMessage(hEdit, EM_SETEVENTMASK, 0, (LPARAM)dwEvent); SetInitialFont(hEdit); //リッチエディットコントロールをWYSIWYGの幅にする //要するにプリンタにセットしてある用紙の幅に合わせる RTF_SetWYSIWYG(hEdit); break; case WM_NOTIFY: switch (((NMHDR*)lp)->code ) { case EN_MSGFILTER: pmf = (MSGFILTER *)lp; if (pmf->msg == WM_RBUTTONDOWN){ x = LOWORD(pmf->lParam); y = HIWORD(pmf->lParam); hMenu = LoadMenu(hInst, "MYPOPUP"); hSub = GetSubMenu(hMenu, 0); pt.x = (LONG)x; pt.y = (LONG)y; ClientToScreen(hEdit, &pt); TrackPopupMenu(hSub, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL); DestroyMenu(hMenu); } break; } break; case WM_SIZE: MoveWindow(hEdit, 0, 0, LOWORD(lp), HIWORD(lp), TRUE); SetFocus(hEdit); break; case WM_INITMENUPOPUP: RTF_CheckMenu(hEdit, (HMENU)wp); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_ALL: RTF_All(hEdit); break; case IDM_FONT: SetMyFont(hEdit); break; case IDM_CENTER: SetCenter(hEdit); break; case IDM_LEFT: SetLeft(hEdit); break; case IDM_RIGHT: SetRight(hEdit); break; case IDM_NEW: RTF_New(hEdit); break; case IDM_SAVE: RTF_Save(hEdit); break; case IDM_SAVEAS: RTF_SaveAs(hEdit); break; case IDM_OPEN: RTF_Open(hEdit); break; case IDM_COPY: SendMessage(hEdit, WM_COPY, 0, 0); break; case IDM_CUT: SendMessage(hEdit, WM_CUT, 0, 0); break; case IDM_PASTE: SendMessage(hEdit, WM_PASTE, 0, 0); break; case IDM_UNDO: SendMessage(hEdit, WM_UNDO, 0, 0); SendMessage(hEdit, EM_SETMODIFY, (WPARAM)FALSE, 0); break; case IDM_PRINT: RTF_Print(hEdit); break; case IDM_PRNSET: PrinterSet(hEdit); RTF_SetWYSIWYG(hEdit); break; case IDM_VERTICAL: RTF_Vertical(hEdit); break; case IDM_HORIZONTAL: RTF_Horizontal(hEdit); break; case IDM_BACKCOLOR: RTF_BackColor(hEdit); break; } 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) { DestroyWindow(hEdit); DestroyWindow(hWnd); } else SetFocus(hEdit); break; case WM_DESTROY: if(FreeLibrary(hRtLib) == 0) MessageBox(NULL, "ライブラリ開放失敗", "Error", MB_OK); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; }

WM_COMMANDのところのIDM_BACKCOLORが増えました。

BOOL SetInitialFont(HWND hEdit)//最初のフォントの設定 { CHARFORMAT cfm; memset(&cfm, 0, sizeof(CHARFORMAT)); cfm.cbSize = sizeof(CHARFORMAT); cfm.dwMask = CFM_BOLD | CFM_CHARSET | CFM_COLOR | CFM_FACE | CFM_ITALIC | CFM_SIZE | CFM_STRIKEOUT | CFM_UNDERLINE; dwMyMask = cfm.dwMask;//以後dwMyMaskの値を使う cfm.bCharSet = SHIFTJIS_CHARSET; strcpy(cfm.szFaceName, "MS ゴシック"); if (SendMessage(hEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfm) == 0) { MessageBox(hEdit, "EM_SETCHARFORMAT失敗です", "Error", MB_OK); return FALSE; } return TRUE; } BOOL SetMyFont(HWND hEdit) { CHARFORMAT cfm; CHOOSEFONT cf; LOGFONT lf; HDC hDC; memset(&cf, 0, sizeof(CHOOSEFONT)); memset(&lf, 0, sizeof(LOGFONT)); cfm.cbSize = sizeof(CHARFORMAT); //今までの設定を取得してそれをCHOOSEFONT構造体に渡す SendMessage(hEdit, EM_GETCHARFORMAT, TRUE, (LPARAM)&cfm); hDC = GetDC(hEdit); lf.lfHeight = MulDiv(cfm.yHeight, GetDeviceCaps(hDC, LOGPIXELSY), -1440); ReleaseDC(hEdit, hDC); cfm.dwMask = dwMyMask; if (cfm.dwEffects & CFE_BOLD) lf.lfWeight = FW_BOLD; else lf.lfWeight = FW_NORMAL; if (cfm.dwEffects & CFE_ITALIC) lf.lfItalic = TRUE; if (cfm.dwEffects & CFE_UNDERLINE) lf.lfUnderline = TRUE; if (cfm.dwEffects & CFE_STRIKEOUT) lf.lfStrikeOut = TRUE; lf.lfCharSet = cfm.bCharSet; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = cfm.bPitchAndFamily; strcpy( lf.lfFaceName, cfm.szFaceName ); cf.rgbColors = cfm.crTextColor; cf.lStructSize = sizeof(CHOOSEFONT); cf.hwndOwner = hEdit; cf.lpLogFont = &lf; cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT; //フォント選択ダイアログを出して新しい設定を取得する if (ChooseFont(&cf)) { cfm.cbSize = sizeof(CHARFORMAT); cfm.dwMask = dwMyMask; cfm.yHeight = 2 * cf.iPointSize; cfm.dwEffects = 0; if (lf.lfWeight >= FW_BOLD) cfm.dwEffects |= CFE_BOLD; if (lf.lfItalic) cfm.dwEffects |= CFE_ITALIC; if (lf.lfUnderline) cfm.dwEffects |= CFE_UNDERLINE; if (lf.lfStrikeOut) cfm.dwEffects |= CFE_STRIKEOUT; cfm.crTextColor = (COLORREF)cf.rgbColors; cfm.bPitchAndFamily = lf.lfPitchAndFamily; cfm.bCharSet = lf.lfCharSet; strcpy(cfm.szFaceName, lf.lfFaceName); if(SendMessage(hEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfm) == 0) { MessageBox(hEdit, "失敗です", "Error", MB_OK); return FALSE; } } SetFocus(hEdit); return TRUE; }

フォントの設定関係のところは前回までと同じです。

BOOL SetCenter(HWND hEdit) { PARAFORMAT pf; memset(&pf, 0, sizeof(PARAFORMAT)); pf.cbSize = sizeof(PARAFORMAT); pf.dwMask = PFM_ALIGNMENT; pf.wAlignment = PFA_CENTER; SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf); SetFocus(hEdit); return TRUE; } BOOL SetLeft(HWND hEdit) { PARAFORMAT pf; memset(&pf, 0, sizeof(PARAFORMAT)); pf.cbSize = sizeof(PARAFORMAT); pf.dwMask = PFM_ALIGNMENT; pf.wAlignment = PFA_LEFT; SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf); SetFocus(hEdit); return TRUE; } BOOL SetRight(HWND hEdit) { PARAFORMAT pf; memset(&pf, 0, sizeof(PARAFORMAT)); pf.cbSize = sizeof(PARAFORMAT); pf.dwMask = PFM_ALIGNMENT; pf.wAlignment = PFA_RIGHT; SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf); SetFocus(hEdit); return TRUE; }

段落の「揃え」の部分に変更はありません。

void ClearCheck(HMENU hMenu) { CheckMenuItem(hMenu, IDM_LEFT, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_RIGHT, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_CENTER, MF_BYCOMMAND | MF_UNCHECKED); return; }

ここも変更はありません。

void RTF_Save(HWND hEdit) { EDITSTREAM eds; HANDLE hFile; if (strcmp(szFName, "") == 0) { MessageBox(hEdit, "ファイル名を設定してください", "ファイル名", MB_OK); RTF_SaveAs(hEdit); } hFile = CreateFile(szFName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL); eds.dwCookie = (DWORD)hFile; eds.dwError = 0; eds.pfnCallback = MySaveProc; switch (nFileType) { case 1: SendMessage(hEdit, EM_STREAMOUT, (WPARAM)SF_RTF, (LPARAM)&eds); break; case 2: // *.txtと*.*はテキストタイプで保存する case 3: SendMessage(hEdit, EM_STREAMOUT, (WPARAM)SF_TEXT, (LPARAM)&eds); break; } CloseHandle(hFile); SendMessage(hEdit, EM_SETMODIFY, (WPARAM)FALSE, 0); return; }

ここの変更点はnFileType(グローバル変数)が2または3のときはテキスト形式で 保存するようにした点です。

void RTF_SaveAs(HWND hEdit) { OPENFILENAME of; HWND hParent; char szTitle[MAX_PATH]; memset(&of, 0, sizeof(OPENFILENAME)); of.lStructSize = sizeof(OPENFILENAME); of.hwndOwner = hEdit; of.lpstrFilter = "RTF(*.rtf)\0 *.rtf\0TEXT(*.txt)\0*.txt\0All Files(*.*)\0*.*\0\0"; of.lpstrFile = szFName; of.nMaxFile = MAX_PATH; of.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; of.lpstrDefExt = "rtf"; if (GetSaveFileName(&of)) { nFileType = of.nFilterIndex;//どのタイプでSaveするかをRTF_Saveに知らせる RTF_Save(hEdit); nFileType = of.nFilterIndex; hParent = GetParent(hEdit); strcpy(szTitle, szAppTitle); strcat(szTitle, " ["); strcat(szTitle, szFName); strcat(szTitle, "]"); SetWindowText(hParent, szTitle); } return; }

さて、この関数の変更点はof.lpstrFilterに(*.*)を加えた点です。

この*.*が曲者でした

実は第75章でも似たようなことを やっているのですが,(*.*)を選択しているときファイル名に いいかげんな拡張子をつけると (たとえば「abc.efg」など)拡張子が「rtf」になってしまうのです (「abc.efg.rtf」)。 これは、GetSaveFileName関数を呼び出す前にof.lpstrDefExtをNULLに 設定していないからだな・・・そこでGetSaveFileName関数を 呼び出す前にnFileTypeで場合わけをしてof.lpstrDefExtを設定して・・・ ところが、nFileTypeはGetSaveFileName関数が終了しないとわかりません。 あれこれ、いじって泥沼に陥りましたがこれは取り越し苦労でした。 Window95/98におまけでついてくるメモ帳もファイルタイプを*.*にして いいかげんな拡張子をつけると拡張子がtxtになってしまいます。 つまり、ファイルタイプが*.*でもいい加減な拡張子をつけては デフォルトの拡張子となってしまいます。(いい加減かどうかはそのシステムで その拡張子がレジストリに登録されているかどうかではないかと愚考しています。)

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; }

これは,前回までと同じです。

void RTF_Open(HWND hEdit) { OPENFILENAME of; HANDLE hFile; EDITSTREAM eds; HWND hParent; char szTitle[MAX_PATH]; int id; if (SendMessage(hEdit, EM_GETMODIFY, 0, 0)) { id = MessageBox(hEdit, "文書が変更されています。\n保存しますか?", "注意!", MB_OKCANCEL | MB_ICONQUESTION); if (id == IDOK) RTF_Save(hEdit); SetFocus(hEdit); } memset(&of, 0, sizeof(OPENFILENAME)); of.lStructSize = sizeof(OPENFILENAME); of.hwndOwner = hEdit; of.lpstrFilter = "RTF(*.rtf)\0 *.rtf\0TEXT(*.txt)\0 *.txt\0All Files(*.*)\0 *.*\0\0"; of.lpstrFile = szFName; of.nMaxFile = MAX_PATH; of.Flags = OFN_PATHMUSTEXIST; of.lpstrDefExt = "rtf"; if (GetOpenFileName(&of) == 0) return; nFileType = of.nFilterIndex; hFile = CreateFile(szFName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { MessageBox(hEdit, "ハンドルが無効です", "Error", MB_OK); return; } eds.dwCookie = (DWORD)hFile; eds.dwError = 0; eds.pfnCallback = MyReadProc; switch (nFileType) { case 1: SendMessage(hEdit, EM_STREAMIN, SF_RTF, (LPARAM)&eds); break; case 2: case 3: SendMessage(hEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&eds); break; } SendMessage(hEdit, EM_SETMODIFY, (WPARAM)FALSE, 0); CloseHandle(hFile); strcpy(szTitle, szAppTitle); strcat(szTitle, " ["); strcat(szTitle, szFName); strcat(szTitle, "]"); hParent = GetParent(hEdit); if (of.Flags & OFN_READONLY) { SendMessage(hEdit, EM_SETOPTIONS, (WPARAM)ECOOP_OR, (LPARAM)ECO_READONLY); strcat(szTitle, " == READONLY =="); } SetWindowText(hParent, szTitle); return; }

この関数もnFileTypeによってオープンの仕方を場合分けしています。

DWORD CALLBACK MyReadProc(DWORD dwCookie, LPBYTE pbBuf, LONG cb, LONG *pcb) { ReadFile((HANDLE)dwCookie, pbBuf, cb, (LPDWORD)pcb, NULL); return(FALSE); }

これは,今までと同じです。

void RTF_CheckMenu(HWND hEdit, HMENU hMenu) { CHARRANGE cr; PARAFORMAT pf; SendMessage(hEdit, EM_EXGETSEL, 0, (LPARAM)&cr); if (cr.cpMin == cr.cpMax) { EnableMenuItem(hMenu, IDM_CUT, MF_GRAYED | MF_BYCOMMAND); EnableMenuItem(hMenu, IDM_COPY, MF_GRAYED | MF_BYCOMMAND); } else { EnableMenuItem(hMenu, IDM_CUT, MF_ENABLED | MF_BYCOMMAND); EnableMenuItem(hMenu, IDM_COPY, MF_ENABLED | MF_BYCOMMAND); } if (SendMessage(hEdit, EM_GETMODIFY, 0, 0)) { EnableMenuItem(hMenu, IDM_UNDO, MF_ENABLED | MF_BYCOMMAND); } else { EnableMenuItem(hMenu, IDM_UNDO, MF_GRAYED | MF_BYCOMMAND); } if (SendMessage(hEdit, EM_CANPASTE, 0, 0)) { EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED | MF_BYCOMMAND); } else { EnableMenuItem(hMenu, IDM_PASTE, MF_GRAYED | MF_BYCOMMAND); } if (SendMessage(hEdit, EM_GETOPTIONS, 0, 0) & ECO_VERTICAL) { EnableMenuItem(hMenu, IDM_VERTICAL, MF_GRAYED | MF_BYCOMMAND); EnableMenuItem(hMenu, IDM_HORIZONTAL, MF_ENABLED | MF_BYCOMMAND); } else { EnableMenuItem(hMenu, IDM_VERTICAL, MF_ENABLED | MF_BYCOMMAND); EnableMenuItem(hMenu, IDM_HORIZONTAL, MF_GRAYED | MF_BYCOMMAND); } memset(&pf, 0, sizeof(PARAFORMAT)); pf.cbSize = sizeof(PARAFORMAT); SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); ClearCheck(hMenu); switch (pf.wAlignment) { case PFA_LEFT: CheckMenuItem(hMenu, IDM_LEFT, MF_CHECKED | MF_BYCOMMAND); break; case PFA_RIGHT: CheckMenuItem(hMenu, IDM_RIGHT, MF_CHECKED | MF_BYCOMMAND); break; case PFA_CENTER: CheckMenuItem(hMenu, IDM_CENTER, MF_CHECKED | MF_BYCOMMAND); break; } return; }

変更はありません。

void RTF_Print(HWND hEdit) { static FORMATRANGE fr; DOCINFO di; HDC hdc; LONG lTextLen; LONG lNextMin = 0; int nPage = 1; //印刷ページ memset(&fr, 0, sizeof(FORMATRANGE)); memset(&di, 0, sizeof(DOCINFO)); di.cbSize = sizeof(DOCINFO); if (strcmp(szFName, "") == 0) di.lpszDocName = "No Title"; else GetFileTitle(szFName, (LPTSTR)di.lpszDocName, sizeof(di.lpszDocName)); hdc = GetPrintInfo(); if (hdc == 0) { MessageBox(hEdit, "プリンタが取得できません", "Error", MB_OK | MB_ICONASTERISK); return; } fr.hdc = hdc; fr.hdcTarget = hdc; fr.rcPage.left = 0; fr.rcPage.top = 0; fr.rcPage.right = MulDiv(GetDeviceCaps(hdc, PHYSICALWIDTH), 1440, GetDeviceCaps(hdc, LOGPIXELSX)); fr.rcPage.bottom = MulDiv(GetDeviceCaps(hdc, PHYSICALHEIGHT), 1440, GetDeviceCaps(hdc, LOGPIXELSY)); //用紙の上下左右は1インチ(1440twip)あけて印刷 fr.rc.top = 1440; fr.rc.left = 1440; fr.rc.right = fr.rcPage.right - 1440; fr.rc.bottom = fr.rcPage.bottom -1440; lTextLen = SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0); fr.chrg.cpMin = 0; fr.chrg.cpMax = lTextLen; StartDoc(hdc, &di); while (fr.chrg.cpMin < lTextLen) { lNextMin = SendMessage(hEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr); StartPage(hdc); SendMessage(hEdit, EM_DISPLAYBAND, 0, (LPARAM)&fr.rc); RTF_AddPageNo(hdc, nPage); EndPage(hdc); fr.chrg.cpMin = lNextMin; nPage++; } SendMessage(hEdit, EM_FORMATRANGE, TRUE, NULL); EndDoc(hdc); DeleteDC(hdc); return; } int PrinterSet(HWND hEdit) { HANDLE hPrint; GetPrintInfo(); OpenPrinter(prninfo[0].pPrinterName, &hPrint, NULL); PrinterProperties(hEdit, hPrint); ClosePrinter(hPrint); return 0; } HDC GetPrintInfo(void) { DWORD dwNeeded, dwReturned; if (EnumPrinters(PRINTER_ENUM_DEFAULT, NULL, 5, (LPBYTE)&prninfo, sizeof(prninfo), &dwNeeded, &dwReturned)) { return CreateDC(NULL, prninfo[0].pPrinterName, NULL, NULL); } return 0; }

印刷関係も変更はありません。

void RTF_All(HWND hEdit) { CHARRANGE cr; cr.cpMin = 0; cr.cpMax = -1; SendMessage(hEdit, EM_EXSETSEL, 0, (LPARAM)&cr); return; } int RTF_AddPageNo(HDC hdc, int nPage) { int wx, wy, x, y; char szPage[64]; char *szPage_Org = "-- %d --"; int nTextW; //テキストの幅 TEXTMETRIC tm; wx = GetDeviceCaps(hdc, PHYSICALWIDTH); wy = GetDeviceCaps(hdc, PHYSICALHEIGHT); wsprintf(szPage, szPage_Org, nPage); GetTextMetrics(hdc, &tm); nTextW = (int)tm.tmAveCharWidth * strlen(szPage); x = (wx - nTextW) / 2; y = 40; TextOut (hdc, x, y, szPage, strlen(szPage)); return nPage; } void RTF_SetWYSIWYG(HWND hEdit) { HDC hdc; //プリンタのhdc int nPrnW; int nLog; int w; //RTFに設定する横幅(twip) hdc = GetPrintInfo(); nPrnW = GetDeviceCaps(hdc, PHYSICALWIDTH); nLog = GetDeviceCaps(hdc, LOGPIXELSX); //左右1インチあけるので1440*2(twip)引く w = MulDiv(nPrnW, 1440, nLog) - 1440 * 2; if (SendMessage(hEdit, EM_SETTARGETDEVICE, (WPARAM)hdc, (LPARAM)w) == 0) MessageBox(hEdit, "RTF横幅設定でエラーが発生しました", "ERROR", MB_OK); return; } void RTF_New(HWND hEdit) { char szTitle[MAX_PATH]; int id; if (SendMessage(hEdit, EM_GETMODIFY, 0, 0)) { id = MessageBox(hEdit, "文書が変更されています。\n保存しますか?", "注意!", MB_OKCANCEL | MB_ICONQUESTION); if (id == IDOK) RTF_Save(hEdit); } SetWindowText(hEdit, ""); strcpy(szTitle, szAppTitle); strcat(szTitle, " [ 無題 ]"); SetWindowText(GetParent(hEdit), szTitle); SendMessage(hEdit, EM_SETMODIFY, FALSE, 0); SetFocus(hEdit); return; } void RTF_Vertical(HWND hEdit) { SendMessage(hEdit, EM_SETOPTIONS, (WPARAM)ECOOP_OR, (LPARAM)ECO_VERTICAL); SetFocus(hEdit); return; } void RTF_Horizontal(HWND hEdit) { SendMessage(hEdit, EM_SETOPTIONS, (WPARAM)ECOOP_XOR, (LPARAM)ECO_VERTICAL); SetFocus(hEdit); return; }

これも,変更はありません。

void RTF_BackColor(HWND hEdit) { CHOOSECOLOR cc; static COLORREF cr = RGB(255, 255, 255);//最初は白に設定 static DWORD dwCustColors[16]; memset(&cc, 0, sizeof(CHOOSECOLOR)); cc.lStructSize = sizeof(CHOOSECOLOR); cc.hwndOwner = hEdit; cc.lpCustColors = dwCustColors; cc.rgbResult = cr; cc.Flags = CC_RGBINIT; if (ChooseColor(&cc)) { cr = cc.rgbResult; SendMessage(hEdit, EM_SETBKGNDCOLOR, (WPARAM)0, (LPARAM)cr); } SetFocus(hEdit); return; }

これが,今回のテーマの背景色の変更です。
[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

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