BITMAP Image won't load from file "INVALID HANDLE" - winapi

This is basic, so only one snippet of code from the drawing function is needed because it has the info necessary about the
void draw()
{
RECT rect;
GetClientRect(hwnd, &rect);
HBITMAP FRAME1ANIMDASH = NULL;
FRAME1ANIMDASH = (HBITMAP) LoadImage(NULL, "Hidden but correct pathname that won't be shown here", 0, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_CREATEDIBSECTION);
if(FRAME1ANIMDASH == NULL)
{
MessageBox(NULL, "CANNOT LOAD", "CANNOT LOAD", MB_OK);
}
HDC device;
PAINTSTRUCT ps;
BITMAP bm;
GetObject(FRAME1ANIMDASH,sizeof(BITMAP),&bm);
HDC hdcdevice=CreateCompatibleDC(device);
SelectObject(hdcdevice,FRAME1ANIMDASH);
BitBlt(device,0,0,0,0,hdcdevice,0,0,SRCCOPY);
UpdateWindow(hwnd);
device=GetDC(hwnd);
DeleteDC(hdcdevice);
DeleteObject((HBITMAP) FRAME1ANIMDASH);
DWORD lastError = GetLastError();
cout << GetLastError();
}
Get last error shows error 6, which is an invalid file handle. The message box shows up, which means the image never loaded and failed, so the code after it is not the primary concern yet.
I am trying to load a bitmap and put it on the Win32 window I have created.
No other code is needed, as there's nothing specific about any other code that would lead to a possible answer overall. Tell me what I can do to make the image load successfully.

