プロが教えるわが家の防犯対策術!

C言語win32api、エディットボックスから文字列を取得しメッセージボックスへ出力
質問1
エディットボックスからフォーカスが外れると
その中の文字列を取得しメッセージボックスに出力したいのですが
思った通りに出力されません。
フォーカスが外れるとメッセージボックス自体は出てくるのですが
エディットボックスに入力した文字列が出力されません。
いろいろ試したんですが文字化けしたり文字列自体が表示されなかったします。
取得と出力の方法を教えていただけませんでしょうか。

kwt[3]=CreateWindowEx(WS_EX_CLIENTEDGE,TEXT("EDIT"), NULL ,
WS_CHILD | WS_VISIBLE |WS_BORDER |ES_LEFT | ES_AUTOHSCROLL ,
90 , 85 , 110 , 25 ,
hAdd ,(HMENU)EDIT_ID02 ,((LPCREATESTRUCT)(lp))->hInstance , NULL);

LPSTR testtex=NULL;

LRESULTCALLBACK SubProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp)
{

LPSTR testtex=NULL;

switch(msg)
{
case WM_COMMAND:

switch(LOWORD(wp))
{

case EDIT_ID02:

if(HIWORD(wp)==EN_KILLFOCUS) //フォーカスが外れたら次の処理をする。
{

strText = (LPSTR)malloc(GetWindowTextLength(hwnd) + 2); //文字数分のメモリを確保

if(testtex) //testtexがゼロでなければ次の処理をする
{
GetWindowText(hwnd , testtex , GetWindowTextLength(hwnd) + 2); //エディットのテキストを取得。問題個所
MessageBox(hwnd , testtex , TEXT("") , MB_OK); //取得したテキストをメッセージボックスで出力。問題個所
}
free(strText); //メモリを解放

return 0;
}

return 0;
}

return 0;
}

return (CallWindowProc(SubP1, hWnd, msg, wp, lp));
}

質問2
エディットボックスに0~9と「.」(ドット)のみを入力できるようにしたいのですが
ウインドウスタイルでES_NUMBERを指定すると「.」が入力できなくなってしまいます。
どのように回避したらいいのでしょうか。

質問3
win32apiとは直接関係ありませんが、たとえば計算結果が1000億を超えるような場合
int型とかの変数ではとても入りきれません。
こういった場合どのようにするのでしょう。

A 回答 (5件)

回答No.3の補足です。



////////// BEGIN{ midugane さんのコード } //////////

strText = (LPSTR)malloc(GetWindowTextLength(hwnd) + 2); //文字数分のメモリを確保

if(testtex) //testtexがゼロでなければ次の処理をする
{
GetWindowText(hwnd , testtex , GetWindowTextLength(hwnd) + 2); //エディットのテキストを取得。問題個所
MessageBox(hwnd , testtex , TEXT("") , MB_OK); //取得したテキストをメッセージボックスで出力。問題個所
}
free(strText); //メモリを解放

////////// END{ midugane さんのコード } //////////

////////// BEGIN{ 修正後 } //////////

LPTSTR strText = (LPTSTR)calloc((GetWindowTextLength(hwnd) + 1), sizeof(TCHAR)); // 文字数 + 終端 null 文字分のメモリを確保
// GetWindowTextLength( ) の戻り値は TCHAR 単位の文字数で返ってくるので、
// TCHAR = wchar_t となる Unicode 環境では注意が必要です。
// 確保したメモリは最初からゼロクリアしておいたほうが何かと便利なので、
// calloc( ) を使っています。
// VC++ では、calloc( ) は最適化されていますので、malloc( ) と比較しても
// 速度面のオーバーヘッドは気にしなくても良いレベルです。

if(strText) // strText が NULL でなければ次の処理をする
{
GetWindowText(hwnd, strText, (GetWindowTextLength(hwnd) + 1)); // エディットのテキストを取得。長さには終端 null 文字分を含めます。
MessageBox(hwnd, strText, TEXT(""), MB_OK); // 取得したテキストをメッセージボックスで出力。
}
free(strText); // メモリを解放

////////// END{ 修正後 } //////////
    • good
    • 0
この回答へのお礼

cとc++の入門書は2冊ずつくらい読んだんですが
calloc関数なんて全然知りませんでした。

2度も丁寧な回答、さらに新たな知識を授けてくださりありがとうございます。
感謝しますm(._.)m

お礼日時:2010/07/03 09:46

 こんばんは。

質問1と2に関してです。

http://msdn.microsoft.com/ja-jp/library/cc364815 …
http://msdn.microsoft.com/en-us/library/ms647591 …

WNDPROC _S_prevEditProc = NULL;

//エディットボックスの入力制限はサブクラス化して行う
LRESULT CALLBACK EditProc(HWND hEdit, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
const TCHAR tcs[] =
{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, //0-9
0x8, 0x9, 0x3, 0xd, 0x16, 0x18,//BS, TAB, ENTER, CTLR+X, CTLR+C, CTLR+V
0x2E}; //.
switch(uMsg)
{
case WM_CHAR:
for(UINT i = 0; i < sizeof(tcs) / sizeof(TCHAR); ++i)
{
if(tcs[i] == wParam)
return ::CallWindowProc(_S_prevEditProc, hEdit, uMsg, wParam, lParam);
}
return FALSE;
}
return ::CallWindowProc(_S_prevEditProc, hEdit, uMsg, wParam, lParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
{
HWND hEdit = ::CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"),
NULL, WS_CHILD | WS_VISIBLE |WS_BORDER | ES_LEFT | ES_AUTOHSCROLL,
90, 85, 110, 25, hWnd, (HMENU)EDIT_ID02,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
_S_prevEditProc = (WNDPROC)::SetWindowLong(hEdit, GWL_WNDPROC, (LONG)&::EditProc);
}
break;

case WM_COMMAND:
{
const INT nCode = HIWORD(wParam);
const INT nID = LOWORD(wParam);
HWND hCtl = (HWND)lParam;
if(nCode == EN_KILLFOCUS)
{
INT len = ::GetWindowTextLength(hCtl);
if(len == 0)break;

//NULL文字の分
++len;

//割り当てバイトサイズ
const INT byte = len * sizeof(TCHAR);
LPTSTR text = (LPTSTR)::malloc(byte);

//バイトサイズではなくてNULL文字を含めた文字数を指定する
const INT result = ::GetWindowText(hCtl, text, len);
::MessageBox(hWnd, text, TEXT("TEST"), MB_OK);
::free(text);
}
}
break;

case WM_CLOSE:
::DestroyWindow(hWnd);
break;

case WM_NCDESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
    • good
    • 0
この回答へのお礼

具体的なソースを示していただきありがとうございます。
大変助かりました。

質問1
エディットボックスのサブクラス化ですが
CreateWindowExの最後の引数
「_S_prevEditProc = (WNDPROC)::SetWindowLong(hEdit, GWL_WNDPROC, (LONG)&::EditProc」
がどうしてもうまく動作せず
GetWindowLongとSetWindowLongで処理しました。

質問2
No1さんの回答の通り指定するハンドルが親ウインドウになっていました。
ソースの記述は参考にさせていただきました。

ありがとうございますm(._.)m

お礼日時:2010/07/03 09:23

> 質問1


提示コードだと testtex がヒープアドレスを指してない(NULL のままになっている)のが
そもそも間違いですが、
ついでにプロジェクトの設定で UNICODE シンボルが有効になっていませんか?
VC++ 2002/2003/2005/2008/2010 の場合、プロジェクト->{プロジェクト名}のプロパティ
->構成プロパティ->全般->文字セットで「Unicode 文字セットを使用する」になっていたら、
TCHAR は char でなく wchar_t に、
LPTSTR は LPSTR でなく LPWSTR に、
LPCTSTR は LPCSTR でなく LPCWSTR に、
GetWindowText( ) は GetWindowTextA( ) でなく GetWindowTextW( ) に切り替わり、
ワイド文字が使用されるようになります。
なので、提示コードでは LPSTR を LPTSTR にしといたほうがいいです。


> 質問3
処理系依存ですが、long long 型(VC++ の場合 __int64 型)を使うのはどうですか?
64bit 整数(8Byte 整数)なので、-9,223,372,036,854,775,808 ~
+9,223,372,036,854,775,807 の範囲の整数を扱えます。

この回答への補足

回答ありがとうございます。
質問1
おっしゃる通りプロジェクトの設定はUNICODEになっています。
testtexですがNULLを外し LPTSTR testtex; としましたが
やはり改善しません。
結局空欄で出てきてしまいます。
どこかに根本的な間違いがあるのでしょうか?

質問3
longlong型ですが、こんな便利なのがあるんですね。
自分で使うアプリなので全然問題ないです。
ありがとうございます。

補足日時:2010/06/27 19:33
    • good
    • 0

> 質問1


×strText -> ○testtex じゃないと意味無い

> 質問2
EN_CHANGEイベントで監視して、数字と「.」以外の入力をチェック

> 質問3
誤差が出るのを覚悟してdouble等を用いるか、自力で巨大整数用の数値計算処理を作るかというところでしょうか。

この回答への補足

回答ありがとうございます。
質問1ですが
書き間違えです。すみません。
GetWindowText(hWnd , testtex , GetWindowTextLength(hWnd) + 2);
MessageBox(hWnd , testtex , TEXT("TEST") , MB_OK);
のようになっていますが実際に処理すると
タイトルウインドウには「TEST」と出ますが
メッセージボックスのクライアントエリアは空欄状態です。
何が間違っているのでしょうか。

質問2に関して
EN_CHANGEイベントの処理、試してみます。

質問3に関して
doubleだとやっぱり誤差がきになるのでNo1さんの回答を行ってみたいと思います。

補足日時:2010/06/27 18:24
    • good
    • 0
この回答へのお礼

質問1
No1さんの回答のとおり指定していたハンドルがそもそも違っていました。

質問2
No4さんの記載してくれたソースをいじっていたら正常に処理できました。

質問3
多倍長演算を使って計算する方法を考えることにしました。

ありがとうございましたm(._.)m

お礼日時:2010/07/03 08:59

>if(testtex) //testtexがゼロでなければ次の処理をする


>{
>GetWindowText(hwnd , testtex , GetWindowTextLength(hwnd) + 2); //エディットのテキストを取得。問題個所
>MessageBox(hwnd , testtex , TEXT("") , MB_OK); //取得したテキストをメッセージボックスで出力。問題個所
>}
>free(strText); //メモリを解放

で、testtexとは?
SubProc()のローカル変数ならば、ほぼNULLかと思われますが。
# static変数であればその限りではありませんけど。

GetWindowText()実行時のhwndは、CreateWindowEx()で作成したエディットボックスのHWNDになっていますか?
上記のコードだと、おそらく親ウィンドウのHWNDになっているかと思われますが。

>エディットボックスに0~9と「.」(ドット)のみを入力できるようにしたいのですが
>どのように回避したらいいのでしょうか。

変更があったときに、EN_CHANGEが通知されます。
前回の通知時に有効な文字のみの場合に記憶しておいて、EN_CHANGEが通知されたら
現在の内容を精査、不正だった場合は前回のものに再設定を行う。
とかで対処可能かと。

>たとえば計算結果が1000億を超えるような場合

多倍長整数という手法を使うことになろうかと。

この回答への補足

回答ありがとうございます。
質問1について
すみません。質問内容の入力を間違えてしまいました。
実際は以下のようになっています。
--
GetWindowText(hWnd , testtex , GetWindowTextLength(hWnd) + 2);
MessageBox(hWnd , testtex , TEXT("TEST") , MB_OK);
--
実際の構造と流れは以下のとおりです。
親ウインドウ

子ウインドウ(プロシージャのサブクラス化)

孫ウインドウ(エディットボックス)

孫ウインドウからフォーカスが外れると子ウインドウのプロシージャにメッセージが飛び
そこで処理をさせています。
この場合プロシージャには孫のハンドルが飛んでないんでしょうか?

質問2、3に関して
調べて試してみます。

補足日時:2010/06/27 18:18
    • good
    • 0
この回答へのお礼

質問1
おっしゃる通りでした。
このメッセージの場合hWndではなくLPARAMがメッセージボックスのハンドルなんですね。

質問2
No4さんの回答の通りに処理したら正常に動作しました。

質問3
調べてみたところ、この辺はアセンブラと同じですね。
各桁に変数を割り当てて計算する事にしました。

ありがとうございますm(._.)m

お礼日時:2010/07/03 08:53

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!