Simple bitmap image in window

I am currently working on the simple idea of a motion tracker using c++, and one of the core components of this is to display the outcome. I know how to do all of the tracking and whatnot; my problem stems from my inability to output the data(a bitmap image) onto a window. I had no idea that this would present such a hurdle, mainly because I could program an image into a python program in one line easily. With c++ it seems to be a function maze to do something that simple, or at least that is how it seems. I have been looking at these sites to find the answer:
http://stackoverflow.com/questions/1754037/how-to-add-picture-box-in-win32-api-using-visual-c
http://msdn.microsoft.com/en-us/library/ms707853
(I have viewed upwards of 15 sites using google and forums so I believed that constitutes as "looked".)
I am using Dev C++, yes I know it is not as nice as visual c++ but I am using it. I am not too advanced in the field of programming so using small words would help immensely.
Just for reference, this is my ill-working code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <windows.h>

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)

{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = GetSysColorBrush(COLOR_3DFACE);

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Motion Tracker",    /* Title Text */
           WS_SYSMENU, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           800,                 /* The programs width */
           480,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nFunsterStil);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            CreateWindow(
                TEXT("button"),
                TEXT("Load"),
                WS_VISIBLE | WS_CHILD,
                10, 400, 80, 25,
                hwnd, (HMENU) 1, NULL, NULL
            );
 
            break;
        case WM_COMMAND:
            if (LOWORD(wParam) == 1) {
                MessageBox(hwnd, "Loaded", "Load", MB_OK | MB_ICONINFORMATION);
                //FIRST ATTEMPT
                //HBITMAP hImage = (HBITMAP) LoadImage(NULL, "curFrame.bmp", IMAGE_BITMAP, 500, 500, LR_LOADFROMFILE);
                //SendMessage(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hImage);
                
                //SECOND ATTEMPT
                /*HBITMAP hImage = (HBITMAP)LoadImage(NULL, (LPCSTR)"curFrame.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
                HDC hdcMem = CreateCompatibleDC(hDC); // hDC is a DC structure supplied by Win32API
                SelectObject(hdcMem, hImage);
                StretchBlt(
                        hDC,         // destination DC
                        0,        // x upper left
                        0,         // y upper left
                        100,       // destination width
                        100,      // destination height
                        hdcMem,      // you just created this above
                        0,
                        0,                      // x and y upper left
                        500,                      // source bitmap width
                        500,                      // source bitmap height
                        SRCCOPY);       // raster operation
                     */   

            }
            break; 
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

Thanks to anyone that helps.
I'm pretty sure that your problem stems from the lacking of code required to complete a task under Windows API compilation.

To load an image in Windows, like any other API mostly, you need to get a pointer to the image data itself(file). And then you'll need to blit the data(from memory)into the program's memory, and have it drawn onto the area of the window you desire.

I don't know how to do it in Windows API, but in SDL(SimpleDirect Media Layer API)I am pretty nooby, but capable of producing images and minimal control over them.

I know in SDL that you get a pointer to a surface where the image is to be loaded, then optimize another pointer to a surface to "draw" the image itself on to by blitting it(or putting it)on the screen with several functions handled and loops to keep repeating the data as the game input must be constant(I do game programming).

Hope I was at least minimally helpful!
Last edited on
Your 2nd attempt is really close. The only thing I see with it that's wrong is that (other than the potential for massive memory leaking) is that you're blitting to "hDC", but you never declare hDC.

You also should probably not draw in your WM_COMMAND message handler, but rather in the WM_PAINT message handler. Even if get this drawing to work this way, if you do something like alt-tab to another program, and switch back your your program, you will find your picture has been erased from the window. Windows will send your window a WM_PAINT message when this happens, which tells you that you need to redraw everything.

The "right" way to do it would be something like this. Note this is greatly simplified and could be improved many ways:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// give these a broad scope.  Global is the quick and dirty way to do it
HDC hdcMem = NULL;
HBITMAP hBmp = NULL;
HBITMAP hBmpOld = NULL;

