先日、画面表示のエラーについて質問させて頂いた者です。
皆さんのおかげでエラーの原因はリソースリークだったようで、ブラシとフォントを
DeleteObjectで解放することでエラー自体は無くなったのですが、今度はコントロールの
背景色とフォントの変更が行われなくなってしまいました。
多分、DeleteObjectを使う場所が悪いのだと思い、一晩色々試してみたのですがわかりま
せんでした、度々申し訳ありませんがよろしくお願いします。
環境
SDK
windowsXP Pro
vc++6.0
case WM_CREATE:
hFont = CreateFont
hEWnd = CreateWindow
SendMessage(hEWnd, WM_SETFONT, (WPARAM)hFont, 0);
Org_EWnd = (WNDPROC)GetWindowLong(hEWnd48, GWL_WNDPROC);
SetWindowLong(hEWnd48, GWL_WNDPROC, (LONG)FocusProc);
すみません、ソースの貼り付け中に間違って送信してしまいました。
hb = CreateSolidBrush
case WM_CREATE:
hFont = CreateFont();
hEWnd = CreateWindow();
SendMessage(hEWnd, WM_SETFONT, (WPARAM)hFont, 0);
Org_EWnd = (WNDPROC)GetWindowLong(hEWnd48, GWL_WNDPROC);
SetWindowLong(hEWnd, GWL_WNDPROC, (LONG)FocusProc);
DeleteObject(hFont);
break;
case WM_CTLCOLOREDIT:
HDC hDC = (HDC)wp;
HWND hCtrl = (HWND)lp;
if(hCtrl == GetDlgItem(Wnd, ID_hEWnd)){
SetBkMode(hDC, TRANSPARENT);
return (LRESULT)hb;}
break;
case WM_COMMAND:
switch(LOWORD(wp)) {
*****************************************
ここに演算式
*****************************************
hFont = CreateFont;
SetWindowText(hEWnd,演算結果);
SendMessage(hEWnd, WM_SETFONT, (WPARAM)hFont, 0);
DeleteObject(hFont);
break;
ソースはこんな感じです、投稿ミスで見苦しいスレッドになってしまいました、申し訳あ
りません。
hFontが生きているのは
hFont = CreateFont();//ここから
(略)
DeleteObject(hFont); //ここまで
かと
BOOL DeleteObject(HGDIOBJ hObject);
指定された GDI オブジェクト(ペン、ブラシ、フォント、ビットマップ、リージョン、
パレット)を削除し、オブジェクトに関連付けられていたシステムリソースをすべて解放
します。
hFontが生きてると思う場所でSendMessageを行ったつもりなのですがフォントが変更され
ないみたいです、僕が何かを根本的に間違ってるのでしょうか・・・?
とりあえず、WM_SETFONTで使うフォントは、対象となったウィンドウがなくなるまで
DeleteObjectしてはいけないかと思います。
hFontをWndProc関数のstatic変数(もしくはグローバル変数)にして、
WM_DESTROYあたりでDeleteObjectするようにしてみては。
で、WM_COMMANDでフォントを変える場合、hFontをDeleteObjectしてCreateFontを呼ぶよ
うにする。
つまり、
if (hFont) DeleteObject(hFont);
hFont = CreateFont; // ?
SetWindowText(hEWnd,演算結果);
SendMessage(hEWnd, WM_SETFONT, (WPARAM)hFont, 0);
//DeleteObject(hFont); 不要
ありがとうございます。
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
static hb = CreateSolidBrush(コントロールの背景色);
static HFONT hFont = CreateFont(フォント);
case WM_CREATE:
hEWnd = CreateWindow();
SendMessage(hEWnd, WM_SETFONT, (WPARAM)hFont, 0);
Org_EWnd = (WNDPROC)GetWindowLong(hEWnd, GWL_WNDPROC);
SetWindowLong(hEWnd, GWL_WNDPROC, (LONG)FocusProc);
break;
case WM_CTLCOLOREDIT:
HDC hDC = (HDC)wp;
HWND hCtrl = (HWND)lp;
if(hCtrl == GetDlgItem(Wnd, ID_hEWnd)){
SetBkMode(hDC, TRANSPARENT);
return (LRESULT)hb;}
break;
case WM_COMMAND:
switch(LOWORD(wp)) {
*****************************************
ここに演算式
*****************************************
SetWindowText(hEWnd,演算結果);
SendMessage(hEWnd, WM_SETFONT, (WPARAM)hFont, 0);
break;
WM_DESTROY
DeleteObject(hb);
DeleteObject(hFont);
break;
}
早速こうしてみたのですが、やっぱりコントロールの中のフォントも背景色も変更されま
せん。
グローバル関数にもしてみたのですが結果は同じでした。
何か間違ってるのでしょうか?
WM_COMMANDではフォントの変更は特にはしないので(内容の同じフォントを作っていまし
た・・・)これで良いと思ったのですが・・・
> SendMessage(hEWnd, WM_SETFONT, (WPARAM)hFont, 0);
の位置は、WM_CREATEの最後
> SetWindowLong(hEWnd, GWL_WNDPROC, (LONG)FocusProc);
の後ろにするのがセオリだと思います。
>static HBRUSH hb = CreateSolidBrush(コントロールの背景色);
>static HFONT hFont = CreateFont(フォント)
を
HBRUSH hb = CreateSolidBrush(コントロールの背景色);
HFONT hFont = CreateFont(フォント)
にするとフォントと背景色は変わりましたがリソースリークのエラーが元通りになる見た
いです。
>> SendMessage(hEWnd, WM_SETFONT, (WPARAM)hFont, 0);
>の位置は、WM_CREATEの最後
>> SetWindowLong(hEWnd, GWL_WNDPROC, (LONG)FocusProc);
>の後ろにするのがセオリだと思います。
その通りに直してみました、ありがとうございます。
>SetWindowLong(hEWnd, GWL_WNDPROC, (LONG)FocusProc);
この関数(FocusProc)が何してるかわからないので判断できないが
WM_SETFONTを引っかけてる等があるならそちらも関係ある可能性もあるし
外してみたらどうでっか?
ちなみに関係はないですが
>WM_COMMANDではフォントの変更は特にはしないので
ということは掲載のソースのみで判断するなら
SetWindowText(hEWnd,演算結果);
//SendMessage(hEWnd, WM_SETFONT, (WPARAM)hFont, 0); ←不要
break;
また破棄ではスタティック変数を使いたくなければ
WM_DESTROY
hFont=(HFONT)SendMessage(hEWnd, WM_GETFONT, 0, 0);
if(hFont) DeleteObject(hFont);
てのも可能
>HBRUSH hb = CreateSolidBrush(コントロールの背景色);
>HFONT hFont = CreateFont(フォント)
>にするとフォントと背景色は変わりましたがリソースリークのエラーが元通りになる見
たいです。
WndProc毎度呼ばれるたびにリソース作ってたら、当然いつかは食いつぶしますよ
static WNDPROC Org_EWnd;
LRESULT CALLBACK FocusProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
if(msg==WM_RBUTTONDOWN)
MessageBox(hwnd,テスト,Message,MB_OK|MB_ICONINFORMATION);
else if(msg==WM_SETFONT){
// DebugBreak();
// return 1;
}
return CallWindowProc(Org_EWnd,hwnd,message,wParam,lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HWND hCtrl;
HDC hDC;
static HWND hEWnd;
static HBRUSH hb = (HBRUSH)CreateSolidBrush(RGB(255,0,255));
static HFONT hFont = CreateFont(20, 0, 0, 0, FW_BOLD, FALSE, FALSE, 0,
SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH, MS 明朝);
switch (message)
{
case WM_CREATE:
hEWnd = CreateWindow(edit,Test Window,
ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER,
0, 0,200, 100,
hWnd,NULL,hInst,NULL);
SendMessage(hEWnd, WM_SETFONT, (WPARAM)hFont, FALSE);
//(WNDPROC)(LONGLONG)GetWindowLong(hEWnd, GWL_WNDPROC);
Org_EWnd = (WNDPROC)SetWindowLongPtr(hEWnd, GWL_WNDPROC,
(LONG_PTR)FocusProc);
break;
case WM_CTLCOLOREDIT:
hDC = (HDC)wParam;
hCtrl = (HWND)lParam;
if(hCtrl == hEWnd){
SetBkMode(hDC, TRANSPARENT);
return (LRESULT)hb;
}
break;
case WM_DESTROY:
DeleteObject(hb);
DeleteObject(hFont);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
横槍になりますけれど、
ウインドウに対してフォントの設定をする時にフォントの変更を
プログラムの実行中に行う必要が無いのであれば、
ウインドウ生成時にフォントの作成と設定を行って置き、
ウインドウ破棄時にフォントの破棄をするべきではないかと思います。
そうすれば、フォントの生成は一回で済みますから。
気をつけるべきなのは設定にしても生成にしても必要最小限に
留めた方がリソースの無駄遣いが防げるという事だと思います。
フォントの変更が必要な場合でも変更時に生成したら
次に変更が必要な状況になるか、ウインドウが破棄されて
フォントが不要になる時まではそのままにしておいて
不要になったら破棄すると言う考え方ですね。
設定したフォントはウインドウが破棄されるか他のフォントに設定しなおされるか
しないと不要にはならないのでその間は保持している必要があるのは既に説明されて
いるとおりです。
GDIに限らずですが、リソースの生成と破棄はプログラミングの中でも
大切な要素の一つなので慎重に対応して慎重すぎると言う事はありません。
まあ、何度かプログラムを不正終了させているうちに段々身については来ますけれど、
意識していないと改善されないので常に意識しておいた方が良いと思います。
ちょっと訂正。
> プログラムの実行中に行う必要が無いのであれば、
プログラムの実行中に行う必要が無いのであれば
と言うよりも
アプリを使っている時に動的に変更する必要がないのであれば
と書くべきですね。
そのように読み替えをお願いします。
みなさん、色々な助言ありがとうございます。
みなさんの言うように1からプログラムを書き直したら上手く動くようになりました。
ありがとうございました。