- ベストアンサー
windowsの構造体にはなぜ自身のサイズを指定しないといけないのか?
windowsのプログラミングをしていると、cbSizeというその構造体自身を 意味するメンバ変数がよく出てきます。 質問は、これが一体なぜ必要なのか?についてです。 内部でその構造体を生のメモリにコピーすることがあり、その場所では その構造体の宣言がなぜか参照できないからか?などと思っていますが、今一 よく解っていません。 これについてご存知方がいらっしゃいましたらご教授お願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
API関数をバージョンアップ出来るようにする為です。 例えば、最初のバージョンで、ある構造体のサイズが50バイトにしたとします。 このAPI関数を呼ぶ場合、どのアプリもcbSizeに50を入れて呼びます。 ある時、API関数に機能が追加され、構造体の中身がソックリ入れ替わり、70バイトになったとします。 古いアプリは、API関数が古いままのつもりで、cbSizeに50を入れて呼びます。 新しいアプリは、API関数が新しくなったつもりで、cbSizeに70を入れて呼びます。 ここで、新しいAPI関数は「古いアプリもサポートする必要がある」ので、cbSizeが50で呼ばれたら古いバージョンと同じ動きをして、cbSizeが70で呼ばれたら追加機能がある新しいバージョンでの動きをします。 このようにすれば「API関数に機能追加をしつつ、古いアプリもサポートできる」ようになります。 なお、API関数が追加機能の無い古いバージョンのまま、追加機能を利用したアプリを走らせて、そのアプリが「API関数が新しいバージョンになっているつもりでAPI関数を呼ぶ」と、古いAPI関数は「cbSizeが不正ですよ~」と言うエラーコードを返します。 アプリは、このエラーコードを見て「このバージョンのWindowsでは実行できません」などのエラー表示を行う事になります。 なお、API関数のバージョンが変わると「構造体の後ろに新しいデータが追加され、前の方は古いバージョンと同じになっている事が多い」ですが、そうとも限りません。 場合によっては「特定の数値変数のサイズが2から4に変わった」とか「特定の数値変数のサイズが4から8に変わった」などで、途中からズレてたり、中身がまるっきり違うなんて事もあります。 まとめると「cbSizeは、呼び出し元のアプリが、どのバージョンのAPI関数を呼んだつもりになっているかを、API関数に知らせる為の物」です。 なお「元からバージョンは1つしかなく、機能追加の予定もなく、今も機能は1つしかない」としても「将来、変わるかもしれない」ので「cbSizeでバージョン判定」が行われているAPI関数が多数あります。
その他の回答 (3)
UI周りでは対象OSによって構造体のメンバが増えるなんぞいつものことです
- notnot
- ベストアンサー率47% (4900/10358)
#1の方のお書きの通りだと思いますが、もう少し違う言い方をすると、 「APIの機能アップをしたいのだが、今の引数構造体だと、新機能の細かい指定をする項目のエリアがない」というような事が起こると困るので、そういう場合に、「構造体の後ろに新項目を継ぎ足して、サイズをその分増やす」という方式を採っているわけです。
- machongola
- ベストアンサー率60% (434/720)
こんばんは。 此れに関して確証が無いのですが、私が読んだ書籍の中には、「指定された構造体のサイズで、windowsやdllのバージョンを判断して挙動を変える」と言った事が書いてありました。 実際に良く出てくるwindowsビットマップ用の構造体でも、そんな感じの使われ方をされています(必ずこういった使い方であるかどうかは不明です)。 http://ja.wikipedia.org/wiki/Windows_bitmap DWORD biSize;//ファイルの先頭からsizeof(BITMAPFILEHEADER)分下がった位置でsizeof(DWORD)分読み込む switch(biSize) { case sizeof(BITMAPINFOHEADER): //windowsビットマップの多くは此れ break; case sizeof(BITMAPCOREHEADER): //os/2 break; case sizeof(BITMAPV4HEADER): //win95, nt4.0 break; case sizeof(BITMAPV5HEADER): //win98, win2000 break; }
お礼
早速の回答ありがとうございます。 皆様もおっしゃっているようにサイズで挙動を変えるが正解のようですね。
お礼
まずは、返答遅れてしまい、申し訳ありませんでした。 丁寧な解説ありがとうございます。なるほど。 dllのインターフェイスに当たる関数のアドレスが変わらない事を 利用した上手いバージョンアップの方法ですね。面白い。