ElektroStudios ElektroStudios - 6 months ago 30
Vb.net Question

How to define 'CreateDIB' function or reproduce its purpose in C#?

I'm trying to translate this C++ code from this MSDN reference, to C# or VB.NET:

case WM_DWMSENDICONICTHUMBNAIL:
{
// This window is being asked to provide its iconic bitmap. This indicates

// a thumbnail is being drawn.
hbm = CreateDIB(HIWORD(lParam), LOWORD(lParam));
if (hbm)
{
hr = DwmSetIconicThumbnail(hwnd, hbm, 0);
DeleteObject(hbm);
}
}
break;


At first sight seems simple, but I need help to understand about the
CreateDIB
function, I don't know what means and which is the purpose of that function, I can't find info about, and also I can't find it inside the Windows SDK header files, nothing of nothing.

Where is defined that function?, It is necessary to follow good practices in that C++ example?, how to declare it from C#, or which is the .NET equivalent for that unmanaged function?.

I found the CImageAllocator.CreateDIB which I'm not sure whether it reffers to that, but the parameters of that function does not corresponds to a kind of
CreateDIB(width, height)
like I seen in this other MSDN code, so probablly is not the same function, and also it is a directshow thing...

Well, this is the current translation I did, it works, but I'm worried about possible memory issues because the lack of
CreateDIB
function or its equivalent managed member:

Case WM_DWMSENDICONICTHUMBNAIL

Dim hwnd As IntPtr = Process.GetCurrentProcess().MainWindowHandle
Dim dWord As Integer = m.LParam.ToInt32()
Dim maxWidth As Short = BitConverter.ToInt16(BitConverter.GetBytes(dWord), 2)
Dim maxHeight As Short = BitConverter.ToInt16(BitConverter.GetBytes(dWord), 0)

Using img As Image = Bitmap.FromFile("C:\Image.jpg")
Using thumb As Bitmap = CType(img.GetThumbnailImage(maxWidth, maxHeight, Nothing, Nothing), Bitmap)

Dim hBitmap As IntPtr = thumb.GetHbitmap()

Dim hresult As Integer = NativeMethods.DwmSetIconicThumbnail(hwnd, hBitmap, 0)
If (hresult <> 0) Then
' Handle error...
' Throw Marshal.GetExceptionForHR(hresult)
End If

NativeMethods.DeleteObject(hBitmap)

End Using
End Using

Answer

That's way too much effort expended to set the thumbnail image. Just keep a copy of the bitmap on your window, and draw it when you need to.

public partial class Form1 : Form
{
    [DllImport("Dwmapi.dll")]
    static extern int DwmSetIconicThumbnail(IntPtr hWnd, IntPtr hbmp, uint dwSITFlags);

    [DllImport("Dwmapi.dll")]
    static extern int DwmSetWindowAttribute(IntPtr hWnd, uint dwAttribute, IntPtr pvAttribute, uint cbAttribute);

    const uint WM_DWMSENDICONICTHUMBNAIL = 0x0323;
    const uint DWMWA_FORCE_ICONIC_REPRESENTATION = 7;
    const uint DWMWA_HAS_ICONIC_BITMAP = 10;

    Size thumbSize = new Size(30, 30);
    Bitmap thumbImage = new Bitmap(30, 30);
    object sync = new object();

    public Form1()
    {
        InitializeComponent();
        using (Graphics g = Graphics.FromImage(this.thumbImage))
        {
            g.Clear(Color.Blue);
            g.DrawRectangle(Pens.Black, new Rectangle(new Point(0, 0), this.thumbSize));
        }
        this.HandleCreated += Form1_HandleCreated;
    }
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_DWMSENDICONICTHUMBNAIL)
        {
            lock (this.sync)
            {
                int x = (int)((m.LParam.ToInt32() >> 16) & 0xffff);
                int y = (int)(m.LParam.ToInt32() & 0xffff);
                if (this.thumbSize != new Size(x, y))
                {
                    this.thumbSize = new Size(x, y);
                    this.UpdateBitmap();
                }
                DwmSetIconicThumbnail(this.Handle, thumbImage.GetHbitmap(), 0);
            }
        }
        base.WndProc(ref m);
    }

    void UpdateBitmap()
    {
        lock (this.sync)
        {
            this.thumbImage = new Bitmap(this.thumbSize.Width, this.thumbSize.Height);
            using (Graphics g = Graphics.FromImage(this.thumbImage))
            {
                g.Clear(Color.Blue);
                g.DrawRectangle(Pens.Black, new Rectangle(new Point(0, 0), this.thumbSize));
                //or: g.DrawImage() with stretching specified.
            }
        }
    }

    private void Form1_HandleCreated(object sender, EventArgs e)
    {
        IntPtr val = Marshal.AllocHGlobal(4);
        Marshal.WriteInt32(val, 1);
        DwmSetWindowAttribute(this.Handle, DWMWA_FORCE_ICONIC_REPRESENTATION, val, 4);
        DwmSetWindowAttribute(this.Handle, DWMWA_HAS_ICONIC_BITMAP, val, 4);
        Marshal.FreeHGlobal(val);
    }
}

C# since the tags on the question list it.

Comments