You are calling GetLastError() too late. The error code is meaningless at that point as it could be overwritten by any of the other functions you are calling. You must call GetLastError() immediately after LoadImage() fails:
HBITMAP FRAME1ANIMDASH = (HBITMAP) LoadImage(...);
if (FRAME1ANIMDASH == NULL)
{
DWORD lastError = GetLastError();
cout << "CANNOT LOAD IMAGE, ERROR " << lastError;
MessageBox(NULL, "CANNOT LOAD IMAGE", "CANNOT LOAD IMAGE", MB_OK);
return; // <-- add this, too!
}
And the reason why LoadImage() is failing is because you are not specifying the LR_LOADFROMFILE flag, and not requesting the image size correctly, per the LoadImage() documentation:
lpszName [in]
...
If the hinst parameter is NULL and the fuLoad parameter omits the LR_LOADFROMFILE value, the lpszName specifies the OEM image to load. The OEM image identifiers are defined in Winuser.h and have the following prefixes.
...
If the fuLoad parameter includes the LR_LOADFROMFILE value, lpszName is the name of the file that contains the stand-alone resource (icon, cursor, or bitmap file). Therefore, set hinst to NULL.
...
cxDesired [in]
...
... If this parameter is zero and LR_DEFAULTSIZE is not used, the function uses the actual resource width.
...
cyDesired [in]
...
... If this parameter is zero and LR_DEFAULTSIZE is not used, the function uses the actual resource height.
...
fuLoad [in]
...
LR_DEFAULTSIZE
... If this flag is not specified and cxDesired and cyDesired are set to zero, the function uses the actual resource size.
...
LR_LOADFROMFILE
... Loads the stand-alone image from the file specified by lpszName (icon, cursor, or bitmap file).
So it should look more like this:
HBITMAP FRAME1ANIMDASH = (HBITMAP) LoadImage(NULL, "pathname", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
Once you fix that, there are other problems with the code.
You are calling CreateCompatibleDC() with an uninitialized HDC variable, and not checking the result of CreateCompatibleDC() for failure. Your call to GetDC() is in the wrong place, it needs to be moved above CreateCompatibleDC(). And you are leaking the HDC that GetDC() returns, you need to call ReleaseDC() to free it.
You are also telling BitBlt() to copy a 0x0 rectangle of pixels, instead of using the true dimensions of the bitmap from the BITMAP structure, or even the window RECT that you are retrieving from GetClientRect().
Try something more like this instead:
void draw()
{
HBITMAP FRAME1ANIMDASH = (HBITMAP) LoadImage(NULL, "pathname", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
if (FRAME1ANIMDASH == NULL)
{
DWORD lastError = GetLastError();
cout << "CANNOT LOAD IMAGE, ERROR " << lastError;
MessageBox(NULL, "CANNOT LOAD IMAGE", "CANNOT LOAD IMAGE", MB_OK);
return;
}
HDC hdcWnd = GetDC(hwnd);
if (hdcWnd === NULL)
{
DeleteObject(FRAME1ANIMDASH);
cout << "CANNOT GET WINDOW DC";
MessageBox(NULL, "CANNOT GET WINDOW DC", "CANNOT GET DC", MB_OK);
return;
}
HDC hdcMem = CreateCompatibleDC(hdcWnd);
if (hdcMem == NULL)
{
ReleaseDC(hwnd, hdcWnd);
DeleteObject(FRAME1ANIMDASH);
cout << "CANNOT CREATE COMPATIBLE DC";
MessageBox(NULL, "CANNOT CREATE COMPATIBLE DC", "CANNOT CREATE DC", MB_OK);
return;
}
BITMAP bm;
GetObject(FRAME1ANIMDASH, sizeof(BITMAP), &bm);
HBITMAP oldBm = (HBITMAP) SelectObject(hdcMem, FRAME1ANIMDASH);
BitBlt(hdcWnd, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, oldBm);
DeleteDC(hdcMem);
ReleaseDC(hwnd, hdcWnd);
DeleteObject(FRAME1ANIMDASH);
UpdateWindow(hwnd);
}
That being said, the PAINTSTRUCT variable implies that your code is being used inside of a WM_PAINT message handler. If that is true, you should be using BeginPaint() instead of GetDC() to get the target HDC to draw on:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
draw(hdc);
EndPaint(hwnd, &ps);
break;
};
void draw(HDC hdcTarget)
{
HBITMAP FRAME1ANIMDASH = (HBITMAP) LoadImage(NULL, "pathname", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
if (FRAME1ANIMDASH == NULL)
{
DWORD lastError = GetLastError();
cout << "CANNOT LOAD IMAGE, ERROR " << lastError;
// DO NOT use MessageBox() in a WM_PAINT handler,
// You will trigger an endless re-paint loop!
return;
}
HDC hdcMem = CreateCompatibleDC(hdcTarget);
if (hdcMem == NULL)
{
DeleteObject(FRAME1ANIMDASH);
cout << "CANNOT CREATE COMPATIBLE DC";
return;
}
BITMAP bm;
GetObject(FRAME1ANIMDASH, sizeof(BITMAP), &bm);
HBITMAP oldBm = (HBITMAP) SelectObject(hdcMem, FRAME1ANIMDASH);
BitBlt(hdcWnd, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, oldBm);
DeleteDC(hdcMem);
DeleteObject(FRAME1ANIMDASH);
}
Otherwise, if you are using your code outside of WM_PAINT, then the code is pretty much useless because UpdateWindow() will trigger a re-paint that erases your drawing. Persistent drawings on a window must be done using WM_PAINT (unless you are using UpdateLayeredWindow() with a WS_EX_LAYERED window).

Related

How to place GDI+ Bitmap onto the clipboard?

I want to place a GDI+ Bitmap onto the clipboard. The obvious way would be to:
use Bitmap.GetHBITMAP to create an HBITMAP
use SetClipboardData to place the HBITMAP onto the clipboard as a CF_BITMAP
So i try pseudo-code:
void PlaceBitmapOnClipboard(Bitmap image)
{
//Convert GDI+ Bitmap to GDI Bitmap
HBITMAP bmp;
image.GetHBITMAP(0, #bmp);
OpenClipboard(this.Handle);
EmptyClipboard();
SetClipboardData(CF_BITMAP, bmp);
CloseClipboard();
}
Error checking has been omitted for expository purposes; but neither function fails:
Not GetHBITMAP and its HRESULT style error
Nor does SetClipboardData return a null
But when i try to use the CF_BITMAP on the clipboard, it can't be pasted into Paint:
So, what is the correct code to fill in the function:
void PlaceBitmapOnClipboard(Bitmap image)
{
//TODO: Ask Stackoverflow to figure this out
}
We need to call:
SetClipboardData(CF_BITMAP, hbitmap_ddb)
Where hbitmap_ddb must be a compatible bitmap (DDB), not DIB which we get from Gdiplus::GetHBitmap
Or we call:
SetClipboardData(CF_DIB, hmemory)
Where hmemory is not HBITMAP. hmemory is described in documentation as:
A memory object containing a BITMAPINFO structure followed by the
bitmap bits.
Example using CF_BITMAP
Use CreateDIBitmap to create a compatible bitmap based on our DIB bitmap. Then call SetClipboardData with the new DDB bitmap.
Gdiplus::Bitmap gdibmp(L"file.bmp");
if(gdibmp.GetLastStatus() != Gdiplus::Ok)
return;
HBITMAP hbitmap;
auto status = gdibmp.GetHBITMAP(0, &hbitmap);
if(status != Gdiplus::Ok)
return;
BITMAP bm;
GetObject(hbitmap, sizeof bm, &bm);
DIBSECTION ds;
if(sizeof ds == GetObject(hbitmap, sizeof ds, &ds))
{
HDC hdc = GetDC(NULL);
HBITMAP hbitmap_ddb = CreateDIBitmap(hdc, &ds.dsBmih, CBM_INIT,
ds.dsBm.bmBits, (BITMAPINFO*)&ds.dsBmih, DIB_RGB_COLORS);
ReleaseDC(NULL, hdc);
if(OpenClipboard(hwnd))
{
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbitmap_ddb);
CloseClipboard();
}
DeleteObject(hbitmap_ddb);
}
DeleteObject(hbitmap);
Example using CF_DIB
Use GlobalAlloc to allocate memory, and copy BITMAPINFOHEADER to that memory, followed by the bits. There is no need to worry about the color table, because Gdiplus::HBitmap returns 32-bit bitmap (at least on modern displays as far as I know)
Gdiplus::Bitmap gdibmp(L"file.bmp");
if(gdibmp.GetLastStatus() != Gdiplus::Ok)
return;
HBITMAP hbitmap;
auto status = gdibmp.GetHBITMAP(NULL, &hbitmap);
if(status != Gdiplus::Ok)
return;
BITMAP bm;
GetObject(hbitmap, sizeof bm, &bm);
BITMAPINFOHEADER bi =
{ sizeof bi, bm.bmWidth, bm.bmHeight, 1, bm.bmBitsPixel, BI_RGB };
std::vector<BYTE> vec(bm.bmWidthBytes * bm.bmHeight);
auto hdc = GetDC(NULL);
GetDIBits(hdc, hbitmap, 0, bi.biHeight, vec.data(), (BITMAPINFO*)&bi, 0);
ReleaseDC(NULL, hdc);
auto hmem = GlobalAlloc(GMEM_MOVEABLE, sizeof bi + vec.size());
auto buffer = (BYTE*)GlobalLock(hmem);
memcpy(buffer, &bi, sizeof bi);
memcpy(buffer + sizeof bi, vec.data(), vec.size());
GlobalUnlock(hmem);
if(OpenClipboard(hwnd))
{
EmptyClipboard();
SetClipboardData(CF_DIB, hmem);
CloseClipboard();
}
DeleteObject(hbitmap);

How to open an image from menu and display on win 32 program?

I have created a simple win32 application to open the dialog from menu, select the bitmap image and display or paint it on window. Now the problem I am facing is that when I get the filename from GetOpenFileName method and pass it to LoadImage function, the image couldn't be loaded. But if I pass the file path "D:/Splash.bmp" directly into the function parameter, the image is loaded. The problem is that GetOpenFileName method gives "D:\Splash.bmp" as path while the program is working with "D:/Splash.bmp". What could be the error?
Here is the code:
//Win32Bitmap.cpp : Defines the entry point for the application.//
#include "stdafx.h"
#include "Win32Bitmap.h"
#include<Windows.h>
#include <Commdlg.h>
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32BITMAP, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32BITMAP));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32BITMAP));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32BITMAP);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
bool LoadAndBlitBitmap(LPTSTR szFileName, HDC hdcWin)
{
HBITMAP hbitmap;
hbitmap = (HBITMAP)LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (hbitmap == NULL)
{
MessageBox(NULL, L"Image couldn't be loaded", L"Error", MB_OK | MB_ICONEXCLAMATION);
return false;
}
//create a memory device context that is compatible with the window
HDC hdclocal = CreateCompatibleDC(hdcWin);
if (hdclocal == NULL)
{
MessageBox(NULL, L"device context not created", L"Error", MB_OK | MB_ICONEXCLAMATION);
return false;
}
//get the bitmap's parameters and verify the get
BITMAP qbitmap;
int ireturn = GetObject(reinterpret_cast<HGDIOBJ>(hbitmap), sizeof(BITMAP), reinterpret_cast<LPVOID>(&qbitmap));
if (!ireturn)
{
MessageBox(NULL, L"Get object failed", L"Error", MB_OK | MB_ICONEXCLAMATION);
return false;
}
//select the loaded bitmap into the device context
HBITMAP holdbitmap = (HBITMAP)SelectObject(hdclocal, hbitmap);
if (holdbitmap==NULL)
{
MessageBox(NULL, L"Get object failed", L"Error", MB_OK | MB_ICONEXCLAMATION);
return false;
}
//transfer the device context from the memory device context to the windows context(actual drawing surface)
bool qRetBlit = BitBlt(hdcWin, 0, 0, qbitmap.bmWidth, qbitmap.bmHeight, hdclocal, 0, 0, SRCCOPY);
if (!qRetBlit)
{
MessageBox(NULL, L"bitblt failed", L"Error", MB_OK | MB_ICONEXCLAMATION);
return false;
}
//deallocate the resources
SelectObject(hdclocal, holdbitmap);
DeleteDC(hdclocal);
DeleteObject(hbitmap);
return true;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
wchar_t szFileName[MAX_PATH] = L"";
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case ID_FILE_OPEN:
{
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn); // SEE NOTE BELOW
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = L"Bitmap Files (*.bmp)\0*.bmp\0All Files (*.*)\0*.*\0";
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = L"bmp";
if (GetOpenFileName(&ofn))
{
MessageBox(NULL, szFileName, L"path", MB_OK);
//InvalidateRect(hWnd, 0, TRUE);
}
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
LoadAndBlitBitmap(L"D:/Splash.bmp", hdc);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
The backslash is not the problem. In fact, windows prefers backslash over forward slash. Your problem is the fact that you have made your szFileName buffer local to window procedure function (WndProc). When you click menu item to select a file, message WM_COMMAND is sent to the window and handled by this its window procedure. You have correctly implemented opening of dialog and retrieving the file path. However, when this handling is complete, function WndProc exits and destroys all local variables from the stack, including the file path contained in szFileName.
To fix your problem, make szFileName a global variable so it does not get destroyed. Also note that the window will not update itself automatically after you select the image file, you need to instruct the window to repaint itself by adding this code after the call to GetOpenFileName:
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
This will invalidate the entire window region and schedule a repainting of window (this means that message WM_PAINT will again be sent to the window and handled by WndProc).

VisualStudio2010 OpenGL project crashes with 0x000007b right on start

I try to setup a simple VisualStudio2010 OpenGL Project
I start with a new Win32 project and replace _tWinMain with the following:
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
//MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_GLPREDICTOR, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HDC hdc = GetDC(hWnd);
if (hdc == NULL)
return FALSE;
if(!SetPF(hdc))
return FALSE;
mainApp = new GLPredictor(hdc);
HGLRC tmpContext = wglCreateContext (hdc);
wglMakeCurrent(hdc, tmpContext);
//create opengl 4.2 context
/*GLenum error = glewInit();
if(error != GLEW_OK)
return false;
int attributes[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
0
};
if(wglewIsSupported("WGL_ARB_create_context")==1){
HGLRC context = wglCreateContextAttribsARB(hdc, NULL,attributes);
wglMakeCurrent(NULL, NULL);
wglDeleteContext(tmpContext);
wglMakeCurrent(hdc,context);
}
else{
return FALSE;
}
int glVersion[2] = {-1,-1};
glGetIntegerv(GL_MAJOR_VERSION, &glVersion[0]);
glGetIntegerv(GL_MINOR_VERSION, &glVersion[1]);
std::cout<<"Using OpenGL: "<<glVersion[0]<<"."<<glVersion[1]<<std::endl;
*/
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GLPREDICTOR));
MSG msg = {0};
while(TRUE)
{
// Check to see if any messages are waiting in the queue
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if(msg.message == WM_QUIT)
break;
}
else
{
mainApp->render();
}
}
return (int) msg.wParam;
}
This runs.
But as soon as i uncomment the commented region (//create opengl 4.2 context) and try to run the app, then i get instantly an error message saying:
The application was unable to start correctly (0x000007b). Click OK to close the application.
but the uncommented code isn't even reached. I can set a breakpoint even on the first line of _tWinMain and it won't be triggered.
I already tried to create a new project and copy the code over, with the same result.
Anyone got an idea why this region causes the project to crash, even if the code it contains is executed?
//edit: the offending line seems to be
GLenum error = glewInit();
as soon as it's in the code, it makes the application crash (although code execution never reaches it). Does this line cause the compiler to add some stuff that may cause the problem?
Okay - I got it. I had to copy "glew32.dll" into my SysWOW64 directory

win32 bitmaps flashing when more than one sprite on screen

I've been using the win32 api to make a game with sprites. For some reason when I have more than one sprite on screen they flash occasionally as if they are disappearing and returning. When there is only one sprite on screen it displays correctly.
I am using C++, win32 API and working with Visual Studio 08
The following is roughly what I have:
//creates rect based on window client area
GetClientRect(ghwnd, &screenRect);
// Initialises front buffer device context (window)
frontHDC = GetDC(ghwnd);
// sets up Back DC to be compatible with the front
backHDC = CreateCompatibleDC(frontHDC);
// Create another hdc to store the bitmap in before the backbuffer
bitmapHDC = CreateCompatibleDC(frontHDC);
//creates bitmap compatible with the front buffer
theOldFrontBitMap = CreateCompatibleBitmap(frontHDC, screenRect.right, screenRect.bottom);
//creates bitmap compatible with the back buffer
theOldBackBitMap = (HBITMAP)SelectObject(backHDC, theOldFrontBitMap);
HBITMAP originalBitMap = (HBITMAP)SelectObject(bitmapHDC,bitmap);
//Transparency function
TransparentBlt( backHDC,
m_Position.x,
m_Position.y,
m_Size.x,
m_Size.y,
bitmapHDC,
0,
0,
m_Size.x,
m_Size.y,
0x00FFFFFF);
SelectObject(bitmapHDC,originalBitMap);
BitBlt(frontHDC, screenRect.left, screenRect.top,
screenRect.right, screenRect.bottom, backHDC, 0, 0, SRCCOPY);
Am I doing this correctly? and if so where am I going wrong? If I have not given enough information please tell me and I will rectify that.
The problem with creating a Win32 game is that, even if you use double buffering, you have no way to wait for the vertical retrace of the monitor to display the buffer.
Displaying the buffer or sprite while the vertical retrace is in progress can cause tearing or even the disappearing sprite that you experience.
The only real way around this is to use an SDK like OpenGL or DirectX to manage and display the buffers.
Here's a sample program that may help you, use the arrow keys to move the white box on the double buffered background:
#include <Windows.h>
RECT rcSize;
HDC hdcBackBuffer, hdcSprite;
HBITMAP hbmBackBuffer, hbmSprite;
int spriteX = 175, spriteY = 175;
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;
switch (msg)
{
case WM_CREATE:
{
HDC hdcWindow = GetDC(hWnd);
// make back buffer
GetClientRect(hWnd, &rcSize);
hdcBackBuffer = CreateCompatibleDC(hdcWindow);
hbmBackBuffer = CreateCompatibleBitmap(hdcBackBuffer, rcSize.right - rcSize.left, rcSize.bottom - rcSize.top);
SelectObject(hdcBackBuffer, hbmBackBuffer); // SHOULD SAVE PREVIOUS...
// make sprite
hdcSprite = CreateCompatibleDC(hdcWindow);
hbmSprite = CreateCompatibleBitmap(hdcSprite, 50, 50);
SelectObject(hdcSprite, hbmSprite); // SHOULD SAVE PREVIOUS...
RECT rcSprite;
SetRect(&rcSprite, 0, 0, 50, 50);
FillRect(hdcSprite, &rcSprite, (HBRUSH)GetStockObject(WHITE_BRUSH));
ReleaseDC(hWnd, hdcWindow);
return 0;
}
case WM_KEYDOWN:
{
// SHOULD REALLY USE GetAsyncKeyState for game, but simplified here
switch (wParam)
{
case VK_LEFT:
spriteX--;
break;
case VK_RIGHT:
spriteX++;
break;
case VK_UP:
spriteY--;
break;
case VK_DOWN:
spriteY++;
break;
}
return 0;
}
case WM_ERASEBKGND:
{
return 1; // INDICATE THAT WE ERASED THE BACKGROUND OURSELVES
}
case WM_PAINT:
{
BeginPaint(hWnd, &ps);
// clear back buffer
FillRect(hdcBackBuffer, &rcSize, (HBRUSH)GetStockObject(BLACK_BRUSH));
// render sprite to back buffer
BitBlt(hdcBackBuffer, spriteX, spriteY, 50, 50, hdcSprite, 0, 0, SRCCOPY);
// render back buffer to screen
BitBlt(ps.hdc, 0, 0, rcSize.right - rcSize.left, rcSize.bottom - rcSize.top, hdcBackBuffer, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
return 0;
}
case WM_DESTROY:
{
// TODO - DESTROY ALL BITMAPS AND DEVICE CONTEXTS
PostQuitMessage(0);
return 0;
}
default:
{
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
}
int WINAPI WinMain(HINSTANCE hPrevInstance, HINSTANCE hInstance, LPSTR lpCmdLine, int nShowCmd)
{
static TCHAR className[] = TEXT("GameClass");
static TCHAR windowName[] = TEXT("A Game");
WNDCLASSEX wcex;
wcex.cbClsExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.cbWndExtra = 0;
wcex.hbrBackground = NULL;
wcex.hCursor = LoadCursor(hInstance, IDC_ARROW);
wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wcex.hIconSm = NULL;
wcex.hInstance = hInstance;
wcex.lpfnWndProc = WndProc;
wcex.lpszClassName = className;
wcex.lpszMenuName = NULL;
wcex.style = 0;
if (!RegisterClassEx(&wcex))
return 0;
HWND hWnd = CreateWindow(className, windowName, WS_CAPTION | WS_BORDER | WS_SYSMENU, 0, 0, 400, 400, NULL, NULL, hInstance, NULL);
if (!hWnd)
return 0;
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
MSG msg;
for (;;)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
break;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
InvalidateRect(hWnd, NULL, FALSE);
}
return msg.wParam;
}
I think your back buffer implementation is wrong although Im not sure exactly where. Try this implementation of a separate back buffer class. I hope it helps.
Here my back buffer class.
#ifndef BACKBUFFER_H
#define BACKBUFFER_H
#include <Windows.h>
class BackBuffer
{
public:
BackBuffer(HWND hWnd, int width, int height);
~BackBuffer();
HDC getDC();
int width();
int height();
void present();
private:
// Make copy constructor and assignment operator private
// so client cannot copy BackBuffers. We do this because
// this class is not designed to be copied because it
// is not efficient--copying bitmaps is slow (lots of memory).
// In addition, most applications will probably only need one
// BackBuffer anyway.
BackBuffer(const BackBuffer& rhs);
BackBuffer& operator=(const BackBuffer& rhs);
private:
HWND mhWnd;
HDC mhDC;
HBITMAP mhSurface;
HBITMAP mhOldObject;
int mWidth;
int mHeight;
};
#endif //BACKBUFFER_H
Heres the implementation:
BackBuffer::BackBuffer(HWND hWnd, int width, int height)
{
//Save a copy of the main window handle
mhWnd = hWnd;
//Get a handle to the device context associated with
// the window
HDC hWndDC = GetDC(hWnd);
//Save the backbuffer dimensions
mWidth = width;
mHeight = height;
//Create system memory device context that is compatible
//with the window one
mhDC = CreateCompatibleDC(hWndDC);
//Create the backbuffer surface bitmap that is compatible
//with the window device context bitmap format. That is
//the surface we will render onto.
mhSurface = CreateCompatibleBitmap(hWndDC, width, height);
//Done with DC
ReleaseDC(hWnd, hWndDC);
//At this point, the back buffer surface is uninitialized,
//so lets clear it to some non-zero value. Note that it
//needs to be a non-zero. If it is zero then it will mess
//up our sprite blending logic.
//Select the backbuffer bitmap into the DC
mhOldObject = (HBITMAP)SelectObject(mhDC, mhSurface);
//Select a white brush
HBRUSH white = (HBRUSH)GetStockObject(WHITE_BRUSH);
HBRUSH oldBrush = (HBRUSH)SelectObject(mhDC, white);
//Clear the backbuffer rectangle
Rectangle(mhDC, 0, 0, mWidth, mHeight);
//Restore the original brush
SelectObject(mhDC, oldBrush);
}
BackBuffer::~BackBuffer()
{
SelectObject(mhDC, mhOldObject);
DeleteObject(mhSurface);
DeleteDC(mhDC);
}
HDC BackBuffer::getDC()
{
return mhDC;
}
int BackBuffer::width()
{
return mWidth;
}
int BackBuffer::height()
{
return mHeight;
}
void BackBuffer::present()
{
//Get a handle to the device context associated with
//the window
HDC hWndDC = GetDC(mhWnd);
//Copy the backbuffer contents over to the
//window client area
BitBlt(hWndDC, 0, 0, mWidth, mHeight, mhDC, 0, 0, SRCCOPY);
//Free window DC when done
ReleaseDC(mhWnd, hWndDC);
}
Try to work your way through this implementation the comments should help you understand. Hope this helps.

Handling WM_NCPAINT "breaks" DWM glass rendering on Vista/Aero

I am trying to make a window that alternates between having an Aero/Glass and a custom rendered frame (by handling WM_NCPAINT) based on a user setting. (Windows Vista).
DwmComposition is enabled. My app comes up with the glass frame, but as soon as I toggle the setting to trigger the custom WM_NCPAINT codepath then toggle back to use DefWindowProc's WM_NCPAINT handling, the native frame is now perpetually stuck in the "Vista Basic" style - it's no longer translucent and the caption buttons look different to the normal Aero/Glass ones.
I've tried just about every way of poking the window from sending SWP_FRAMECHANGED to changing the window style then changing it back, hiding it, etc, but all to no avail. It seems like as soon as I handle WM_NCPAINT for a glass window rather than deferring to DefWindowProc my window is forever "broken".
I found a C#/WPF example on MSDN (code dot msdn dot microsoft dot com slash chrome ) that seemed to indicate that one simply needed to stop handling WM_NCPAINT and the glass would return, but that does not seem to work in my own app.
Is there a way to reset this state cleanly? My code is in C++ and lives here:
http://bengoodger.dreamhosters.com/software/chrome/dwm/
#include <windows.h>
#include <dwmapi.h>
static const wchar_t* kWindowClass = L"BrokenGlassWindow";
static const wchar_t* kWindowTitle =
L"BrokenGlass - Right click client area to toggle frame type.";
static const int kGlassBorderSize = 50;
static const int kNonGlassBorderSize = 40;
static bool g_glass = true;
bool IsGlass() {
BOOL composition_enabled = FALSE;
return DwmIsCompositionEnabled(&composition_enabled) == S_OK &&
composition_enabled && g_glass;
}
void SetIsGlass(bool is_glass) {
g_glass = is_glass;
}
void ToggleGlass(HWND hwnd) {
SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM w_param,
LPARAM l_param) {
PAINTSTRUCT ps;
HDC hdc;
RECT wr;
HBRUSH br;
RECT* nccr = NULL;
RECT dirty;
RECT dirty_box;
MARGINS dwmm = {0};
WINDOWPOS* wp = NULL;
switch (message) {
case WM_CREATE:
SetCursor(LoadCursor(NULL, IDC_ARROW));
break;
case WM_ERASEBKGND:
return 1;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &wr);
br = GetSysColorBrush(IsGlass() ? COLOR_APPWORKSPACE : COLOR_WINDOW);
FillRect(hdc, &wr, br);
EndPaint(hwnd, &ps);
break;
case WM_NCPAINT:
if (IsGlass())
return DefWindowProc(hwnd, message, w_param, l_param);
GetWindowRect(hwnd, &wr);
if (!w_param|| w_param == 1) {
dirty = wr;
dirty.left = dirty.top = 0;
} else {
GetRgnBox(reinterpret_cast<HRGN>(w_param), &dirty_box);
if (!IntersectRect(&dirty, &dirty_box, &wr))
return 0;
OffsetRect(&dirty, -wr.left, -wr.top);
}
hdc = GetWindowDC(hwnd);
br = CreateSolidBrush(RGB(255,0,0));
FillRect(hdc, &dirty, br);
DeleteObject(br);
ReleaseDC(hwnd, hdc);
break;
case WM_NCACTIVATE:
// Force paint our non-client area otherwise Windows will paint its own.
RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
break;
case WM_NCCALCSIZE:
nccr = w_param ? &reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0]
: reinterpret_cast<RECT*>(l_param);
nccr->bottom -= IsGlass() ? kGlassBorderSize : kNonGlassBorderSize;
nccr->right -= IsGlass() ? kGlassBorderSize : kNonGlassBorderSize;
nccr->left += IsGlass() ? kGlassBorderSize : kNonGlassBorderSize;
nccr->top += IsGlass() ? kGlassBorderSize : kNonGlassBorderSize;
return WVR_REDRAW;
case WM_RBUTTONDOWN:
SetIsGlass(!g_glass);
ToggleGlass(hwnd);
break;
case 0x31E: // WM_DWMCOMPOSITIONCHANGED:
ToggleGlass(hwnd);
break;
case 0xAE: // WM_NCUAHDRAWCAPTION:
case 0xAF: // WM_NCUAHDRAWFRAME:
return IsGlass() ? DefWindowProc(hwnd, message, w_param, l_param) : 0;
case WM_WINDOWPOSCHANGED:
dwmm.cxLeftWidth = kGlassBorderSize;
dwmm.cxRightWidth = kGlassBorderSize;
dwmm.cyTopHeight = kGlassBorderSize;
dwmm.cyBottomHeight = kGlassBorderSize;
DwmExtendFrameIntoClientArea(hwnd, &dwmm);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, w_param, l_param);
}
return 0;
}
ATOM RegisterClazz(HINSTANCE instance) {
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = instance;
wcex.lpszClassName = kWindowClass;
return RegisterClassEx(&wcex);
}
int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int show_command) {
RegisterClazz(instance);
HWND hwnd = CreateWindow(kWindowClass, kWindowTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL,
instance, NULL);
ShowWindow(hwnd, show_command);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
When toggling between Aero/Glass and your custom rendered frame it you can use the following to explicitly control the non-client area rendering policy:
DWMNCRENDERINGPOLICY policy = DWMNCRP_ENABLED; // DWMNCRP_DISABLED to toggle back
DwmSetWindowAttribute(hwnd,
DWMWA_NCRENDERING_POLICY,
(void*)&policy,
sizeof(DWMNCRENDERINGPOLICY));

Resources