Win32アプリのデフォルトアイコンを設定するときは、リソースに IDR_MAINFRAME という名の*.icoファイルを追加する。32*32と16*16分けるときはどうすればいいんかいな。
久々に C でハマってしまった事例があるので、紹介。
もちろんハマるの意味は熱中するほうではなく、どつぼにはまる
*1
状態を指しています。
データをファイルに出力するとき、よくあるケースとして構造体をそのまま書き込むことがあると思います。
// ビットマップヘッダを書き込む
WriteFile(hF, (BITMAPFILEHEADER*)&bmFH, sizeof(BITMAPFILEHEADER), &dwResult, NULL);
この例だと、BITMAPFILEHEADER構造体をそのままメモリからファイルへ出力しています。
通常、この構造体は PlatformSDK に含まれる WinGDI.h に定義されていて、実際には Windows.h をインクルードした時点で参照されています。
これを使う分には問題は発生しないのですが、先日ある理由により上記ヘッダファイルをインクルードせずに自分でBITMAPFILEHEADER構造体を定義して使っていたのです。具体的にはこんな感じ。
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
(MSDN に記載されているそのままです)
さて、このとき何が起こるのか予想できますか?
実はこの方法でBMPファイルを作成したところ、ペイント等でファイルを開こうとしてもエラーが出るだけです。不思議に思ってファイルをダンプしてみたところ、先頭部分(この構造体がまるまる入っている)がこんな感じになっていました。
42 4D 00 00 38 10 0E 00 00 00 00 00 38 00 00 00
(本当は ↓ みたいになるはず)
42 4D 36 10 0E 00 00 00 00 00 36 00 00 00 28 00
BITMAPFILEHEADER構造体の使い方を知らない方のために説明しておくと、通常のBMPでは bfType には常に 0x4d42 が入れてあり、bfReserved1 と bfReserved2 には 0 が入ってなくてはなりません。
しかし実際には上記のとおり、bfReserved1 に 0x000E が入ってしまっていました。
何度プログラムを見直しても、単に構造体をぶち込んでいるだけなのでミスは見当たりません。
よーく考えてみると、そもそも 3バイト目と4バイト目が0になっているのもおかしい。
はい。結論をいいますと、構造体では WORD bfType; となっているのに、実際のメモリ上にはWORD(2バイト)+パディング(2バイト)が入っていたのです。
通常のコンパイラだとデフォルト設定で構造体のアライメントが4バイトになっているのをすっかり忘れておりました。
これは 通常通りにWindows.hをインクルードして使っている分には問題は発生しません。期待通りに構造体がそのまま出力されます。WinGDI.hを よくよく見てみると
#include <pshpack2.h>
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
#include <poppack.h>
このように定義されているじゃありませんか。pshpack2の中にアライメントを2バイトに設定する指定が入っていて、poppackで再度設定を戻すようになっています。
原因がわかったので自前の構造体定義にも 同様の設定になるようにします。
#pragma pack(push, 2)
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
#pragma pack(pop)
これが正解。アライメント指定の記述方法がちと違いますが、これもアリです。
これによって構造体が2バイトアライメントされるようになり、構造体メンバはすべて2バイトと4バイトのものしかありませんので、ファイルに出力した場合でも余計なパディングはできません。
あーまた変なとこで時間くっちゃったい。
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |