開発環境はVC++6です。

CFileDialogやChooseColor関数ででる色の設定ダイアログに使われている言葉を英語表記にしたいと考えているのですが、どのようにすればできるのでしょうか?
回答いただきたく宜しくお願いします。

回答の条件
  • URL必須
  • 1人2回まで
  • 登録:2007/06/13 17:32:31
  • 終了:2007/06/20 17:35:02

回答(1件)

id:jack_sonic No.1

じゃっくそにっく回答回数123ベストアンサー獲得回数252007/06/15 23:27:07

ポイント60pt

こんにちは。

説明

前の質問のコメントでご要望を頂いた、

Spy++などを使わずに、CFileDialogやChooseColorのダイアログ文字を

コントロールIDなしで

便利に書き換える方法を説明します。

1.ダイアログ上の文字=Staticテキストも、ウィンドウです。

2.フック関数の中で、FindWindowEx()で、ダイアログを親ウィンドウとし、キャプション文字を指定して子ウィンドウ(Static)を検索します。

この方法だと、コントロールIDを知る必要がないです。

3.英語にすると、文字が長くなって横に入りきらなくなる場合があるので、フォントも指定できる必要があります。

4.キャプションの置換においては、

{置換前文字,置換後文字,フォント}などの、置換情報を格納した構造体の配列を用意して使います。

この方法だと、置換対照表を一目瞭然に見やすくかけます。

5.ウィンドウのタイトルを判断し、どの置換情報構造体の配列を使うかを振り分けます。

置換情報構造体の例

// フォント情報
LOGFONT rLogfont;			// 論理フォント変数
HFONT hFontSmall=NULL;		// 小さめのフォント
/////////////////////////////
// 置換情報構造体
typedef struct repItem {
	char strBefore[100];	// 置換前文字
	char strAfter[100];		// 置換後文字
	HFONT*	phFont;			// 適用フォントへのポインタ
} stRepItem;
// タイトルの情報と関連付ける置換配列
typedef struct repTitle {
	char strBefore[100];	// 置換前タイトル
	char strAfter[100];		// 置換後タイトル
	HFONT* phFont;			// 適用フォントへのポインタ
	repItem * pRepItem;		// 使用する置換配列
	int aryLength;
} stRepTitle;

// 置換情報を含む構造体配列定義
stRepItem repColDlg[] =
{
	{"キャンセル" , "cancel" , NULL},
	{"基本色(&B):", "BaseColor(&B)", NULL},
	{"作成した色(&C):", "CreatedColor(&C): to change color from white,down Light", &hFontSmall},
	{"色の作成(&D) >>" , "Create Color(&D) >>", NULL},
	{"色合い(&E):", "Hue(&E):", NULL},
	{"鮮やかさ(&S):", "Saturation(&S):", &hFontSmall },
	{"明るさ(&L):", "Light(&L):", NULL },

	{"赤(&R):", "Red(&R):", NULL},
	{"緑(&G):", "Green(&G):", &hFontSmall},
	{"青(&U):", "Blue(&U):", NULL},
	{"色の追加(&A)", "Add Color(&A)", NULL},
	{"色" , "col", NULL},
	{"| 純色(&O)" , "| pure col(&O)", &hFontSmall}

};
// ファイルを開くダイアログ用
stRepItem repFileDlg[] =
{
	{"ファイルの場所(&I):", "Location(&I):" , NULL},
	{"ファイル名(&N):", "File Name(&N):", NULL},
	{"ファイルの種類(&T):", "File Type(&T):", NULL},
	{"キャンセル", "Cancel", NULL},
	{"開く(&O)", "Open(&O)", NULL},
	{"表示メニュー", "Menu" , NULL},
	{"縮小版(&H)", "mini(&H)" , NULL}
};
// タイトルと関連付けの定義
stRepTitle repTitle[] = 
{
	{ "色の設定", "Color Settings", NULL , repColDlg,  sizeof(repColDlg)/sizeof(stRepItem) },
	{ "ファイルを開く", "Open File", NULL , repFileDlg,  sizeof(repFileDlg)/sizeof(stRepItem) }
};