// call this function once in your WM_COMMAND handler, or wherever you want the image to be loaded
void LoadPic()
{
  if(hdcMem)
    return;  // already loaded, no need to load it again

  // note:  here you must put the file name in a TEXT() macro.  DO NOT CAST IT TO LPCSTR
  hBmp = (HBITMAP)LoadImage(NULL, TEXT("curFrame.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );

  if(!hBmp)  // the load failed (couldn't find file?  Invalid file?)
    return;

  hdcMem = CreateCompatibleDC(NULL);
  hBmpOld = (HBITMAP)SelectObject(hdcMem, hBmp);
}

// call this function when the program is done (shutting down)
void FreePic()
{
  if(hdcMem)
  {
    SelectObject(hdcMem, hBmpOld);
    DeleteObject(hBmp);
    DeleteDC(hdcMem);
  }
}

// ...

// do this in your WM_COMMAND message handler (when you want to load the image):
LoadPic();  // call our LoadPic function to load the image
InvalidateRect(hwnd,NULL);  // tell the window it needs to redraw (sends a WM_PAINT message)

// ...

// do this in your WM_PAINT message handler:
PAINTSTRUCT ps;
HDC screen = BeginPaint(hwnd,&ps);
StretchBlt( screen, ... /* fill in your coords and junk here */ );
EndPaint( hwnd, &ps );



As you might notice, creation cleanup of these HDCs/HBITMAPs is a large chunk of code. What's more, you'll probably want to use it in more than one place. Therefore I recommend putting it all in a class.
Last edited on
Disch, that code doesn't make any sense. How is it specifying any form of coordinates or ways of gathering an area to blit the image to the window? Or blitting it in any way at all?
How is it specifying any form of coordinates or ways of gathering an area to blit the image to the window?


It's not. I commented that part out. See line 44:

StretchBlt( screen, ... /* fill in your coords and junk here */ );

Note the comment. I didn't feel like plugging in his numbers. He can do that on his own.

Or blitting it in any way at all?


With the StretchBlt line. See line 44:

StretchBlt( screen, ... /* fill in your coords and junk here */ );

That's a blit.
Thank you Disch, your replay worked perfectly.
Okay, I know I am bringing back a dead horse, but I have some questions dealing with displaying images again.
I have been monkeying around with this new code. I am trying to understand the information flow when using the hdcMem. I don't seem to grasp why I cannot select a HBITMAP that I stored in a variable. The problem starts at line 140. Could someone explain HDC and the information flow to me, in itty bitty words, because I have attempted to research it on my own and I have gotten nowhere with making it work properly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#include <windows.h>
#include <vfw.h>
#include <stdio.h>
#pragma comment(lib,"vfw32.lib")
#pragma comment(lib,"gdi32.lib")

LRESULT CALLBACK WindowProc (HWND, UINT, WPARAM, LPARAM);
PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp);
void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);

char szAppName [] = TEXT("Motion Tracker");
HWND camhwnd;
HDC hdc ;
HDC hdcMem;
PAINTSTRUCT ps;
HBITMAP hbm;
RECT rc;
//Globals for the frame comparison
HBITMAP curFrame, lasFrame = NULL, bakFrame;
//WinMain -- Main Window
int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow )
{

    HWND hwnd;
    MSG msg;

    WNDCLASS wc;
    wc.style = CS_HREDRAW|CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
    wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szAppName;

    RegisterClass (&wc);

// Create the window
    hwnd = CreateWindow (szAppName,
		                 szAppName,
						 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,
						 CW_USEDEFAULT,
						 CW_USEDEFAULT,
						 775,525,0,0,
						 hInstance,0);

    ShowWindow (hwnd,SW_SHOW);
    UpdateWindow (hwnd);

    while (GetMessage(&msg,0,0,0))
    {
        if (!IsDialogMessage(hwnd, &msg))
        {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
        }
    }
    return msg.wParam;
}

//Main Window Procedure WindowProc
LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);

