I am still learning to program Native Windows and the GDI. I am wanting to make a simple picture viewer. Here is what I have. These two cases are in seperate switch statements. I didn't want to post the whole program for obvious reasons.
When I run it with this, a Open Dialog opens. I select the image I want to open, but it won't display it. I have checked everything. I don't know what is wrong. Does anyone know? Thanks.
@ rajenipcv should you call the invalidate function while you are in the middle of handling a WM_PAINT message?
@ guestgulkan
Yes.
No.
The WM_PAINT message is sent in response to one or more calls to the invalidation functions. If you immediately invalidate what you just drew, you'll only put your application into a time-consuming cycle of constant repainting.
I don't actually see anything wrong with your painting. At the end of the OPEN_FILE case you properly call InvalidateRect() and even UpdateWindow() (though the second isn't strictly necessary --but don't take it out ;-)
The problem comes from the use of LoadBitmap(). That function only loads resources linked into the executable. It won't load files. :-O Yep. Only linked resources. Hence, the resource fails to load and any attempt to draw NULL in WM_PAINT fails.
Probably the simplest fix is to use the LoadImage() function. However, it doesn't work on Windows NT, so I'll recommend you take the effort to load it properly. (It also has a bug or two involving transparent colors.) You would think that the Win32 API would provide a function to do this for us...
Basically you have to extract and assemble the bitmap yourself. Unfortunately there isn't a whole lot of straight-forward information about this on the internet, so here's a little function to do it for you.
#include <windows.h>
HBITMAP BMPLoadFromFile( LPCTSTR filename )
{
HANDLE f;
BITMAPFILEHEADER bmFH;
DWORD size;
HGLOBAL g;
LPVOID p;
HDC dc;
DWORD count;
BOOL ok;
HBITMAP result = 0;
/* Open the bitmap file */
f = CreateFile(
filename,
GENERIC_READ,
FILE_SHARE_READ,
NULL, /* no security attributes: handle cannot be inherited */
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, /* optimize for how we'll use the file */
NULL
);
if (f == INVALID_HANDLE_VALUE) return 0;
/* Read and validate the bitmap file header */
ok = ReadFile( f, (LPVOID)&bmFH, sizeof( BITMAPFILEHEADER ), &count, NULL );
if (!ok || (count != sizeof( BITMAPFILEHEADER )) || (bmFH.bfType != 0x4D42))
goto done_file;
/* Get the size of the bitmap structure */
size = GetFileSize( f, NULL );
if (size == 0xFFFFFFFF) goto done_file;
size -= sizeof( BITMAPFILEHEADER );
/* And try to allocate and load it */
g = GlobalAlloc( GHND, size );
if (g == NULL) goto done_file;
p = GlobalLock( g );
if (p == NULL) goto done_global;
ok = ReadFile( f, p, size, &count, NULL );
if (!ok || (count != size)) goto done_global;
/* OK, now we can get down to business and turn our data into an HBITMAP */
dc = GetDC( NULL );
if (dc == NULL) goto done_global;
result = CreateDIBitmap(
dc,
(BITMAPINFOHEADER*)p,
CBM_INIT,
(LPVOID)((CHAR*)p +bmFH.bfOffBits), /* don't assume packed .bmp */
(BITMAPINFO*)p,
DIB_RGB_COLORS
);
ReleaseDC( NULL, dc );
done_global: GlobalFree( g );
done_file: CloseHandle( f );
return result;
}
If it fails to load you'll get back NULL. Otherwise be sure to dispose of the HBITMAP you get from this using DeleteObject(). And of course you are linking with libgdi32, right?
Thirdly, if you want to take issue with something, don't just whine and complain. Either suggest something better and correct or link to something that does.
It appears that the latest MSDN LoadImage documentation has removed the caveat about LR_LOADFROMFILE (see http://msdn.microsoft.com/en-us/library/ms648045.aspx ) and a quick check with Google advised me that some people report that NT versions as old as 3.51 work just fine with it. Given the MSDN info, I suspect that Microsoft may have fixed it with a service pack.
If you want more information about handling BMP files beyond what I have posted, this is a very good tutorial: http://www.runicsoft.com/bmp.php
PS. There is a little blue "edit" button on the bottom right of your post. Please use it.
> Probably the simplest fix is to use the LoadImage() function. However, it doesn't work on Windows NT,
What is this Bullshit ?
Sadly, Thats a typical unhelpful response I would expect from him Duoas. It's entirely feasible someone is doing work on WindowsNT at a university or polytechnic somewhere. Or even an in organisation (banks are shockers for old OS's).
MSDN is the only available doc http://msdn.microsoft.com/en-us/library/ms648045.aspx
It has always worked on NT >= 3.51, for 13 years...
(and I've used it at least 2000 times on every MS OS, it has always worked perfectly)
That's funny because I have a fairly extensive collection of Microsoft's own help files on my harddisk. The danger with MSDN is that Microsoft is notorious for modifying their documentation to represent the current state of things without any respect for past states.
It has always worked on NT >= 3.51, for 13 years...
If some past employee on the Redmond documentation team felt it noteworthy to indicate that LoadImage() cannot do LR_LOADFROMFILE on Windows NT, then it is better to code against the possibility that someone, somewhere may have an ancient, unpatched, dysfunctional version of NT where LoadImage() will fail to load a BMP from file --no matter how many instances can be found where it works without problem. Anectdotal evidence is not proof of anything.
I have not personally experienced any problems with LoadImage( ... LR_LOADFROMFILE ) either. But then again, I have never used NT. If the OP can guarantee that his target audience is using 4.7x or greater then there isn't any problem. But if he can't, then he should code appropriately. That's all.