画面サンプル

[f:id:jack_sonic:20070615230450j:image]

[f:id:jack_sonic:20070615230449j:image]

色選択ダイアログには、

「白から色を変えるときは明るさを下げるように」

という注意書きも追加しています。

(コントロールIDでなく、ウィンドウで処理しており、

フォントの種類を変えることも容易です。)


ダウンロードファイル+詳細はこちら、

VC++/システム・コモンダイアログの文字を書き換える - 情報処理研究所 ジャックズラボ(jack's Lab)

ソースファイル 一部 DialogFunc.h

// DialogFunc.h
#pragma once

// カラー選択ダイアログ表示関数
// (オーナーウィンドウ, 結果格納COLORREF, 初期カラー, 初期カラーを使うかどうか)
BOOL ColorDlg(HWND hWnd, COLORREF* p_crResult, 
			  COLORREF crFirst, BOOL bUseFirstColor, DWORD dwSpCustomColors[] );
// プロトタイプ宣言
LRESULT CALLBACK LocalHookProc (int nCode, WPARAM wParam ,LPARAM lParam );
int AfxMessageBoxHooked( LPCSTR message , UINT nType );


int	HookFileDialogDoModal( CFileDialog * pFileDialog );


DialogFunc.cpp

#include "StdAfx.h"  // VC++のときインクルード
// StfAfx.hインクルード プリコンパイル済み~のエラーを出さないために必要
// ヘッダインクルード
#include "DialogFunc.h"

//////////////////////////////////////////////////////////////////
// フックハンドル用の変数をグローバルで宣言する。
HHOOK MyHookHandle;	// フックハンドル変数

int LangRep = 1;		// 書き換えを行うかどうかのフラグ

// OKの文字列と、キャンセルの文字列
// ボタンの文字を変更したい場合はここを変更してください
LPCSTR strOK = "OK";			// OKボタンの文字
LPCSTR strCancel = "Cancel";	// キャンセルボタンの文字
// フォント情報
LOGFONT rLogfont;			// 論理フォント変数
HFONT hFontSmall=NULL;		// 小さめのフォント
/////////////////////////////
// 置換情報構造体
typedef struct repItem {
	char strBefore[100];	// 置換前文字
	char strAfter[100];		// 置換後文字
	HFONT*	phFont;			// 適用フォントへのポインタ
} stRepItem;
// タイトルの情報と関連付ける置換配列
typedef struct repTitle {
	char strBefore[100];	// 置換前タイトル
	char strAfter[100];		// 置換後タイトル
	HFONT* phFont;			// 適用フォントへのポインタ
	repItem * pRepItem;		// 使用する置換配列
	int aryLength;
} stRepTitle;

// 置換情報を含む構造体配列定義
stRepItem repColDlg[] =
{
	{"キャンセル" , "cancel" , NULL},
	{"基本色(&B):", "BaseColor(&B)", NULL},
	{"作成した色(&C):", "CreatedColor(&C): to change color from white,down Light", &hFontSmall},
	{"色の作成(&D) >>" , "Create Color(&D) >>", NULL},
	{"色合い(&E):", "Hue(&E):", NULL},
	{"鮮やかさ(&S):", "Saturation(&S):", &hFontSmall },
	{"明るさ(&L):", "Light(&L):", NULL },

	{"赤(&R):", "Red(&R):", NULL},
	{"緑(&G):", "Green(&G):", &hFontSmall},
	{"青(&U):", "Blue(&U):", NULL},
	{"色の追加(&A)", "Add Color(&A)", NULL},
	{"色" , "col", NULL},
	{"| 純色(&O)" , "| pure col(&O)", &hFontSmall}

};
// ファイルを開くダイアログ用
stRepItem repFileDlg[] =
{
	{"ファイルの場所(&I):", "Location(&I):" , NULL},
	{"ファイル名(&N):", "File Name(&N):", NULL},
	{"ファイルの種類(&T):", "File Type(&T):", NULL},
	{"キャンセル", "Cancel", NULL},
	{"開く(&O)", "Open(&O)", NULL},
	{"表示メニュー", "Menu" , NULL},
	{"縮小版(&H)", "mini(&H)" , NULL}
};
// タイトルと関連付けの定義
stRepTitle repTitle[] = 
{
	{ "色の設定", "Color Settings", NULL , repColDlg,  sizeof(repColDlg)/sizeof(stRepItem) },
	{ "ファイルを開く", "Open File", NULL , repFileDlg,  sizeof(repFileDlg)/sizeof(stRepItem) }
};


////////////////////////////////////////////////////////////////////
//
//		ダイアログ内容書き換えのための
//		フック関数(ローカルフック用)
//		※ グローバル関数である必要があります。
//		この関数の中を変えるときは慎重に行って下さい。
//
LRESULT CALLBACK LocalHookProc (int nCode, WPARAM wParam ,LPARAM lParam )
{
	// コード判断
	if (nCode >= 0)
	{
		if ( nCode == HCBT_ACTIVATE)
		{

			if( LangRep == 1 ){
               //論理フォント構造体の指定
               rLogfont.lfHeight= 10 ;// 大きさ
               rLogfont.lfWidth= 0 ;
               rLogfont.lfEscapement= 0 ;
               rLogfont.lfOrientation= 0 ;
               rLogfont.lfWeight= 0 ;
               rLogfont.lfItalic= FALSE ;
               rLogfont.lfUnderline= FALSE ;
               rLogfont.lfStrikeOut= FALSE ;
               rLogfont.lfCharSet= ANSI_CHARSET ;
               rLogfont.lfOutPrecision= OUT_DEFAULT_PRECIS ;
               rLogfont.lfClipPrecision= CLIP_DEFAULT_PRECIS ;
               rLogfont.lfQuality= DEFAULT_QUALITY ;
               rLogfont.lfPitchAndFamily= VARIABLE_PITCH | FF_SWISS ;
               wsprintf(rLogfont.lfFaceName,_T("MS UI Gothic"));

               //フォントを作成
                hFontSmall = CreateFontIndirect(&rLogfont) ;

				int i,numAry;
				stRepItem * pRepItem=NULL;
				char strType[50];
				strcpy(strType, "");
				HWND myWnd;
				// タイトルの書き換え
				for( i = 0; i < (sizeof(repTitle)/sizeof(repItem)) ; i++)
				{
					char buff[50];
					GetWindowText((HWND)wParam,buff, sizeof(buff));
					if( strcmp(buff,repTitle[i].strBefore ) == 0 )
					{
						// 一致したものがあった
						SetWindowText((HWND)wParam, repTitle[i].strAfter );

						pRepItem = repTitle[i].pRepItem;
						numAry = repTitle[i].aryLength;
						strcpy( strType , repTitle[i].strBefore );
						if( strcmp(strType,"Open File") == 0 )
						{
							HWND hwndTB ;

							hwndTB = FindWindowEx((HWND)wParam,0, "ToolbarWindow32", NULL);
							if( hwndTB != 0)
							{
								::SetWindowText((HWND)wParam,"aa");
								CToolBar tb;
								tb.m_hWnd = hwndTB;
								//tb.Attach(hwndTB);
								CString strTmp;
								tb.SetButtonText(1, "aaaa");

							}


						}


						break;
					}
				}
				for(  i = 0; i < numAry ; i++)
				{
					// FindWindowEx(親ウィンドウ, 開始子ウィンドウ番号, クラス名 , キャプション);
					myWnd =  FindWindowEx( (HWND)wParam,  0, NULL, pRepItem[i].strBefore );
					if( myWnd != 0)
					{
						SetWindowText(myWnd, pRepItem[i].strAfter );
						if( pRepItem[i].phFont != NULL)
						{
							::SendMessage(myWnd,WM_SETFONT,(WPARAM)*pRepItem[i].phFont,(LPARAM) 1);

						}
					}
				}
			}			
			// OKボタン(IDOK)の内容を書き換える
			SetDlgItemText( ( HWND )wParam, IDOK, strOK );
			// キャンセルボタン(IDCANCEL)の内容を書き換える
			SetDlgItemText( ( HWND )wParam, IDCANCEL, strCancel );

			HRESULT ret;
			// フック関数をアンインストール(フック解除!)
			ret = UnhookWindowsHookEx ( MyHookHandle );
			MyHookHandle = NULL;
		}
	}
	// 次のフックに渡す
	return CallNextHookEx ( MyHookHandle, nCode, wParam, lParam);
}
/////////////////////////////////////////////////////////////
//
//			ファイル選択ダイアログをフック付きで呼び出す関数
//
int	HookFileDialogDoModal( CFileDialog * pFileDialog )
{
	MyHookHandle = SetWindowsHookEx ( WH_CBT, LocalHookProc, NULL, GetCurrentThreadId( ) ); 

	return pFileDialog->DoModal();

}




///////////////////////////////////////////////////////////
//
//	ColorDlg() カラー選択ダイアログ関数
//	カスタムカラー配列はstaticで保存されます。
//		@param  hWnd		:   オーナーウィンドウ
//		@param  p_crResult	:	結果を受け取るCOLORREFのポインタ 
//		@param	crFirst		:  初期選択色
//		@param	bUserFirstColor: 初期選択色を使うかどうか
//		@param dwSpCustomColors[] 
//					: カスタムカラー配列を独自に指定する場合(NULL: デフォルト保存)
//		@return TRUE:選択 , FALSE :キャンセル
//
BOOL ColorDlg(HWND hWnd, COLORREF* p_crResult, 
			  COLORREF crFirst, BOOL bUseFirstColor, DWORD dwSpCustomColors[] )
{
	// TODO: この位置にコントロール通知ハンドラ用のコードを追加してください

	// CHOOSECOLOR構造体定義
	CHOOSECOLOR cc;
	// カスタムカラーボックスのデータ配列定義
	// 16個のCOLORREF変数の配列 ( staticで宣言すること)
	static DWORD       dwDefaultCustomColors[16];   
	// COLORREF構造体定義
	static COLORREF crDefaultFirst = RGB(255,255,255);

	// CHOOSECOLOR構造体クリア
	ZeroMemory(&cc,sizeof(CHOOSECOLOR));
	// CHOOSECOLOR構造体サイズ設定
	cc.lStructSize = sizeof(CHOOSECOLOR);
	// オーナーウィンドウ設定
	cc.hwndOwner =(HWND ) hWnd;
	// カスタムカラーボックスのデータ配列設定
	cc.lpCustColors = ( dwSpCustomColors != NULL)? dwSpCustomColors: dwDefaultCustomColors;

	// 	初期選択色
	cc.rgbResult =  (bUseFirstColor == TRUE)? crFirst: crDefaultFirst;
	// フラグ設定
	// CC_FULLOPEN : カスタムカラー設定表示
	// CC_RGBINIT  : rgbResultの色を初期選択
	// CC_ANYCOLOR : 使用可能な全ての色を表示する
	cc.Flags = CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT;
	

	// フック関数(MsgBoxHookProc)をインストールする SetWindowHookEx
	MyHookHandle = SetWindowsHookEx ( WH_CBT, LocalHookProc, NULL, GetCurrentThreadId( ) ); 

	// カラーダイアログを表示
	if(ChooseColor(&cc)){
		*p_crResult = cc.rgbResult;
		return TRUE;
	}
	return FALSE;
}

/////////////////////////////////////////////////////////////////////
//
//		AfxMessageBoxHooked(メッセージ, 
//
int AfxMessageBoxHooked( LPCSTR message , UINT nType )
{
	// フック関数(MsgBoxHookProc)をインストールする SetWindowHookEx
	MyHookHandle = SetWindowsHookEx ( WH_CBT, LocalHookProc, NULL, GetCurrentThreadId( ) ); 
	return ( AfxMessageBox(message, nType) ); 

}
id:harunoharuno

いつも丁寧に回答していただきありがとうございます。

特にデータの定義方法に関しては

自分にない整然としたもので勉強になります。

コーディングで3点気になる場所がありましたので質問します。

①LocalHookProcの以下記述の部分ですが、

 名前変更方法に関係なさそうに思えました。

 

if( strcmp(strType,"Open File") == 0 )

{

HWND hwndTB ;

hwndTB = FindWindowEx((HWND)wParam,0, "ToolbarWindow32", NULL);

if( hwndTB != 0)

{

::SetWindowText((HWND)wParam,"aa");

CToolBar tb;

tb.m_hWnd = hwndTB;

//tb.Attach(hwndTB);

CString strTmp;

tb.SetButtonText(1, "aaaa");

}

}

これはjack_sonicさんが、

ツールチップの名前を変更する方法を検討してくれたことから

出来たコーディングなのでしょうか?

 

②typedefはあまり使っていないので自信ないですが、

サイトを調べたら変数の別称定義と説明してありました

(http://www.geocities.jp/bleis_tift/cpp/typedef.html)。

そのことから考えると、

stRepTitle型のrepTitleを定義すると問題がおこるような、、、

たとえば

sizeof(repTitle)とすると


typedef struct repTitle {

char strBefore[100]; // 置換前タイトル

char strAfter[100]; // 置換後タイトル

HFONT* phFont; // 適用フォントへのポインタ

repItem * pRepItem; // 使用する置換配列

int aryLength;

} stRepTitle;

の構造体のサイズか

stRepTitle repTitle[] =

{

{ "色の設定", "Color Settings", NULL , repColDlg, sizeof(repColDlg)/sizeof(stRepItem) },

{ "ファイルを開く", "Open File", NULL , repFileDlg, sizeof(repFileDlg)/sizeof(stRepItem) }

};

の配列のサイズかわからなくなると思いますが問題ないのでしょうか?

③LocalHookProcのダイアログの種類判定を行うためのFor文ですが、

for( i = 0; i < (sizeof(repTitle)/sizeof(repItem)) ; i++)

のsizeof(repItem)は、

typedef struct repTitle {

char strBefore[100]; // 置換前タイトル

char strAfter[100]; // 置換後タイトル

HFONT* phFont; // 適用フォントへのポインタ

repItem * pRepItem; // 使用する置換配列

int aryLength;

} stRepTitle;

のrepTitleの間違いですよね?

それと、ツールチップを書き換える方法を調べていただいたようで・・・・。

ありがとうございます。

私としては、、、、、

ファイルオープンダイアログに派生クラスを作成した後

ツールチップを表示しないようにし、

http://hp.vector.co.jp/authors/VA016117/esccd.html

に説明されている方法で、

フォルダ位置を制御するボタンを追加できたらなぁ

などと考えていました、、、が、、、

ボタンは作れても、フォルダ位置を制御する方法をしらないので、

壁壁壁で、ショートしていました。

なんどもお手数をおかけしますが、、jack_sonicさんが調べて下さった

ツールチップを書き換える方法も教えていただけると助かります。

なにとぞ宜しくお願いします。

質問終了後1000ポイント送ります。

2007/06/18 00:48:59
  • id:jack_sonic
    harunoharuno様
    >①
    ツールチップ書き換えを検討したときに
    残ったコードで、そこは通りませんので、
    お察しのとおり今回のものには関係ないで気にしなくて大丈夫です。

    締め切られていましたので、
    ツールチップ書き換えについてはこちらに回答しました。
    http://q.hatena.ne.jp/1181795123

    >②,③
    厳密には、structの後ろにつくものは構造体タグ名という種類のもので
    今回の動作上は問題は起きないのですが、被っていたりする
    ところは分けたほうがいいです。
    構造体タグ名には、慣例的にtag~という接頭辞をつけます。


この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません