• ベストアンサー

C言語とWin32APIで全角かなの文字を取得する方法について。

いつも、お世話になっております。 小生、只今、WinXPSP3上でC言語とWin32APIを使い、BCC5.5.1でコンパイルしながら、Windowsプログラミングを勉強しています。 今回、ご質問させて頂きたい内容は、 クライアント領域において、全角かなの文字を取得する方法についてです。 自分自身で考えてみたのですが、WM_CHARメッセージの箇所を工夫して利用し、文字を取得する方法と、エディットコントロールにて文字を取得する方法です。 自分自身、WM_CHARメッセージを最近、勉強し始めたところなので、 出来ればWM_CHARメッセージを使用し、処理してみたいのですが。。。 以上です。 お忙しい中、本当に申し訳ございませんが、先輩方アドバイス宜しくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

文字制限がありましたので、2回に分けて投稿します。 前回投稿したプログラムのアルゴリズムに構造上、間違いがありましたので、修正します。(「ア」は受け付けるけど「ン」は受け付けませんでした。) >クライアント領域において、全角かなのカタカナの文字を取得する方法をご教授願いたいのです。 正直言いますと、もう少し具体的に質問して欲しいです。どういうプログラムを作りたいのかを具体的に書くと答えやすいのですが。。 全角カタカナを取得するだけなら、特にいじらなくても、普通に、WM_CHARを処理すれば、取得できます。入力した文字が、全角カタカナかどうかを判別するという意味でしょうか? それを前提として回答いたします。 文字の種別を判別するWindows-APIとして、 GetStringTypeEx というものがあります。 BOOL GetStringTypeEx( LCID Locale, // ロケール識別子 DWORD dwInfoType, // 取得する情報の種類を指定する値 LPCTSTR lpSrcStr, // 調査対象文字列のアドレス int cchSrc, // 調査対象文字列のサイズ(バイト数または文字数) LPWORD lpCharType // 出力バッファのアドレス ); 以下、関数の詳細は省略。 次のプログラムでは、全角文字のときだけ入力を受けつけ、クライアント領域に表示しています。表示部分の関数は省略しています(TextOutを使っています)。 全角カタカナかどうかは、自作のデバッグウィンドウに出力しています。 >何故、漢字に変換する際、(c1 | c2 << 8)の処理が必要になるかも、ご教授頂きたいです。 「<<」 は左シフト演算子とよび、指定したビット数左にシフトします。 例: 1 << 1 = 10(2進数) , 1 << 2 = 100(2進数) , 101(2進数) << 2 = 10100(2進数) 例: 0x83(16進数) << 8 = 0x8300(16進数) 「|」はビット単位の論理和演算子(OR)です。 1バイトは8ビットでできているのはご存知ですか? また、文字の最小単位は1バイトで、半角だと全て1バイトにおさまりますが、全角文字は2バイト以上必要です(文字コードにより様々です。SHIFT-JISだと2バイトです)。 char型は1バイト、short型は2バイトですので、SHIFT-JISだと、漢字1文字収めるには、short型が必要になります。もしくは配列を使うなど・・こちらの方が汎用性があると思われる。 後述するソースコードのプログラムを実行したとき、自作のデバッグ用ダイアログには次のように情報が表示されます。 「あ」を入力したときの出力結果・・ 0 : 33 , 0 0 : 82 , 1 0 : a0 , 0 文字 : あ 1 : 82 , a0 2 : 82 , a0 3 : pwType[0] = 8020 , pwType[1] = 0000 「ア」を入力したときの出力結果・・ 0 : 83 , 1 0 : 41 , 0 文字 : ア 1 : 83 , 41 2 : 83 , 41 3 : pwType[0] = 8090 , pwType[1] = 0000 4 : 全角カタカナです 0 : 83 , 1 0 : 41 , 0 より、「ア」を入力したとき、WM_CHARメッセージには、最初に0x83、次に0x41がきていることが分かります。 1 : 83 , 41 2 : 83 , 41 の出力結果が同じくなることに注目してソースコードを読んで下さい。 このとき、 0x41 << 8という処理の結果は1バイト分左にシフトするので、0x4100となります。 そして、0x83 | 0x4100は0x4183となります。 ちなもに、0x83 + 0x4100としても、0x4183となりますが、ビット演算のときは、「|」を使うのが普通です。 つまり「ア」という漢字はshort型で表すと0x4183です。 (c1 | c2 << 8)には、そのような意味があります。 お分かりいただけたでしょうか? このプログラムはあくまでも質問に答えるためだけに作ったということを強調しておきます。この手のプログラムの専門家ではありません。 あくまでも、SHIFT-JISを前提として、私の環境ではうまくいったというだけで、自分のプログラムに組み込むときは、改造や研究をしてください。 「<<」と「|」演算子については、C言語の基本ですのでしっかりマスターしましょう。

HackHack
質問者

お礼

ご回答頂き誠にありがとうございます。 漢字に変換する際のビット演算の解説、とても参考になりました。 miswaki7Zさんには本当にお世話になりっぱなしで申し訳ないです。 しかし、なにぶん、私はC言語しかわからない若輩者なので、 C++のコードから、Cのコードに変換するという作業は少々、辛いものがあり、今回質問を刷新して、投稿し直してみる所存であります。 miswaki7Zさんには本当にお世話になりました。 心より感謝と謝罪の念でいっぱいです。 本当に申し訳ございませんでした。

その他の回答 (4)

回答No.5

先ほどの続きです。 以下がソースコードです。 /* DebugText()関数は自作のデバッグ用関数。デバッグ用ダイアログボックスのテキストボックスに文字列を追加する。 */ LRESULT CTheView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if(message == WM_CHAR){ BYTE c; c = (BYTE)wParam; BOOL bIsDBCS = (BYTE)IsDBCSLeadByte(c); DebugText("0 : %02x , %d\r\n" , c , bIsDBCS); if(m_bIsDBCS){ short s = (m_cByte1 | c << 8); char ch[sizeof(short)+1]; ZeroMemory(ch , sizeof(ch)); StringCchCat(ch , sizeof(ch) , (const char *)&s); BYTE *p_s = (BYTE *)&s; DebugText("文字 : %s\r\n" , (char *)ch); DebugText("1 : %02x , %02x\r\n" , m_cByte1 , c); DebugText("2 : %02x , %02x\r\n" , p_s[0] , p_s[1]); int str_len = 2; WORD *pwType = new WORD[str_len]; GetStringTypeEx(LOCALE_SYSTEM_DEFAULT , CT_CTYPE3 , (LPCTSTR)ch , -1 , pwType); DebugText("3 : pwType[0] = %04x , pwType[1] = %04x\r\n" , pwType[0] , pwType[1]); /* C3_NONSPACING 0x0001 非スペース符号 C3_DIACRITIC 0x0002 分音符 C3_VOWELMARK 0x0004 母音字 C3_SYMBOL 0x0008 シンボル文字 C3_KATAKANA 0x0010 カタカナ C3_HIRAGANA 0x0020 ひらがな C3_HALFWIDTH 0x0040 全角文字 C3_FULLWIDTH 0x0080 半角文字 C3_IDEOGRAPH 0x0100 表意文字 C3_KASHIDA 0x0200 アラビックカシダ文字 C3_LEXICAL 0x0400 単語の一部と見なされる区切り記号(カシダ、ハイフン、女性/男性オーディナル、等号、その他) C3_ALPHA 0x8000 言語学上のすべての文字(アルファベット、音節文字、表意文字) */ if(pwType[0] == (C3_ALPHA | C3_FULLWIDTH | C3_KATAKANA)){ //pwType[0] == 0x8090 DebugText("4 : 全角カタカナです\r\n"); } delete [] pwType; m_str += ch; m_bIsDBCS = FALSE; Invalidate(); }else{ if(bIsDBCS){ //c = 2 バイト文字セット(DBCS)の第 1 バイト m_bIsDBCS = TRUE; m_cByte1 = c; }else{ //c = 2 バイト文字セット(DBCS)の第 1 バイトではない。 m_bIsDBCS = FALSE; } } } return CView::WindowProc(message, wParam, lParam); }

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.3

>クライアント領域において、全角かなのカタカナの文字を取得する方法をご教授願いたいのです。 ちっとも詳しくないですが。 で、WM_CHARで、全角ひらがなではない、ふつうの英数字を取得することはできているのでしょうか? できているならば、その状態で、漢字入力モードにして(英語キーボードならALT+~を押す)、適当に入力してみて、WM_CHARにはどんな値が来ているのか確認してみてはどうでしょうか?

HackHack
質問者

補足

ご回答頂き、誠にありがとうございます。 提示させて頂いた質問内容が意図を全く含んでいなかった事、 心よりお詫び申しあげます。 再度、詳しくご質問させて頂きます。 1.ウィンドウを作成、表示する。 2.そのウィンドウのクライアント領域に"ア"など全角カタカナの入力を行う。 3.入力した文字をクライアント領域に表示する。 以上です。 ご参考になればと思い、メモ帳で作成した、イメージを添付させて頂きました。 少しご拝見しづらいとは思いますが、ご確認の程、宜しくお願い致します。

回答No.2

当方は、Visual C++を使っていますが、できるだけコンパイラ依存を避けたつもりですが、一部互換性がないところもありますが、意味は理解していただけると思います。 WM_CHARで可能です。 全角かなとは漢字の意味でしょうか? 以下、漢字として説明しますが、文字コードの問題などは抜きにしてあくまでも大雑把に説明します。 またここでは、漢字は2バイトという前提で説明します。 マルチバイト文字(半角ではない文字。ここではDBCS)の最初の1バイトが漢字かどうかを判別するWindows-APIとしてIsDBCSLeadByte()関数があります。 BOOL IsDBCSLeadByte( BYTE TestChar // 調べるべき文字 ); マルチバイト文字を入力した場合、WM_CHARが連続して呼び出されます。 これを順番に配列などに入れていけば、問題なく、文字列になるのですが、1つの漢字を形成したいとすると、以下のようになります。 message == WM_CHARのとき、 wParamに文字が入ります。 1回目にWM_CHARが呼び出されたときの文字がc1、2回目にWM_CHARが呼び出されたときの文字がc2とすると、2つをあわせたときの漢字は、 (c1 | c2 << 8) で表現できます。 これは2バイトなので、short型になります。 例として、漢字を入力したときだけ、入力を受け付けるソースコードを以下に示します。 /* CTheViewクラスのメンバ変数 BOOL m_bIsDBCS=前回、WM_CHARが呼び出されたときに、漢字の1バイト目だったかどうか。 BYTE m_cByte1=前回、WM_CHARが呼び出されたときの文字を保持する。 C++を使っていますので、Cを使う場合は、上記の変数をグローバル変数にするとよいでしょう。 -------- StringCchCat()の方がstrcat()よりセキュリティ的に安全。ただし、 #include <strsafe.h> が必要。使えない場合は、strncat()やstrcat()などで代用。 */ LRESULT CTheView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if(message == WM_CHAR){ BYTE c; c = (BYTE)wParam; //入力した文字 BOOL bIsDBCS = (BYTE)IsDBCSLeadByte(c); if(bIsDBCS){ //今、WM_CHARがきたときの文字が漢字の1バイト目だったかどうか //c = 2 バイト文字セット(DBCS)の第 1 バイト m_bIsDBCS = TRUE; //フラグ m_cByte1 = c; //文字を保持 }else{ if(m_bIsDBCS){ //前回、WM_CHARがきたときの文字が漢字の1バイト目だったかどうか short s = (m_cByte1 | c << 8); //2つの文字をあわせて漢字に変換 char ch[sizeof(short)+1]; ZeroMemory(ch , sizeof(ch)); //配列chを0で埋める。 StringCchCat(ch , sizeof(ch) , (const char *)&s); m_str += ch; ////・・VC依存? } m_bIsDBCS = FALSE; //リセット } Invalidate(); //・・VC依存。画面更新関数です。画面描画の箇所で、m_strを表示しています。 } return CView::WindowProc(message, wParam, lParam); } 文字コード(SHIFT-JISやUNICODEやEUC-JP)に関しては、追求すれば追及するほど難しい問題です。時代の流れは、UNICODEに向かっていますが、まだまだWindowsではSHIFT-JISが多用されています。

HackHack
質問者

補足

ご回答頂き、誠にありがとうございます。 大変、申し訳ございません。 私の質問の内容が説明不足の点があり、 miswaki7Zさんから、せっかく頂いた回答と少しズレが生じました。 本当に申し訳ございません。 以下、再度、詳しく質問させて頂きます。 クライアント領域において、全角かなのカタカナの文字を取得する方法をご教授願いたいのです。 ご提示頂いたコード、ご回答は今後のご参考にさせて頂きます。 よろしければ、何故、漢字に変換する際、(c1 | c2 << 8)の処理が必要になるかも、ご教授頂きたいです。 お忙しい中、大変申し訳ございませんが、再度アドバイス宜しくお願い致します。

回答No.1

Win32API環境ということで、文字はシフトJISコードと考えます。 WM_CHARメッセージは基本的に1バイト文字の入力を通知するメッセージなので、日本語文字の場合はシフトJISコードを1バイトずつ2回に分けて発行されます。 最初にWM_CHARメッセージでシフトJISの1バイト目のコードを受け取ったら、それを保持しておきます。次のWM_CHARメッセージで2バイト目が送られてきたら、両方を合わせてシフトJISのコードに戻して処理してください。 注意するのは入力される文字が日本語文字とは限らないので、シフトJISコードかどうかチェックする必要があることです。日本語文字の場合もひらがな以外の場合もありえます。

HackHack
質問者

補足

ご回答頂き誠にありがとうございます。 ご提示していただいた回答の中に、質問があり、以下に記述させて頂きます。 >次のWM_CHARメッセージで2バイト目が送られてきたら、両方を合わせてシフトJISのコードに戻して処理してください。 上記でご指摘された、シフトJISのコードに戻す処理とは、どのように処理すればいいでのしょうか? 自分なりにGoogleで"Win32API SHIT-JIS"等と入力し、各サイトを回り調べたのですが、有力な情報は見つかりませんでした。 以上、お忙しい中、申し訳ございませんが、再度アドバイス宜しくお願い致します。

関連するQ&A

  • C言語とWin32APIで全角のカタカナの文字を取得、表示する方法について。

    いつも、お世話になっております。 小生、只今、WinXPSP3上でC言語とWin32APIを使い、BCC5.5.1でコンパイルしながら、Windowsプログラミングを勉強しています。 今回、ご質問させて頂きたい内容は、 1.ウィンドウを作成。 2.1で作成したウィンドウに全角のカタカナを1文字入力。 3.入力されたカタカナを入力した箇所の下に描画。 4.再度、カタカナの文字があった場合は、入力されている文字を消去し、2のステップに戻る。 5.カタカナ以外の文字が入力された場合はメッセージボックスにて、   "カタカナ以外の文字が入力されました"を出現させ、クライアント領域には何も描画しない。 以上です。 前回、同じような質問を投稿させて頂いた際に、WM_CHARメッセージの箇所を工夫して利用し、文字を取得する方法をお教え頂いたので、WM_CHARメッセージでの処理の仕方をご教授願いたいと思っております。 そして、あつかましいようで申し訳ございませんが、ソースを記述して頂く際、C言語での記述で宜しくお願い致します。 以上です。 色々とわがままを言い、本当に申し訳ございません。 お忙しい中、本当に申し訳ございませんが、先輩方アドバイス宜しくお願いします。

  • C言語win32api、エディットボックスから文字列を取得しメッセージ

    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; LRESULT CALLBACK 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型とかの変数ではとても入りきれません。 こういった場合どのようにするのでしょう。

  • Win32APIにて、アイコンの情報を取得する方法を教えてください。

    いつもお世話になっております。 只今、小生WindowsXPSP3上で、C言語とWin32APIを使い、BCC5.5.1でコンパイルし、Windowsプログラミングを勉強しています。 今回質問させて頂きたいのは、 「ウィンドウにアイコンを描画する際、  BitBlt関数の第4・5引数に指定する転送元画像の幅と高さを取得する  際にはどうすればいいか」 です。 例えば、ビットマップ画像の幅、高さを取得する際は、 GetObject(hBitmap, (int)sizeof(BITMAP), &bmp_info); をして、 w = bmp_info.bmWidth; h = bmp_info.bmHeight; とし、x, yをBitBlt関数の第4・5引数に指定する方法というのは知っているのですが、アイコンの場合はどのようにして、幅、高さを求められるのでしょうか?? 先輩方、ご教授宜しくお願い致します。

  • Win32Apiで書式付リッチエディットの内容をコピーしたい。

    Win32Api(MFCやCLRではない)で書式付リッチエディットの内容をコピーしたいのですがGetWindowText関数を使い、char型の変数に入れてやると文字色やフォントなどの情報がなくなってしまいます。 このような場合書式付の文字を取得する場合どうすればよろしいでしょうか。

  • Win32APIで困っています

    Win32APIでWM_PAINTメッセージを使って変数Bufの中の文字列を表示した場合に 表示した後になんらかのイベントを発生させて表示されている文字列に違う文字列を代入しても、画面に変化がありません。 画面を再描画する方法を教えてください よろしくお願いします。

  • Win32 APIに関する質問

    Win32 APIでwidowsプログラミングをしているのですが、 メニューを開きとあるダイアログを開きボタン(これを押すとエディットから、入力されている文字列を取得する) を押すとエディットに入力されている、文字列をメッセージボックスに表示するはずなんですが (Messengerはその問題のボタンがついているプログラム) 「Messenger が原因で USER.EXEにエラーが発生しました。Messenger は終了します」 と出てそのプログラム(Messenger)が、終了させられてしまいます。 GetDlgText()というAPIが原因だと言う所までは分かりましたが、そこからさきがまったく分かりません このバグの解決方法を教えてください ↓がソースです(結構長いのでダイアログのコールバックだけ書きます) BOOL CALLBACK Dialog_RoomOption(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp){ int error; LPTSTR s; HWND edit_RoomAbout; switch(msg){ case WM_INITDIALOG: SetDlgItemText(hwnd,EID_PASSWORDEDIT,"パスワードを入力してください"); return TRUE; case WM_COMMAND: switch(LOWORD(wp)){ case BID_CREATE: GetDlgItemText(hwnd,EID_PASSWORDEDIT,RoomPassword,sizeof(RoomPassword)); MessageBox(hwnd,RoomPassword,TEXT("TESTTEST"),MB_OK); EndDialog(hwnd,BID_CREATE); return TRUE; } break; case WM_CLOSE: EndDialog(hwnd,NULL); return TRUE; } return FALSE; }

  • Win32APIによるタイマイベントの種類について。

    小生、只今WindowsXPSP3上でC言語とWin32APIを使用し、BCC5.5.1でコンパイルしながら、Windowsプログラミングを勉強しています。 そこで質問なのですが、 「猫でもわかるWindowsプログラミング第2版」にて、 デジタル時計の実践という章があり、そこで下記のようなコメントの付いたコードがありました。 switch(msg){ case WM_CREATE: //タイマの作成 SetTimer(hWnd, ID_MYTIMER, 500, NULL); break; case WM_TIMER: //関係ないタイマイベントはDefWindowProcに任せる if(wp != ID_MYTIMER){ return (DefWindowProc(hWnd, msg, wp, lp)); } 上記の関係ないタイマイベントとは具体的にどのような種類があるんでしょうか。 お忙しい中、申し訳ございませんが、先輩方アドバイス宜しくお願いします。

  • Win32 API エディットボックス内文字列の色変更

    Win32 APIについて質問です。 (Microsoft Visual Studio .NET 2002、XP、API) エディットコントロールに表示されている文字列の 色(またはフォント)を変更したいと思っています。 エディットボックスに「0」という数字を入力し その後「更新ボタン」をクリックすると、「0」の 文字色が赤色(または赤太文字)へ変更される という具合です。 Win32 APIを始めて間もない者(Cも始めて間もないです) なので、かなり苦戦しております。 「SendMessage() 」みたいな関数を使用しエディット ボックスのハンドルへメッセージを送ることで 実現させるのかなぁ程度しか理解しておりません。 ご存じの方すいませんがよろしくお願いします。

  • ExcelVBAでAPIを使って外部ウインドウのエディットテキストを取得する方法

    ●やりたいこと ExcelVBAで、APIを実行し、外部ソフトのウィンドウに含まれている エディットテキストを取得して、セルに出力したい 使用する関数・宣言、できればコードを教えていただけませんでしょうか。 イメージはこちらをご参考いただけると幸いです。 ​http://situmon-img.blogspot.com/2008/08/1.html​ 変数hwindowに親ウィンドウのハンドルが取得されています。 エディットボックスのハンドル、IDは分かりません。 エディットボックスのハンドルを取得し、 分かっているクラス・ハンドルの文字列を取得 といった流れになるのではと思っております。 変数にさえ文字列が取得できれば、 当然ですが、Range("B2")=変数 で大丈夫です。 変数は、ひとつを使いまわしで構いません。 変数をエディットテキストの数だけ用意しても構いません。

  • Win32APIを始めたのですが・・・。

    Window Handleについての質問です。Win32APIではCreateWindow()でチェックボックスを作ることが出来るのですが、 C++でプログラミングしていたところ、困ったことになりました。 まず、クラスのメンバーとしてHWND m_Hwndを宣言し、メンバー関数(CreateChk())において m_Hwnd = CreateWindow(...)とし、WM_CREATEのメッセージ処理内で関数CreateChk()を呼び出して チェックボックスを作るようにしたのですが、WM_CREATEのメッセージ処理を終えると同時にm_Hwndの内容が意味を持たないものに 変わってしまい、チェックボックスの状態を利用することが出来ません。 変数の寿命に関係したものだとは思うのですが、クラスを用いたオブジェクト指向プログラミングも始めたばかりでよくわかりません。 どなたか対処方法をご存知でないでしょうか?

専門家に質問してみよう