Solved

Bitmaps, from handles (HBitmap, Hbmp)

Posted on 2004-04-14
6
1,324 Views
Last Modified: 2013-12-03
Aright, I need sample code for this, as I am through beating my head against the wall, and not getting it.

Background: I'm injecting a Paint Hook dll into a process, to grab the window before it is scaled.

What I need:
Working, unmanaged, C++ code that can create a Bitmap. I do not care what kind, because it is going into C# land, I can manipulate it from there.

Here a portion of the code :

HBITMAP hBmp = NULL;

    {
        HDC hDC = GetDC(hWnd);
        hBmp = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);
        ReleaseDC(hWnd, hDC);
    }
      hOld = SelectObject(hDCMem, hBmp);

I need a bitmap created from hBmp. And this code is going into a DLL.

I want headers, prototypes, whatever, give it all to me as long as it works.
0
Comment
Question by:rossryan
  • 3
  • 2
6 Comments
 
LVL 14

Expert Comment

by:Daniel Junges
ID: 10822193


HDC hDC = GetDC(hWnd);

CBitmap hBmp;
BOOL result = hBmp.CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);

0
 
LVL 48

Accepted Solution

by:
AlexFM earned 500 total points
ID: 10823515
Hi rossryan, I have some code which shows how we can create bitmap in unmanaged code and pass it to managed code. Unmanaged Dll creates bitmap, fills it with some image, and copies bitmap bits to pointer supplied by caller (C# application). Having this sample you can continue your work, changing pointer supplied by caller to memory-mapped file.

Create unmanaged C++ Win32 Dll BMPServer. Visual Studio creates two files in this project: BMPServer.h and BMPServer.cpp. Paste the following code to BMPServer.h (overwriting existing code):

#ifdef BMPSERVER_EXPORTS
#define BMPSERVER_API __declspec(dllexport)
#else
#define BMPSERVER_API __declspec(dllimport)
#endif

extern "C" BMPSERVER_API void CreateBMP(BYTE* pBits, int nWidth, int nHeight);

Paste the following code to BMPServer.cpp (overwriting existing code):

#include "stdafx.h"
#include "BMPServer.h"
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                               )
{
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
      break;
    }
    return TRUE;
}


BMPSERVER_API void CreateBMP(BYTE* pBits, int nWidth, int nHeight)
{
    LPBITMAPINFO lpbi;

    lpbi = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD))];
    lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    lpbi->bmiHeader.biWidth = nWidth;
    lpbi->bmiHeader.biHeight = nHeight;
    lpbi->bmiHeader.biPlanes = 1;
    lpbi->bmiHeader.biBitCount = 32; //24;
    lpbi->bmiHeader.biCompression = BI_RGB;
    lpbi->bmiHeader.biSizeImage = nWidth * nHeight; //    WIDTHBYTES((DWORD)nWidth * 8) * nHeight;
    lpbi->bmiHeader.biXPelsPerMeter = 0;
    lpbi->bmiHeader.biYPelsPerMeter = 0;
    lpbi->bmiHeader.biClrUsed = 0;
    lpbi->bmiHeader.biClrImportant = 0;

    BYTE* pTmp;

    HBITMAP hBitmap = CreateDIBSection(
        NULL,
        lpbi,
        DIB_RGB_COLORS,
        (void **)&pTmp,
        NULL,
        0 );

    delete[] lpbi;

    HDC hDC = CreateCompatibleDC(NULL);
    SelectObject(hDC, hBitmap);

    HPEN pen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
    HBRUSH brush = CreateSolidBrush(RGB(255, 255, 255));

    SelectObject(hDC, pen);
    SelectObject(hDC, brush);

    Rectangle(hDC, 0, 0, nWidth, nHeight);
    TextOut(hDC, 20, 20, "Hello", (int)strlen("Hello"));


    DWORD ImageSize = 4 * nWidth * nHeight;

    GetBitmapBits(hBitmap, ImageSize, pBits);


    DeleteObject(pen);
    DeleteObject(brush);

    DeleteObject(hBitmap);
    DeleteDC(hDC);
}

Create Windows C# application BMPClient and paste the following code to Form1.cs:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;
using System.IO;
using System.Drawing.Imaging;


namespace BMPClient
{
    /// <summary>
    /// Summary description for Form1.
    /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.PictureBox pictureBox1;
        private System.Windows.Forms.Button button1;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        public Form1()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            //
            // TODO: Add any constructor code after InitializeComponent call
            //
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.pictureBox1 = new System.Windows.Forms.PictureBox();
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            //
            // pictureBox1
            //
            this.pictureBox1.Location = new System.Drawing.Point(16, 24);
            this.pictureBox1.Name = "pictureBox1";
            this.pictureBox1.Size = new System.Drawing.Size(232, 136);
            this.pictureBox1.TabIndex = 0;
            this.pictureBox1.TabStop = false;
            //
            // button1
            //
            this.button1.Location = new System.Drawing.Point(72, 200);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(136, 32);
            this.button1.TabIndex = 1;
            this.button1.Text = "Run";
            this.button1.Click += new System.EventHandler(this.button1_Click);
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
            this.ClientSize = new System.Drawing.Size(264, 245);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.pictureBox1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }

        [DllImport ("BMPServer.dll")]
        public static extern void CreateBMP(IntPtr pBits, int nWidth, int nHeight);

        [DllImport ("Gdi32.dll")]
        public static extern Int32 SetBitmapBits(IntPtr hBmp, Int32 cbBytes, IntPtr lpBits);

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


        private void button1_Click(object sender, System.EventArgs e)
        {
            int nWidth = 200;
            int nHeight = 100;

            IntPtr pBitmapBits = Marshal.AllocHGlobal(nWidth*nHeight*4);

            CreateBMP(pBitmapBits, nWidth, nHeight);

            Bitmap bmp = new Bitmap(nWidth, nHeight, PixelFormat.Format32bppRgb);

            IntPtr hBitmap = bmp.GetHbitmap();

            SetBitmapBits(hBitmap, nWidth*nHeight*4, pBitmapBits);

            Bitmap bmpResult = Bitmap.FromHbitmap(hBitmap);

            DeleteObject(hBitmap);

            pictureBox1.Image = bmpResult;

            Marshal.FreeHGlobal(pBitmapBits);
        }
    }
}