//some buttons
    HWND hButtStartCam;
    HWND hButtStopCam;
    HWND hButtGrabFrame;

    switch (message)                  /* handle the messages */
    {

    case WM_CTLCOLORSTATIC:
        SetBkMode(hdc,TRANSPARENT);
        return (LRESULT)CreateSolidBrush(0xFFFFFF);

    case WM_CREATE:
    {
        hButtStartCam = CreateWindowEx(0,"BUTTON","Start Camera",WS_CHILD | WS_VISIBLE,
                                       10,120,100,20,hwnd,(HMENU)1,hInstance, 0);
        hButtStopCam = CreateWindowEx(0,"BUTTON","Stop Camera",WS_CHILD | WS_VISIBLE,
                                      10,160,100,20,hwnd,(HMENU)2,hInstance, 0);
        hButtGrabFrame = CreateWindowEx(0,"BUTTON","Grab Frame",WS_CHILD | WS_VISIBLE,
                                        10,200,100,20,hwnd,(HMENU)3,hInstance, 0);

        camhwnd = capCreateCaptureWindow ("camera window", WS_CHILD , 10, 10, 100, 100, hwnd, 0);
		SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
        SendMessage(camhwnd,WM_CAP_DLG_VIDEOSOURCE,0,0);
        break;
    }

    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {

        case 1:
        {
            ShowWindow(camhwnd,SW_SHOW);
            SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
            SendMessage(camhwnd, WM_CAP_SET_SCALE, true , 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEW, true , 0);
            break;
        }

        case 2:
        {
            ShowWindow(camhwnd,SW_HIDE);
            SendMessage(camhwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
            break;
        }

        case 3:
        {
			//Grab a Frame
            SendMessage(camhwnd, WM_CAP_GRAB_FRAME, 0, 0);
			//Copy the frame we have just grabbed to the clipboard
            SendMessage(camhwnd, WM_CAP_EDIT_COPY,0,0);
			//Copy the clipboard image data to a HBITMAP object called hbm

            hdc = BeginPaint(camhwnd, &ps);
            hdcMem = CreateCompatibleDC(hdc);
            if (hdcMem != NULL)
            {
                if (OpenClipboard(camhwnd))
                {
                    hbm = (HBITMAP) GetClipboardData(CF_BITMAP);
                    SelectObject(hdcMem, hbm);
                    GetClientRect(camhwnd, &rc);
                    CloseClipboard();
                }
            }
			////////////////
			//PROBLEM AREA//
			///////////////
			lasFrame = curFrame;
			curFrame = hbm;
			
			DeleteDC(hdcMem);
			hdcMem = CreateCompatibleDC(NULL);
			SelectObject(hdcMem,lasFrame);
			///////////////
			InvalidateRect(hwnd,NULL,true);  // tell the window it needs to redraw (sends a WM_PAINT message)

            SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
            SendMessage(camhwnd, WM_CAP_SET_SCALE, true , 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEW, true , 0);
            break;
        }
        }
        break;
    }

    case WM_DESTROY:
    {
        SendMessage(camhwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
        PostQuitMessage(0);   /* send a WM_QUIT to the message queue */
        break;
    }
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC screen = BeginPaint(hwnd,&ps);
		StretchBlt( screen,         // destination DC
                    120,        // x upper left
                    10,         // y upper left
                    640,//384,       // destination width
                    480,//288,      // destination height
                    hdcMem,      // you just created this above
                    0,
                    0,                      // x and y upper left
                    640,                      // source bitmap width
                    480,                      // source bitmap height
                    SRCCOPY);       // raster operation
		EndPaint( hwnd, &ps );
	}
    default:              /* for messages that we don't deal with */
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}
1
2
3
4
5
lasFrame = curFrame; // this is crazy.  Don't do this.  There is little reason to keep track of
curFrame = hbm;  // previous frames. (why are you doing it?)
			
DeleteDC(hdcMem);  // <- why are you deleting the DC...
hdcMem = CreateCompatibleDC(NULL); // <- only to recreate it? 


Could someone explain HDC and the information flow to me, in itty bitty words, because I have attempted to research it on my own and I have gotten nowhere with making it work properly.


The best way I can explain it is through analogy. Think of an offscreen DC as sort of an art easel, and a Bitmap is like a piece of paper.

In order to do anything with a bitmap, it needs to be selected into a DC. But a DC is more than just a bitmap. It also has other things, like a pen, a brush, a font, etc, etc.

When you call SelectObject and give it an HBITMAP, 2 things happen:

1) The HBITMAP that is currently in the DC is removed (but not destroyed! it still exists, it just isn't in the DC anymore -- like taking the piece of paper off an easel -- the paper still exists)

2) The new HBITMAP is placed in the DC



When you destroy a DC with DeleteDC, to avoid leaks/strange behavior, you MUST make sure the DC is exactly as it was when you created it. That means the bitmap that was in it when created is selected back into it before it is deleted. Any other things that you did SelectObject on must also be restored (like Pens, Brushes, etc).

