[index] [詰め合わせ] [ダイアログボックス] [メニュー] [アクセラレータ] [String Table] [その他]
ストリングテーブル(string table)
Win32 API のストリングリソース (文字列リソース) の形式で、モジュール(実行ファイル)にストリングテーブルを組み込みます。モジュールにデータのセクションを持たせる、というのが簡単な理解です。
通常、わざわざリソーススクリプトによって文字列テーブルを作らなくても、ソースプログラム内(.c や .cpp) でリテラルに、つまり直接記述で、ダブルコーテーション " を使って、"これは文字列だよ" のようにすれば文字列を使えるので、このストリングテーブルの必要性を感じません。
・ ストリングテーブルは、例えばアプリケーションのエラーメッセージなど、(自分が)テーブルとして整理してリスト形式のようにしておきたい場合に活用したりします。
・ また、コントロールの一つである "ツールバーコントロール" を利用するときで、それにツールチップ※ で文字列を表示させたいときは、このツールバーの仕様 (やりかた) により、そのツールチップ用の文字列はストリングテーブルとして用意しなくてはいけません。つまり、ときおり、Windows API 関数が "文字列" を扱う場合、ストリングテーブルを使わなくてはいけない (関数がそのようになっている)、場面があります。
※ なんのアプリケーションでもいいから、ボタンの上でカーソルを停止させてほうっておくと、ちっちゃい説明のようなものが現れます(ることがあります)。それが ツールチップ です。
好きずきではありますが、ストリングテーブルよりもソースコード内のリテラル表記に頼る場合のほうが圧倒的に多いでしょう。
ストリングテーブルのための関数は、LoadString() 関数です。
// #include <windows.h> // #include <commctrl.h> // #include "myprog.h" #define IDS_STRING1 100 #define IDS_STRING2 101 #define IDS_LONGSTRING 102 STRINGTABLE { IDS_STRING1 "I am the string 1" IDS_STRING2 "I am \0the string 2\0\0" IDS_LONGSTRING "A long string can be described like " "this.\r\n" "And a style" "like this " "is \"also\" OK" }
ダイアログボックスやコントロール、メニューの場合でもすべて同じですが、リソーススクリプトで文字列を表現する場合の、"〜" で囲まれた中では、\r\n は 「改行」、\" は表示される文字としてのダブルコーテーション 「"」、\0 は 「NULL (ヌル、ナル) 文字」 です。
※ NULL文字 \0 は C 言語では 終端文字ということもあります。C言語文字列の終端を表します。ただしリテラルな文字列の表記では、特に意図しなければ \0 を明示しなくても コンパイラにより自動的に \0 が付加して扱われます。
STRINGTABLE{〜} のなかに、「複数」 の文字列を記述(定義)することが可能です。
[ NULL 文字 '\0' ]
各文字列は明示的に NULL 文字 \0 で終わる必要はありませんが、文字列の途中に \0 を含めることが可能です。ストリングテーブルを使用する関数には、ときおり、
[ つなげ方 ]
長い文字列を書きたい場合、(テキストエディタ上で) 一行で長長と書かず、二行以上に分けて書きたい場合があります。そのような場合は、
IDS_LONGSTRING "A long string can be described like this.
\r\nAnd a stylelike this is \"also\" OK"となります。改行は
\r\n により明示的に書くことによって指定します。テキストエディタ上で 「改行し」 たところでリソースコンパイラには改行の意図は伝わりません。
[ エスケープ文字 '\' ]
基本的に \ はエスケープ文字といいます。C 言語ソースでも同様にそういいます。\ の後に特定の文字を加えることによって、ダブルコーテーションのなか "〜" で、ここまでで述べてきたように、特殊な役割を果たします。C 言語では、"〜" 内に限らず、マクロ定義の記述のときに 二行以上にわたって定義の記述を続けたい場合に、次の行に続くよ、という意味でも \ が使われます。
・ [つなげ方] のところの二行以上にわたる書き方は、エスケープ文字 '\' を使って、
IDS_LONGSTRING
"なんとかかんとか\のようにしてつなげることもできます。
・ また、\" は 3つ連続の " 、つまり、""" でも代用できます。両者とも使ってみたことがありますが、とくにこちらはたいそう記述がみにくくなります。
[ LoadString() 関数 ]
文字列リソースを使うには LoadString() 関数を使用します。ほかにも、特定の関数で文字列リソースを使う場合もあります。
他のリソースの例によらず、この関数だけは ハンドル を返しません。
LoadString( GetModuleHandle(NULL) ,
IDS_STRING1 , szBuffer, 1024 ) ;のように、プログラムが用意したバッファ (szBuffer) に直接 「コピー」 するだけ内容であるため、ハンドルで管理するという考え方が不要なのです。
1024 は許容バッファサイズです。
IDS_STRING1 の大きさに一致する必要はありません。もちろんこの場合、szBuffer はたとえば char szBuffer[1024] ; のように 1024バイト か、それ以上であるべきです。戻り値はコピーされた文字数。失敗なら 0 です。
[ 参考 ] やけっぱち AllocLoadString() 関数 (マイ関数)。
LoadString() 関数では、バッファの大きさ(最大)をあらかじめ指定しなくてはなりません。この点はおそらく誰しも ストリングテーブルを利用する場合のネックだと感ずるところです (いまいち気持ちよく使う気になれない)。この AllocLoadString() 関数では、それを気にすることなくストリングテーブルをロードすることができます。妙な手順を踏んでいますが、文字列リソースは時間に迫られて頻繁にロードするようなものではないので、パフォーマンスは気にしなくて良いから、少々くどい手順を踏んでも大丈夫です。
ただし、この関数は malloc() 関数によりメモリを確保し、 malloc() の戻り値を返す関数です。だからメモリの使用後は、free() 関数によりその開放を必ずするようにします。Win32 API としての統一性にためには、GlobalAlloc() 関数などを利用して、グローバルメモリオブジェクトを使ってみるのもいいかもしれませんね。
#include <stdio.h> // わたくしとしては一応こうしておきます。 #include <windows.h> char *AllocLoadString( UINT id_string ) ; // prototype declaration char *AllocLoadString( UINT id_string ) { char *ret = (char *)malloc(4096) ; HINSTANCE hInst = GetModuleHandle(NULL) ; for( int n=0 ; ret ; n ++ , ret = (char *)realloc( ret , 4096 + n*4096 ) ) { memset( ret, '\0', 4096 + n*4096 ) ; int nBytesCopied = LoadString( hInst , id_string , ret , 4096 + n*4096 ) ; if( nBytesCopied < 4096 + n*4096 - 1 ) { char *pc = ret + 4096 + n*4096 - 1 ; for( ; pc != ret && *pc == '\0' ; pc -- ) ; if( *pc ) pc ++ ; // assert( *pc == '\0' ) ; // <assert.h> ret = (char *)realloc( ret , pc - ret + 1 ) ; break ; } } return ret ; }
この関数内部の malloc() 関数の失敗は AllocLoadString() の戻り値が NULL かそうでないかで判別してください。LoadString() 関数の失敗は、AllocLoadString() の戻り値の示すアドレスの内容が '\0' (つまり 0) かそうでないかを参考にするなどして判断してみてください。
コピーされたサイズが 4095 (+α) の場合は、テーブルが 4095 ぴったりの可能性があるので、さらにもう一つ次の制御に移ります。
また、この例では確保されて返されるバッファのサイズ(\0含めた全部)は、( ストリングリソースのバイト長さ + 1 : 終端NULL分の 1バイト ) です。
※ (自分で改変する場合には) ストリングテーブルには "終端ではない\0" が含まれる可能性があることに注意しましょう。strlen() を使うのはミスのもとです。
[トップ] [level4:言葉] [index]