Draw image to screen using StretchBlt and GetDesktopWindow

0

I'm trying to display a Bitmap to the screen using GetDesktopWindow() to get a handle of the desktop window, and StretchBlt to copy an image to it.
However, this does not work. It shows either a completely blank image, or a completely white image, depending if I use SRCCOPY or other constants.

Here's the code:

[DllImport("GDI32.DLL", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
    private static extern bool StretchBlt(IntPtr hdcDest, int nXDest, int nYDest, int nDestWidth, int nDestHeight,
        IntPtr hdcSrc, int nXSrc, int nYSrc, int nSrcWidth, int nSrcHeight, TernaryRasterOperations dwRop);

    [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern IntPtr GetDC(IntPtr hWnd);

    [DllImport("user32.dll", ExactSpelling = true)]
    private static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);

    [DllImport("gdi32.dll", ExactSpelling = true)]
    private static extern IntPtr BitBlt(IntPtr hDestDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);

    [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
    private static extern IntPtr GetDesktopWindow();

    public enum TernaryRasterOperations
    {
        SRCCOPY = 0x00CC0020, /* dest = source*/
        SRCPAINT = 0x00EE0086, /* dest = source OR dest*/
        SRCAND = 0x008800C6, /* dest = source AND dest*/
        SRCINVERT = 0x00660046, /* dest = source XOR dest*/
        SRCERASE = 0x00440328, /* dest = source AND (NOT dest )*/
        NOTSRCCOPY = 0x00330008, /* dest = (NOT source)*/
        NOTSRCERASE = 0x001100A6, /* dest = (NOT src) AND (NOT dest) */
        MERGECOPY = 0x00C000CA, /* dest = (source AND pattern)*/
        MERGEPAINT = 0x00BB0226, /* dest = (NOT source) OR dest*/
        PATCOPY = 0x00F00021, /* dest = pattern*/
        PATPAINT = 0x00FB0A09, /* dest = DPSnoo*/
        PATINVERT = 0x005A0049, /* dest = pattern XOR dest*/
        DSTINVERT = 0x00550009, /* dest = (NOT dest)*/
        BLACKNESS = 0x00000042, /* dest = BLACK*/
        WHITENESS = 0x00FF0062, /* dest = WHITE*/
    };
    public static void DrawBitmapToScreen(Bitmap bmp, TernaryRasterOperations operations)
    {
        int width = bmp.Width;
        int height = bmp.Height;

        IntPtr hwnd = GetDesktopWindow();
        IntPtr hdc = GetDC(hwnd);

        //create Graphic from source bitmap

        Graphics bmpGraphic = Graphics.FromImage(bmp);
        //because (when uncommented) the following line works for coping a block from the form???
        //Graphics bmpGraphic = this.CreateGraphics();

        //get handle to source graphic
        IntPtr srcHdc = bmpGraphic.GetHdc();

        //copy it
        bool res = StretchBlt(hdc, 20, 20, width, height,
            srcHdc, 0, 0, width, height, operations);

        //release handles
        bmpGraphic.ReleaseHdc();
        ReleaseDC(hwnd, hdc);
    }

To call it I then use:

DrawBitmapToScreen((Bitmap)pictureBox1.Image, TernaryRasterOperations.SRCCOPY);

What have I done wrong?

EDIT: I need that the image gets deleted from the screen if you refresh Windows Explorer or move a window on it

c#
dll
handle
asked on Stack Overflow Jan 22, 2020 by Adryzz • edited Jan 23, 2020 by Adryzz

1 Answer

1

I found a solution that not uses StretchBlt() or BitBlt() (outside of the underlying code of the Graphics class). The only unmanaged code is GetDC(), GetDesktopWindow() and ReleaseDC(). Here's the code

[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern IntPtr GetDC(IntPtr hWnd);

    [DllImport("user32.dll", ExactSpelling = true)]
    private static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);

    [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
    private static extern IntPtr GetDesktopWindow();

    public static void DrawBitmapToScreen(Bitmap bmp)
    {
        int width = bmp.Width;
        int height = bmp.Height;

        IntPtr hwnd = GetDesktopWindow();
        IntPtr hdc = GetDC(hwnd);
        using (Graphics g = Graphics.FromHdc(hdc))
        {
            g.DrawImage(bmp, new Point(0, 0));
        }

        ReleaseDC(hwnd, hdc);
    }
answered on Stack Overflow Jan 24, 2020 by Adryzz • edited Oct 13, 2020 by Adryzz

User contributions licensed under CC BY-SA 3.0