Here's a typical example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
HDC dc = /*create a DC somehow */

HBITMAP newbitmap = /* Create bitmap somehow */
HBITMAP originalbitmap = (HBITMAP)SelectObject(dc,newbitmap);

// here, 'newbitmap' is in our 'dc'
// 'originalbitmap' is the bitmap that was originally in the dc upon creation.
// when it's time to clean up, we must restore the dc to its original state
//  we do this by putting the original bitmap back in the dc


SelectObject(dc, originalbitmap);

// here, newbitmap is no longer in 'dc', because 'originalbitmap' is in 'dc'
// so it's OK to delete 'dc'
DeleteDC(dc);

// it's also OK to delete newbitmap because it's not in any DC anymore
//  note:  do this only if you were responsible for creating newbitmap!
DeleteObject(newbitmap);

// however, we do NOT delete originalbitmap, because we never created it.
//  we only clean up the things we create. 




If you're getting a bitmap from another source (like from the clipboard), what you would do is similar:

1
2
3
4
5
6
7
8
9
HDC dc = /*create a dc*/
HBITMAP bitmap = /*get the bitmap from the clipboard */
HBITMAP old = (HBITMAP)SelectObject(dc,bitmap);

// do whatever with 'dc' here, blit it to another DC or whatever

SelectObject(dc,old);
DeleteDC(dc);
 // DeleteObject(bitmap); // <- ???  See below! 


I'm not sure if you are responsible for deleting a bitmap that you get from the clipboard. Read the documentation for GetClipboardData.

If you aren't responsible for cleanup, it's possible that the bitmap is being destroyed when you close the clipboard, which would make your HBITMAP invalid.
in the line:
1
2
lasFrame = curFrame;
curFrame = hbm;

I am keeping track of the previous frames because I am going to compare them later. I want to display the bitmap in lasFrame, so that I know it exists.
Last edited on
Newest Attempt:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
case 3:
        {
			//Grab a Frame
            SendMessage(camhwnd, WM_CAP_GRAB_FRAME, 0, 0);
			//Copy the frame we have just grabbed to the clipboard
            SendMessage(camhwnd, WM_CAP_EDIT_COPY,0,0);
			//Copy the clipboard image data to a HBITMAP object called hbm

            hdc = BeginPaint(camhwnd, &ps);
            hdcMem = CreateCompatibleDC(hdc);
            if (hdcMem != NULL)
            {
                if (OpenClipboard(camhwnd))
                {
                    hbm = (HBITMAP) GetClipboardData(CF_BITMAP);
					lasFrame = curFrame;
					curFrame = hbm;
                    SelectObject(hdcMem, hbm);
                    GetClientRect(camhwnd, &rc);
                    CloseClipboard();
                }
            }
			
			InvalidateRect(hwnd,NULL,true);  // tell the window it needs to redraw (sends a WM_PAINT message)


            SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
            SendMessage(camhwnd, WM_CAP_SET_SCALE, true , 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEW, true , 0);
            break;
        }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC screen = BeginPaint(hwnd,&ps);
		hdcMem = CreateCompatibleDC(screen);
		bufFrame = (HBITMAP)SelectObject(hdcMem, curFrame);
		SelectObject(hdcMem, lasFrame);
		StretchBlt( screen,         // destination DC
                    120,        // x upper left
                    10,         // y upper left
                    640,//384,       // destination width
                    480,//288,      // destination height
                    hdcMem,      // you just created this above
                    0,
                    0,                      // x and y upper left
                    640,                      // source bitmap width
                    480,                      // source bitmap height
                    SRCCOPY);       // raster operation
		SelectObject(hdcMem,bufFrame);
		DeleteDC(hdcMem);
		EndPaint( hwnd, &ps );
	}

(Those are the parts that I changed)

Still doesn't work.
Describe "doesn't work"

What are you expecting to happen? What is actually happening?
What I want to happen is for it to grab an image from the webcam, which it does and works perfectly. The next time it takes a picture I want it to store the last image for use when comparing movement. The last thing I want it to do is display the old image. (The idea of displaying the old image was originally to see that the variable held the old image, but I will need to understand hdc anyway.) right now it is not displaying any image when you press grab. If you remove the code:
1
2
3
4
5
6
hdcMem = CreateCompatibleDC(screen);
bufFrame = (HBITMAP)SelectObject(hdcMem, curFrame);
SelectObject(hdcMem, lasFrame);
. . .
SelectObject(hdcMem,bufFrame);
DeleteDC(hdcMem);

