Win32 C/C++ Load Image from Memory Buffer

Win32 C/C++ Load Image from memory buffer

Nevermind, I found my solution! Here's the initializing code:

std::ifstream is;
is.open("Image.bmp", std::ios::binary);
is.seekg (0, std::ios::end);
length = is.tellg();
is.seekg (0, std::ios::beg);
pBuffer = new char [length];
is.read (pBuffer,length);
is.close();

tagBITMAPFILEHEADER bfh = *(tagBITMAPFILEHEADER*)pBuffer;
tagBITMAPINFOHEADER bih = *(tagBITMAPINFOHEADER*)(pBuffer+sizeof(tagBITMAPFILEHEADER));
RGBQUAD rgb = *(RGBQUAD*)(pBuffer+sizeof(tagBITMAPFILEHEADER)+sizeof(tagBITMAPINFOHEADER));

BITMAPINFO bi;
bi.bmiColors[0] = rgb;
bi.bmiHeader = bih;

char* pPixels = (pBuffer+bfh.bfOffBits);

char* ppvBits;

hBitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void**) &ppvBits, NULL, 0);
SetDIBits(NULL, hBitmap, 0, bih.biHeight, pPixels, &bi, DIB_RGB_COLORS);

GetObject(hBitmap, sizeof(BITMAP), &cBitmap);

Displaying all Bitmap Types from a Memory Buffer with MFC or Win32

Hans is correct to say that bi.bmiColors was not being treated correctly. Instead of handling the bi.bmiColors table directly, just point pBitmapInfo to the appropriate offset in BITMAPFILEHEADER and cast. This takes care of the color table automatically. And yes, pBitmapInfo and pBitmapInfoHeader do point to the same place; what they point to is casted differently in each case. Both of those pointers a required by the CreateDIBitmap() function.

pBitmapFileHeader = (LPBITMAPFILEHEADER)buf1;
pBitmapInfoHeader = (LPBITMAPINFOHEADER)(buf1+sizeof(BITMAPFILEHEADER));
pBitmapInfo = (LPBITMAPINFO)(buf1+sizeof(BITMAPFILEHEADER));
pPixels = (buf1+pBitmapFileHeader->bfOffBits);

Then in OnPaint() do:

g_hBmp = CreateDIBitmap(dcPaint, pBitmapInfoHeader, CBM_INIT, (VOID *) pPixels, pBitmapInfo, DIB_RGB_COLORS);

Write to a memory buffer and check if it is full with a SEH exception on Win32 platform?

Yes. Use VirtualAlloc. With VirutalProtect used in conjunction, you can even make this guard zone only memory page sized (4096 bytes, not whole 64KB).

Note that for stack it is handled by OS, you can only control this by SetThreadStackGuarantee to set the amount of buffer before stack overflow, and _resetstkoflw to fix (restore) guard after stack overflow exception is hadnled.

How can I retrieve an image data buffer from clipboard memory (uintptr)?

@JimB is correct: user32!GetClipboardData() returns a HGLOBAL, and a comment example over there suggests using kernel32!GlobalLock() to a) globally lock that handle, and b) yield a proper pointer to the memory referred to by it.

You will need to kernel32!GlobalUnlock() the handle after you're done with it.

As to converting pointers obtained from Win32 API functions to something readable by Go, the usual trick is casting the pointer to an insanely large slice. To cite the "Turning C arrays into Go slices" of "the Go wiki article on cgo":

To create a Go slice backed by a C array (without copying the original
data), one needs to acquire this length at runtime and use a type
conversion to a pointer to a very big array and then slice it to the
length that you want (also remember to set the cap if you're using Go 1.2 > or later), for example (see http://play.golang.org/p/XuC0xqtAIC for a
runnable example):

import "C"
import "unsafe"
...
var theCArray *C.YourType = C.getTheArray()
length := C.getTheArrayLength()
slice := (*[1 << 30]C.YourType)(unsafe.Pointer(theCArray))[:length:length]

It is important to keep in mind that the Go garbage collector will not
interact with this data, and that if it is freed from the C side of
things, the behavior of any Go code using the slice is nondeterministic.

In your case it will be simpler:

h := GlobalLock()
defer GlobalUnlock(h)
length := somehowGetLengthOfImageInTheClipboard()
slice := (*[1 << 30]byte)(unsafe.Pointer((uintptr(h)))[:length:length]

Then you need to actually read the bitmap.

This depends on the format of the Device-Independent Bitmap (DIB) available for export from the clipboard.

See this and this for a start.

As usually, definitions of BITMAPINFOHEADER etc are easily available online in the MSDN site.

Unable to load .bmp files win32

It seems that you never allocate a buffer for the filename.

The different data types can be found in this SO answer.

Your szFileName is defined as an

LPTSTR = char* or wchar_t* depending on _UNICODE

so it's a pointer, but in your code sample you didn't reserve memory for this pointer.

ofn.lpstrFile = (LPWSTR)szFileName;        // in WndProc
LoadAndBlitBitmap(LPCWSTR szFileName...) // passed as CONST
LoadImage(NULL, szFileName...) // passed as parameter
OpenFileDialog(hWnd, szFileName, ...) // passed as parameter
if (szFileName) ... // check if !NULL
LoadAndBlitBitmap(szFileName, hdc); // passed as parameter

But you never allocate the necessary memory to the pointer...

In the OPENFILENAME structure lpstrFile is defined as:

The file name used to initialize the File Name edit control.

The first character of this buffer must be NULL if initialization is not necessary.

When the GetOpenFileName or GetSaveFileName function returns successfully, this buffer contains the drive designator, path, file name, and extension of the selected file...

If the buffer is too small, the function returns FALSE and the CommDlgExtendedError function returns FNERR_BUFFERTOOSMALL. In this case, the first two bytes of the lpstrFile buffer contain the required size, in bytes or characters.

So you simply need to assign a buffer to szFileName to fix that problem.

That will solve your

In the case ID_FILE_LOADIMAGES, the "szFileName" is testing false even after the user has chosen a certain bmp image and clicked ok.

problem. It returns FALSE because your "buffer" (=none) is too small.



Related Topics



Leave a reply



Submit