Dictionary.TryGetValue()にはまった。
このメソッドから制御が戻るときに、キーが見つかった場合は、指定したキーに関連付けられている値が格納されます。それ以外の場合は value パラメータの型に対する既定の値。このパラメータは初期化せずに渡されます。と書かれているものの深く読んでなくて、valueは変更されないものと勘違い。
書かれているとおり、見つからなかった場合は既定値で初期化されます。
.NETとWin32ネタが主です。UNIXもいじるのでその辺りも混じるかも。
Dictionary.TryGetValue()にはまった。
このメソッドから制御が戻るときに、キーが見つかった場合は、指定したキーに関連付けられている値が格納されます。それ以外の場合は value パラメータの型に対する既定の値。このパラメータは初期化せずに渡されます。と書かれているものの深く読んでなくて、valueは変更されないものと勘違い。
ごめんなさい、ColorPaletteのAccessViolationExceptionは別の原因でした。
Bitmapコンストラクタには
scan0パラメータで指定されたメモリブロックの割り当てと解放は呼び出し元が行いますが、関連するBitmapが解放されるまでメモリは解放されません。とありますが、これを守っていませんでした。Bitmapコンストラクタが終了した時点でメモリブロックを解放していました。Bitmap.LockBits()をするのが正解なようです。
複数のBitmapが同一のColorPaletteを持つとき、このColorPaletteが非常に扱いづらい。
Bitmap[] bitmaps; // ここにColorPaletteを設定したいちゃんとColorを設定しているつもりでも、毎回ColorPaletteが生成され直してColor値が保存されない。じゃあ、どうするかというと
Color[] colors; // このColorを設定したい
foreach( Bitmap bitmap in bitmaps ){
for( int i = 0; i < 256; i++ )
bitmap.Palette.Entries[i] = color[i];
bitmap.MakeTransparent(); // ついでに透明色の設定
}
Bitmap[] bitmaps; // ここにColorPaletteを設定したいこんな感じ。コンストラクタが提供されないにも係わらず、インスタンスの設定が求められるのはおかしい。
Color[] colors; // このColorを設定したい
foreach( Bitmap bitmap in bitmaps ){
ColorPalette palette = bitmap.Palette; // ColorPaletteを取得、この時点でBitmapとは切り離されている
for( int i = 0; i < 256; i++ )
palette.Entries[i] = color[i];
bitmap.Palette = palette;
bitmap.MakeTransparent(); // ついでに透明色の設定
}
Bitmap[] bitmaps; // ここにColorPaletteを設定したいこうすればColorPaletteの作成は1回で済む…というのは罠です。ColorPaletteはクラスなので、複数のBitmapでインスタンスが共有されてしまいます。具体的にはMakeTransparent()でAccessViolationExceptionが発生したりする。
Color[] colors; // このColorを設定したい
ColorPalette palette = bitmaps[0].Palette; // ColorPaletteを取得、この時点でBitmapとは切り離されている
for( int i = 0; i < 256; i++ )
palette.Entries[i] = color[i];
foreach( Bitmap bitmap in bitmaps ){
bitmap.Palette = palette;
bitmap.MakeTransparent(); // ついでに透明色の設定
}
セカンド・オピニオン OS小論:OSの構造をもう少し考えてみるを見つけました。
奥深くまでいろいろ語られていて参考になりました。その影響で「インサイドWindows第4版上」なる本を買ってしまいました。下は売ってなかったのでそのうちにでも。
コンピュータのプロパティはVistaだとこんな感じ。xpもダイアログは違うけど、プロセッサについて書かれてる。周波数は2回書かれてるし、空白のバランスが悪い。
でもこれには理由があって、赤下線部分の文字列、これはCPUから直接取得できる。こんな感じ。Visual C++依存のコードです。
#include <stdio.h>
#include <intrin.h>
int main(){
int cpuInfo[4];
__cpuid( cpuInfo, 0x80000000 );
if( cpuInfo[0] >= 0x80000004 ){
char brand[48];
__cpuid( (int*)&brand[ 0], 0x80000002 );
__cpuid( (int*)&brand[16], 0x80000003 );
__cpuid( (int*)&brand[32], 0x80000004 );
printf( "%.48s\n", &brand[0] );
}
return 0;
}
IDataObject、DataFormats.Format、FORMATETCこの辺りは定義がいい加減で困る。
しょーもないところではIDataObject.DUnadvise()。戻り値voidなのに戻り値の解説がついてます。Cの#define値を見せられてもどうにもなりません…そもそもどうやって返せと。.NET Framework 3.5ではドキュメント修正されてめでたしめでたし…んなことありません。
お隣りのIDataObject.DAdvise()。戻り値intだから解説が…ふむふむ真っ当に見える? ところが、OLE_E_ADVISENOTSUPPORTEDを返そうとすると、refやらoutの値を設定しなさいとコンパイルエラーが。いえ、設定できないからOLE_E_ADVISENOTSUPPORTEDを返したいのですが…結局、戻り値ではなく例外を投げることに。
本題はこっち。FORMATETC.cfFormatはshort型。実際の値としてはshortで負になる値がよく使われる。
でもDataFormats.Format.Idとしてはint型なので正に…単純に==演算子で比較すると一致しません。結局
FORMATETC formatEtc;とするしかないでしょうか。
DataFormats.Format dataFormat;
if( formatEtc.cfFormat == unchecked((short)dataFormat.Id) ){
...;
}