It will print out the current image from the cam.
Okay I think I see the problem.

1
2
3
4
5
6
7
case 3:
        {
            SendMessage(camhwnd, WM_CAP_GRAB_FRAME, 0, 0);
            SendMessage(camhwnd, WM_CAP_EDIT_COPY,0,0);

            hdc = BeginPaint(camhwnd, &ps);  // <-  !!!!!!!!!!
            hdcMem = CreateCompatibleDC(hdc);


There are several things wrong with this.

#1 is you should only call BeginPaint when you are painting (ie: in the WM_PAINT message handler). It's possible, since there are no paint messages pending, that BeginPaint is giving you a worthless DC.

#2 you have no matching EndPaint call. Every BeginPaint must have a matching EndPaint, just like every new must have a matching delete, every CreateDC must have a matching DeleteDC, etc.

#3 you don't need the screen DC here anyway. CreateCompatibleDC(NULL) will create a DC that matches the current display... but that doesn't really matter because....

#4 you don't need to (and shouldn't) be repeatedly destroying and recreating this DC. I would just do it once at program startup and destroy it once at program shutdown. Constantly tearing it down and rebuilding it is not only way more complicated but also it hurts performance.



Also, I don't see ANY DeleteObject() calls in your code, so you might be leaking MASSIVE memory. A 640x480 image is about 1 MB, which means that every time you capture an image your program leaks 1 MB of memory. Do it a few dozen times while keeping an eye on your program's memory usage in task manager -- you'll probably see it climb steadily.
My program only ever seems to work when I use curFrame in the dc and not lasFrame, is there a reason for that?.
This code works (Displays curFrame):
1
2
3
4
5
6
7
8
9
10
11
12
13
bufFrame = (HBITMAP)SelectObject(hdcMem, curFrame);
		SelectObject(hdcMem, curFrame);
		StretchBlt( screen,         // destination DC
                    120,        // x upper left
                    10,         // y upper left
                    640,//384,       // destination width
                    480,//288,      // destination height
                    hdcMem,      // you just created this above
                    0,
                    0,                      // x and y upper left
                    640,                      // source bitmap width
                    480,                      // source bitmap height
                    SRCCOPY);       // raster operation 


This code doesn't work (Doesn't display lasFrame):
1
2
3
4
5
6
7
8
9
10
11
12
13
bufFrame = (HBITMAP)SelectObject(hdcMem, lasFrame);
		SelectObject(hdcMem, lasFrame);
		StretchBlt( screen,         // destination DC
                    120,        // x upper left
                    10,         // y upper left
                    640,//384,       // destination width
                    480,//288,      // destination height
                    hdcMem,      // you just created this above
                    0,
                    0,                      // x and y upper left
                    640,                      // source bitmap width
                    480,                      // source bitmap height
                    SRCCOPY);       // raster operation 
Last edited on
Well I don't quite know why but if I display both curFrame and lasFrame, it works fine. So I am happy with how it turned out. Thank you so much Disch, again. Your ability to put up with all my questions is amazing, I cannot thank you enough for helping me understand the exciting world of hdc.

If anyone is searching this up on google here is the final code I achieved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <windows.h>
#include <vfw.h>
#include <stdio.h>
#pragma comment(lib,"vfw32.lib")
#pragma comment(lib,"gdi32.lib")
//Remember to Link to vfw32 Library, gdi32 Library

LRESULT CALLBACK WindowProc (HWND, UINT, WPARAM, LPARAM);
PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp);
void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);

char szAppName [] = TEXT("Motion Tracker");
HWND camhwnd;
HDC hdcMem = CreateCompatibleDC(NULL);
PAINTSTRUCT ps;
HBITMAP hbm;
//Globals for the frame comparison
HBITMAP curFrame = NULL, lasFrame = NULL, bakFrame = NULL, bufFrame = NULL;
//WinMain -- Main Window
int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow )
{

    HWND hwnd;
    MSG msg;

    WNDCLASS wc;
    wc.style = CS_HREDRAW|CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
    wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szAppName;

    RegisterClass (&wc);

// Create the window
    hwnd = CreateWindow (szAppName,
		                 szAppName,
						 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,
						 CW_USEDEFAULT,
						 CW_USEDEFAULT,
						 775,525,0,0,
						 hInstance,0);

    ShowWindow (hwnd,SW_SHOW);
    UpdateWindow (hwnd);

    while (GetMessage(&msg,0,0,0))
    {
        if (!IsDialogMessage(hwnd, &msg))
        {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
        }
    }
    return msg.wParam;
}

