thanks Hutch!
a bit problem is that temporary file of @@@@.@@@ were left on the hard disk at sometimes.
ResImageLoad proc ResID:QWORD
LOCAL hRes :QWORD
LOCAL pRes :QWORD
LOCAL lRes :QWORD
LOCAL pbmp :QWORD
LOCAL hBmp :QWORD
LOCAL npng :QWORD
mov hRes, rv(FindResource,0,ResID,RT_RCDATA) ; find the resource
mov pRes, rv(LoadResource,0,hRes) ; load the resource
mov lRes, rv(SizeofResource,0,hRes) ; get its size
mrm npng, "@@@@.@@@" ; temp file name
invoke save_file,npng,pRes,lRes ; create the temp file
invoke GdipCreateBitmapFromFile,L(npng),ADDR pbmp ; create a GDI+ bitmap
invoke GdipCreateHBITMAPFromBitmap,pbmp,ADDR hBmp,0 ; create normal bitmap handle from it
invoke GdipDisposeImage,pbmp ; remove the GDI+ bitmap
invoke DeleteFile,npng ; delete the temp file
mov rax, hBmp ; return the bitmap handle in RAX
ret
ResImageLoad endp
> invoke DeleteFile,npng ; delete the temp file
You would need to make sure that the resource you load is valid or you may feed the wrong info to the procedure. None the less even if you have managed to crash it with the wrong data, a simple text file is easy enough to fix, just delete it. Be aware that RC.EXE will leave junk behind if you feed it the wrong info as well.
There is a GdipCreateBitmapFromResource() function for that purpose ?
:biggrin:
It works fine anyway. :tongue:
the following code by Vortex can load bitmap from res. but jpg can't. so the created exefile is large.
CreateBmpFromMem PROC USES RSI RDI hWnd:QWORD,pBmp:QWORD
LOCAL hDC:QWORD
invoke GetDC,hWnd
test rax,rax
jz @f
mov hDC,rax
mov rsi,pBmp
lea rdi,[rsi + SIZEOF BITMAPFILEHEADER] ; start of the BITMAPINFOHEADER header
xor rax,rax
mov eax,BITMAPFILEHEADER.bfOffBits[rsi]
add rsi,rax
invoke CreateDIBitmap,hDC,rdi,CBM_INIT,rsi,rdi,DIB_RGB_COLORS
push rax
invoke ReleaseDC,hWnd,hDC
pop rax
@@:
ret
CreateBmpFromMem ENDP
ResImageLoad proc ResID:QWORD
LOCAL hRes:QWORD
LOCAL pRes:QWORD
LOCAL lRes:QWORD
LOCAL hBitmap:QWORD
invoke FindResource,0,ResID,RT_RCDATA
mov hRes, rax
invoke LoadResource,0,hRes
mov pRes, rax ; load the resource
invoke SizeofResource,0,hRes
mov lRes, rax ; get its size
invoke CreateBmpFromMem,hWinMain,pRes
mov hBitmap,rax
invoke GdipCreateBitmapFromHBITMAP,hBitmap,0,addr pImg
invoke CloseHandle,hBitmap
mov rax, pImg ; return the image handle in RAX
ret
ResImageLoad endp
You can use LoadImage() to load a BMP file, you don't need GDI+.
With Timo's suggestion, the function in 64 bit does not seem to work. Any variation in labelling the resource does not change the error message. The version I use has been super reliable since I originally wrote it, that is why I use it and it will load most formats, JPG BMP TIF PNG and GIF and while its the wrong function it will load an icon as well.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
GetResImg proc ResID:QWORD
LOCAL lbmp :QWORD
invoke GdipCreateBitmapFromResource,hInstance,ResID,ptr$(lbmp)
invoke MessageBox,hWnd,LastError$(),"LastError$",MB_ICONINFORMATION
mov rax, lbmp
ret
GetResImg endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
In C, GdipCreateBitmapFromStream()#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shlwapi.h>
#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "shlwapi.lib")
...
HBITMAP BitmapFromResource(HMODULE hMod, LPCTSTR ResID)
{
HBITMAP hBitmap = NULL;
HRSRC hRSrc = FindResource(hMod, ResID, RT_RCDATA);
if (!hRSrc) return 0;
DWORD nSize = SizeofResource(hMod, hRSrc);
HGLOBAL hResData = LoadResource(hMod, hRSrc);
PVOID pResData = LockResource(hResData);
IStream* pStream = NULL;
pStream = SHCreateMemStream(pResData, nSize);
FreeResource(hResData);
GpBitmap *gpBitmap;
int rc = GdipCreateBitmapFromStream(pStream, &gpBitmap);
pStream->lpVtbl->Release(pStream);
if (!rc) {
rc = GdipCreateHBITMAPFromBitmap(gpBitmap, &hBitmap, 0);
GdipDisposeImage(gpBitmap);
return hBitmap;
}
return 0;
}
Looks good but its a different set of functions, it does not include "GdipCreateBitmapFromResource".
hi,TimoVJL
thanks you for the SHCreateMemStream(pResData, nSize)
_PSHCreateMemStream typedef PROTO :QWORD,:QWORD
PSHCreateMemStream typedef ptr _PSHCreateMemStream
.data?
hShlwapi_dll dq ?
lPSHCreateMemStream PSHCreateMemStream ?
_GdipCreateImageFromResource proc ResID:QWORD
LOCAL hRes:QWORD
LOCAL pRes:QWORD
LOCAL lRes:QWORD
LOCAL @IStream:QWORD
invoke FindResource,0,ResID,RT_RCDATA
mov hRes, rax
invoke LoadResource,0,hRes
mov pRes, rax ; load the resource
invoke SizeofResource,0,hRes ; get its size
mov lRes, rax
invoke lPSHCreateMemStream,pRes,lRes
mov @IStream,rax
invoke FreeResource,hRes
invoke GdipLoadImageFromStream,@IStream,addr pImg
mov rax, pImg ; return the IMAGE handle in RAX
ret
_GdipCreateImageFromResource endp
invoke LoadLibrary,CStr("Shlwapi.dll")
.if eax
mov hShlwapi_dll,rax
invoke GetProcAddress,hShlwapi_dll,CStr("SHCreateMemStream")
mov lPSHCreateMemStream,rax
.else
invoke MessageBox,NULL,CStr("Shlwapi.dll load Failed"),CStr("LoadLibrary"),MB_OK
.endif
invoke _GdipCreateImageFromResource,IDC_IMGID
mov _GpImage,rax
Hi timo,
I got this to work from the C++ code you posted. About the only thing I could not convert was the line,
pStream->lpVtbl->Release(pStream);
I could not find a construction in the shlwapi or anywhere else that would do this.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
LoadResImage proc ResID:QWORD
LOCAL MemStream :QWORD
LOCAL pBMP :QWORD
LOCAL hBMP :QWORD
LOCAL hRsc :QWORD
LOCAL rSiz :QWORD
LOCAL rDat :QWORD
LOCAL strm :QWORD
mov MemStream, rvcall(GetProcAddress,rvcall(GetModuleHandle,"shlwapi.dll"),"SHCreateMemStream")
mov hRsc, rvcall(FindResource,0,ResID,RT_RCDATA) ; find the resource
mov rSiz, rvcall(SizeofResource,0,hRsc) ; get its size
mov rDat, rvcall(LoadResource,0,hRsc) ; load the resource
mov strm, rvcall(MemStream,rDat,rSiz) ; create the memory stream
rcall GdipCreateBitmapFromStream,strm,ptr$(pBMP) ; create a GDI+ bitmap
rcall GdipCreateHBITMAPFromBitmap,pBMP,ptr$(hBMP),0 ; convert it to a Windows bitmap
rcall GdipDisposeImage,pBMP ; delete the GDI+ bitmap
mov rax, hBMP ; return the bitmap handle
ret
LoadResImage endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Hi Hutch,
pStream->lpVtbl->Release(pStream);
The code to release streams :
ReleasePict:
mov rcx,pPicture
mov rax,QWORD PTR [rcx]
call IPicture.Release[rax]
ReleaseStream:
mov rcx,pStream
mov rax,QWORD PTR [rcx]
call IStream.Unknown.Release[rax]
Attached is my library loading various image formats from memory and file. It's converted to Masm 64-bit.
Hello,
Here is a GdipCreateBitmapFromResource sample.
.ifeq edx,WM_CREATE
mov rax,OFFSET StartupInfo
mov GdiplusStartupInput.GdiplusVersion[rax],1
invoke GdiplusStartup,ADDR token,ADDR StartupInfo,0
invoke GdipCreateBitmapFromResource,hInstance,1000,\
ADDR BmpImage
invoke GdipCreateHBITMAPFromBitmap,BmpImage,\
ADDR hBitmap,0
invoke GdipDisposeImage,BmpImage
Thanks Erol, these will be very useful.
Erol,
A question, have you used any different library for any of the GDI+ functions ?
I can run your example and it builds fine and works correctly but when I paste your code into a test piece I am using, I get an error message that "GdipCreateBitmapFromResource" can't find the resource.
LoadResImage proc ResID:QWORD
LOCAL hMemDC :QWORD
LOCAL BmpImage :QWORD
invoke GdipCreateBitmapFromResource,hInstance,ResID,ADDR BmpImage
; rcall MessageBox,hWnd,LastError$(),"LastError$",MB_ICONINFORMATION
invoke GdipCreateHBITMAPFromBitmap,BmpImage,ADDR hBmp,0
invoke GdipDisposeImage,BmpImage
mov rax, hBmp
ret
LoadResImage endp
I moved the init and shutdown to the start of the test piece and replaced the ones I normally use but it did not change anything.
.data?
hBmp dq ?
stui GdiplusStartupInput <?>
token dq ?
.code
........
mov rax,OFFSET stui
mov GdiplusStartupInput.GdiplusVersion[rax],1
invoke GdiplusStartup,ADDR token,ADDR stui,0
........
invoke GdiplusShutdown,token
Quote from: hutch-- on June 03, 2020, 01:38:31 AM
Hi timo,
I got this to work from the C++ code you posted. About the only thing I could not convert was the line,
pStream->lpVtbl->Release(pStream);
I could not find a construction in the shlwapi or anywhere else that would do this.
It was just C, not C++, in C++ it's pStream.Release();
mov rax,pStream
mov rax, [rax]
call [rax+10h]
as Release offset is 0+8+8 = 16
typedef struct IUnknownVtbl {
BEGIN_INTERFACE
HRESULT (STDMETHODCALLTYPE *QueryInterface)(IUnknown*,REFIID,void**);
ULONG (STDMETHODCALLTYPE *AddRef)(IUnknown*);
ULONG (STDMETHODCALLTYPE *Release)(IUnknown*);
END_INTERFACE
} IUnknownVtbl;
interface IUnknown {
CONST_VTBL struct IUnknownVtbl *lpVtbl;
};
Thanks timo,
That worked perfectly.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
LoadResImage proc ResID:QWORD
LOCAL MemStream :QWORD
LOCAL pBMP :QWORD
LOCAL hBMP :QWORD
LOCAL pRes :QWORD
LOCAL rSiz :QWORD
LOCAL rDat :QWORD
LOCAL stream :QWORD
LOCAL var :QWORD
mov MemStream, rvcall(GetProcAddress,rvcall(GetModuleHandle,"shlwapi.dll"),"SHCreateMemStream")
mov pRes, rvcall(FindResource,0,ResID,RT_RCDATA) ; find the resource
mov rSiz, rvcall(SizeofResource,0,pRes) ; get its size
mov rDat, rvcall(LoadResource,0,pRes) ; load the resource
mov stream, rvcall(MemStream,rDat,rSiz) ; create the memory stream
rcall GdipCreateBitmapFromStream,stream,ptr$(pBMP) ; create a GDI+ bitmap
rcall GdipCreateHBITMAPFromBitmap,pBMP,ptr$(hBMP),0 ; convert it to a Windows bitmap
rcall GdipDisposeImage,pBMP ; delete the GDI+ bitmap
mov rax, stream
mov rax, [rax]
call QWORD PTR [rax+16] ; release the stream
; rcall MessageBox,hWnd,LastError$(),"Title",MB_ICONINFORMATION
mov rax, hBMP ; return the bitmap handle
ret
LoadResImage endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Hi Hutch,
I didn't use any other library. Also, my resource file defines only a bitmap. I will try to modify my example to simulate your project.
Hi Hutch,
Could you try the attached new version? Here are the modifications :
start PROC
mov rax,OFFSET StartupInfo
mov GdiplusStartupInput.GdiplusVersion[rax],1
invoke GdiplusStartup,ADDR token,ADDR StartupInfo,0
.
.
.ifeq edx,WM_CREATE
invoke LoadRsrcImage,1000
.elseifeq edx,WM_PAINT
LoadRsrcImage PROC ResID:QWORD
LOCAL BmpImage :QWORD
invoke GdipCreateBitmapFromResource,hInstance,ResID,\
ADDR BmpImage
invoke GdipCreateHBITMAPFromBitmap,BmpImage,\
ADDR hBitmap,0
invoke GdipDisposeImage,BmpImage
mov rax,hBitmap
ret
LoadRsrcImage ENDP
Hi Erol,
Your version worked as before but I have tracked it down using your working example. It seems that the GDI+ function will only work with a BMP file. I changed it to a PNG and it no longer worked.
// 1000 BITMAP logo.bmp
1000 RCDATA "logo.png"
This is unfortunate as the code was clean and simple.
GdipCreateBitmapFromStream is much more flexible, as it just needs a pointer. That can come from InputFile or from an RCDATA resource, or even straight from the Internet. GuiImage (http://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1375) can use all three modes.
Here is a jpg loader from memory based on the cooperation of CreateStreamOnHGlobal and GdipCreateBitmapFromStream :
invoke CreateStreamOnHGlobal,hGlobal,\
TRUE,ADDR pStream
test rax,rax
jz @f
invoke GlobalUnlock,hGlobal
invoke GlobalFree,hGlobal
jmp _exit
@@:
invoke GdipCreateBitmapFromStream,pStream,\
ADDR BitmapImage
invoke GdipCreateHBITMAPFromBitmap,BitmapImage,\
ADDR hBitmap,0
Thanks Erol,
this looks good. I am up to my eyeballs in code at the moment but I will test it on different image formats soon as I need to be able to load JPG and PNG files from resources.