CreateDIBSectionでエラーとなってしまいます。

解決


C3055  2009-07-07 19:55:08  No: 146049  IP: 192.*.*.*

VB2005を使用しています。

カメラから画像Dataを取得し、API関数で
モノクロで画像を表示させようとしています。


 Dim memDC As Integer
 Dim hDIBSection As Integer
 Dim hOldBmp As Integer
 Dim lpDIB As Integer
 
 'まずはメモリDCを作る
 memDC = CreateCompatibleDC(hdc)

 'DIBSectionを作る
 hDIBSection = CreateDIBSection(memDC, bmpInfo, DIB_RGB_COLORS, lpDIB, 0, 0)

ここで、”保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。”

と言うエラーが出てしまって苦戦しています。
どなたか、御教授頂けますでしょうか。
よろしくお願いします。

編集 削除
aetos  2009-07-08 09:48:55  No: 146050  IP: 192.*.*.*

memDC、hDIBSection、hOldBmp、lpDIB はすべてポインタかハンドルですので、IntPtr にすべきです。
あとは、各引数が間違えていないことを確認するくらいしか、提示されたコードで言えることはありません。
lpDIB あたりが怪しそうではありますが。

編集 削除
C3055  2009-07-08 10:38:53  No: 146051  IP: 192.*.*.*

aetos様返答ありがとうございます。
memDC、hDIBSection、hOldBmp、lpDIB をIntPtr にしました。
仮にlpDIB=0 として見ましたが、やはりエラーとなります。
コードの詳細を記載させて頂きます。

間違えている所がありましたら、皆様御指摘よろしくお願いします。


    ’API宣言
    Public Declare Function SetDIBColorTable Lib "gdi32" (ByVal hdc As IntPtr, ByVal uStartIndex As Integer, ByVal cEntries As Integer, ByVal pColors As RGBQUAD) As Integer
    Public Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As IntPtr) As Integer
    Public Declare Function CreateDIBSection Lib "gdi32" (ByVal hdc As IntPtr, ByVal pBitmapInfo As BITMAPINFOHEADER, ByVal un As Integer, ByVal lplpVoid As Integer, ByVal handle As Integer, ByVal dw As Integer) As Integer
    Public Declare Function SelectObject Lib "GDI32" (ByVal hDC As Integer, ByVal hObject As Integer) As Integer
    Public Declare Function StretchDIBits Lib "GDI32" (ByVal hDC As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal dx As Integer, ByVal dy As Integer, ByVal SrcX As Integer, ByVal SrcY As Integer, ByVal wSrcWidth As Integer, ByVal wSrcHeight As Integer, ByRef lpBits As Byte, ByRef lpBitsInfo As BITMAPINFOHEADER, ByVal wUsage As Integer, ByVal dwRop As Integer) As Integer
    Public Const SRCCOPY As Integer = &HCC0020



        Dim bmpInfo As BITMAPINFOHEADER
        Dim bmiColors(255) As RGBQUAD         ' DIBカラー設定格納
        Dim memDC As IntPtr
        Dim hDIBSection As IntPtr
        Dim hOldBmp As IntPtr
        Dim lpDIB As IntPtr            
        Dim hdc As IntPtr
        Dim PixelData(76800) As Byte


  'BITMAPINFOHEADER
        bmpInfo.biBitCount = 8       ' カメラからの出力が8bitなので8を設定
        bmpInfo.biClrImportant = 0
        bmpInfo.biClrUsed = 0
        bmpInfo.biCompression = 0
        bmpInfo.biHeight = 240
        bmpInfo.biPlanes = 1
        bmpInfo.biSize = 40 ' SizeOf(BITMAPINFOHEADER)
        bmpInfo.biSizeImage = 76800
        bmpInfo.biWidth = 320
        bmpInfo.biXPelsPerMeter = 0
        bmpInfo.biYPelsPerMeter = 0

        For i = 0 To 255
            bmiColors(i).rgbBlue = i
            bmiColors(i).rgbGreen = i
            bmiColors(i).rgbRed = i
            bmiColors(i).rgbReserved = 0
        Next i

        ' デバイスコンテキストハンドル取得
        hdc = Form1.Picture1.CreateGraphics.GetHdc

        'まずはメモリDCを作る
        memDC = CreateCompatibleDC(hdc)

        'DIBSectionを作る
        hDIBSection = CreateDIBSection(memDC, bmpInfo, DIB_RGB_COLORS, lpDIB, 0, 0)

        'DIBSectionとhMemDCを関連付ける
        hOldBmp = SelectObject(memDC, hDIBSection)

        'カラーパレットを変更する
        SetDIBColorTable(memDC, 0, 255, bmiColors(0))

        '画像を表示する
        StretchDIBits(hdc, 0, 0, 320, 240, 0, 0, 320, 240, PixelData(0), bmpInfo, DIB_RGB_COLORS, SRCCOPY)

よろしくお願いします。

編集 削除
aetos  2009-07-08 12:05:36  No: 146052  IP: 192.*.*.*