Build both projects. Ensure that BMPServer.dll is available at runtime from BMPClient.exe and run C# client. Press the button and see result.
0
 

Author Comment

by:rossryan
ID: 10828783
Hmm, DIB. Very nice. On a previous discussion, things were getting out of hand (first we start up GDI+, then make the image, then shut it down...pain).

I'm going to merge this code with what I have after work.
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 

Author Comment

by:rossryan
ID: 10829187
//CPP
HWND hWnd = NULL;
HBITMAP hBmp = NULL;
HGDIOBJ hOld = NULL;
HDC hDCMem = NULL;
HANDLE hMap = NULL;
SapphireData* SapphireData;
HANDLE hSapphireData = NULL;
void* SapphireDataMap = NULL;
CPaintHook hook;




void HookWindow2(HWND hWnd)
{
      
      hMap = CreateFileMapping(INVALID_HANDLE_VALUE,    // current file handle
    NULL,                              // default security
    PAGE_READWRITE,                    // read/write permission
    0,                                 // max. object size
    0,                                 // size of hFile
    "SapphireFSwap");            // name of mapping object


      if (hMap != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
      {
    CloseHandle(hMap);
    hMap = NULL;
      }

      
      if (hMap != NULL)
      {
    CloseHandle(hMap);
    hMap = NULL;
      }
      SapphireDataMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, "SapphireFSwap");

      if (SapphireDataMap != NULL)
      {
      hSapphireData = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
      }
   
      if (hSapphireData != NULL)
      {
            SapphireData = (struct SapphireData*)hSapphireData;
      }
      

      

      
   

    hook.SubClass(hWnd);


    hDCMem = CreateCompatibleDC(NULL);

    RECT rect;

    GetWindowRect(hWnd, & rect);

    hBmp = NULL;

    {
        HDC hDC = GetDC(hWnd);
        hBmp = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);
        ReleaseDC(hWnd, hDC);
    }
      hOld = SelectObject(hDCMem, hBmp);

}

void UpdateWindow2()
{  
      GdiplusStartupInput gdiplusStartupInput;
      ULONG_PTR gdiplusToken;
      GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
      SendMessage(hWnd, WM_PRINT, (WPARAM) hDCMem, PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT | PRF_OWNED);
      SapphireData->SapphireSwap = Bitmap::FromHBITMAP(hBmp);
      //delete image;
    GdiplusShutdown(gdiplusToken);
    return 0;

}

void DestroyWindow2()
{

      
 

      SelectObject(hDCMem, hOld);
    DeleteObject(hDCMem);

      /*
    OpenClipboard(hWnd);
 
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hBmp);
    CloseClipboard();
      */

      if (hSapphireData)
      {
    UnmapViewOfFile(hSapphireData);
    SapphireData = NULL;
      }
      CloseHandle(SapphireDataMap);

}

//H
struct SapphireData
{
CBitmap SapphireSwap;
};





void CaptureWindow(HWND hWnd);
void HookWindow2(HWND hWnd);
void UpdateWindow2();
void DestroyWindow2();



Hmm. Aright, how do I redefine the above struct to carry the bits (or a full bitmap) into shared memory?


CreateBMP(BYTE* pBits, int nWidth, int nHeight)

Hmm. I have a handle to a bitmap (hBmp), not the bits, so, I'll probably have to lock memory to get them. Width and Height I can grab from getClientRect.
0
 

Author Comment

by:rossryan
ID: 10829461
I've got one other question for you Alex (not code related). I've told you about Sapphire, do you think it's pointless?

I mean, I've studied MS Task Gallery, Sun's Project Looking Glass, 3DOsX, 3DTop, 3DWM, LiteStep...the list goes on. I've looked at their interfaces, compared what I think are the best parts, considered whether they are relevant or a dead end.

What do you think?
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 10830466
I don't know nothing about Sapphire, so I cannot help here.

About your code:

hBmp = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);

Replace this with lines:

    LPBITMAPINFO lpbi;

    ...

    delete[] lpbi;

By this way you have DIB instead of DDB. Lines from my code:

    HDC hDC = CreateCompatibleDC(NULL);

    ...

    TextOut(hDC, 20, 20, "Hello", (int)strlen("Hello"));

are used to fill bitmap, you have your own code for this. Line:

   GetBitmapBits(hBitmap, ImageSize, pBits);

write bitmap bits to buffer supplied by called. Instead of this write bitmap bits to memory mapped file.
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now