The MASM Forum

General => The Workshop => Topic started by: six_L on June 02, 2020, 03:13:04 AM

Title: Re: JpgTool application
Post by: six_L on June 02, 2020, 03:13:04 AM
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

Title: Re: Re: JpgTool application
Post by: hutch-- on June 02, 2020, 09:12:03 AM
>     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.
Title: Re: Re: JpgTool application
Post by: TimoVJL on June 02, 2020, 01:59:08 PM
There is a GdipCreateBitmapFromResource() function for that purpose ?
Title: Re: Re: JpgTool application
Post by: hutch-- on June 02, 2020, 03:31:37 PM
 :biggrin:

It works fine anyway.  :tongue:
Title: Re: Re: JpgTool application
Post by: six_L on June 02, 2020, 07:56:56 PM
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
Title: Re: Re: JpgTool application
Post by: hutch-- on June 02, 2020, 08:56:11 PM
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

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Title: Re: Re: JpgTool application
Post by: TimoVJL on June 02, 2020, 09:56:22 PM
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;
}
Title: Re: Re: JpgTool application
Post by: hutch-- on June 02, 2020, 10:21:47 PM
Looks good but its a different set of functions, it does not include "GdipCreateBitmapFromResource".
Title: Re: Re: JpgTool application
Post by: six_L on June 02, 2020, 11:31:26 PM
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
Title: Re: JpgTool application
Post by: 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.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

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

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Title: Re: JpgTool application
Post by: Vortex on June 03, 2020, 06:25:25 AM
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.
Title: Re: JpgTool application
Post by: Vortex on June 03, 2020, 07:11:11 AM
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
Title: Re: JpgTool application
Post by: hutch-- on June 03, 2020, 09:45:36 AM
Thanks Erol, these will be very useful.
Title: Re: JpgTool application
Post by: hutch-- on June 03, 2020, 12:26:09 PM
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




Title: Re: JpgTool application
Post by: TimoVJL on June 03, 2020, 03:29:30 PM
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 = 16typedef 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;
};
Title: Re: JpgTool application
Post by: hutch-- on June 03, 2020, 04:33:21 PM
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

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Title: Re: JpgTool application
Post by: Vortex on June 03, 2020, 11:06:03 PM
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.
Title: Re: JpgTool application
Post by: Vortex on June 04, 2020, 05:19:34 AM
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
Title: Re: JpgTool application
Post by: hutch-- on June 04, 2020, 06:31:37 AM
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.
Title: Re: JpgTool application
Post by: jj2007 on June 04, 2020, 08:02:08 AM
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.
Title: Re: JpgTool application
Post by: Vortex on June 05, 2020, 04:07:25 AM
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
Title: Re: JpgTool application
Post by: hutch-- on June 05, 2020, 05:22:47 AM
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.