って言うか、カメラからはどうやって画像データを取得するんでしょうか。

編集 削除
C3055  2009-07-08 12:35:07  No: 146053  IP: 192.*.*.*

画像Dataの取得は、
カメラに付属の関数を用いて
画像Dataを取得しています。

PixelData(76800)の配列の中にDataは
格納されています。dim宣言の後に取得しています。

編集 削除
aetos  2009-07-08 13:05:04  No: 146054  IP: 192.*.*.*

そのカメラ付属の関数の宣言を載せてください。

編集 削除
C3055  2009-07-08 13:45:07  No: 146055  IP: 192.*.*.*

申し訳ありません。
カメラ付属の関数の宣言を載せることが出来ません。

イメージとしては、320×240の画像を1枚取得します。(Dataは8bitです)
そのDataをStretchDIBits関数で表示します。

編集 削除
aetos  2009-07-08 14:13:40  No: 146056  IP: 192.*.*.*

その関数は、引数に BYTE* を取り、アプリ側で確保したバッファを渡して呼び出すようなものですか?
要は、そのためのポインタが取得できればよいわけで、それなら、CreateDIBSection など使うより楽な方法があるのではないでしょうか。

例えば、Bitmap オブジェクトを作り、その LockBits メソッドを呼ぶと、ビットバッファへのポインタが手に入ります。
これをカメラの関数に渡すのはどうでしょう。

編集 削除
K.J.K.  2009-07-08 15:07:43  No: 146057  IP: 192.*.*.*

第4引数は、 ByVal ではなく、 ByRef です。

編集 削除
C3055  2009-07-08 20:01:58  No: 146058  IP: 192.*.*.*

>第4引数は、 ByVal ではなく、 ByRef です。

御指摘ありがとうございます。
修正してみましたが、やはりエラーとなってしまいます。

>例えば、Bitmap オブジェクトを作り、その LockBits メソッドを呼ぶと、ビットバッファへのポインタが手に入ります。

この方法を試してみたいと思います。

上記方法以外に、PixelData(76800)の画素Dataを
PictuerBOXに表示する一番簡単な方法はありますでしょうか?

編集 削除
Hongliang  2009-07-08 20:14:36  No: 146059  IP: 192.*.*.*

「画像データ」の中身次第ですが、Bitmap(Integer, Integer, Integer, PixelFormat, IntPtr) コンストラクタを使って Bitmap オブジェクトを生成するとか。

編集 削除
subaru  2009-07-08 22:07:59  No: 146060  IP: 192.*.*.*

StretchDIBits で描画するんだったら、作成したメモリDC や DIBSection
は一切使われていないので全く意味がありませんね。
BITMAPINFOHEADER の後にパレットのデータがメモリが連続して配置されていれば
配列の内容を書き換えるだけで適用されます。

Bitmap オブジェクトで作る方が楽なので aetos さんか Hongliang さんの方法を
おすすめします。
#ちなみに StretchDIBits は重いです。

編集 削除
C3055  2009-07-09 09:59:08  No: 146061  IP: 192.*.*.*

皆様、返信ありがとうございます。
Bitmap オブジェクトだとやはり時間がかかってしまいます…。

>StretchDIBits で描画するんだったら、作成したメモリDC や DIBSection
>は一切使われていないので全く意味がありませんね。
>BITMAPINFOHEADER の後にパレットのデータがメモリが連続して配置されていれば
>配列の内容を書き換えるだけで適用されます。

上記内容をもう少し具体的に教えて頂けないでしょうか?
出来れば、コード等のアドバイスもよろしくお願いします。

編集 削除
subaru  2009-07-09 10:40:25  No: 146062  IP: 192.*.*.*

>Bitmap オブジェクトだとやはり時間がかかってしまいます…。

具体的にどの部分で時間がかかりますか?
最初に8ビットの Bitmap オブジェクトが構築できたら
描画用に32ビットに変換して、そちらを使った方がいいと思います。

>上記内容をもう少し具体的に教えて頂けないでしょうか?
>出来れば、コード等のアドバイスもよろしくお願いします。

まず、DIB でも DIBSection でも8ビット以下のビットマップの場合は
BITMAPINFOHEADER と RGBQUAD のメモリが連続していることが
重要なので、bmpInfo 変数を無理矢理渡しているのはまずい気がします。
RGBQUAD を256個持つ BITMAPINFO 構造体を定義した方がいいのではないでしょうか。

DIBSection を使う場合は作成後に、選択しているメモリDCに対して
SetDIBitsToDevice で画素を転送しておきます。
ウインドウへの描画には StretchBlt や BitBlt を使用します。

#APIの宣言についてはまだ見直す必要がありそうです。

編集 削除
K.J.K.  2009-07-09 10:55:24  No: 146063  IP: 192.*.*.*

第2引数も、 ByVal ではなく ByRef です。

編集 削除
C3055  2009-07-09 18:56:02  No: 146064  IP: 192.*.*.*

皆様、お陰様で画像を出す事が出来ました。
本当に助かりました!
ありがとうございました!

編集 削除