• ベストアンサー

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