//Main Window Procedure WindowProc
LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);

//some buttons
    HWND hButtStartCam;
    HWND hButtStopCam;
    HWND hButtGrabFrame;

    switch (message)                  /* handle the messages */
    {
    case WM_CREATE:
    {
        hButtStartCam = CreateWindowEx(0,"BUTTON","Start Camera",WS_CHILD | WS_VISIBLE,
                                       10,120,100,20,hwnd,(HMENU)1,hInstance, 0);
        hButtStopCam = CreateWindowEx(0,"BUTTON","Stop Camera",WS_CHILD | WS_VISIBLE,
                                      10,160,100,20,hwnd,(HMENU)2,hInstance, 0);
        hButtGrabFrame = CreateWindowEx(0,"BUTTON","Grab Frame",WS_CHILD | WS_VISIBLE,
                                        10,200,100,20,hwnd,(HMENU)3,hInstance, 0);

        camhwnd = capCreateCaptureWindow ("camera window", WS_CHILD , 10, 10, 100, 100, hwnd, 0);
		SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
        SendMessage(camhwnd,WM_CAP_DLG_VIDEOSOURCE,0,0);
        break;
    }

    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {

        case 1:
        {
            ShowWindow(camhwnd,SW_SHOW);
            SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
            SendMessage(camhwnd, WM_CAP_SET_SCALE, true , 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEW, true , 0);
            break;
        }

        case 2:
        {
            ShowWindow(camhwnd,SW_HIDE);
            SendMessage(camhwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
            break;
        }

        case 3:
        {
			//Grab a Frame
            SendMessage(camhwnd, WM_CAP_GRAB_FRAME, 0, 0);
			//Copy the frame we have just grabbed to the clipboard
            SendMessage(camhwnd, WM_CAP_EDIT_COPY,0,0);
			//Copy the clipboard image data to a HBITMAP object called hbm
			if (OpenClipboard(camhwnd))
            {
				if (curFrame != NULL) {
					lasFrame = curFrame;
				}
                curFrame = (HBITMAP) GetClipboardData(CF_BITMAP);
                CloseClipboard();
            }
			
			InvalidateRect(hwnd,NULL,true);  // tell the window it needs to redraw (sends a WM_PAINT message)


            SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
            SendMessage(camhwnd, WM_CAP_SET_SCALE, true , 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEW, true , 0);
            break;
        }
        }
        break;
    }
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC screen = BeginPaint(hwnd,&ps);
		if (lasFrame != NULL) {
			bufFrame = (HBITMAP)SelectObject(hdcMem, lasFrame);
			SelectObject(hdcMem, lasFrame);
			StretchBlt(screen,         // destination DC
						120,        // x upper left
						10,         // y upper left
						256,       // destination width
						192,      // destination height
						hdcMem,      // you just created this above
						0,
						0,                      // x and y upper left
						640,                      // source bitmap width
						480,                      // source bitmap height
						SRCCOPY);       // raster operation
		}
		bufFrame = (HBITMAP)SelectObject(hdcMem, curFrame);
		SelectObject(hdcMem, curFrame);
		StretchBlt(screen,         // destination DC
                    386,        // x upper left
                    10,         // y upper left
                    256,       // destination width
                    192,      // destination height
                    hdcMem,      // you just created this above
                    0,
                    0,                      // x and y upper left
                    640,                      // source bitmap width
                    480,                      // source bitmap height
                    SRCCOPY);       // raster operation
		EndPaint( hwnd, &ps );
		break;
	}
	case WM_DESTROY:
    {
		SelectObject(hdcMem, bufFrame);
		DeleteDC(hdcMem);
		DeleteObject(curFrame);
		DeleteObject(lasFrame);
        SendMessage(camhwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
        PostQuitMessage(0);   /* send a WM_QUIT to the message queue */
        break;
    }
    default:              /* for messages that we don't deal with */
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}
Topic archived. No new replies allowed.