続けざまの質問で申し訳ないのですがアクセラレータキーに関する質問です。
いつもは猫でも分かる〜のアクセラレータキーの書き方でやっていたので
特に問題はなかったのですが、今やっているプログラムの場合猫でもの
書き方と違いWinMain関数に直にCreateWindowなどを書いています。
その状態でアクセラレータキーをロードしてメッセージループに
猫でもと同じようにアクセラレータキーのメッセージも動くように
コードを記述したのにもかかわらず、アクセラレータキーが動きません。
これはどうしてでしょうか?
以下に書いたコードを書いておきます。
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lParamszCmd, int nCmdShow){
HWND hWnd;
MSG msg;
HACCEL hAccel;
HWND hMWnd;
WNDCLASSEX wcex;
wcex.hInstance = hInstance;
wcex.lpszClassName = szWinName;
wcex.lpfnWndProc = WndProc;
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
wcex.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
if(!RegisterClassEx(&wcex)){
return(0);
}
hWnd = CreateWindow(szWinName, "Mail Viewer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
hMWnd = hWnd;
hParent = hWnd;
hInst = hInstance;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hAccel = LoadAccelerators(hCurInst, MAKEINTRESOURCE(IDR_ACCELERATOR1));
if(hParent == NULL){
return(0);
}
while(GetMessage(&msg, NULL, 0, 0)){
if(!TranslateAccelerator(hParent, hAccel, &msg)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return(msg.wParam);
}
hCurInstって何ですか?
LoadAcceleratorsは正しいハンドルを返していますか?
でもって……。
> wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
はやめましょうよ。ゲームとかならともかく……。
画面のプロパティでウィンドウの色をいじってみるとよくわかると思います。
#wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);を利用。
#場合によってはCOLOR_APPWORKSPACE + 1を使う場合も。
あっ書き間違いです。>hCurInst
これはhInstanceが入ります。
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);に直したのを載せます。
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lParamszCmd, int nCmdShow){
HWND hWnd;
MSG msg;
HACCEL hAccel;
HWND hMWnd;
WNDCLASSEX wcex;
wcex.hInstance = hInstance;
wcex.lpszClassName = szWinName;
wcex.lpfnWndProc = WndProc;
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
wcex.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
if(!RegisterClassEx(&wcex)){
return(0);
}
hWnd = CreateWindow(szWinName, "Mail Viewer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
hMWnd = hWnd;
hParent = hWnd;
hInst = hInstance;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
if(hParent == NULL){
return(0);
}
while(GetMessage(&msg, NULL, 0, 0)){
if(!TranslateAccelerator(hParent, hAccel, &msg)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return(msg.wParam);
}
http://knekodo.hp.infoseek.co.jp/new.htmlのMailViewerのリンクから
この状態のファイルをダウンロードできるようにしたのでこれで確認を
お願いできないでしょうか?
アクセラレータは正しくロードできているのですか?
記述されたソースでは一切チェックされていないのですが。
#ウィンドウの作成のチェックもタイミングが間違っているし……。
また,アクセラレータが動かないと言うのは,
・TranslateAcceleratorが失敗する
・TranslateAcceleratorは成功しているがWM_COMMAND(or WM_SYSCOMMAND)が来ない
のどちらですか。また,前者であればGetLastErrorで得られるエラーは何ですか?
掲示板で質問する前に,このような基本的な事項は調べて置いてください。
ウィンドウ作成のタイミングを猫でも〜のものと同じように修正して
もう一度試してみたのですがやっぱりアクセラレータキーが動作しないようです。
ちなみにGetLastErrorを表示できる関数を別のページから探して
実装してみたのですが、そうすると最初に「アクセスが拒否されました」と出て
それ以降は「インデックスの値が無効です」というものがずっと出ていました。
基本的事項がうまく調べられなくて本当にごめんなさいです。(>_<)
あと追加で「システムコールに渡されるデータ領域が小さすぎます」と
表示されました。
http://knekodo.hp.infoseek.co.jp/mview_src.lzhにエラーコードを
ステータスバーに出すものを載せたので見ていただけないでしょうか?
今までは出来ていたのにいきなり出来なくなったのでどうしてかなぁって
なってしまったので本当に困っています。
だからぁ……。
どのタイミングで失敗しているのかが分からないと答えようがないです。
前から書いているように,失敗する可能性があるのは二ヶ所。
・LoadAccelerators
・TranslateAccelerator
です。どちらが原因で失敗しているのかをまず突き止めてください。
その上で,GetLastError(とFormatMessage APIやErrlook.exe)を使って,失敗の原因を突き止めるのです。
もちろん,MSDNを参照するのは必須事項です。
質問をするならそのあとです。
デバッグもしていないようなソースを見る気にはなりません。
>どちらが原因で失敗しているのかをまず突き止めてください。
>もちろん,MSDNを参照するのは必須事項です。
やっと失敗する原因がわかりました。
後者のTranslateAcceleratorが失敗しているようです。
LoadAcceleratorsで失敗したのであればhAccelがNULLで
読み込み失敗のメッセージボックスが表示されるのに表示されずに
通り抜けていったのと、設定したアクセラレータキーを押すと
TranslateAcceleratorの戻り値(失敗)を返すのでおかしいと
思われるのはTranslateAcceleratorです。
過去に作ったNMail(NyantaMail)などのソースではこのような
LoadAcceleratorsで失敗する事がなかったのでどうしてこんな事に
なったのかがいまいち理解できていないです。
問題があると思われる部分のコードを載せます。
HINSTANCE hInst;
HWND hParent;
HACCEL hAccel;
static HWND hStatus;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lParamszCmd, int nCmdShow){
MSG msg;
hInst = hInstance;
if(!hPrevInst){
if(!InitApp(hInstance)){
return FALSE;
}
}
if(!InitInstance(hInstance, nCmdShow)){
return FALSE;
}
hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
if(hAccel == NULL){
MessageBox(NULL, "アクセラレータの組込みに失敗しました", "Mail Viewer", MB_OK);
}
if(hParent == NULL){
return(0);
}
while(GetMessage(&msg, NULL, 0, 0)){
if(!TranslateAccelerator(hParent, hAccel, &msg)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
//ウィンドウ・クラスの登録
ATOM InitApp(HINSTANCE hInst)
{
WNDCLASSEX wcex;
wcex.hInstance = hInst;
wcex.lpszClassName = szWinName;
wcex.lpfnWndProc = WndProc;
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1));
wcex.hIconSm = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
return(RegisterClassEx(&wcex));
}
//ウィンドウの生成
BOOL InitInstance(HINSTANCE hInst, int nCmdShow)
{
HWND hWnd;
hWnd = CreateWindow(szWinName, "Mail Viewer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
if(!hWnd){
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hParent = hWnd;
return TRUE;
}
で,その時のGetLastErrorの戻り値は?
もちろん,本来WM_COMMANDを生成するはずのメッセージに対するときの戻り値をチェックする必要があります。
で,GetLastErrorの戻り値は?
もちろん,本来WM_COMMANDを生成するはずのメッセージに対するときの戻り値をチェックする必要があります。
>で,その時のGetLastErrorの戻り値は?
エラーの番号で言うと122の「システムコールに渡されるデータ領域が小さすぎます」です。
>もちろん,本来WM_COMMANDを生成するはずのメッセージに対するときの戻り値をチェックする必要があります。
WM_COMMANDまでメッセージは渡っているのですが、それ以降の
動作(メール受信やメールの削除、アプリケーションの終了等)が
動作しないという状況です。
他のプログラムではそのような変な動作はしませんでした。
→試しに猫でも〜のアクセラレータキーつきのメニューのプログラムを
別に打ってみて実行しましたが問題なくアクセラレータキーが動作しました。
上の追加なのですがWM_COMMANDが発生する時のwParamの部分に
ブレークポイントを置いてアクセラレータキーを押したあとに
ステップイン実行を行ったのです。
正常なプログラムだと指定されたメニューのコマンドに飛ぶのですが、
問題のこのプログラムの場合はWM_COMMANDのbreakまで飛んでしまいました。
もちろんアクセラレータキーは正しく読み込まれていています。
埒があかないのでアクセラレータキーがちゃんと動く雛形プログラムを
作ってその中に今まで作った関数を組み込んでみて正常にアクセラレータキーが
動くか試してみようと思います。
もしだめだった場合は報告を、成功した場合は次のメッセージで
この問題は終了(解決)したいと思います。
アクセラレータキーの正常に動作する雛形プログラムに組み込んだところ
正常にアクセラレータキーが動くようになりました。
プロジェクト自体の名前やDSWやDSPファイルの中の名前を修正したりしたのが
原因なのかもしれません。
今回はこういう形での解決となってしまい本当にごめんなさいです。>YuOさん
> 問題のこのプログラムの場合はWM_COMMANDのbreakまで飛んでしまいました。
それは,単にIDを間違えただけでは?
>それは,単にIDを間違えただけでは?
いえ、そんな事はなかったですよ。
ちゃんとリソースエディタのアクセラレータキーの所で
メニューのIDを指定して割り当てるキーも設定しました。
ツイート | ![]() |