Write file from memory

I have a .PNG file that I am using as background in my window by handling the WM_PAINT message.

I've included the .PNG with the .EXE and everything works fine.

I want to add the .PNG to my resource file and when the program executes it should write the .PNG to file and then use it as background.

I've added the .PNG to the resource file. My problem is showing the write method the binary data in memory. I really don't know what arguments to pass it. The current arguments in my source code is just garbage from my futile attempts.

I'm using Visual C++ 2005 SP1.

Thanks in advance for any help!

Here is my code:

void writefile ()
{
HRSRC hRsrc = FindResource (0, MAKEINTRESOURCE(IDR_PNG1), L"PNG");
HGLOBAL hGlobal = LoadResource (0, hRsrc);
LPVOID lpVoid = LockResource (hGlobal);

wofstream background (L"backg.png", ios::out | ios::binary | ios::trunc);
background.write (reinterpret_cast<wchar_t*>(lpVoid), sizeof(lpVoid));
background.close();
}
[1082 byte] By [links] at [2007-11-20 11:05:25]
# 1 Re: Write file from memory
background.write (reinterpret_cast<wchar_t*>(lpVoid), sizeof(lpVoid));Here you are writing 4 bytes to that stream (the size of void pointer is 4).
You should use GlobalSize() to find the size of that memory block.
The entire solution looks strange. So you already have PNG data in memory, and you write it to file so it will then be loaded back? Why won't you create your PNG image from that memory block?
VladimirF at 2007-11-9 13:32:27 >
# 2 Re: Write file from memory
Thank you for your reply.

The ideal is to use the PNG directly from memory, but I'm unable to get it to work so now I'm trying to write it to file.

I get what you're saying about the pointer size. I've changed my code as seen below but when the program executes it still only creates a 0kb PNG file.

Any further help please?

void writefile ()
{
HRSRC hRsrc = FindResource (0, MAKEINTRESOURCE(IDR_PNG1), L"PNG");
HGLOBAL hGlobal = LoadResource (0, hRsrc);
LPVOID lpVoid = LockResource (hGlobal);
SIZE_T test = GlobalSize (hGlobal);
wofstream background (L"backg.png", ios::out | ios::binary | ios::trunc);
background.write (reinterpret_cast<wchar_t*>(lpVoid), test);
background.close();
}
links at 2007-11-9 13:33:26 >
# 3 Re: Write file from memory
Any further help please?Well,
- was the resource found?
- what was its size?
- why do you cast your pointer to wchar_t?
VladimirF at 2007-11-9 13:34:24 >
# 4 Re: Write file from memory
Or perhaps a better question is "Why use wide character stream to write a Binary Output File ( http://msdn2.microsoft.com/en-us/library/4yy87z4f(VS.80).aspx)?".
Boris K K at 2007-11-9 13:35:29 >
# 5 Re: Write file from memory
bool writefile () {
//check if it exists
HRSRC hRsrc = FindResource (0, MAKEINTRESOURCE(IDR_PNG1), L"PNG");
if (hRsrc == NULL) return false;

//check if it can be loaded (it may be corrupted)
HGLOBAL hGlobal = LoadResource (GetModuleHandle(NULL), hRsrc);
if (hGlobal == NULL) return false;

//lock it
char *theData = (char *)LockResource (hGlobal);
//get resource size
size_t resSize = static_cast<size_t> (SizeofResource(NULL,hRsrc));

if(resSize==0) return false;


ofstream background ("backg.png", ios::out | ios::binary | ios::trunc);
background.write (theData, resSize);
background.close();

return true;
}

I hope this one works for you. Although I did not test it, but I hope it works.

regards
Ali Imran at 2007-11-9 13:36:28 >
# 6 Re: Write file from memory
Thank you Ali, your code works perfectly. Looks like my biggest problem was using a wide stream. Stupid me.

I would now like to skip the writing of the file to disk and use it directly in memory.

I'm using GDI+ to draw the PNG image as follows:

Image image(L"backg.png");
graphics.DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight());

I've looked through the MSDN documentation, but can't find a suitable constructor. How would I go about drawing the image directly from memory?
links at 2007-11-9 13:37:37 >
# 7 Re: Write file from memory
Well if you go with GDIplus that is much better, since it has support of more image formats, especially Portangle Network Graphics that you are using.

I've looked through the MSDN documentation, but can't find a suitable constructor. How would I go about drawing the image directly from memory?

I think that is what your code is doing, drawing an image. Sorry I could not follow.

Besides, following link contains much info about GDI+ used for images.
http://www.dev-archive.com/cpp/g-m/gdi/gdi/article.php/c3687/

I hope this helps.

regards
Ali Imran at 2007-11-9 13:38:39 >
# 8 Re: Write file from memory
I would now like to skip the writing of the file to disk and use it directly in memory.Check out these functions:
Image::Image Constructor
Creates an Image object based on a stream.

Syntax

Image( IStream *stream,
BOOL useEmbeddedColorManagement
);

and

CreateStreamOnHGlobal()
VladimirF at 2007-11-9 13:39:31 >
# 9 Re: Write file from memory
First of all, I think there must be some methods to load image from resurces directly in GDI+, I never used it so cant say.
Following may help though (based on constructor Image(IStream *stream,BOOL useEmbeddedColorManagement);) VladimirF talked about:

HRSRC hRsrc = FindResource (0, MAKEINTRESOURCE(IDR_PNG1), L"PNG");
HGLOBAL hGlobal = LoadResource (GetModuleHandle(NULL), hRsrc);
char *bin = (char *)LockResource (hGlobal);

IStream * istream=NULL;
CreateStreamOnHGlobal((HGLOBAL)bin,false,&istream);
Image image(istream, true);
graphics.DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight());

It is just rough way, I did not test btw, you must consider error checking. Secondly I suggest you look into details of constructors and other methods of loading image from resources in class Image of GDI+.

I hope that will help.

regards
Ali Imran at 2007-11-9 13:40:38 >
# 10 Re: Write file from memory
It doesn't work. I've added some error checking. CreateStreamOnHGlobal returns S_OK, but when I debug I get an error message (see attached screenshot).

Here's the code:

HRSRC hRsrc = FindResource (0, MAKEINTRESOURCE(IDR_PNG1), L"PNG");
if (hRsrc == NULL)
MessageBox(0, L"FindResource Error", L"Error", MB_OK);

HGLOBAL hGlobal = LoadResource (GetModuleHandle(0), hRsrc);
if (hGlobal == NULL)
MessageBox(0, L"LoadResource Error", L"Error", MB_OK);

char *bin = (char *)(LockResource (hGlobal));

IStream * istream = 0;
HRESULT hResult = CreateStreamOnHGlobal((HGLOBAL)bin, FALSE, &istream);
switch (hResult)
{
case E_INVALIDARG:
MessageBox(0, L"E_INVALIDARG Error", L"Error", MB_OK);
case E_OUTOFMEMORY:
MessageBox(0, L"E_OUTOFMEMORY Error", L"Error", MB_OK);
case S_OK:
MessageBox(0, L"S_OK", L"Error", MB_OK);
}
Image image(istream, TRUE);
graphics.DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight());
links at 2007-11-9 13:41:38 >
# 11 Re: Write file from memory
Try saving 'bin' to some file and check if it is same as the png in resources, if not then resource is not being loaded and may cause error. Secondly, if bin is written successfully, then try copying it first to some other char * variable allocated exactly sa,me using GlobalAlloc, and pass that one to CreateStreamOnHGlobal function, remember to deallocate using GlobalFree when done.

regards
Ali Imran at 2007-11-9 13:42:35 >