Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Bitmaps, from handles (HBitmap, Hbmp)

Posted on 2004-04-14
6
Medium Priority
?
1,368 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 2000 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 does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 

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

Ask an Anonymous Question!

Don't feel intimidated by what you don't know. Ask your question anonymously. It's easy! Learn more and upgrade.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

782 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