BMPファイルを扱う際、BMP.HeightやBMP.Widthを設定しようとすると、"EOutofresources - Not enough storage"が表示されます。これらの指示の直後、スタックトレースが(この順番で)表示されます。 ntdll.dll.RtlLeaveCriticalSection, kernel32.dll.FileTimeToDosDateTime, GDI32.dll.GdiReleaseDC, GDI32.dll.PatBlt, kernel32.dll.ReadFile などのスタックトレースとなります。
|7E429130|user32.dll GetParent
|7C90FF2D|ntdll.dll RtlGetNtGlobalFlags
|77F15A00|GDI32.dll GdiReleaseDC
|7C83069E|kernel32.dll FileTimeToDosDateTime
|7C9010E0|ntdll.dll RtlLeaveCriticalSection
| |my function (where I set BMP.Height or BMP.Width)
システムは私の画像を処理するのに十分な空きメモリを持っていますが、メモリが断片化されているため、画像を保持するのに十分な大きさのブロックがありませんでした。しかし、Windowsの起動から11秒後に一度だけ、この現象が発生したのです。私のプログラムは、画像を処理するループを一度だけ循環させたのです。つまり、これはRAMの断片化とは関係ないのです。
このエラーが発生したときの別の状況(しかし、まだ描画に関連している)を以下に示します。
|77F16A7E|GDI32.dll IntersectClipRect
|77F16FE5|GDI32.dll BitBlt
|7E429011|user32.dll OffsetRect
|7E42A97D|user32.dll CallWindowProcA
|7E42A993|user32.dll CallWindowProcA
|7C9010E0|ntdll.dll RtlLeaveCriticalSection
|7E4196C2|user32.dll DispatchMessageA
|7E4196B8|user32.dll DispatchMessageA
|0058A2E1|UTest.exe UTest.dpr
|7C90DCB8|ntdll.dll ZwSetInformationThread
BMP.Heightの後のスタックトレースに必ず 'RtlLeaveCriticalSection'の呼び出しがあると思うのですが。
Windowsのレジストリキーを編集することで解決できる可能性を指摘する投稿がこちらにあります。しかし、この投稿では、Win XPにのみ適用されると書かれています。私の場合は、Win 7でも表示されました。
私は多くの似たような書き込みを参照してください(それらのいくつかは、ファイルをディスクに保存することに近い接続されている)しかし、誰も彼がエラーを修正したことを報告するために戻ってくるまで。
更新しました。
ご要望のとおり、これはエラーが表示されるコードです。
procedure TMyBitmap.SetLargeSize(iWidth, iHeight: Integer);
CONST ctBytesPerPixel= 3;
begin
{ Protect agains huge/empty images }
if iWidth< 1 then iWidth:= 1 else
if iWidth> 32768 then iWidth:= 32768;
if iHeight< 1 then iHeight:= 1 else
if iHeight> 32768 then iHeight:= 32768;
{ Set image type }
if iWidth * iHeight * ctBytesPerPixel > 9000000 {~9MB}
then HandleType:= bmDIB { Pros and cons: -no hardware acceleration, +supports larger images }
else HandleType:= bmDDB;
{ Total size is higher than 1GB? }
if (iWidth* iHeight* ctBytesPerPixel) > 1*GB then
begin
Width := 8000; { Set a smaller size }
Height := 8000; { And rise an error }
RAISE Exception.Create('Image is too large.');
end;
{ Set size }
Width := iWidth; <----------------- HERE
Height:= iHeight;
end;
私の実験によると、最大ビットマップサイズは、以下のものに依存します。
そのため、巨大なデータ(画面上のビットマップの解像度以上)を扱う場合、ビットマップの割り当てが成功するかどうかはわかりません。
ここにいくつかの解決策があります (私はそのうちのいくつかを使用しました)。
完璧な解決策はありません。(私の好みは小さい画像を使うことで、簡単にマルチスレッド処理できる利点があるので、新しいCPUではかなり速くなるかもしれません)また、リソース配分は、あなたの真新しい64ビットWindows 7 PCではうまくいっても、あなたの顧客の32ビットXPコンピュータでは失敗するかもしれないことを認識しておいてください。