this is a demo about the GDI+ gif animation from Mikl__'s example.
1. Select a gif file in your disk, click "ApplyF" to play.
2. Use "msctls_trackbar32" and "ApplyT" to adjust speed.
3. Open the config dialogue with hotkey"ctrl+t", pasue with hotkey"ctrl+s",restore with hotkey"ctrl+a".
option casemap:none
option win64:7
include \UASM64\include\windows.inc
include \UASM64\include\Commctrl.inc
include \UASM64\include\ShlObj.inc
include \UASM64\include\gdiplus.inc
includelib \UASM64\Lib\user32.lib
includelib \UASM64\Lib\kernel32.lib
includelib \UASM64\Lib\shell32.lib
includelib \UASM64\Lib\gdi32.lib
includelib \UASM64\Lib\gdiplus.lib
TBrowseInfo struct
hwndOwner dq ?
pIDLRoot dq ?
pszDisplayName dq ?
lpszTitle dq ?
ulFlags dq ?
lpfn dq ?
lParam dq ?
iImage dq ?
TBrowseInfo ends
PItemIDList typedef ptr TBrowseInfo
ICO_MAIN equ 1000
DLG_MAIN equ 1001
DLG_CONFIG equ 1002
IDC_HOTKEYRESTORE equ 2000
IDC_HOTKEYPAUSE equ 2001
IDC_HOTKEYSETUPPARAMETERS equ 2002
IDC_EDT equ 3000
IDC_OPENFILE equ 3001
IDC_APPLYF equ 3002
ID_VSPEED equ 3003
ID_SLIDER equ 3004
IDC_APPLYT equ 3005
IDC_DEFALUTSPEED equ 90
xPROPID equ 05100h
.data?
hInstance dq ?
Main_hWnd dq ?
m_gdiplusToken dd ?
hHeap dq ?
.data
Guid_dimensionID \
dd 06AEDBD6Dh
dw 03FB5h
dw 0418Ah
db 083h,0A6h,07Fh,045h,022h,09Dh,0C8h,072h
nWidth dd 0
nHeight dd 0
vdxClient dd 0
vdyClient dd 0
nFrameCount dd 0
pPropertyItem_buffer dq 0
hImage dq 0
Vspeed SDWORD 90
STOP_FLAG BOOL FALSE
PAUSE_FLAG BOOL FALSE
hThread dq 0
NewPosition dq 0
szBuf db 260 dup(0)
.code
CenterScreen PROC USES rsi rdi hWnd:QWORD
LOCAL wRect:RECT
LOCAL h:DWORD
LOCAL w:DWORD
LOCAL x:DWORD
LOCAL y:DWORD
invoke GetWindowRect,hWnd,addr wRect
mov esi, wRect.bottom
sub esi, wRect.top
mov h,esi
shr esi, 1
mov edi, wRect.right
sub edi, wRect.left
mov w,edi
shr edi, 1
invoke GetSystemMetrics,SM_CYSCREEN
shr rax, 1
sub rax, rsi
mov y, eax
invoke GetSystemMetrics,SM_CXSCREEN
shr rax, 1
sub rax, rdi
mov x, eax
invoke MoveWindow,hWnd,x,y,w,h,TRUE
ret
CenterScreen ENDP
atodq proc uses rsi rdi pString:QWORD
; ----------------------------------------
; Convert decimal string into qword value
; return value in rax
; ----------------------------------------
xor rax, rax
mov rsi, pString
xor rcx, rcx
xor rdx, rdx
mov al, [rsi]
inc rsi
cmp al, 2Dh
jne proceed
mov al, [rsi]
not rdx
inc rsi
jmp proceed
@@:
sub al, 30h
lea rcx, [rcx+4*rcx]
lea rcx, [rax+2*rcx]
mov al, [rsi]
inc rsi
proceed:
or al, al
jne @B
lea rax, [rdx+rcx]
xor rax, rdx
ret
atodq endp
xSelectFile proc USES rbx hWin:QWORD,pTitle:QWORD,pOutBuf:QWORD
LOCAL xInfo:TBrowseInfo
invoke RtlZeroMemory,ADDR xInfo,sizeof TBrowseInfo
lea rax, xInfo
mov rcx, CStr("SelectFile")
mov (TBrowseInfo PTR [rax]).pszDisplayName, rcx
mov rcx,pTitle
mov (TBrowseInfo PTR [rax]).lpszTitle, rcx
mov rcx,hWin
mov (TBrowseInfo PTR [rax]).hwndOwner, rcx
mov (TBrowseInfo PTR [rax]).ulFlags, BIF_RETURNONLYFSDIRS or BIF_BROWSEINCLUDEFILES
invoke SHBrowseForFolder, addr xInfo
cmp rax, 0
je @Exit
mov rbx,rax
invoke SHGetPathFromIDList,rax,pOutBuf
invoke GlobalFree,rbx
@Exit:
ret
xSelectFile endp
InitGgdiplus proc
local @gdis:GdiplusStartupInput
mov @gdis.GdiplusVersion,1
mov @gdis.DebugEventCallback,0
mov @gdis.SuppressBackgroundThread,0
mov @gdis.SuppressExternalCodecs,0
invoke GdiplusStartup,addr m_gdiplusToken,addr @gdis,NULL
ret
InitGgdiplus endp
WorkerThread proc hWnd:HWND
LOCAL hDC:HDC
LOCAL graphics:QWORD
LOCAL FrameIndex:DWORD
.while STOP_FLAG == FALSE
invoke GetDC, hWnd
mov hDC, rax
invoke GdipCreateFromHDC,hDC,addr graphics
invoke GdipDrawImageRectI,graphics,hImage,0,0,nWidth,nHeight
;Selects the frame in this Image object specified by a dimension and an index.
invoke GdipImageSelectActiveFrame,hImage,addr Guid_dimensionID,FrameIndex
.if PAUSE_FLAG == FALSE
inc FrameIndex
mov eax,nFrameCount
sub eax,FrameIndex
jnz @f
mov FrameIndex,eax
.endif
@@:
invoke GdipDeleteGraphics,graphics
invoke ReleaseDC,hWnd, hDC
invoke Sleep,Vspeed
.endw
ret
WorkerThread endp
RestartThread proc
mov STOP_FLAG,TRUE
invoke WaitForSingleObject,hThread,INFINITE
invoke CloseHandle,hThread
mov STOP_FLAG,FALSE
invoke CreateThread,NULL,NULL,offset WorkerThread,Main_hWnd,NULL,NULL
mov hThread,rax
ret
RestartThread endp
InitGifFileParameters proc plFile:QWORD
LOCAL xw:DWORD
LOCAL xh:DWORD
LOCAL ptDiff:POINT
LOCAL rctWnd:RECT
LOCAL rctClient:RECT
LOCAL @Wfile[1024]:BYTE
LOCAL count:DWORD
LOCAL pDimensionIDs:QWORD
LOCAL xSize:DWORD
invoke RtlZeroMemory,addr @Wfile,sizeof @Wfile
invoke MultiByteToWideChar,CP_ACP,0,plFile,-1,addr @Wfile,1024
invoke GdipDisposeImage,hImage
invoke GdipLoadImageFromFile,addr @Wfile,addr hImage
;Gets the number of frame dimensions in this Image object.
invoke GdipImageGetFrameDimensionsCount,hImage,addr count
xor rcx,rcx
mov ecx,count
test ecx,ecx
jz @f
shl rcx,4
mov rax,rcx
invoke HeapAlloc,hHeap,HEAP_ZERO_MEMORY,rax
mov pDimensionIDs,rax
;Gets the identifiers for the frame dimensions of this Image object.
invoke GdipImageGetFrameDimensionsList,hImage,rax,count
;Gets the number of frames in a specified dimension of this Image object.
invoke GdipImageGetFrameCount,hImage,pDimensionIDs,addr nFrameCount
;Gets the size, in bytes, of a specified property item of this Image object.
invoke GdipGetPropertyItemSize,hImage,xPROPID,addr xSize
xor rcx,rcx
mov ecx,xSize
shl ecx,2
mov rax,rcx
invoke HeapAlloc,hHeap,HEAP_ZERO_MEMORY,rax
mov pPropertyItem_buffer,rax
;Gets a specified property item (piece of metadata) from this Image object.
invoke GdipGetPropertyItem,hImage,xPROPID,xSize,rax
invoke HeapFree,hHeap,HEAP_ZERO_MEMORY,pDimensionIDs
@@:
invoke GdipGetImageWidth,hImage,addr nWidth
invoke GdipGetImageHeight,hImage,addr nHeight
invoke GetClientRect,Main_hWnd,addr rctClient
invoke GetWindowRect,Main_hWnd,addr rctWnd
mov eax,rctWnd.right
sub eax,rctWnd.left
sub eax,rctClient.right
mov ptDiff.x,eax
mov eax,rctWnd.bottom
sub eax,rctWnd.top
sub eax,rctClient.bottom
mov ptDiff.y,eax
mov ecx,nHeight
add ecx,ptDiff.y
mov xh,ecx ;nHeight
mov ecx,nWidth
add ecx,ptDiff.x
mov xw,ecx
invoke MoveWindow,Main_hWnd,500,300,xw,xh,1
ret
InitGifFileParameters endp
ConfigDlg proc hWnd:QWORD,uMsg:DWORD,wParam:QWORD,lParam:QWORD
mov eax,uMsg
.if eax == WM_INITDIALOG
invoke SendDlgItemMessage,hWnd,ID_SLIDER,TBM_SETRANGEMIN,FALSE,0
invoke SendDlgItemMessage,hWnd,ID_SLIDER,TBM_SETRANGEMAX,FALSE,100
invoke SendDlgItemMessage,hWnd,ID_SLIDER,TBM_SETTICFREQ,2,0
.elseif eax == WM_COMMAND
mov rcx,wParam
.if cx == IDC_APPLYF
invoke RtlZeroMemory,addr szBuf,sizeof szBuf
invoke GetDlgItemText,hWnd,IDC_EDT,ADDR szBuf,sizeof szBuf
.if rax
invoke InitGifFileParameters,ADDR szBuf
invoke CenterScreen,Main_hWnd
invoke RestartThread
.else
invoke MessageBox, 0,CStr("Need GifFile"), CStr("Error:GetDlgItemText"), MB_OK or MB_ICONINFORMATION
.endif
.elseif cx == IDC_APPLYT
invoke RtlZeroMemory,addr szBuf,sizeof szBuf
invoke GetDlgItemText,hWnd,ID_VSPEED,ADDR szBuf,sizeof szBuf
.if rax
invoke atodq,ADDR szBuf
mov rcx,2000
mul rcx
mov rcx,100
div rcx ;(0-100%)*2000
mov Vspeed,eax
.else
mov Vspeed,IDC_DEFALUTSPEED
.endif
.elseif cx == IDC_OPENFILE
invoke RtlZeroMemory,addr szBuf,sizeof szBuf
invoke xSelectFile,hWnd,CStr("Select Your File"),addr szBuf
invoke SetDlgItemText,hWnd,IDC_EDT,addr szBuf
.endif
.elseif eax == WM_HSCROLL
mov rax,wParam
.if ax == TB_THUMBPOSITION ; Same as SB_THUMBPOSITION
mov rax,wParam
shr eax,16
xor rcx,rcx
mov cx,ax
mov NewPosition,rcx
invoke SendDlgItemMessage,hWnd,ID_SLIDER,TBM_SETPOS,TRUE,NewPosition
invoke RtlZeroMemory,addr szBuf,sizeof szBuf
invoke wsprintf,addr szBuf,CStr("%d"),NewPosition
invoke SendDlgItemMessage, hWnd,ID_VSPEED, WM_SETTEXT, FALSE, addr szBuf
.elseif ax == TB_THUMBTRACK ; Same as SB_THUMBTRACK
mov rax,wParam
shr eax,16
xor rcx,rcx
mov cx,ax
mov NewPosition,rcx
invoke SendDlgItemMessage,hWnd,ID_SLIDER,TBM_SETPOS,TRUE,NewPosition
invoke RtlZeroMemory,addr szBuf,sizeof szBuf
invoke wsprintf,addr szBuf,CStr("%d"),NewPosition
invoke SendDlgItemMessage, hWnd,ID_VSPEED, WM_SETTEXT, FALSE, addr szBuf
.endif
.elseif eax == WM_CLOSE
invoke EndDialog,hWnd,NULL
.else
mov rax,FALSE
ret
.endif
mov rax,TRUE
ret
ConfigDlg endp
MainDlgProc proc hWnd:QWORD,uMsg:DWORD,wParam:QWORD,lParam:QWORD
mov eax,uMsg
.if eax == WM_CREATE
mov rax,hWnd
mov Main_hWnd,rax
invoke RegisterHotKey, hWnd, IDC_HOTKEYPAUSE, MOD_CONTROL,"S"
invoke RegisterHotKey, hWnd, IDC_HOTKEYRESTORE, MOD_CONTROL,"A"
invoke RegisterHotKey, hWnd, IDC_HOTKEYSETUPPARAMETERS, MOD_CONTROL,"T"
invoke CreateDialogParam,hInstance,DLG_CONFIG,hWnd,offset ConfigDlg,NULL
invoke CloseHandle,rax
.elseif eax == WM_HOTKEY
mov rax, wParam
.if rax == IDC_HOTKEYPAUSE
mov PAUSE_FLAG,TRUE
.elseif rax == IDC_HOTKEYRESTORE
mov PAUSE_FLAG,FALSE
.elseif rax == IDC_HOTKEYSETUPPARAMETERS
invoke CreateDialogParam,hInstance,DLG_CONFIG,hWnd,offset ConfigDlg,NULL
invoke CloseHandle,rax
.endif
.elseif eax == WM_SIZE
mov rax,lParam
xor rcx,rcx
mov cx,ax
mov vdxClient,ecx
shr rax,16
xor rcx,rcx
mov cx,ax
mov vdyClient,ecx
.elseif eax == WM_CLOSE
mov STOP_FLAG,TRUE
invoke GdipDisposeImage,hImage
invoke HeapFree,hHeap,HEAP_ZERO_MEMORY,pPropertyItem_buffer
invoke DestroyWindow,hWnd
invoke PostQuitMessage,NULL
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor rax,rax
ret
MainDlgProc endp
_WinMain proc
LOCAL @stWndClass:WNDCLASSEX
LOCAL @stMsg:MSG
LOCAL hWnd:HANDLE
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
invoke LoadIcon,hInstance,ICO_MAIN
mov @stWndClass.hIcon,rax
mov @stWndClass.hIconSm,rax
invoke LoadCursor,0,IDC_ARROW
mov @stWndClass.hCursor,rax
mov rax,hInstance
mov @stWndClass.hInstance,rax
mov @stWndClass.cbSize,sizeof WNDCLASSEX
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW
lea rax,MainDlgProc
mov @stWndClass.lpfnWndProc,rax
mov @stWndClass.hbrBackground,COLOR_WINDOW + 1
mov rax,CStr("GdiTourClass")
mov @stWndClass.lpszClassName,rax
invoke RegisterClassEx,addr @stWndClass
invoke CreateWindowEx,WS_EX_CLIENTEDGE,CStr("GdiTourClass"),CStr("GDI+ gif animation"),\
WS_OVERLAPPEDWINDOW,400,200,400,300,NULL,NULL,hInstance,NULL
mov hWnd,rax
invoke ShowWindow,hWnd,SW_SHOWNORMAL
invoke UpdateWindow,hWnd
.while TRUE
invoke GetMessage,addr @stMsg,NULL,0,0
.break .if rax == 0
invoke TranslateMessage,addr @stMsg
invoke DispatchMessage,addr @stMsg
.endw
ret
_WinMain endp
WinMainCRTStartup Proc
invoke InitGgdiplus
invoke GetModuleHandle,NULL
mov hInstance,rax
invoke GetProcessHeap
mov hHeap, rax
invoke _WinMain
invoke GdiplusShutdown,m_gdiplusToken
invoke ExitProcess,NULL
ret
WinMainCRTStartup Endp
end
#include <\UASM64\include\resource.h>
#define ICO_MAIN 1000
#define IDC_CONFIG 1002
#define IDC_EDT 3000
#define IDC_OPENFILE 3001
#define IDC_APPLYF 3002
#define ID_VSPEED 3003
#define ID_SLIDER 3004
#define IDC_APPLYT 3005
ICO_MAIN ICON "Amain.ico"
IDC_CONFIG DIALOGEX 1,1,230,75
STYLE 0xD0C80000 | DS_CENTER | WS_MINIMIZEBOX | WS_CHILD | WS_VISIBLE | WS_SYSMENU
FONT 8,"Consolas"
CAPTION "Setup Gif Parameters"
BEGIN
LTEXT "Gif File:",-1,2,8,50,14,ES_LEFT
EDITTEXT IDC_EDT,40,6,172,14,ES_LEFT | ES_AUTOHSCROLL | WS_BORDER,WS_EX_CLIENTEDGE
PUSHBUTTON "...",IDC_OPENFILE,213,6,15,12,0
PUSHBUTTON "ApplyF",IDC_APPLYF,92,55,30,14,0
LTEXT "Speed:", -1, 8, 32, 24, 14
CONTROL "Slider",ID_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | 0x50000000,33,27,175,24
EDITTEXT ID_VSPEED,210,32,18,12,ES_READONLY | ES_CENTER | ES_NUMBER | WS_BORDER,WS_EX_CLIENTEDGE
PUSHBUTTON "ApplyT",IDC_APPLYT,127,55,30,14,0
END
if you can't immediately build exe and wanna to know "What is it? What does it do?". the post has bin attachment.
Hi six_L,
Can you help me understand more about the gdi+ functions that you use here.
I am trying to learn more about gdi+ myself, if you haven't seen my recent thread here. (https://masm32.com/board/index.php?topic=12605)
Specifically, I don't understand why you are calling GdipDisposeImage before you have even loaded the image or use hImage:
invoke GdipDisposeImage,hImage
invoke GdipLoadImageFromFile,addr @Wfile,addr hImage
That seems backwards to me, if I am not mistaken. Any reason to do it that way that I might be missing?
Thanks in advance, zedd
Hi,zedd151
Thanks for you did a respone.
If no one is interested, it's sad.
QuoteSpecifically, I don't understand why you are calling GdipDisposeImage before you have even loaded the image or use hImage.
the API releases hImage object and hImage's resources from memory. Frist time, the API will failed because of No hImage. But it does not influence the process.
While you are watching a gif animation, it is not the gif animation that you'r interesting. you'll open another gif file to watch. At this point, you need to call GdipDisposeImage. otherwise, The memory consumed by the process will be more and more.
Regards
six_L
Oh, okay.
Your explanation sounds quite logical, since it will run multiple times.
And yes, it does animate the .gif nicely. Nice work!
I am just recently learning about gdi+.
So maybe I can ask you some questions about gdi+ later?
Quote from: six_L on March 13, 2025, 07:58:14 AMIf no one is interested, it's sad.
Don't be too sad, six_L.
That happens sometimes. Even I have sevaral examples that I posted recently, no one left me any replies but a few members have downloaded the attachments.
We just don't have a lot of active members now, like we did even a few years ago.
Many members have left and they don't come back here anymore.
Plus remember it is not only forum members that can see your code examples that you post here, but Guests also see your code and can learn from it.
That is why I will always still post more examples even when no members are interested in it, because maybe some guests are interested in it and can learn from my examples. :smiley:
regards, Larry
Quote from: zedd151 on March 13, 2025, 08:31:54 AMEven I have sevaral game examples that I posted recently, no one left me any replies but a few members have downloaded the attachments
You are doing a great job with these examples, Zedd :thumbsup:
Quote from: jj2007 on March 13, 2025, 08:49:22 AMYou are doing a great job with these examples, Zedd :thumbsup:
Its not about me here, but six_L, he needs morale support.
Have you tried his example? He wants or needs feedback on what people think about it.
Quote from: six_L on January 23, 2025, 02:13:48 PMthis is a demo about the GDI+ gif animation from Mikl__'s example.
I don't have the \UASM\ setup to build the example, but the exe works fine - well done :thumbsup:
This isn't necessary, and depending on your windows settings, may breakpoint if you run it in a debugger:
invoke CreateDialogParam,hInstance,DLG_CONFIG,hWnd,offset ConfigDlg,NULL
invoke CloseHandle,rax
CloseHandle is for kernel objects, windows are user objects. Just ignore the HWND if you don't want it.
Also SHBrowseForFolder requires CoInitialize and the PIDL should be freed with CoTaskMemFree
Hi,zedd151
QuoteSo maybe I can ask you some questions about gdi+ later?
Sure. I have been here for a long time. Much something has been needed to learn forever. I have a feel that the newbies is belonged to me forever . so let's learn from each other.
Hi,adeyblue
QuoteThis isn't necessary, and depending on your windows settings, may breakpoint if you run it in a debugger:
invoke CreateDialogParam,hInstance,DLG_CONFIG,hWnd,offset ConfigDlg,NULL
invoke CloseHandle,rax
CloseHandle is for kernel objects, windows are user objects. Just ignore the HWND if you don't want it.
Also SHBrowseForFolder requires CoInitialize and the PIDL should be freed with CoTaskMemFree
Thanks you for the helpful information.
Regards
six_L
Quote from: adeyblue on March 13, 2025, 01:54:57 PMAlso SHBrowseForFolder requires CoInitialize
I don't think that is entirely true, since from what I have read elsewhere SHBrowseForFolder already calls CoInitialize internally already to initialize COM. Still wouldn't hurt to add it though, I would think.
This though, is definitely needed. :thumbsup:
Quoteand the PIDL should be freed with CoTaskMemFree
and I missed noticing that it was not in the source.
Thank you six_L, :thumbsup:
Is it possible to post a link to the example source code?
Thank you in advance. :smiley:
Quote from: ognil on Today at 04:59:41 AMIs it possible to post a link to the example source code?
Copy it to the clipboard and paste it into a file. Then save it...
If you are referring to Mikl_'s example where six_L is learning from, its here:
https://masm32.com/board/index.php?msg=67154 (https://masm32.com/board/index.php?msg=67154)
Is that the right one, six_L???
Thanks,
I tried to compile with masm64 VS but I get the error:
"cannot open include file '\UASM64\include\resource.h'"
I don't have UASM64 and I don't use macros in my code. Sorry :sad: