News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

How to properly load a .png resource for use with GdipDrawImageRectI?

Started by zedd151, April 10, 2025, 01:49:24 AM

Previous topic - Next topic

zedd151

Quote from: Vortex on April 11, 2025, 06:33:35 AMUsing SHCreateMemStream is simplifying the code. Plus, you don't need resources as you can embed any binary data into your executable with Hutch's file data assembler fda.exe. This tool converts any binary file to a MS COFF object module

Hi Vortex. I did indeed test your program, and it works very well.  :thumbsup:  :thumbsup:  (two thumbs up)

I made some adjustments to the source as usual to allow drawing .png images with true transparency.
; original code by Vortex
; modified by zedd151

include LoadPNGfromMem.inc
include logo.inc

ApiFunc TYPEDEF proto :dword, :dword
DrawImage proto :dword, :dword, :dword, :dword

.data

ClassName  db 'ImageClass', 0
AppName    db 'Display PNG from memory', 0
shlwapi    db 'shlwapi.dll', 0
func        db 'SHCreateMemStream', 0

.data?

hInstance  dd ?
hBitmap    dd ?
GdiPStatus  dd ?
StartupInfo GdiplusStartupInput <?>
token      dd ?
hDll        dd ?
PNGimage    dd ?
pStream    dd ?

.code

start:

    invoke  GetModuleHandle, 0
    mov    hInstance, eax
    invoke  GetCommandLine
    invoke  WinMain, hInstance, 0, eax, SW_SHOWDEFAULT
    invoke  ExitProcess, eax

WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:dword

    local wc:WNDCLASSEX
    local msg:MSG
    local hwnd:HWND

    xor    eax, eax
    mov    wc.cbSize, SIZEOF WNDCLASSEX
    mov    wc.style, CS_HREDRAW or CS_VREDRAW
    mov    wc.lpfnWndProc, offset WndProc
    mov    wc.cbClsExtra, eax
    mov    wc.cbWndExtra, eax
    push    hInstance
    pop    wc.hInstance
    mov    wc.hbrBackground,COLOR_WINDOW+1
    mov    wc.lpszMenuName, 0
   
    mov    wc.lpszClassName, offset ClassName
    invoke  LoadIcon, eax, IDI_APPLICATION
    mov    wc.hIcon, eax
    mov    wc.hIconSm, eax
    invoke  LoadCursor, 0, IDC_ARROW
    mov    wc.hCursor, eax
    invoke  RegisterClassEx, addr wc

    xor    eax, eax
    invoke  CreateWindowEx, eax, addr ClassName, addr AppName, \
            WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, \
            CW_USEDEFAULT, 290, 90, eax, eax, \
            hInst, eax
           
    mov    hwnd, eax
    invoke  ShowWindow, hwnd, SW_SHOWNORMAL
    invoke  UpdateWindow, hwnd
   
    .while  TRUE
            invoke GetMessage, addr msg, 0, 0, 0
    .break    .if (!eax)
            invoke TranslateMessage, addr msg
            invoke DispatchMessage, addr msg
    .endw
   
    mov    eax, msg.wParam
    ret

WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    local ps:PAINTSTRUCT
    local rct:RECT
    local hdc:HDC
    local hMemDC:HDC
    local hBackBrush:HBRUSH
    local hMemBmp:HBITMAP
    local hMemBmp_old:HBITMAP
    local bm:BITMAP
    .if uMsg==WM_CREATE
        mov eax, offset StartupInfo
        mov GdiplusStartupInput.GdiplusVersion[eax], 1
        mov GdiPStatus, eax
        invoke GdiplusStartup, addr token, addr StartupInfo, 0
        invoke LoadLibrary, addr shlwapi
        mov hDll, eax
        invoke GetProcAddress, eax, addr func
        assume eax:ptr ApiFunc
        invoke eax, addr pPNG, ln_pPNG ; ln_pPNG is defined in logo.inc
        assume eax:nothing ; created by file data assembler fda
        mov pStream, eax
        invoke GdipCreateBitmapFromStream, pStream, addr PNGimage
    .elseif uMsg == WM_ERASEBKGND
        mov eax, 1
        ret
    .elseif uMsg==WM_PAINT
        invoke BeginPaint, hWnd, addr ps
        mov hdc, eax
        invoke GetClientRect, hWnd, addr rct
        invoke  CreateCompatibleDC, hdc
        mov    hMemDC, eax
        invoke  CreateCompatibleBitmap, hdc, rct.right, rct.bottom
        mov    hMemBmp, eax
        invoke SelectObject, hMemDC, hMemBmp
        mov hMemBmp_old, eax
        invoke CreateSolidBrush, 00FFDFBFh  ;; a nice light blue colr
        mov hBackBrush, eax  ;; save the brush handle
        invoke FillRect, hMemDC, addr rct, hBackBrush              ; fill rectangle in memory DC
        invoke DeleteObject, hBackBrush
       
        invoke DrawImage, hMemDC, PNGimage, 20, 12

        invoke BitBlt, hdc, 0, 0, rct.right, rct.bottom, hMemDC, 0, 0, SRCCOPY
        invoke SelectObject, hMemDC, hMemBmp_old
        invoke DeleteObject, hMemBmp
        invoke DeleteDC, hMemDC
        invoke EndPaint, hWnd, addr ps
    .elseif uMsg==WM_DESTROY
        invoke GdipDisposeImage, PNGimage
        coinvk pStream, IStream, Release
        invoke FreeLibrary, hDll
        invoke DeleteObject, hBitmap
        invoke GdiplusShutdown, GdiPStatus
        invoke PostQuitMessage, 0
    .ELSE
        invoke DefWindowProc, hWnd, uMsg, wParam, lParam
        ret
    .endif
    xor eax, eax
    ret
WndProc endp

DrawImage proc hDC:dword, Image:dword, x:dword, y:dword
local wid:dword, hgt:dword, pGraphics:dword
    invoke GdipCreateFromHDC, hDC, addr pGraphics
    invoke GdipGetImageWidth, Image, addr wid
    invoke GdipGetImageHeight, Image, addr hgt
    invoke GdipDrawImageRectI, pGraphics, Image, x, y, wid, hgt
    invoke GdipDeleteGraphics, pGraphics
    ret
DrawImage endp

end start

I have also modified your .png image to have the background as tranparent 32 bit RGBA, replacing the white background color with transparency for demonstration here. The light blue color is the window background color, not part of the image (for clarification).

Results upon running the modified program:


Original image 24 bit RGB, has actual white background 00FFFFFFh:


It is definitely a viable contender to replace loading .png images at runtime by the end user, even though that seems to be the easiest method. Never mind what I said in my last post. I confess that I hadn't looked at your program in any great detail, before posting that. I had briefly forgotten about it, until looking through this thread... I have occasional memory leaks, I forget things often.

I will be integrating your methods into my Connect4 project!  :smiley:
I'll deposit a substantial fee to your top secret account in the Cayman Islands.  :biggrin:

Quote from: TimoVJL on April 11, 2025, 10:10:09 PMThis was a good topic for GDI+
Yes. More to come... there are a lot of things I want to learn how to do with gdiplus.

adeyblue

QuoteThis was a good topic for GDI+
This is what happens if you treat unknowns as things to attack and learn from rather than things to be scared of

Quote from: TimoVJL on April 11, 2025, 10:10:09 PMIf users abandon Windows XP, SHCreateMemStream will be best choice for streams for GDI+.
If it's loaded it with ordinal 12 rather than by name, it goes back to Win2000.

zedd151

It did not occur to me immediately. That is a list for SHCreateMemStream from each version and service pack of Windows, maybe not all of them though.

I must be having a senior moment.  :rolleyes:

Originally this post contained something very different.


Biterider

Hi adeyblue
From were did you get that information?
It can be usefull for a lot of other things!

Regards, Biterider

jj2007

Quote from: Biterider on April 12, 2025, 03:35:41 PMFrom were did you get that information?

QuoteWhat are the ordinal numbers for SHCreateMemStream in various Windows versions?


ChatGPT said:
The SHCreateMemStream function in Windows is a utility function provided by Shell32.dll (or sometimes Shlwapi.dll) that creates a memory-based IStream object. The "ordinal number" of a function refers to its position in the export table of a DLL, and some functions (especially undocumented or internal ones) can be exported by ordinal only (i.e., without a name).

Here's a breakdown of SHCreateMemStream ordinal numbers across different Windows versions:

🧾 Known Ordinal Numbers for SHCreateMemStream
DLL    Windows Version    Ordinal    Notes
shlwapi.dll    Windows XP–7    12    Exported by ordinal only (not by name)
shlwapi.dll    Windows 8/8.1    Deprecated    Function moved or removed
shell32.dll    Windows 10+    Not by ordinal    Exported by name instead

TimoVJL

May the source be with you

jj2007

M$ Learn: Prior to Windows Vista, this function was not included in the public Shlwapi.h file, nor was it exported by name from Shlwapi.dll. To use it on earlier systems, you must call it directly from the Shlwapi.dll file as ordinal 12.

zedd151

Quote from: jj2007 on April 14, 2025, 01:05:37 AMM$ Learn: Prior to Windows Vista, this function was not included in the public Shlwapi.h file, nor was it exported by name from Shlwapi.dll. To use it on earlier systems, you must call it directly from the Shlwapi.dll file as ordinal 12.
In other words, if you are running any OS prior to Windows Vista, maybe an OS upgrade in long overdue? Just kidding, kind of.  :biggrin:

Of course a lot of users use a virtual machine for running older OS's, sometimes used for compatibility testing of programs for older Windows versions.

And a few diehards that run antique hardware that can only run older OS versions.



guga

The export SHCreateMemStream function located at shlwapi - which is also called "SHCreateMemStreamStub" (originallly from it´s pdb) is a export helper (uses delayload library).

In Windows10 the true function SHCreateMemStream is located inside the dll shcore.

Don´t know about other windows versions, but if in other versions of Windows, the shcore.dll also contains the SHCreateMemStream function, better call them directly. For example:

call 'shcore.SHCreateMemStream' 0, 100
If on windowsXP-7, the export is also a delayload import (I don´t doubt it can be), and if on those older systems the shcore also contains the SHCreateMemStream, then, there´s no worries. Just load this function from shcore rather then shlwapi


Note: Internally, the api SHCreateMemStream is a Com object, that uses classes such as the ones from: https://github.com/tpn/winsdk-10/blob/master/Include/10.0.14393.0/winrt/wrl/implements.h
https://github.com/microsoft/wil/blob/master/tests/workarounds/wrl/wrl/implements.h
such as: CanCastT and friends
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

TimoVJL

May the source be with you

TimoVJL

May the source be with you

zedd151

A quick mention of issues with various API's and their functions is common during discussion of any topic.

But continuing discussion like this may be more suited in its own topic? (Especially since the discussion does not return to the main intent of the topic.)

Just asking btw, not demanding...  :smiley:

I do not want any posts removed from here, but am asking politely that maybe a new topic might be more appropriate if this discussion about "shlwapi" and company is going to continue.