Quantcast
Channel: Common Language Runtime Internals and Architecture forum
Viewing all articles
Browse latest Browse all 1710

Unable to get CreateDIBSection to work

$
0
0
The project I am on has the need to pass an image from C# to unmanaged C++ wherein a propriatary C++ SDK will manipulate the image bits. Through trial & error I have concluded that using Bitmap::GetHBitmap() to fetch the interop image will not work since the SDK can't deal with 32bpp formatted images.  I've been trying, with no success, to work out how to get the image in a very specific format prior to passing the image bytes over to the C++ SDK.

I've hit a wall because I can't successfully call CreateDIBSection(). It always returns a NULL handle and no image bits.  When I call Marshall.GetLastWin32Error() it always returns zero (no error). Yup, I've tagged the CreateDIBSection declaration with "SetLastError = true".

I've been at this for a few days now and it's driving me a bit nuts. Any help would be greatly appreciated! Here's my code...

using System;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;

namespace Digimarc.Interop
{
    internal class BitmapInterop
    {
        [DllImport("user32.dll")]
        public static extern IntPtr GetDC(IntPtr hwnd);

        [DllImport("user32.dll")]
        public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);

        [DllImport("gdi32.dll")]
        public static extern int BitBlt(IntPtr hdcDst, int xDst, int yDst, int w, int h, IntPtr hdcSrc, int xSrc, int ySrc, int rop);

        [DllImport("gdi32.dll")]
        public static extern IntPtr CreateCompatibleDC(IntPtr hdc);

        [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
        static extern IntPtr CreateDIBSection(IntPtr hdc, ref BITMAPINFO bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset);

        [DllImport("gdi32.dll")]
        public static extern int DeleteDC(IntPtr hdc);

        [DllImport("gdi32.dll")]
        public static extern bool DeleteObject(IntPtr hObject);

        [DllImport("gdi32.dll")]
        public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

        // Copied from WinGDI.h
        static uint BI_RGB = 0;
        static uint DIB_RGB_COLORS = 0;
        static int SRCCOPY = 0x00CC0020;

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public class BITMAPINFO
        {
            public uint biSize;
            public int biWidth;
            public int biHeight;
            public ushort biPlanes;
            public ushort biBitCount;
            public uint biCompression;
            public uint biSizeImage;
            public int biXPelsPerMeter;
            public int biYPelsPerMeter;
            public uint biClrUsed;
            public uint biClrImportant;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
            public uint[] cols;    // Not used since we're doing RGB (not PAL) 

            public BITMAPINFO() { biSize = 40; }    // C++ BITMAPINFOHEADER is 40 bytes
        }

        internal static bool GetCPlusPlusDIB(Bitmap bitmap, out BITMAPINFO bmpInfo, out IntPtr imageBytes)
        {
            bool dibCreated = false;
            int width = bitmap.Width;
            int height = bitmap.Height;
            IntPtr hWinDC = IntPtr.Zero;
            IntPtr hSrcDC = IntPtr.Zero;
            IntPtr hDestDC = IntPtr.Zero;
            IntPtr hSrcHandle = IntPtr.Zero;
            IntPtr hDestHandle = IntPtr.Zero;

            ushort targetBPP = 24;        // For now, hard code a 24bpp target
            double inchesPerMeter = 39.3700787;

            imageBytes = IntPtr.Zero;
            bmpInfo = new BITMAPINFO();
            try
            {
                // Initialize the bitmap info
                bmpInfo.biWidth = width;
                bmpInfo.biHeight = -(int)height;
                bmpInfo.biPlanes = 1;
                bmpInfo.biBitCount = targetBPP;
                bmpInfo.biCompression = BI_RGB;
                bmpInfo.biSizeImage = (uint)(width * height * 3);
                bmpInfo.biXPelsPerMeter = Convert.ToInt32(bitmap.HorizontalResolution * inchesPerMeter);
                bmpInfo.biYPelsPerMeter = Convert.ToInt32(bitmap.VerticalResolution * inchesPerMeter);
                bmpInfo.biClrUsed = 0;
                bmpInfo.biClrImportant = 0;

                // Allocate the destination image handle
                hWinDC = GetDC(IntPtr.Zero);
                hDestHandle = CreateDIBSection(hWinDC, ref bmpInfo, DIB_RGB_COLORS, out imageBytes, IntPtr.Zero, 0);

                // This ALWAYS returns 0 (no error)
                int lastErr = Marshal.GetLastWin32Error();

                if (hDestHandle != IntPtr.Zero)
                {
                    // Prepare the source image
                    hSrcHandle = bitmap.GetHbitmap();
                    hSrcDC = CreateCompatibleDC(hWinDC);
                    SelectObject(hSrcDC, hSrcHandle);

                    // Prepare the destination image
                    hDestDC = CreateCompatibleDC(hWinDC);
                    SelectObject(hDestDC, hDestHandle);

                    // Copy the bits
                    BitBlt(hDestDC, 0, 0, width, height, hSrcDC, 0, 0, SRCCOPY);

                    // Indicate that the DIB was created
                    dibCreated = true;
                }
            }
            finally
            {
                // Clean up
                if (hDestHandle != IntPtr.Zero)
                    DeleteObject(hDestHandle);
                if (hDestDC != IntPtr.Zero)
                    DeleteDC(hDestDC);
                if (hSrcHandle != IntPtr.Zero)
                    DeleteObject(hSrcHandle);
                if (hSrcDC != IntPtr.Zero)
                    DeleteDC(hSrcDC);
                if (hWinDC != IntPtr.Zero)
                    ReleaseDC(IntPtr.Zero, hWinDC);
            }
            return dibCreated;
        }
    }
}
 

Viewing all articles
Browse latest Browse all 1710

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>