Hi Guys, i'm trying to color a normal button inside a dialog without using BS_OWNERDRAW or sublassing the dialog etc. For that i made a function that is called through WM_CTLCOLORBTN. It seems to be ok when painting the button (no need to release the dc, perhaps). But i´m failing to recover the text on the button. The goal is to paint the button with a specific color (in case:Red = 177, G = 179, B = 182) and paint the text (label) with white (Red = 255, G = 255, B = 255).
The code for painting the button is as:
; BITMAPINFO Structure
[BtnImgHdr:
BtnImgHdr.bmiHeader.biSize: D$ len
BtnImgHdr.bmiHeader.biWidth: D$ RAINBOW_WIDTH
BtnImgHdr.bmiHeader.biHeight: D$ RAINBOW_HEIGHT
BtnImgHdr.bmiHeader.biPlanes: W$ 1
BtnImgHdr.bmiHeader.biBitCount: W$ 32
BtnImgHdr.bmiHeader.biCompression: D$ 0
BtnImgHdr.bmiHeader.biSizeImage: D$ (RAINBOW_WIDTH*RAINBOW_HEIGHT)
BtnImgHdr.bmiHeader.biXPelsPerMeter: D$ 0
BtnImgHdr.bmiHeader.biYPelsPerMeter: D$ 0
BtnImgHdr.bmiHeader.biClrUsed: D$ 0
BtnImgHdr.bmiHeader.biClrImportant: D$ 0
BtnImgHdr.bmiColors.rgbBlue: B$ 0
BtnImgHdr.bmiColors.rgbGreen: B$ 0
BtnImgHdr.bmiColors.rgbRed: B$ 0
BtnImgHdr.bmiColors.rgbReserved: B$ 0]
; RECT Structure
[BtnRect:
BtnRect.left: D$ 0
BtnRect.top: D$ 0
BtnRect.right: D$ 0
BtnRect.bottom: D$ 0]
; hIcon = Handle of the window/dialog where the button is located
; hOldDc - DC of the button
; hCtrl = Handle of the control/button
Proc DrawButton:
Arguments @hIcon, @hOldDC, @hCtrl
Local @NewDC, @pvBits, @BtnWidth, @BtnHeight, @memBM
Structure @PAINTSTRUCT 64, @PAINTSTRUCT.hdcDis 0, @PAINTSTRUCT.fEraseDis 4,
@PAINTSTRUCT.rcPaint.X1Dis 8, @PAINTSTRUCT.rcPaint.Y1Dis 12, @PAINTSTRUCT.rcPaint.X2Dis 16, @PAINTSTRUCT.rcPaint.Y2Dis 20,
@PAINTSTRUCT.fRestoreDis 24, @PAINTSTRUCT.fIncUpdateDis 28, @PAINTSTRUCT.rgbReservedDis 32
Uses ecx, edx
; Just to clear the PAINTSTRUCT structure when we 1st start
call 'Rosmem.ZeroMemory' D@PAINTSTRUCT, Size_of_PAINTSTRUCT
; Create a compatible DC biased on the one from the control button
call 'GDI32.CreateCompatibleDC' D@hOldDC | mov D@NewDC eax
; Get it´ dimensions
call 'USER32.GetClientRect' D@hCtrl, BtnRect
mov eax D$BtnRect.right | sub eax D$BtnRect.left | mov D@BtnWidth eax
mov eax D$BtnRect.bottom | sub eax D$BtnRect.top | mov D@BtnHeight eax
; Set the dimensions of the control to the BITMAPINFOHEADER stucture used in CreateDIBSection
mov eax D@BtnWidth | mov D$BtnImgHdr.bmiHeader.biWidth eax
mov eax D@BtnHeight | mov D$BtnImgHdr.bmiHeader.biHeight eax
mov eax D@BtnWidth | imul eax D@BtnHeight | mov D$BtnImgHdr.bmiHeader.biSizeImage eax
mov W$BtnImgHdr.bmiHeader.biPlanes 1 ; at least one plane is necessary
mov W$BtnImgHdr.bmiHeader.biBitCount 32 ; and make teh image with 32 Bits. Enough for a good quality of a button
; The size stored at this variable is RAINBOW_WIDTH*RAINBOW_HEIGHT*4 bytes
; Create bitmap as DIB section. pvBits are the actual pixels of the image to be created
lea eax D@pvBits | mov D$eax 0
call 'GDI32.CreateDIBSection' D@NewDC, BtnImgHdr, &DIB_RGB_COLORS, eax, &NULL, 0
mov D@memBM eax
; Now we can styart filling our pixels on teh created image with whatever colorschema we like. Here i made a simple paint of
; the whole image with Red = 177, G = 179, B = 182
call FillbtnColor D@pvBits, D@BtnWidth, D@BtnHeight, {RGB 177,179,182}
call 'GDI32.SelectObject' D@NewDC, D@memBM
call 'USER32.BeginPaint' D@hCtrl, D@PAINTSTRUCT
mov eax D@hOldDC | mov D@PAINTSTRUCT.hdcDis eax
; make sure we are painting on the Button area only
mov eax D@BtnWidth | mov D@PAINTSTRUCT.rcPaint.X2Dis eax
mov eax D@BtnHeight | mov D@PAINTSTRUCT.rcPaint.Y2Dis eax
; Synchronize
call 'GDI32.GdiFlush'
call 'GDI32.BitBlt' D@PAINTSTRUCT.hdcDis, 0, 0, D@BtnWidth, D@BtnHeight, D@NewDC, 0, 0, &SRCCOPY
call 'USER32.ReleaseDC' D@hCtrl, D@PAINTSTRUCT.hdcDis
call 'USER32.EndPaint' D@hCtrl, D@PAINTSTRUCT
; the new dc is no longer needed, since we blitted/painted onto the old one
call 'GDI32.DeleteDC' D@NewDC
EndP
The above code generated something like this (I tested on the 1st button only):
(https://i.ibb.co/dgDyWVW/painting-Image2.png) (https://imgbb.com/)
It can be called like this:
...Else_If D@Message = &WM_CTLCOLORBTN
call DrawButton D@hWnd, D@wParam, D@lParam ; wParam = Dc of the button, lParam = Handle of the button
Note: The small rectangle over the text (the one that shows the btn is focused) was gone because i painted over the entire area (If i delete the old Dc (the original Dc from the btn) and create a new one, it reapppears, but it means i´ll need to delete the new dc later which i choose not to create another dc for the button, but use it´s own to repaint). The rectangle may be achieved through DrawFrameControl , but i didn´t analysed it yet
To try to paint the text with white i used
call 'GDI32.SetTextColor' D@NewDC, {RGB 255,255,255}
On the newdc before the BitBlit function...but..nothing happened. The returned value was ok, but no text showed up
Then i tried to use it after the bitblit (before releasing it) and again..nothing happened. It returned the old color of the font (black), but didn´t showed up the new color (white)
Any ideas without needing to use owerdraw stylings ?
I also tried to directly have access to the pixels of the button and manipulate them as will...but don´t know how to access them. If i could access the pixels of the control directly, it mwans i may could also use similar technique to acess the pixels of the fonts, and manipulate both directly. ut i have no idea how to achieve them
Hi Guga,
Google is your friend - it's not possible without using BS_OWNERDRAW :sad:
http://masm32.com/board/index.php?topic=4623.0
https://www.codeguru.com/cpp/controls/buttonctrl/advancedbuttons/article.php/c8395/Enhanced-Colored-Button.htm
Attention there is an issue with visual styles enabled:
https://stackoverflow.com/questions/20815233/owner-drawn-button-wm-ctlcolorbtn-and-wm-drawitem-clearing-an-hdc
Attached a snippet showing which messages are sent by an ordinary button - just run the exe.
Guga,
It sounds like you need to write a simple custom control and depending on what you need, it can be either a text button or a bitmap button. If you do it this way, its a pain the first time but then you can reuse it forever.
I would select the memBM into the NewDC just after creating it
call 'GDI32.SelectObject' D@NewDC, D@memBM
Save the previous/older dc so that it can be restored and deleted at end of painting operation
call 'GDI32.SelectObject' D@NewDC, D@memBM | mov D@memBMold eax
Then i would use GDI FillRect to paint using a rectangle and a brush:
Move D@BtnWidth into rect.right and D@BtnHeight into rect.bottom, could call a helper function like:
;------------------------------------------------------------------------------
; FillBtnColor - Fills a rectangle with a specific color
;
; lpFillRect is a pointer to a RECT containing the bounding box to fill
; dwFillColor is an RGBCOLOR to paint fill the rectangle with
;------------------------------------------------------------------------------
FillBtnColor PROC hdc:HDC, lpFillRect:LPRECT, FillColor:MUICOLORRGB
LOCAL hBrush:DWORD
LOCAL hBrushOld:DWORD
LOCAL rect:RECT
; Adjust rect for FillRect call
Invoke CopyRect, Addr rect, lpFillRect
inc rect.right
inc rect.bottom
Invoke GetStockObject, DC_BRUSH
mov hBrush, eax
Invoke SelectObject, hdc, eax
mov hBrushOld, eax
Invoke SetDCBrushColor, hdc, FillColor
Invoke FillRect, hdc, Addr rect, hBrush
.IF hBrushOld != 0
Invoke SelectObject, hdc, hBrushOld
Invoke DeleteObject, hBrushOld
.ENDIF
.IF hBrush != 0
Invoke DeleteObject, hBrush
.ENDIF
ret
FillBtnColor ENDP
Call it with:
call FillBtnColor, D@NewDC, Addr rect, {RGB 177,179,182}
For the text, you can use GDI SetBkColor to set it to the same color as the fill color used for the rectangle and using SetBkMode to OPAQUE. SetTextColor for the white color you desire.
Use GetWindowText to retrieve the buttons text using D@lParam is the button's handle and store in a temp buffer
Use DrawText to output the text retrieved and specify a few other flags like DT_SINGLELINE or DT_CENTER or DT_VCENTER - and it will paint the text the color specified by the value used in SetTextColor and the back area of the text part the color specified by value used in the SetBkColor call previously.
Only other thing to consider before calling DrawText is the font used which needs to be selected into the hdc first before calling DrawText, either a font handle passed to function or retrieved somehow:
call 'GDI32.SelectObject' D@NewDC, D@hFont | mov D@FontOld eax
After all the drawing, do the Bitblt and then clean up.
During clean up phase before deleting D@NewDC, reselect the old bitmap and old font into dc before deleting all the stuff now not required
call 'GDI32.SelectObject' D@NewDC, D@FontOld
call 'GDI32.DeleteObject' D@FontOld
; no call to delete font as perhaps its passed in as a param or stored somewhere and we will need it next time we call
call 'GDI32.SelectObject' D@NewDC, D@memBMold
call 'GDI32.DeleteObject' memBMold
call 'GDI32.DeleteObject' memBM ; dont need this now as it will be recreated each time
Have a look at the code i wrote for the ModernUI_Button (a custom button control) which you can take the code for and adapt any or all parts for your own usage: https://github.com/mrfearless/ModernUI/tree/master/Controls/ModernUI_Button
The focus rectangle can be a little awkward to add, as it needs to work with the main hdc and not a buffer, see _MUI_ButtonPaintFocusRect as an example
Some examples here:
http://abreojosensamblador.epizy.com/?Tarea=6&SubTarea=4#EjemplosFormatoNoEstandar
Hi guys, thanks a lot for the feedback. I´m quite close now, i guess. :mrgreen: :mrgreen:
(https://i.ibb.co/31wTmhR/Image122.png) (https://ibb.co/31wTmhR)
Hi JJ. I saw some articles saying it wasn´t possible, but, in fact, it seems to be possible. I suceeded to make it work (well...kind of), without using Owenerdraw or visual themes at all. Mr. Feerles library is really really handy to make the text works as expected :)
Hi Steve...Yup...it´s a custom control, i´m trying to make. I found an excellent example here:
https://stackoverflow.com/questions/18745447/how-can-i-change-the-background-color-of-a-button-winapi-c
But this one seems to use Ownerdraw or visual themes, but perhaps i can adapat the one i made to have those gradient colors as well. I´ll still need to see how the button will behave on hovering or clicking on it. The idea is retrieve the state of the button only using the function called from WM_CTLCOLORBTN to make it works on a single place, rather hen having to write several functions for each behaviour or forf windows messagees, such as WM_MOUSEMOVE etc etc.
I´ll take a look at Mr. Fearless library because it is really amazing. :thumbsup: :thumbsup: :thumbsup:
Hi Mr. Fearless...thank you a lot !!!!!! :greenclp: :greenclp: :greenclp: I was testing some of your functions to see how they work, such as MUIDPIScaleRect or MUIDPIScaleFont and implemented the suggestions you made . Apparently i suceeded to make it work, but i´ll only need to clean the code to make further tests. If it is ok, i´ll upload the file with at least one of the btns working before implement other routines (btn highlight or when we press on it, etc)
I saw your ModernUI Library a couple of days ago, and it is really amazing !!!! Btw...take a look at the link i posted to steve on the colored btn with gradient. Perhaps, this can also be implemented on your library :)
Btw...i have a small question about the way you suggested to make the FillBtnColor. I did as you suggested and it worked ok. But, why copying the pixels to a new brush etc, when we could simply draw over the pixels in pvBits ?
I mean, the original function i made for that was simply this:
Proc FillbtnColor:
Arguments @Pixels, @Width, @Height, @Color
Local @NextLine
Uses ebx, ecx, esi, edi
mov eax D@Width | shl eax 2 | mov D@NextLine eax
mov edi D@Pixels
mov esi D@Color
xor ebx ebx
.Do
xor ecx ecx
Do
mov D$edi+ecx*4 esi
inc ecx
Loop_Until ecx >= D@Width
add edi D@NextLine
inc ebx
.Loop_Until ebx >= D@Height
EndP
No need to create a new brush or use copyrect, fill rect etc. Is necessary to use this...
Proc FillbtnColorEx:
Arguments @hDC, @pFillRect, @FillColor
Local @hBrush, @hBrushOld
Structure @RECT 16, @RECT.leftDis 0, @RECT.topDis 4, @RECT.rightDis 8, @RECT.bottomDis 12
Uses ebx, ecx, esi, edi
; Adjust rect for FillRect call
call 'USER32.CopyRect' D@RECT, D@pFillRect
inc D@RECT.rightDis
inc D@RECT.bottomDis
call 'GDI32.GetStockObject' &DC_BRUSH
mov D@hBrush eax
call 'GDI32.SelectObject' D@hDC, eax
mov D@hBrushOld eax
call 'GDI32.SetDCBrushColor' D@hDC, D@FillColor
call 'USER32.FillRect' D@hDC, D@RECT, D@hBrush
If D@hBrushOld <> 0
call 'GDI32.SelectObject' D@hDC, D@hBrushOld
call 'GDI32.DeleteObject' D@hBrushOld
End_If
If D@hBrush <> 0
call 'GDI32.DeleteObject' D@hBrush
End_If
EndP
rather then the old function i made ? I mean, what is the difference of using al those Api´s rather then modifying the pixels directly ?
Thank you caballero. I´ll take a look right now :)
Thanks guga.
QuotePerhaps, this can also be implemented on your library :)
I did have a gradient filled background for an older version of what would become the ModernUI controls, so I could add it again at some point. Still to refactor some controls, and all of it is still work in progress ;-) but i will add it to be todo list.
QuoteI mean, what is the difference of using al those Api´s rather then modifying the pixels directly ?
At a guess its speed, accessing the pixels individually vs using FillRect - dont have anything scientific or speed measurement to say its faster tho - could be exactly the same. In my head i'm assuming FillRect is a gpu hardware supported operation which might be quicker - but no evidence to support that theory, just a belief.
I've added a MUIGDIPaintGradient function in preparation for using it in some controls (at some point) - It uses GradientFill from msimg32: https://github.com/mrfearless/ModernUI/blob/master/ModernUI/MUIGDIPaintGradient.asm
I will probably add in a few additional property definitions to the likes of ModernUI_Button
@ButtonBackColor EQU 24 ; Colorref, -1 = transparent
@ButtonBackColorAlt EQU 28 ; Colorref
@ButtonBackColorSel EQU 32 ; Colorref
@ButtonBackColorSelAlt EQU 36 ; Colorref
@ButtonBackColorDisabled EQU 40 ; Colorref
@ButtonBackColorTo EQU 44 ; Colorref, Gradient color to, -1 = not using gradients
@ButtonBackColorAltTo EQU 48 ; Colorref
@ButtonBackColorSelTo EQU 52 ; Colorref
@ButtonBackColorSelAltTo EQU 56 ; Colorref
@ButtonBackColorDisabledTo EQU 60 ; Colorref
By default the 'To' ones are set to -1, if there are not -1 then will use the base @ButtonBackColorXXX property for the gradient from color, and the @ButtonBackColorXXXTo property for the gradient to color - if that all makes sense. Thats the plan anyhow.
Ok, added in those changes to ModernUI_Button, and created a demo for it, setting the gradient colors to something gaudy looking for normal view so that the gradient effect is highly visible, and a subtle grey gradient for when mouse moves over the button
(https://i.postimg.cc/Vs3k0Fqs/MUIButton-Gradient.gif)
Hi guys,
I didn´t understood one thing regarding DrawText. When i have a text inside a rectangle that does not fits on it, i supposedly to use DT_CALCRECT to compute the dimensions of the text rectangle, but...i tried it and it don´t fits. Also, if i remove the DT_SINGLELINE the text don´t fits vertically.
So, how to proper calculate the area of the text rectangle on a way that when it exceeds the dimensions of the button, it rearranges the text to fit the rectangle ?
This is what i´ve got so far.
(https://i.ibb.co/jrDh1tB/Image1.png) (https://ibb.co/jrDh1tB)
The text "Save to RosAsm" is outside the rectangle boundaries.
The routine i did to display the text is as:
hCtrl - handle of the button control
pRect - pointer to the dimensions of the control. (i.e: It´s RECT structure)
hDC - Pointer to the destination DC where the text will be displayed
BgColor - The background color of the text
bkMode - The background mode of the text color (transparent or opaque)
TextColor - The color of the text
Proc SetTextColorEx:
Arguments @hCtrl, @pRect, @hDC, @BgColor, @bkMode, @TextColor
Local @TextSize
Structure @ControlText 264, @TmpControlTextDis 0
Uses edi, ecx, edx
If D@bkMode = &OPAQUE
call 'GDI32.SetBkColor' D@hDC, D@BgColor
End_If
call 'GDI32.SetBkMode' D@hDC, D@bkMode
call 'GDI32.SetTextColor' D@hDC, D@TextColor
call 'USER32.SendMessageA' D@hCtrl, &WM_GETTEXT, 264, D@ControlText
;call 'USER32.DrawTextA' D@hDC, D@ControlText, eax, D@pRect, &DT_VCENTER+&DT_CENTER+&DT_CALCRECT ?????
call 'USER32.DrawTextA' D@hDC, D@ControlText, eax, D@pRect, &DT_VCENTER+&DT_CENTER+&DT_SINGLELINE;+&DT_CALCRECT
EndP
I´ll post the full source once i succeed to fix this issue on the text. It may be good for others to build buttons on a customized way without the needs of visual styles or ownerdraw.
DT_CALCRECT will adjust the rectangle to the new size that would fit the text, if the text wont fit anyhow then this doesnt change that fact. In theory you might adjust the size of the button height to reflect that, if its multiline. For single line then same applies, if text wont fit the specified rect (based on buttons space to paint on) then it cant re-adjust to fit this rect.
You could change the font size and use GetTextExtent etc to figure out if the current fontsize would fit in the rect calc'd from DT_CALCRECT, but then the button text would be a lot smaller for one button.
Best bet is just to change the button text to "Save..." or "Export" to fit in with the button size and text size of the other buttons.
Thanks :) Done :)
Seems to be working now.
I made the routine as:
Proc SetTextColorEx:
Arguments @hCtrl, @pRect, @hDC, @BgColor, @bkMode, @TextColor
Local @TextSize, @CxCtrl, @CyCtrl, @WidthCtrl, @HeightCtrl, @WidthText, @HeightText
Structure @ControlText 280, @TmpControlTextDis 0, @RECT.LeftDis 264, @RECT.TopDis 268, @RECT.RightDis 272, @RECT.BottomDis 276
Uses edi, ecx, edx
mov D@RECT.LeftDis 0
mov D@RECT.TopDis 0
mov D@RECT.RightDis 0
mov D@RECT.BottomDis 0
If D@bkMode = &OPAQUE
call 'GDI32.SetBkColor' D@hDC, D@BgColor
End_If
call 'GDI32.SetBkMode' D@hDC, D@bkMode
call 'GDI32.SetTextColor' D@hDC, D@TextColor
call 'USER32.SendMessageA' D@hCtrl, &WM_GETTEXT, 264, D@ControlText
mov D@TextSize eax
lea edx D@RECT.LeftDis
call 'USER32.DrawTextA' D@hDC, D@ControlText, eax, edx, &DT_VCENTER+&DT_CENTER+&DT_CALCRECT
mov eax D@RECT.RightDis | sub eax D@RECT.LeftDis | mov D@WidthText eax
mov eax D@RECT.BottomDis | sub eax D@RECT.TopDis | mov D@HeightText eax
mov ecx D@pRect
mov eax D$ecx+RECT.rightDis | sub eax D$ecx+RECT.leftDis | mov D@WidthCtrl eax
mov eax D$ecx+RECT.bottomDis | sub eax D$ecx+RECT.topDis | mov D@HeightCtrl eax
mov eax D@WidthText
mov ecx D@HeightText
mov edx &DT_VCENTER+&DT_CENTER+&DT_SINGLELINE
If_Or eax > D@WidthCtrl, ecx > D@HeightCtrl
mov edx &DT_WORDBREAK+&DT_CENTER
End_If
mov eax D@TextSize
call 'USER32.DrawTextA' D@hDC, D@ControlText, eax, D@pRect, edx
EndP
here is the attached file.
The highlited buttons are working too (the focused button) and also when you click on it, the appearance obeys the rules of the pushed button (for the text).
The app currently opens only 32x32 icons or apps (dlls, exe etc) that contains 32x32 icons. (I´ll try update it later to open others icon formats/sizes as well.. The "save to rosAsm' button (on this version), do nothing except, exit the app. (I´ll later make this small test app on a dll to be used inside rosasm and also as a standalone app to use without rosasm).
When you open an icon (or exe), the icon is showed on the draw area, where you can directly draw/edit on the icon with the pencil cursor that shows when you hover on the draw area).
The 16 squares are the color palette used on the icon . When you use the left mouse btn and click on them the pencil will be drawn with the color that was selected.
When you right click on any of the 16 squares (after clicking in one of them), a rainbow palette will show up and you can choose whatever color you want. While you are in the rainbow, if you left click, it will choose the new color and also replace the color of the icon previously chosen. And if you right click while the rainbow is activated, you will exit the rainbow and go back to the draw area without changing any color.
The last btn (the 16th one - top bottom right ) is to choose any color for the pencil without changing the other colors of the icon.
Whenever you are in the rainbow area a hovering window will show up simulating the effect of a tooltip showing the Red, Green and Blue colors where the mouse cursor is located on the rainbow.
The buttons/menus are:
New - Create a new empty icon
Open - Open a ico file (32x32 only)
Save (save a ico file to disk)
Import (Impor a icon 32x32 from exe, dlls. etc)
Export to (export the icon to the exe. So it will replace the icon on the executavle with the one you draw/edit). be carefull if using this, because i didn´t finished testing it yet the export to an exe.
Save to rosAsm - Currently only exits the app. Soon i´ll reimport it to rosAsm to be used as a dll.
help - Currently do nothing.
The main routines for customizing the btn are:
;;
hIcon - Handle to the Window were the control belong to
hOldDC - Handle of thee Dc of the control as defined by WM_CTLCOLORBTN
hCtrl - Handle to the Button control
;;
Proc DrawButtonEx:
Arguments @hIcon, @hOldDC, @hCtrl
Local @NewDC, @pvBits, @BtnWidth, @BtnHeight, @memBM, @hFont, @OldFont, @memBMOld, @BtnStatus
Structure @BtnRect 16, @BtnRect.leftDis 0, @BtnRect.topDis 4, @BtnRect.rightDis 8, @BtnRect.bottomDis 12
Uses ecx, edx, ebx
mov D@BtnRect.leftDis 0
mov D@BtnRect.topDis 0
mov D@BtnRect.rightDis 0
mov D@BtnRect.bottomDis 0
call GetButtonStatus D@hCtrl
mov D@BtnStatus eax
; 1st Create a compatible DC biased on the one from the control button. This Dc is the one we are going to paint in.
call 'GDI32.CreateCompatibleDC' D@hOldDC | mov D@NewDC eax
; 2nd create a new font for the control and set it to our control....
call CreateNewControlFont D@hCtrl | mov D@hFont eax
; ... and select it to save it on the new DC
call 'GDI32.SelectObject' D@NewDC, D@hFont | mov D@OldFont eax
; Get the control dimensions and create a Dib image of it. So, we will retrieve their pixels to manipulate them directly
lea ecx D@pvBits | mov D$ecx 0
lea eax D@BtnWidth
lea ebx D@BtnHeight
call CreateDibButton D@hCtrl, D@NewDC, D@BtnRect, eax, ebx, ecx
mov D@memBM eax
; 3rd select the generated Dib image onto the Source Dc and save it to be blitted
call 'GDI32.SelectObject' D@NewDC, D@memBM | mov D@memBMOld eax
; Now we can start filling our pixels on the created image with whatever colorschema we like. Here i made a simple paint of
; the whole image with Red = 177, G = 179, B = 182
mov eax D@BtnWidth | imul eax D@BtnHeight | shl eax 2
call FastBtnFill D@pvBits, eax, {RGB 80,80,80}
Test_If D@BtnStatus &BST_FOCUS
call DrawFocusBtn D@NewDC, D@BtnWidth, D@BtnHeight, {RGB 0,0,0}
Test_End
Test_If D@BtnStatus &BST_PUSHED
add D@BtnRect.leftDis 2
add D@BtnRect.topDis 2
Test_End
call SetTextColorEx D@hCtrl, D@BtnRect, D@NewDC, {RGB 80,80,80}, &OPAQUE, {RGB 255,255,255}
call PaintButton D@hCtrl, D@hOldDC, D@NewDC, D@BtnWidth, D@BtnHeight
; and finally start cleaning all of this
call SafeCleanGDIObject D@NewDC, D@OldFont
call SafeCleanGDIObject D@NewDC, D@memBMOld ; this will also delete the pixels RainbowData
call 'GDI32.DeleteObject' D@memBM
; the new dc is no longer needed, since we blitted/painted onto the old one
call 'GDI32.DeleteDC' D@NewDC
EndP
___________________________________________________________________________________________________________
Proc GetButtonStatus:
Arguments @hCtrl
Uses ecx, edx
call 'USER32.SendMessageA' D@hCtrl, &BM_GETSTATE, 0, 0
; Check here if i can force a checking for the mouse hovering here to emulate a hottrack
EndP
;;
Create a new font for the control
hCtrl = Handle of the control that contains a font. It can be a button, tatic control etc.
Return value:
The fucntion will return in eax a new handle for the font
;;
Proc CreateNewControlFont:
Arguments @hCtrl
Uses ecx, edx, ebx
; Retrieves the font with which the control is currently drawing its text.
call 'USER32.SendMessageA' D@hCtrl, &WM_GETFONT, 0, 0
If eax = &NULL
; if no font is found, get the system one
call 'GDI32.GetStockObject' &SYSTEM_FONT
mov ebx eax
; ... and apply it to our control
call 'USER32.SendMessageA' D@hCtrl, &WM_SETFONT, eax, &TRUE
mov eax ebx
End_If
EndP
___________________________________________________________________________________________________________
[BITMAPINFO.bmiHeader.biSizeDis 0
BITMAPINFO.bmiHeader.biWidthDis 4
BITMAPINFO.bmiHeader.biHeightDis 8
BITMAPINFO.bmiHeader.biPlanesDis 12
BITMAPINFO.bmiHeader.biBitCountDis 14
BITMAPINFO.bmiHeader.biCompressionDis 16
BITMAPINFO.bmiHeader.biSizeImageDis 20
BITMAPINFO.bmiHeader.biXPelsPerMeterDis 24
BITMAPINFO.bmiHeader.biYPelsPerMeterDis 28
BITMAPINFO.bmiHeader.biClrUsedDis 32
BITMAPINFO.bmiHeader.biClrImportantDis 36
BITMAPINFO.bmiColors.rgbBlueDis 40
BITMAPINFO.bmiColors.rgbGreenDis 41
BITMAPINFO.bmiColors.rgbRedDis 42
BITMAPINFO.bmiColors.rgbReservedDis 43]
[Size_of_BITMAPINFO 44]
Proc CreateDibButton:
Arguments @hCtrl, @hDC, @pCtrlRect, @pBtnWidth, @pBtnHeight, @pvbits
Structure @BtnBitMapInfoPlus 60, @BITMAPINFO.bmiHeader.biSizeDis 0, @BITMAPINFO.bmiHeader.biWidthDis 4, @BITMAPINFO.bmiHeader.biHeightDis 8, @BITMAPINFO.bmiHeader.biPlanesDis 12,
@BITMAPINFO.bmiHeader.biBitCountDis 14, @BITMAPINFO.bmiHeader.biCompressionDis 16, @BITMAPINFO.bmiHeader.biSizeImageDis 20,
@BITMAPINFO.bmiHeader.biXPelsPerMeterDis 24, @BITMAPINFO.bmiHeader.biYPelsPerMeterDis 28, @BITMAPINFO.bmiHeader.biClrUsedDis 32,
@BITMAPINFO.bmiHeader.biClrImportantDis 36, @BITMAPINFO.bmiColors.rgbBlueDis 40, @BITMAPINFO.bmiColors.rgbGreenDis 41,
@BITMAPINFO.bmiColors.rgbRedDis 42, @BITMAPINFO.bmiColors.rgbReservedDis 43,
@RECT.LeftDis 44, @RECT.TopDis 48, @RECT.RightDis 52, @RECT.BottomDis 56
Uses ecx, edx
; The default RosAsm macro does not allows (yet) multiple structures inside a procedure/function such as:
; LOCAL wc :WNDCLASSEX
; LOCAL msg :MSG
; So, to overcome this, simply is needed to build the proper displacements of more then one structure in the same structure macro.
; Therefore, BtnBitMapInfoPlus is nothing more then the displacement of 2 structures BITMAPINFO and RECT one after the other
; and '60' is the total size of both. i.e: 44 for BITMAPINFO + 16 for RECT
; Important: In rosAsm, the structure macro ALWAYS comes after the Local macro. The macro 'uses' where created to preserves the registers (Push at beginning and pop before exiting the function)
; Clean the BtnBitMapInfoPlus structure before using it
call 'Rosmem.ZeroMemory' D@BtnBitMapInfoPlus, 60
; 1st get the dimensions of the controls
lea eax D@RECT.LeftDis
call 'USER32.GetClientRect' D@hCtrl, eax
; Then we copy our Ctrl rect to the output
mov ecx D@pCtrlRect
mov eax D@RECT.LeftDis | mov D$ecx+RECT.LeftDis eax
mov eax D@RECT.TopDis | mov D$ecx+RECT.TopDis eax
mov eax D@RECT.RightDis | mov D$ecx+RECT.RightDis eax
mov eax D@RECT.BottomDis | mov D$ecx+RECT.BottomDis eax
; calculate the width and height for output and also to use those values on the BITMAPINFO header structure
mov ecx D@pBtnWidth | mov eax D@RECT.RightDis | sub eax D@RECT.LeftDis | mov D$ecx eax
mov edx D@pBtnHeight | mov ecx D@RECT.BottomDis | sub ecx D@RECT.TopDis | mov D$edx ecx
; Fill BITMAPINFO structure with the dimensions of the control to the BITMAPINFOHEADER stucture used in CreateDIBSection and a minimum of information to generate the dib
mov D@BITMAPINFO.bmiHeader.biSizeDis Size_of_BITMAPINFO ; set the size of BITMAP Info structure
mov D@BITMAPINFO.bmiHeader.biWidthDis eax
mov D@BITMAPINFO.bmiHeader.biHeightDis ecx
mov W@BITMAPINFO.bmiHeader.biPlanesDis 1 ; at least one plane is necessary
mov W@BITMAPINFO.bmiHeader.biBitCountDis 32 ; and make the image with 32 Bits. Enough for a good quality of a button
; Since we zeroed at start, it means our image compression is BI_RGB (value = 0 = uncompressed). Therefore, no ned to set this member again
; Also, the bmicolors are set to zero too (NULL).
; mov D@BITMAPINFO.bmiHeader.biCompressionDis &BI_RGB
; mov B@BITMAPINFO.bmiColors.rgbBlueDis 0
; mov D@BITMAPINFO.bmiColors.rgbGreenDis 0
; mov D@BITMAPINFO.bmiColors.rgbRedDis 0
; mov B@BITMAPINFO.bmiColors.rgbReservedDis 0
; One last note. Since biCompression = BI_RGB, the biSizeImage member can also be settled to 0 (Already is, since we zeroed the whole structure at start)
; Therefore, we don´t have to calculate the size of the bitmap.
; All we need to understand is that for 32 bit images the pixels are in RGBA format, so 4 bytes, on a total array of width*height*4 bytes (Size of a dword = 4).
; Ref: https://docs.microsoft.com/pt-br/previous-versions/dd183376(v=vs.85)
; mov D@BITMAPINFO.bmiHeader.biSizeImageDis 0
; Finally we can create our dib image and retrieve the pixel data that will be stored in pvbits
call 'GDI32.CreateDIBSection' D@hDC, D@BtnBitMapInfoPlus, &DIB_RGB_COLORS, D@pvBits, &NULL, 0
EndP
; I chose to use SSE to fill the button to paint it way faster.
Proc FastBtnFill:
Arguments @pDest, @Length, @Color
Structure @FullSize 16, @DataSize1Dis 0, @DataSize2Dis 4, @DataSize3Dis 8, @DataSize4Dis 12
Uses esi, edi, ecx, edx, eax
mov edi D@pDest
mov esi D@FullSize
mov eax D@Color
mov D$esi eax | mov D$esi+4 eax | mov D$esi+8 eax | mov D$esi+12 eax
movdqu XMM1 X$esi
; we are copying a memory from 128 to 128 bytes at once
mov ecx D@Length
mov eax ecx | shr ecx 4 ; integer count. Divide by 16 (4 dwords)
jz L0> ; The memory size if smaller then 16 bytes long. Jmp over
; No we must compute he remainder, to see how many times we will loop
mov edx ecx | shl edx 4 | sub eax edx ; remainder. It can only have be 0 to 15 remainders bytes
mov edx 0 ; here it is used as an index
L1:
movdqu X$edi+edx*8 XMM1 ; copy the 1st 4 dwords from register XMM to edi
dec ecx
lea edx D$edx+2
jnz L1<
test eax eax | jz L4> ; No remainders ? Exit
jmp L9> ; jmp to the remainder computation
L0:
; If we are here, It means that the data is smaller then 16 bytes, and we ned to compute the remainder.
mov edx ecx | shl edx 4 | sub eax edx ; remainder. It can only have be 0 to 15 remainders bytes
L2:
; If the memory is not 4 dword aligned we may have some remainder here So, just clean them.
test eax eax | jz L4> ; No remainders ? Exit
L9:
lea edi D$edi+edx*8 ; mul edx by 8 to get the pos
L3: movsb | dec eax | jnz L3<
L4:
EndP
; FillbtnColorEx
[X_BORDERFOCUS 2]
[Y_BORDERFOCUS 2]
Proc DrawFocusBtn:
Arguments @hDC, @Width, @Height, @Color
Local @hPen, @hPenOld, @Cx, @Cy, @NewWidth, @NewHeight, @hBrush, @hBrushOld
Structure @RECT 16, @RECT.leftDis 0, @RECT.topDis 4, @RECT.rightDis 8, @RECT.bottomDis 12
call 'GDI32.GetStockObject' &DC_BRUSH
mov D@hBrush eax
call 'GDI32.SelectObject' D@hDC, eax
mov D@hBrushOld eax
call 'GDI32.SetDCBrushColor' D@hDC, D@Color
; cx and cy will be located a biut before the border of the btn
mov D@Cx X_BORDERFOCUS
mov D@Cy Y_BORDERFOCUS
mov eax D@Width | sub eax D@Cx | mov D@NewWidth eax | mov D@RECT.rightDis eax
mov eax D@Height | sub eax D@Cy | mov D@NewHeight eax | mov D@RECT.bottomDis eax
mov D@RECT.leftDis X_BORDERFOCUS
mov D@RECT.topDis Y_BORDERFOCUS
call 'USER32.FrameRect' D@hDC, D@RECT, D@hBrush
call SafeCleanGDIObject D@hDC, D@hBrushOld
call 'GDI32.DeleteObject' D@hBrush
EndP
; see later using ExtTextOutA
Proc SetTextColorEx:
Arguments @hCtrl, @pRect, @hDC, @BgColor, @bkMode, @TextColor
Local @TextSize, @CxCtrl, @CyCtrl, @WidthCtrl, @HeightCtrl, @WidthText, @HeightText
Structure @ControlText 280, @TmpControlTextDis 0, @RECT.LeftDis 264, @RECT.TopDis 268, @RECT.RightDis 272, @RECT.BottomDis 276
Uses edi, ecx, edx
mov D@RECT.LeftDis 0
mov D@RECT.TopDis 0
mov D@RECT.RightDis 0
mov D@RECT.BottomDis 0
If D@bkMode = &OPAQUE
call 'GDI32.SetBkColor' D@hDC, D@BgColor
End_If
call 'GDI32.SetBkMode' D@hDC, D@bkMode
call 'GDI32.SetTextColor' D@hDC, D@TextColor
call 'USER32.SendMessageA' D@hCtrl, &WM_GETTEXT, 264, D@ControlText
mov D@TextSize eax
lea edx D@RECT.LeftDis
call 'USER32.DrawTextA' D@hDC, D@ControlText, eax, edx, &DT_VCENTER+&DT_CENTER+&DT_CALCRECT
mov eax D@RECT.RightDis | sub eax D@RECT.LeftDis | mov D@WidthText eax
mov eax D@RECT.BottomDis | sub eax D@RECT.TopDis | mov D@HeightText eax
mov ecx D@pRect
mov eax D$ecx+RECT.rightDis | sub eax D$ecx+RECT.leftDis | mov D@WidthCtrl eax
mov eax D$ecx+RECT.bottomDis | sub eax D$ecx+RECT.topDis | mov D@HeightCtrl eax
mov eax D@WidthText
mov ecx D@HeightText
mov edx &DT_VCENTER+&DT_CENTER+&DT_SINGLELINE
If_Or eax > D@WidthCtrl, ecx > D@HeightCtrl
mov edx &DT_WORDBREAK+&DT_CENTER
End_If
mov eax D@TextSize
call 'USER32.DrawTextA' D@hDC, D@ControlText, eax, D@pRect, edx
EndP
Proc PaintButton:
Arguments @hCtrl, @hDCDest, @hDCSrc, @BtnWidth, @BtnHeight
Structure @PAINTSTRUCT 64, @PAINTSTRUCT.hdcDis 0, @PAINTSTRUCT.fEraseDis 4,
@PAINTSTRUCT.rcPaint.X1Dis 8, @PAINTSTRUCT.rcPaint.Y1Dis 12, @PAINTSTRUCT.rcPaint.X2Dis 16, @PAINTSTRUCT.rcPaint.Y2Dis 20,
@PAINTSTRUCT.fRestoreDis 24, @PAINTSTRUCT.fIncUpdateDis 28, @PAINTSTRUCT.rgbReservedDis 32
Uses ecx, edx
call 'Rosmem.ZeroMemory' D@PAINTSTRUCT, Size_of_PAINTSTRUCT
call 'USER32.BeginPaint' D@hCtrl, D@PAINTSTRUCT
mov eax D@hDCDest | mov D@PAINTSTRUCT.hdcDis eax
; make sure we are painting on the area only
mov eax D@BtnWidth | mov D@PAINTSTRUCT.rcPaint.X2Dis eax
mov eax D@BtnHeight | mov D@PAINTSTRUCT.rcPaint.Y2Dis eax
; Synchronize
call 'GDI32.GdiFlush'
call 'GDI32.BitBlt' D@PAINTSTRUCT.hdcDis, 0, 0, D@BtnWidth, D@BtnHeight, D@hDCSrc, 0, 0, &SRCCOPY
; release the DC and end the painting
call 'USER32.ReleaseDC' D@hCtrl, D@PAINTSTRUCT.hdcDis
call 'USER32.EndPaint' D@hCtrl, D@PAINTSTRUCT
EndP
; this function cleans the gdi objectes previously selected onto a DC
Proc SafeCleanGDIObject:
Arguments @hDC, @hObject
Uses ecx, edx
call 'GDI32.SelectObject' D@hDC, D@hObject
call 'GDI32.DeleteObject' D@hObject
EndP
The main function DrawButtonEx is used only once. I used it only at &WM_CTLCOLORBTN message . For that i created another function to hold it just for my tests, like:
...Else_If D@Message = &WM_CTLCOLORBTN
call ChangeButtonControlEx D@Adressee, D@wParam, D@lParam, {RGB 255,255,255}
mov eax D$hDialogBrush ; i created a brush on the WM_INITDIALOG message. So, in practise, eax doesn´t need to return anything at all !
ExitP
Proc ChangeButtonControlEx:
Arguments @hWnd, @hdc, @hControl, @Color
Local @hControlFrom
Uses ecx, edx
; 1st change the ex_style of all static controls
call 'user32.GetWindowLongA' D@hControl, &GWL_EXSTYLE ;// get current window styles
or eax &WS_EX_TRANSPARENT
call 'user32.SetWindowLongA' D@hControl, &GWL_EXSTYLE, eax ;// set the new header styles
; 2nd get the Button control we want to change the text color or dimensions etc
call DrawButtonEx D@hWnd, D@hdc, D@hControl
EndP
Note: All the pallette (btns) and the draw/rainbow area are not controls. They where created and drawn directly onto the dialog window. The only controls that do exists are the buttons and the static control i used to display the "Thumbnail" string.
Cool.
Noticed a tiny problem, GDI handles increase by 2 each time you paint a cell. Must be something not released or deleted somewhere, causing the gdi leak.
Tks :)
I´ll take a look on it. probably i forgot to delete some object. I´m still learning how to use the GDI Api properly. This icon editor in RosAsm was there for ages without any review. I was building other routines, but decided to stop a while and try to rebuild the icon editor completely.
Btw...How you detected the GDI leaking ? What is the app you used to it ? And how to know when a leak happens ?
I was just viewing GDI Handles on Process Explorer. Right click on the process and properties brings up the info. The Handles section bottom right of the performance tab. Click and paint and watch the GDI handles increase.
(https://i.postimg.cc/tgZT76F0/iconeditorgdileak.png)
guga,
With GDI, ALWAYS test your return values and keep track of what you allocate and must delete after. It sounds old fashioned but that is how you get GDI leak free.
Hi Steve
QuoteWith GDI, ALWAYS test your return values and keep track of what you allocate and must delete after. It sounds old fashioned but that is how you get GDI leak free.
Tks. :thumbsup: :thumbsup:
I´ll give a test on the app tonight to try to get rid of the leaking once i finished one more small routine. I managed to update one of the functions using BITMAPV5HEADER and forcing the dib to create the pixels in RGBA format rather then the default RGBQUAD. Msdn is poorly documented on this, but i suceeded to make it works . I was trying to understand what a hell this BI_BITFIELDS equate is all about when used to create a bitmap (or icon) with createdib.
Under the BMIHEADERV5 things becomes a bit hard to follow, but, to make the output be in RGBA all is necessary to invert the pixel mask and make sure to use BI_BITFIELDS rather then the default BI_RGB. I´m still giving a test on this to check for speed etc, but it seems fast when not use others Gdi apis to manipulate the pixels. I.e: when manipulating them directly it seems to be faster.
The updated function i created to paint a button is as:
______________________________________________
[BITMAPINFO_V5.bmiHeaderV5.bv5SizeDis 0
BITMAPINFO_V5.bmiHeaderV5.bv5WidthDis 4
BITMAPINFO_V5.bmiHeaderV5.bv5HeightDis 8
BITMAPINFO_V5.bmiHeaderV5.bv5PlanesDis 12
BITMAPINFO_V5.bmiHeaderV5.bv5BitCountDis 14
BITMAPINFO_V5.bmiHeaderV5.bV5CompressionDis 16
BITMAPINFO_V5.bmiHeaderV5.bv5SizeImageDis 20
BITMAPINFO_V5.bmiHeaderV5.bv5XPelsPerMeterDis 24
BITMAPINFO_V5.bmiHeaderV5.bv5YPelsPerMeterDis 28
BITMAPINFO_V5.bmiHeaderV5.bv5ClrUsedDis 32
BITMAPINFO_V5.bmiHeaderV5.bv5ClrImportantDis 36
BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 40
BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 44
BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 48
BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 52
BITMAPINFO_V5.bmiHeaderV5.bv5CSTypeDis 56
BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzXDis 60
BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzYDis 64
BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzZDis 68
BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzXDis 72
BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzYDis 76
BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzZDis 80
BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzXDis 84
BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzYDis 88
BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzZDis 92
BITMAPINFO_V5.bmiHeaderV5.bv5GammaRedDis 96
BITMAPINFO_V5.bmiHeaderV5.bv5GammaGreenDis 100
BITMAPINFO_V5.bmiHeaderV5.bv5GammaBlueDis 104
BITMAPINFO_V5.bmiHeaderV5.bV5IntentDis 108
BITMAPINFO_V5.bmiHeaderV5.bV5ProfileDataDis 112
BITMAPINFO_V5.bmiHeaderV5.bV5ProfileSizeDis 116
BITMAPINFO_V5.bmiHeaderV5.bV5ReservedDis 120
BITMAPINFO_V5.bmiColors.rgbBlueDis 124
BITMAPINFO_V5.bmiColors.rgbGreenDis 125
BITMAPINFO_V5.bmiColors.rgbRedDis 126
BITMAPINFO_V5.bmiColors.rgbReservedDis 127]
[Size_of_BITMAPINFO_V5 128]
[Size_Of_BITMAPV5HEADER 124]
;;
CreateDibButtonEx function
Arguments:
hCtrl (in) - Handle of the button control to be painted
hDC (in) - Handle of the DC of the control. The Dc is the destination one, where the control will be painted to.
pCtrlRect (out) - Pointer to a RECT structure that will be used to save the coordinates of the rectangle (button).
This argument is optional.
pBtnWidth (out) - Pointer to a variable (Dword size) use to save the width of the control.
pBtnHeight (out) - Pointer to a variable (Dword size) use to save the height of the control
pvbits (out) - Pointer to a variable (Dword size) where it will be used to store the pointer to the pixels array
of the generated dib file.
TopDown (in) - A variable used as a flag to determine the order of the dib pixels. It is the same behaviour as in any of
the BITMAPINFOHEADER, BITMAPINFO_V5, BITMAPINFO_V4, BITMAPINFO_V3 structures.
When the height of the bitmap (in pixels) is positive, the bitmap is a bottom-up DIB and its origin is the lower-left corner.
If the height is negative, the bitmap is a top-down DIB and its origin is the upper-left corner.
This flag is used to automate the order process. Therefore.
If TopDown is settled to &TRUE, the dib image is a top-down DIB (i.e.: the height becomes negative)
If TopDown is settled to &FALSE, the dib image is a bottom-up DIB (i.e.: the height becomes positive).
Setting to &FALSE is the default one for bitmaps, since the majority of the bitmaps are created in bottom-up order.
For icons, they are created using top-down DIBs so we must set this flag to &TRUE when working on icons.
IsRGBA (in) - A dib (bitmap) is generally created in gdi with RGBQUAD format as described in BITMAPINFO structure.
Afterall, a BITMAPINFO structure is formed by a BITMAPINFOHEADER (or BITMAPINFO_V5, BITMAPINFO_V4, BITMAPINFO_V3) followed
with a RGBQUAD array of structures, like this:
[RGBQUAD:
RGBQUAD.Blue: B$ 0
RGBQUAD.Green: B$ 0
RGBQUAD.Red: B$ 0
RGBQUAD.Alpha: B$ 0]
However, we can change the order of the pixels, and make the dib contains the pixel array in RGBA format.
This is what this parameter is used for.
If IsRGBA is settled to &TRUE, the pixels are in RGBA format (COLORREF). I.e:
[RGBA:
RGBA.Red: B$ 0
RGBA.Green: B$ 0
RGBA.Blue: B$ 0
RGBA.Alpha: B$ 0]
Note: Remembering that RGBA format is the same as COLORREF
[COLORREF:
COLORREF.Red: B$ 0
COLORREF.Green: B$ 0
COLORREF.Blue: B$ 0
COLORREF.Alpha: B$ 0]
Otherwise, if IsRGBA is settled to &FALSE, the pixels are in RGQUAD format.
Remarks:
If biHeight is negative, indicating a top-down DIB (i.e: when TopDown is &TRUE), biCompression must be either BI_RGB or BI_BITFIELDS.
Top-down DIBs cannot be compressed.
Therefore, the CreateDibButtonEx checks either the Dib must use BI_BITFIELDS or RGB. The rule (although unddocumented in msdn) is simple:
Whenever we set IsRGBA to TRUE, we invert the order of the pixels (channels red and blue are switched), forcing it to be displayed in RGBA format. Thus, the BI_BITFIELDS flag
is applied internally to make sure the result will be in RGBA.
When you want the DIB to be created in RGBQUAD simply set IsRGBA flag to &FALSE, and the BI_RGB will be applied internally using the default masks that
creates the RGBQUAD pixel order.
References:
Example of using BITMAPV5HEADER at:
https://chromium.googlesource.com/chromium/chromium/+/master/ui/gfx/icon_util.cc
https://stackoverflow.com/questions/4455655/how-do-i-create-a-bitmap-using-the-bitmapv5header-header
https://ios.develop-bugs.com/article/16690047/BITMAPV5HEADER+getting+RGBA+keep+A+at+255
https://msdn.microsoft.com/en-us/ie/dd372216(v=vs.100)#_color_bitmap.exe_a_command_line_utility_for_converting_bitmap_headers
;;
Proc CreateDibButtonEx:
Arguments @hCtrl, @hDC, @pCtrlRect, @pBtnWidth, @pBtnHeight, @pvbits, @TopDown, @IsRGBA
Structure @BtnBitMapInfoPlus 144, @BITMAPINFO_V5.bmiHeaderV5.bv5SizeDis 0, @BITMAPINFO_V5.bmiHeaderV5.bv5WidthDis 4, @BITMAPINFO_V5.bmiHeaderV5.bv5HeightDis 8,
@BITMAPINFO_V5.bmiHeaderV5.bv5PlanesDis 12, @BITMAPINFO_V5.bmiHeaderV5.bv5BitCountDis 14, @BITMAPINFO_V5.bmiHeaderV5.bV5CompressionDis 16,
@BITMAPINFO_V5.bmiHeaderV5.bv5SizeImageDis 20, @BITMAPINFO_V5.bmiHeaderV5.bv5XPelsPerMeterDis 24, @BITMAPINFO_V5.bmiHeaderV5.bv5YPelsPerMeterDis 28,
@BITMAPINFO_V5.bmiHeaderV5.bv5ClrUsedDis 32, @BITMAPINFO_V5.bmiHeaderV5.bv5ClrImportantDis 36, @BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 40,
@BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 44, @BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 48, @BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 52,
@BITMAPINFO_V5.bmiHeaderV5.bv5CSTypeDis 56, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzXDis 60,
@BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzYDis 64, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzZDis 68,
@BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzXDis 72, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzYDis 76,
@BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzZDis 80, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzXDis 84,
@BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzYDis 88, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzZDis 92,
@BITMAPINFO_V5.bmiHeaderV5.bv5GammaRedDis 96, @BITMAPINFO_V5.bmiHeaderV5.bv5GammaGreenDis 100, @BITMAPINFO_V5.bmiHeaderV5.bv5GammaBlueDis 104,
@BITMAPINFO_V5.bmiHeaderV5.bV5IntentDis 108, @BITMAPINFO_V5.bmiHeaderV5.bV5ProfileDataDis 112, @BITMAPINFO_V5.bmiHeaderV5.bV5ProfileSizeDis 116,
@BITMAPINFO_V5.bmiHeaderV5.bV5ReservedDis 120, @BITMAPINFO_V5.bmiColors.rgbBlueDis 124, @BITMAPINFO_V5.bmiColors.rgbGreenDis 125,
@BITMAPINFO_V5.bmiColors.rgbRedDis 126, @BITMAPINFO_V5.bmiColors.rgbReservedDis 127,
@RECT.LeftDis 128, @RECT.TopDis 132, @RECT.RightDis 136, @RECT.BottomDis 140
Uses ecx, edx
; The default RosAsm macro does not allows (yet) multiple structures inside a procedure/function such as:
; LOCAL wc :WNDCLASSEX
; LOCAL msg :MSG
; So, to overcome this, simply is needed to build the proper displacements of more then one structure in the same structure macro.
; Therefore, BtnBitMapInfoPlus is nothing more then the displacement of 2 structures BITMAPINFO and RECT one after the other
; and '144' is the total size of both. i.e: 128 for BITMAPINFO_V5 (Labeled here as: BMIHEADERV5, that is simply BITMAPINFO_V5 + one RGBQUAD) + 16 for RECT
; Important: In rosAsm, the structure macro ALWAYS comes after the Local macro. The macro 'uses' where created to preserves the registers (Push at beginning and pop before exiting the function)
; Clean the BtnBitMapInfoPlus structure before using it
call 'Rosmem.ZeroMemory' D@BtnBitMapInfoPlus, 144
; 1st get the dimensions of the controls
lea eax D@RECT.LeftDis
call 'USER32.GetClientRect' D@hCtrl, eax
; Then we copy our Ctrl rect to the output
If D@pCtrlRect <> 0
mov ecx D@pCtrlRect
mov eax D@RECT.LeftDis | mov D$ecx+RECT.LeftDis eax
mov eax D@RECT.TopDis | mov D$ecx+RECT.TopDis eax
mov eax D@RECT.RightDis | mov D$ecx+RECT.RightDis eax
mov eax D@RECT.BottomDis | mov D$ecx+RECT.BottomDis eax
End_If
; calculate the width and height for output and also to use those values on the BITMAPV5HEADER header structure
mov ecx D@pBtnWidth | mov eax D@RECT.RightDis | sub eax D@RECT.LeftDis | mov D$ecx eax
; TopDown height = negative
; bottom-up , height = positive
mov edx D@pBtnHeight | mov ecx D@RECT.BottomDis | sub ecx D@RECT.TopDis | mov D$edx ecx | On D@TopDown <> 0, neg ecx ; Default for top-down bitmap is &FALSE.
; Fill BITMAPINFO structure with the dimensions of the control to the BITMAPINFOHEADER stucture used in CreateDIBSection and a minimum of information to generate the dib
mov D@BITMAPINFO_V5.BMIHEADERV5.bv5SizeDis Size_Of_BITMAPV5HEADER ; set the size of BITMAPV5HEADER Info structure
mov D@BITMAPINFO_V5.BMIHEADERV5.bv5WidthDis eax
mov D@BITMAPINFO_V5.BMIHEADERV5.bv5HeightDis ecx
mov W@BITMAPINFO_V5.BMIHEADERV5.bv5PlanesDis 1 ; at least one plane is necessary
mov W@BITMAPINFO_V5.BMIHEADERV5.bv5BitCountDis 32 ; and make the image with 32 Bits. Enough for a good quality of a button
; Since we zeroed at start, it means our image compression is BI_RGB (value = 0 = uncompressed). Therefore, no need to set this member again
; Also, the bmicolors are set to zero too (NULL).
;mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_BITFIELDS
; mov B@BITMAPINFO_V5.bmiColors.rgbBlueDis 0
; mov D@BITMAPINFO_V5.bmiColors.rgbGreenDis 0
; mov D@BITMAPINFO_V5.bmiColors.rgbRedDis 0
; mov B@BITMAPINFO_V5.bmiColors.rgbReservedDis 0
; One last note. Since biCompression = BI_RGB, the biSizeImage member can also be settled to 0 (Already is, since we zeroed the whole structure at start)
; Therefore, we don´t have to calculate the size of the bitmap.
; All we need to understand is that for 32 bit images the pixels are in RGBA format, so 4 bytes, on a total array of width*height*4 bytes (Size of a dword = 4).
; Ref: https://docs.microsoft.com/pt-br/previous-versions/dd183376(v=vs.85)
; mov D@BITMAPINFO_V5.bmiHeader.biSizeImageDis 0
; Initializing the bitmap format to 32 bit ARGB. Ref: https://chromium.googlesource.com/chromium/chromium/+/master/ui/gfx/icon_util.cc
If D@IsRGBA = &TRUE
; make it in RGBA order
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 0FF
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 0FF00
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 0FF0000
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 0FF000000
mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_BITFIELDS
Else
; Setting to know. Transform the pixel order to RGBQUAD (the default one)
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 0FF0000
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 0FF00
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 0FF
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 0FF000000
mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_RGB
End_If
; Use the system color space. The default value is LCS_CALIBRATED_RGB, which
; causes us to crash if we don't specify the approprite gammas, etc.
; See: http://msdn.microsoft.com/en-us/library/ms536531(VS.85).aspx
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5CSTypeDis &LCS_WINDOWS_COLOR_SPACE
; Use a valid value for bV5Intent as 0 is not a valid one.
; See http://msdn.microsoft.com/en-us/library/dd183381(VS.85).aspx
mov D@BITMAPINFO_V5.bmiHeaderV5.bV5IntentDis &LCS_GM_IMAGES
; Finally we can create our dib image and retrieve the pixel data that will be stored in pvbits
call 'GDI32.CreateDIBSection' D@hDC, D@BtnBitMapInfoPlus, &DIB_RGB_COLORS, D@pvBits, &NULL, 0
EndP
called it as:
lea ecx D@pvBits | mov D$ecx 0
lea eax D@BtnWidth
lea ebx D@BtnHeight
call CreateDibButtonEx D@hCtrl, D@NewDC, D@BtnRect, eax, ebx, ecx, &FALSE, &TRUE
mov D@memBM eax
I also gave a test on a gradient fill outine (the one i posted earlier) and i will later try the ones from Mr. Fierless to check the speed. The result, so far is as:
(https://i.ibb.co/7Jdns04/Image1.png) (https://ibb.co/7Jdns04)
Once i succeed to fix the gdi leaking, i´ll rewrite the functions to coloring a button again and try to make it easier to use and post it here (maybe i´ll create a tiny library for that). Using BITMAPV5HEADER seems better then the default BITMAPINFO structure, because (in theory) it can be used to create transparent bitmaps without the needs of visual style or owerdrawn etc.
Hi Guys.
Can someone help me fix or understand what i´m doing wrong ? I´m trying to eliminate the gdi leaking, but got nothing yet. I believe it happens in one of the 2 main functions that uses gdi, but don´t know what i´m doing wrong.
One of them is this. Is it correct/preserving the gdi api ? This is the functions that creates the rainbow area (the color picker).
The color picker is created at WM_INITDIALOG. It creates the pvbits (the pixels) to be manipulated later on the app, and also exports the Gdi handle (rainbowDC) and the dib file to be used OldRainbowBitMap.
It works like this:
...If D@Message = &WM_INITDIALOG
call 'GDI32.CreateSolidBrush' {RGB 50,50, 50} | mov D$hDialogBrush eax
(...)
call CreateRainbowImage D$IconEditorHandle, OldRainbowBitMap, RainbowDC, RainbowData, D$SlideGreenPos
; Build a 2 dimensions color table in memory (blue/red):
[RainbowDC: D$ 0]
[RainBowHandle: D$ 0]
[OldRainbowBitMaP: D$ 0]
[IsRainbowActive: D$ 0]
[RainbowData: D$ 0] ; Rainbow pixels are stored here
(...)
- parameters - hIcon was the handle of the main windows (dispites it´s name), but it is not being used since i associated the dc with the whole screen rather then the dialog at call 'USER32.GetDC' &NULL
Proc CreateRainbowImage:
Arguments @hIcon, @pRainbowBitMap, @pRainBowDC, @pRainBowData, @SliderPos
Local @pvBits, @hDCImage, @hImageHandle
; Get any DC
call 'USER32.GetDC' &NULL | mov D@hDCImage eax
mov edi D@pRainBowDC
call 'GDI32.CreateCompatibleDC' D@hDCImage
mov D$edi eax
lea eax D@pvBits | mov D$eax 0
call InitializeDib D$edi, 256, 256, eax, RAINBOW_ORDER, RAINBOW_FORMAT
mov D@hImageHandle eax ; dibm
; copy our pvbit (the pixels) to our output and create the rainbow to it
mov eax D@pvBits
mov ecx D@pRainBowData | mov D$ecx eax
; filling colors data: The pixels ae in RGBA format (Same as COLORREF structure)
call CreateRainbowData D@pvBits, RAINBOW_FORMAT
; Select our created rainboww bitmnap to our created compatible handle to do whatever operations we want
; and later use BitBlt to display the image on screen
call 'GDI32.SelectObject' D$edi, D@hImageHandle
; Release DC
call 'user32.ReleaseDC' &NULL, D@hDCImage
mov edi D@pRainbowBitMap
mov eax D@hImageHandle
mov D$edi eax
EndP
RAINBOW_ORDER and RAINBOW_FORMAT are just equates to create the dib on a top-down or bottom-up order or in RGBA or RGBQUAD formats
[RAINBOW_ORDER_NORMAL &TRUE]
[RAINBOW_ORDER_INVERTED &FALSE]
[RAINBOW_ORDER RAINBOW_ORDER_NORMAL];NORMAL] ; &TRUE = Normal dib (TopDown. Height = negative). &FALSE = inverted dib (Bottom-Up. Height = positive)
[RAINBOW_IS_RGB 1]
[RAINBOW_IS_RGBQUAD 0]
[RAINBOW_FORMAT RAINBOW_IS_RGB] ; The format of the Rainbow in memory and also in physical format of the pixels. If the foprmat is RGB, we use &TRUE (RAINBOW_IS_RGB). Otherwise it is false (RAINBOW_IS_RGBQUAD)
InitializeDib is the function that creates the dib (similar to CreateDibButtonEx i used for the buttons)
Proc InitializeDib:
Arguments @hDC, @pBtnWidth, @pBtnHeight, @pvbits, @TopDown, @IsRGBA
Structure @BtnBitMapInfoPlus 144, @BITMAPINFO_V5.bmiHeaderV5.bv5SizeDis 0, @BITMAPINFO_V5.bmiHeaderV5.bv5WidthDis 4, @BITMAPINFO_V5.bmiHeaderV5.bv5HeightDis 8,
@BITMAPINFO_V5.bmiHeaderV5.bv5PlanesDis 12, @BITMAPINFO_V5.bmiHeaderV5.bv5BitCountDis 14, @BITMAPINFO_V5.bmiHeaderV5.bV5CompressionDis 16,
@BITMAPINFO_V5.bmiHeaderV5.bv5SizeImageDis 20, @BITMAPINFO_V5.bmiHeaderV5.bv5XPelsPerMeterDis 24, @BITMAPINFO_V5.bmiHeaderV5.bv5YPelsPerMeterDis 28,
@BITMAPINFO_V5.bmiHeaderV5.bv5ClrUsedDis 32, @BITMAPINFO_V5.bmiHeaderV5.bv5ClrImportantDis 36, @BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 40,
@BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 44, @BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 48, @BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 52,
@BITMAPINFO_V5.bmiHeaderV5.bv5CSTypeDis 56, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzXDis 60,
@BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzYDis 64, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzZDis 68,
@BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzXDis 72, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzYDis 76,
@BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzZDis 80, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzXDis 84,
@BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzYDis 88, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzZDis 92,
@BITMAPINFO_V5.bmiHeaderV5.bv5GammaRedDis 96, @BITMAPINFO_V5.bmiHeaderV5.bv5GammaGreenDis 100, @BITMAPINFO_V5.bmiHeaderV5.bv5GammaBlueDis 104,
@BITMAPINFO_V5.bmiHeaderV5.bV5IntentDis 108, @BITMAPINFO_V5.bmiHeaderV5.bV5ProfileDataDis 112, @BITMAPINFO_V5.bmiHeaderV5.bV5ProfileSizeDis 116,
@BITMAPINFO_V5.bmiHeaderV5.bV5ReservedDis 120, @BITMAPINFO_V5.bmiColors.rgbBlueDis 124, @BITMAPINFO_V5.bmiColors.rgbGreenDis 125,
@BITMAPINFO_V5.bmiColors.rgbRedDis 126, @BITMAPINFO_V5.bmiColors.rgbReservedDis 127,
@RECT.LeftDis 128, @RECT.TopDis 132, @RECT.RightDis 136, @RECT.BottomDis 140
Uses ecx, edx
; Clean the BtnBitMapInfoPlus structure before using it
call 'Rosmem.ZeroMemory' D@BtnBitMapInfoPlus, 144
mov eax D@pBtnWidth
mov ecx D@pBtnHeight | On D@TopDown <> 0, neg ecx ; Default for top-down bitmap is &FALSE.
; Fill BITMAPINFO structure with the dimensions of the control to the BITMAPINFOHEADER stucture used in CreateDIBSection and a minimum of information to generate the dib
mov D@BITMAPINFO_V5.BMIHEADERV5.bv5SizeDis Size_Of_BITMAPV5HEADER ; set the size of BITMAPV5HEADER Info structure
mov D@BITMAPINFO_V5.BMIHEADERV5.bv5WidthDis eax
mov D@BITMAPINFO_V5.BMIHEADERV5.bv5HeightDis ecx
mov W@BITMAPINFO_V5.BMIHEADERV5.bv5PlanesDis 1 ; at least one plane is necessary
mov W@BITMAPINFO_V5.BMIHEADERV5.bv5BitCountDis 32 ; and make the image with 32 Bits. Enough for a good quality of a button
; Since we zeroed at start, it means our image compression is BI_RGB (value = 0 = uncompressed). Therefore, no need to set this member again
; Also, the bmicolors are set to zero too (NULL).
;mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_BITFIELDS
; mov B@BITMAPINFO_V5.bmiColors.rgbBlueDis 0
; mov D@BITMAPINFO_V5.bmiColors.rgbGreenDis 0
; mov D@BITMAPINFO_V5.bmiColors.rgbRedDis 0
; mov B@BITMAPINFO_V5.bmiColors.rgbReservedDis 0
; One last note. Since biCompression = BI_RGB, the biSizeImage member can also be settled to 0 (Already is, since we zeroed the whole structure at start)
; Therefore, we don´t have to calculate the size of the bitmap.
; All we need to understand is that for 32 bit images the pixels are in RGBA format, so 4 bytes, on a total array of width*height*4 bytes (Size of a dword = 4).
; Ref: https://docs.microsoft.com/pt-br/previous-versions/dd183376(v=vs.85)
; mov D@BITMAPINFO_V5.bmiHeader.biSizeImageDis 0
; Initializing the bitmap format to 32 bit ARGB. Ref: https://chromium.googlesource.com/chromium/chromium/+/master/ui/gfx/icon_util.cc
If D@IsRGBA = &TRUE
; make it in RGBA order
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 0FF
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 0FF00
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 0FF0000
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 0FF000000
mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_BITFIELDS
Else
; Setting to know. Transform the pixel order to RGBQUAD (the default one)
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 0FF0000
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 0FF00
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 0FF
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 0FF000000
mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_RGB
End_If
; Use the system color space. The default value is LCS_CALIBRATED_RGB, which
; causes us to crash if we don't specify the approprite gammas, etc.
; See: http://msdn.microsoft.com/en-us/library/ms536531(VS.85).aspx
mov D@BITMAPINFO_V5.bmiHeaderV5.bv5CSTypeDis &LCS_WINDOWS_COLOR_SPACE
; Use a valid value for bV5Intent as 0 is not a valid one.
; See http://msdn.microsoft.com/en-us/library/dd183381(VS.85).aspx
mov D@BITMAPINFO_V5.bmiHeaderV5.bV5IntentDis &LCS_GM_IMAGES
; Finally we can create our dib image and retrieve the pixel data that will be stored in pvbits
call 'GDI32.CreateDIBSection' D@hDC, D@BtnBitMapInfoPlus, &DIB_RGB_COLORS, D@pvBits, &NULL, 0
EndP
; CreateRainbowData is the function that manipulates the pixels in the rainbow directly.
; Showing Square Rainbow for color choice:
Proc CreateRainbowData:
Arguments @pOutput, @IsRGB
If D@IsRGB = &TRUE
call CreateRainbowData_RGBA D@pOutput
Else
call CreateRainbowData_RGBQUAD D@pOutput
End_If
EndP
Proc CreateRainbowData_RGBA:
Arguments @pOutput
Uses ebx, ecx, edi
mov edi D@pOutput
xor ebx ebx
.Do
xor ecx ecx
Do
mov B$edi+ecx*4+RGBA.RedDis cl
mov B$edi+ecx*4+RGBA.GreenDis 0
mov B$edi+ecx*4+RGBA.BlueDis bl
mov B$edi+ecx*4+RGBA.AlphaDis 0
inc ecx
Loop_Until ecx >= 256
add edi (256*4)
inc ebx
.Loop_Until ebx >= 256
EndP
Proc CreateRainbowData_RGBQUAD:
Arguments @pOutput
Uses ebx, ecx, edi
mov edi D@pOutput
xor ebx ebx
.Do
xor ecx ecx
Do
mov B$edi+ecx*4+RGBQUAD.rgbBlueDis cl
mov B$edi+ecx*4+RGBQUAD.rgbGreenDis 0
mov B$edi+ecx*4+RGBQUAD.rgbRedDis bl
mov B$edi+ecx*4+RGBQUAD.rgbReservedDis 0
inc ecx
Loop_Until ecx >= 256
add edi (256*4)
inc ebx
.Loop_Until ebx >= 256
EndP
To show the rainbow a function was made to be used under mouse action. So, it is located inside other functions after WM_LBUTTONUP and WM_MOUSEMOVE. The main function is called ShowRainbow. This function is activated when the user right click on the toolbox squares and also when the user click the trackbar.
; call ShowRainbow D$IconEditorHandle, D$RainbowDC, D$RainbowData, D$SlideGreenPos
Proc ShowRainbow:
Arguments @hIcon, @hRainBowBC, @pRainbowPixels, @SliderPos
Local @RainbowData
Structure @PAINTSTRUCT 64, @PAINTSTRUCT.hdcDis 0, @PAINTSTRUCT.fEraseDis 4,
@PAINTSTRUCT.rcPaint.leftDis 8, @PAINTSTRUCT.rcPaint.topDis 12, @PAINTSTRUCT.rcPaint.rightDis 16, @PAINTSTRUCT.rcPaint.bottomDis 20,
@PAINTSTRUCT.fRestoreDis 24, @PAINTSTRUCT.fIncUpdateDis 28, @PAINTSTRUCT.rgbReservedDis 32
Uses ecx, edx
call FillRainBowNew D@pRainbowPixels, D@SliderPos
call 'Rosmem.ZeroMemory' D@PAINTSTRUCT, Size_of_PAINTSTRUCT
call 'USER32.BeginPaint' D@hIcon, D@PAINTSTRUCT
call 'USER32.GetDC' D@hIcon | mov D@PAINTSTRUCT.hdcDis eax
; Synchronize before we manipulate the pixels
call 'GDI32.GdiFlush'
call 'GDI32.BitBlt' D@PAINTSTRUCT.hdcDis, RAINBOW_CX_PIXEL_POS, RAINBOW_CY_PIXEL_POS, RAINBOW_WIDTH, RAINBOW_HEIGHT, D@hRainBowBC, 0, 0, &SRCCOPY
call 'USER32.ReleaseDC' D@hIcon, D@PAINTSTRUCT.hdcDis
call 'USER32.EndPaint' D@hIcon, D@PAINTSTRUCT
EndP
; FillRainBowNew is the one responsiblee for direct manipulation of the pixels when the user clicck teh trackbar, for example
; Fill Rainbow data biased on green pos of tracker
Proc FillRainBowNew:
Arguments @pOutput, @Slider
Uses ebx, ecx, edi
mov eax D@Slider
mov edi D@pOutput
xor ebx ebx
.Do
xor ecx ecx
Do
mov B$edi+ecx*4+RGBA.GreenDis al
inc ecx
Loop_Until ecx >= 256
add edi (256*4)
inc ebx
.Loop_Until ebx >= 256
EndP
The cleanup of the rainbow iss done when the user exits the app, so at WM_CLOSE or WM_DESTROY messages, like this:
Proc DeleteRainbowDCEx:
call 'GDI32.DeleteObject' D$OldRainbowBitMap ; dibm
; pvBits is no longer valid!!!
call 'GDI32.DeleteDC' D$RainbowDC ; dc1 this will also delete the pixels RainbowData
EndP
So, at CreateRainbowImage, do i need to use selectobject api ? If so, why / how ?
Hi Guga!
First brush is never deleted ¿?. But upload the file to see more.
Hi HSE, thanks :)
Here is the file. Remembering that the source is embedded. You need to open the file in RosAsm to see/edit the source.
There´s no brush on the function CreateRainbowImage, but, yes, the dib created at InitializeDib and the DC handle at CreateCompatibleDC are only deleted when the apps exits. The reason is to make the pixels (at pvBits) be available to direct manipulation on other parts of the app. I don´t know if i need to use selçect api on thiss part of the function etcc. I´m trying to understand how this leaking works and how to properly use the selectobject etc. The leaking is happenning in other parts of the app on functions that draws the icon on the screen, but those i´ll post later once i understand if this part of the code at CreateRainbowImage is correct or not.
Hi guga,
CreateSolidBrush
0040a96c
0040817b Proc
0040815a
make sure that every brush created with CreateSolidBrush gets properly destroyed, no other memory leaks found :tongue: I took an example program from the first page...
Thks LiaoMi
How you achieved the addresses of the leaking GDI ? Which program did you used to see the addresses ?
Quote from: guga on November 01, 2019, 05:27:46 AM
Thks LiaoMi
How you achieved the addresses of the leaking GDI ? Which program did you used to see the addresses ?
using Deleaker utility - deleaker.com, sometimes helps!
After CreateCompatibleDC must be DeleteDC, not ReleaseDC (ej line 1369)
I've also used this in the past: http://www.nirsoft.net/utils/gdi_handles.html
But quick checking with process explorer is my first step to see if there are any leaks first.
Hi fearless
yes, this is the one i´m currently using. I gave a test on the one LiaoMi told (deleaker), but, it accused no leak whatsoever Then i gave a try on GDIView and a few things i´m not understanding.
Here a shot, for example. Take a look at the fonts dc. When i force GDiVioew to refresh every second, the "detect counter' keeps ground. So i presume it is due to a gdi leaking right ?
(https://i.ibb.co/2j7bFMv/vfgsdffa-Image1.png) (https://ibb.co/2j7bFMv)
But...on the routines i made for the font, i was unable to find where it is leaking. That routine is like this:
Proc DrawButtonEx:
Arguments @hIcon, @hDCDest, @hCtrl
Local @NewDC, @pvBits, @BtnWidth, @BtnHeight, @memBM, @hFont, @OldFont, @memBMOld, @BtnStatus, @IsGradientFill
Structure @BtnRect 16, @BtnRect.leftDis 0, @BtnRect.topDis 4, @BtnRect.rightDis 8, @BtnRect.bottomDis 12
Uses ecx, edx, ebx
mov D@IsGradientFill &FALSE ; later make it as a structure to be usd in the btn conrols
mov D@BtnRect.leftDis 0
mov D@BtnRect.topDis 0
mov D@BtnRect.rightDis 0
mov D@BtnRect.bottomDis 0
call GetButtonStatus D@hCtrl
mov D@BtnStatus eax
; 1st Create a compatible DC biased on the one from the control button. This Dc is the one we are going to paint in.
call 'GDI32.CreateCompatibleDC' D@hDCDest | mov D@NewDC eax
; 2nd create a new font for the control and set it to our control....
call CreateNewControlFont D@hCtrl | mov D@hFont eax
; ... and select it to save it on the new DC
call 'GDI32.SelectObject' D@NewDC, D@hFont | mov D@OldFont eax
; Get the control dimensions and create a Dib image of it. So, we will retrieve their pixels to manipulate them directly
lea ecx D@pvBits | mov D$ecx 0
lea eax D@BtnWidth
lea ebx D@BtnHeight
call CreateDibButtonEx D@hCtrl, D@NewDC, D@BtnRect, eax, ebx, ecx, &FALSE, &TRUE
mov D@memBM eax
; 3rd select the generated Dib image onto the Source Dc and save it to be blitted
call 'GDI32.SelectObject' D@NewDC, D@memBM | mov D@memBMOld eax
.If D@IsGradientFill = &FALSE
; Now we can start filling our pixels on the created image with whatever colorschema we like. Here i made a simple paint of
; the whole image with Red = 177, G = 179, B = 182
mov eax D@BtnWidth | imul eax D@BtnHeight | shl eax 2
call FastBtnFill D@pvBits, eax, {RGB 80,80,80}
.Else
call CreateGradientFill D@pvBits, D@BtnWidth, D@BtnHeight, {RGB 255,180, 0}, {RGB 180, 0,0}
.End_If
Test_If D@BtnStatus &BST_FOCUS
call DrawFocusBtn D@NewDC, D@BtnWidth, D@BtnHeight, {RGB 0,0,0} ; here it is in RGB format
Test_End
Test_If D@BtnStatus &BST_PUSHED
add D@BtnRect.leftDis 2
add D@BtnRect.topDis 2
Test_End
call SetTextColorEx D@hCtrl, D@BtnRect, D@NewDC, {RGB 80,80,0}, &TRANSPARENT, {RGB 255,255,255} ; here color are in RGB format
call PaintButton D@hCtrl, D@hDCDest, D@NewDC, D@BtnWidth, D@BtnHeight
; and finally start cleaning all of this
call SafeCleanGDIObject D@NewDC, D@OldFont
call SafeCleanGDIObject D@NewDC, D@memBMOld ; this will also delete the pixels RainbowData
call 'GDI32.DeleteObject' D@memBM
; the new dc is no longer needed, since we blitted/painted onto the old one
call 'GDI32.DeleteDC' D@NewDC
EndP
The only function responsible for handling the font is at CreateNewControlFont
;;
Create a new font for the control
hCtrl = Handle of the control that contains a font. It can be a button, tatic control etc.
Return value:
The fucntion will return in eax a new handle for the font
;;
Proc CreateNewControlFont:
Arguments @hCtrl
Uses ecx, edx, ebx
; Retrieves the font with which the control is currently drawing its text.
call 'USER32.SendMessageA' D@hCtrl, &WM_GETFONT, 0, 0
If eax = &NULL
; if no font is found, get the system one
call 'GDI32.GetStockObject' &SYSTEM_FONT
mov ebx eax
; ... and apply it to our control
call 'USER32.SendMessageA' D@hCtrl, &WM_SETFONT, eax, &TRUE
mov eax ebx
End_If
EndP
DrawButtonEx is thbee one called from WM_CTLCOLORBTN messages....but....the font dc is deleted before the function ends, with SafeCleanGDIObject
; this function cleans the gdi objectes previously selected onto a DC
Proc SafeCleanGDIObject:
Arguments @hDC, @hObject
Uses ecx, edx
call 'GDI32.SelectObject' D@hDC, D@hObject
call 'GDI32.DeleteObject' D@hObject
EndP
So, since i deleted the new font at " call SafeCleanGDIObject D@NewDC, D@OldFont", shouldn´t be no leak at all ?
The only way i was ablee to remove the font for being listed in gdiview is adding a "call 'GDI32.DeleteObject' D@hFont" imemdiatelly before the end of the DrawButtonEx function. But, if i do that, the font become weird (fat/large) .
in safeclean: DeleteObject,eax
Indeed...but..now the font becomes weird.
(https://i.ibb.co/cDxH6Tk/Font-Image4.png) (https://ibb.co/cDxH6Tk)
How to make the font be thin again and release gdi at the same time ?
Hi Guga!
You have to:
- make font handle persistent (global in your application)
- create font at initialization (in WM_CREATE usually)
- delete the font at the end (in WM_DESTROY usually)
Quote from: HSE on November 01, 2019, 11:58:05 PM
- delete the font at the end (in WM_DESTROY usually)
Raymond Chen: (https://devblogs.microsoft.com/oldnewthing/?p=8683)
QuoteThe building is being demolished. Don't bother sweeping the floor and emptying the trash cans and erasing the whiteboards
Hi HSE
yes, i´m afraid i´ll have to do it on WM_CREATE/WM_INITDIALOG. Somehow windows is changing the font height whenever it calls a msg to WM_GETFONT (call 'USER32.SendMessageA' D@hCtrl, &WM_GETFONT). The original font height is 11 pixels, but after the 2nd time the routine enter on WM_CTLCOLORBTN to colorize other buttons, the font height is changed to 13. Also, the font in the static controls are changed too.
I´ll see what is happenning before trying to put some routines in WM_CREATE/WM_INITDIALOG, because perhaps there are being some changes in WM_FONTCHANGE whenever the gdi handles the font ?
Quote from: jj2007 on November 02, 2019, 01:25:05 AM
Raymond Chen: (https://devblogs.microsoft.com/oldnewthing/?p=8683)QuoteThe building is being demolished. Don't bother sweeping the floor and emptying the trash cans and erasing the whiteboards
It's the anti leak protocol to close everything you open :biggrin:
You close, free or release everything when you no longer need it while the program is running. But there is no need to close anything before calling ExitProcess.
Btw we had a thread over 6 years ago (http://masm32.com/board/index.php?topic=1762.msg18113#msg18113) where we launched 1,000 times an application that created 1,000 brushes without freeing them. Test it :badgrin:
Quote from: jj2007 on November 02, 2019, 06:47:08 AM
Btw we had a thread over 6 years ago (http://masm32.com/board/index.php?topic=1762.msg18113#msg18113) where we launched 1,000 times an application that created 1,000 brushes without freeing them. Test it :badgrin:
I follow several thread about same thing, and read the links you post !
Quote from: jj2007 on November 02, 2019, 06:47:08 AM
But there is no need to close anything before calling ExitProcess.
I know but I think leak detection system don't like that (:biggrin: I even remember).
Anyway the API is going to be called by the system. :thumbsup:
Ok, i succeeded to fix the gdi leaking for the fonts. Now, the font object is deleted on buttons. It does not show on GDIView anylonger.
(https://i.ibb.co/2S1hSVj/456-Image7.png) (https://ibb.co/2S1hSVj)
The only problem is that it works for buttons, only. On static controls, the font was also messed up.
The font is changed due to a weird behaviour on WM_ACTIVATE. Somehow it increases the height of the font of the controls if we use gdi to paint them and delete the old fonts. The solution was create a new font for each control (with one single function) on WM_CTLCOLORBTN (and probably i´ll have to do the same for WM_CTLCOLORSTATIC).
I don´t know why WM_ACTIVATE behave like that, but it is the cause of the fonts height being messed up.
I´ll clean up the code, fix the same problem for static controls, and restart searching for the other leakings, before posting the result here
Oki, guys...
I´m still struggling to understand why it is leaking. I´ll have to do it on the way Steve said, but still it is leaking somewhere.
In the meanwhile i made a routine onto RosAsm debugger to make easier to see those issues and alsso find the exact routine responsible for the leaking or the creation of the object (in RosAsm it should be easier to retrieve the correct label and address of the loaded object, but i didn´t implemented it yet).
(https://i.ibb.co/vcN61Dg/vgfsdg-Image1.png) (https://ibb.co/vcN61Dg)
It works the same as in GDiView (for 64 Bits, currently . Later i´ll adapt it to make it works on Win32 OS as well. Here i have AMD 64 Bits, so i cannot tests it on my old OS :( )...But...i have a small question concerning this GDIView and the way it get´s the type of objects
I grabbed all the necessary data to see the GDI objects through PE64, reaching the values on NtWow64QueryInformationProcess64 Api inside NTDLL (after adapted RosAsm debugger to work on it). Once i retrieved the PROCESS_BASIC_INFORMATION data, i then passed it through ReadProcessMemory using PEB64 as the parameter of lpBaseAddress member of this Api.
So far, so good. It read the GDITable of PEB64 at PEB64.GdiSharedHandleTable (I updated PEB structure for RosAsm, btw) and i succeeded to get the GDICELL Structure which is formed as:
[GDICELL_WOW64:
GDICELL_WOW64.pKernelAddress: Q$ 0
GDICELL_WOW64.wProcessId: W$ 0
GDICELL_WOW64.wCount: W$ 0
GDICELL_WOW64.wUpper: W$ 0
GDICELL_WOW64.wType: W$ 0
GDICELL_WOW64.pUserAddress: Q$ 0]
And the displacement (equates) of the above structure, is:
[GDICELL_WOW64.pKernelAddressDis 0
GDICELL_WOW64.wProcessIdDis 8
GDICELL_WOW64.wCountDis 10
GDICELL_WOW64.wUpperDis 12
GDICELL_WOW64.wTypeDis 14
GDICELL_WOW64.pUserAddressDis 16]
[Size_Of_GDICELL_WOW64 24]
To retrieve the handle of the GDI Object and the Type of object all is needed is:
movzx eax W$esi+GDICELL_WOW64.wUpperDis | shl eax 16 | add eax D@iCounter | mov D@GDIHandle eax
movzx eax W$esi+GDICELL_WOW64.wTypeDis | and eax 07F | mov D@GDIType eax
So, once i succeeded to get the Type, i then created more then 30 different types of GDI Objects to be analyzed, since Brushes, Bitmaps, Fonts (Logical or smaller fonbts etc etc), Colorspaces, directdraw, enhanced metafile, region, clip object, palette, etc etc etc
The problem is.....
On GDIView it displays sometimes extended information of certain types of Objects. For example, when analyzing some Bitmaps it sometimes display it like: "Width: %d, Height: %d, Bits/Pixel: %d"...BUT...it don´t collect the data of all objects that do exists...why is that ???? I mean, once GDIView (and mine) knows that there is a Bitmap object, why it collects info of some of them and other cases it fails miserably ?
I mean, to retrieve the "extended" information GDIView (and mine version) passes the GDiHandle to GetObject Api. So, Once we know the type of object i wrote a function like this:
[Size_Of_BITMAP 24]
Proc GDIViewGetBitMapInfo:
Arguments @GDIHandle, @pOutput
; Local @NewDC, @NewObject <--- Tried also to create a new DC and select the object trough it, but....nothing happened. Still returning 0
Structure @BITMAP 24, @BITMAP.bmTypeDis 0, @BITMAP.bmWidthDis 4, @BITMAP.bmHeightDis 8, @BITMAP.bmWidthBytesDis 12, @BITMAP.bmPlanesDis 16, @BITMAP.bmBitsPixelDis 18, @BITMAP.bmBitsDis 20
Uses edi, ecx, edx
call 'RosMem.ZeroMemory' D@BITMAP, Size_Of_BITMAP
call 'GDI32.GetObjectA' D@GDIHandle, Size_Of_BITMAP, D@BITMAP
On eax = 0, ExitP
mov edi D@pOutput
movzx eax W@BITMAP.bmBitsPixelDis
movzx ecx W@BITMAP.bmPlanesDis
imul eax ecx
If eax = 1
mov eax 1
Else_If eax <= 4
mov eax 4
Else_If eax <= 8
mov eax 8
Else_If eax <= 16
mov eax 16
Else_If eax <= 24
mov eax 24
Else
mov eax 32
End_If
C_call FormatStr edi, {'Width: %d, Height: %d, Bits/Pixel: %d, Format: %d bits', 0}, D@BITMAP.bmWidthDis, D@BITMAP.bmHeightDis, D@BITMAP.bmBitsPixelDis, eax
add edi eax
mov B$edi 0
EndP
The main problem is that GetObject constantly returns 0 . In mine version and also in GDIView one. But..why it is returning 0, if we retrieved the GDI Handle of the object ????
Also....is there another way to collect the "extra' info of certain objects directly through one of the PEB structures, rather then using GetObject Api ???
Another question...What is this pUserAddress in GDICELL all about ? It does not seems the same address as it was stored the object inside the App. Someone knows what exactly is this member of the GDICELL structure ?
Note: Later i´ll implement the counter of objects to try seeking for leaking as it have in GDIview, but, i´ll try to see if i can collect the extra info 1st.
Reference of updated PEB/TEB structures in:
http://terminus.rewolf.pl/terminus
Also, more references i used are:
https://codeday.me/es/qa/20190409/458369.html
http://www.siddim.com/archives/7296.html
https://docs.microsoft.com/en-us/previous-versions/bb985767(v=msdn.10)?redirectedfrom=MSDN
http://www.verysource.com/code/5942649_1/PogyGDI.cpp.html
https://docs.microsoft.com/en-us/previous-versions/bb985767(v=msdn.10)?redirectedfrom=MSDN
https://reactos.org/wiki/Techwiki:Win32k/gdiobjects
extended info: https://reactos.org/wiki/Techwiki:Win32k/gdiobjects
https://www.yumpu.com/en/document/read/58026165/lpe-vulnerabilities-exploitation-on-windows-10-anniversary-update/3
https://chromium.googlesource.com/external/github.com/giampaolo/psutil/+/master/psutil/arch/windows/process_info.c
https://wj32.org/processhacker/forums/viewtopic.php?t=181
https://gist.github.com/hasherezade/87158b926e33418f5d3b0a0026d0ccc2
https://chromium.googlesource.com/external/github.com/giampaolo/psutil/+/master/psutil/arch/windows/process_info.c
https://github.com/w4kfu/whook/blob/master/src/include/pestuff.h <-----
from reactOS https://doxygen.reactos.org/df/ddf/ntgdihdl_8h_source.html
https://github.com/sam-b/windows_kernel_address_leaks <----- (GdiSharedHandleTable)
http://bytepointer.com/resources/tebpeb64.htm
http://terminus.rewolf.pl/terminus/structures/ntdll/_PEB_x64.html
https://github.com/securesean/Shim-Process-Scanner/tree/master/Shim-Process-Scanner
http://blog.rewolf.pl/blog/?p=1438#more-1438
https://labs.f-secure.com/archive/a-tale-of-bitmaps/
https://aloiskraus.wordpress.com/2016/06/25/show-gdi-handles-by-type-in-windbg/
https://stackoverflow.com/questions/13905661/how-to-get-list-of-gdi-handles
Btw....PEB64 is given like this (Updated to the last Windows 10 version
[PEB64:
PEB64.InheritedAddressSpace: B$ 0
PEB64.ReadImageFileExecOptions: B$ 0
PEB64.BeingDebugged: B$ 0
PEB64.SpareBool: B$ 0
PEB64.Padding1: D$ 0
PEB64.Mutant: Q$ 0
PEB64.ImageBaseAddress: Q$ 0
PEB64.LdrData: Q$ 0
PEB64.ProcessParameters: Q$ 0
PEB64.SubSystemData: Q$ 0
PEB64.ProcessHeap: Q$ 0
PEB64.FastPebLock: Q$ 0
PEB64.FastPebLockRoutine: Q$ 0
PEB64.FastPebUnlockRoutine: Q$ 0
PEB64.EnvironmentUpdateCount: Q$ 0
PEB64.KernelCallbackTable: Q$ 0
PEB64.EventLogSection: D$ 0
PEB64.EventLog: D$ 0
PEB64.FreeList: Q$ 0
PEB64.TlsExpansionCounter: Q$ 0
PEB64.TlsBitmap: Q$ 0
PEB64.TlsBitmapBits: D$ 0 #2
PEB64.ReadOnlySharedMemoryBase: Q$ 0
PEB64.ReadOnlySharedMemoryHeap: Q$ 0
PEB64.ReadOnlyStaticServerData: Q$ 0
PEB64.AnsiCodePageData: Q$ 0
PEB64.OemCodePageData: Q$ 0
PEB64.UnicodeCaseTableData: Q$ 0
PEB64.NumberOfProcessors: D$ 0
PEB64.NtGlobalFlag: D$ 0
PEB64.CriticalSectionTimeout: Q$ 0
PEB64.HeapSegmentReserve: Q$ 0
PEB64.HeapSegmentCommit: Q$ 0
PEB64.HeapDeCommitTotalFreeThreshold: Q$ 0
PEB64.HeapDeCommitFreeBlockThreshold: Q$ 0
PEB64.NumberOfHeaps: D$ 0
PEB64.MaximumNumberOfHeaps: D$ 0
PEB64.ProcessHeaps: Q$ 0
PEB64.GdiSharedHandleTable: Q$ 0
PEB64.ProcessStarterHelper: Q$ 0
PEB64.GdiDCAttributeList: Q$ 0
PEB64.LoaderLock: Q$ 0
PEB64.OSMajorVersion: D$ 0
PEB64.OSMinorVersion: D$ 0
PEB64.OSBuildNumber: W$ 0
PEB64.OSCSDVersion: W$ 0
PEB64.OSPlatformId: D$ 0
PEB64.ImageSubSystem: D$ 0
PEB64.ImageSubSystemMajorVersion: D$ 0
PEB64.ImageSubSystemMinorVersion: D$ 0
PEB64.Padding2: D$ 0
PEB64.ImageProcessAffinityMask: Q$ 0
PEB64.GdiHandleBuffer: Q$ 0 #30
PEB64.PostProcessInitRoutine: Q$ 0
PEB64.TlsExpansionBitmap: Q$ 0
PEB64.TlsExpansionBitmapBits: D$ 0 #32
PEB64.SessionId: D$ 0
PEB64.Padding3: D$ 0
PEB64.AppCompatFlags: Q$ 0
PEB64.AppCompatFlagsUser: Q$ 0
PEB64.pShimData: Q$ 0
PEB64.AppCompatInfo: Q$ 0
PEB64.CSDVersion.UnicodeStr64.Length: D$ 0
PEB64.CSDVersion.UnicodeStr64MaximumLength: D$ 0
PEB64.CSDVersion.UnicodeStr64Buffer: Q$ 0
PEB64.ActivationContextData: Q$ 0 ; Points to ACTIVATION_CONTEXT_DATA structure
PEB64.ProcessAssemblyStorageMap: Q$ 0
PEB64.SystemDefaultActivationContextData: Q$ 0 ; Points to ACTIVATION_CONTEXT_DATA structure
PEB64.SystemAssemblyStorageMap: Q$ 0
PEB64.MinimumStackCommit: Q$ 0
PEB64.FlsCallback: Q$ 0
PEB64.FlsListHead.Flink: Q$ 0
PEB64.FlsListHead.Blink: Q$ 0
PEB64.FlsBitmap: Q$ 0
PEB64.FlsBitmapBits: D$ 0 #4
PEB64.FlsHighIndex: Q$ 0
PEB64.WerRegistrationData: Q$ 0
PEB64.WerShipAssertPtr: Q$ 0
PEB64.pContextData: Q$ 0
PEB64.pImageHeaderHash: Q$ 0
PEB64.TracingFlags: D$ 0
PEB64.Padding4: D$ 0
PEB64.CsrServerReadOnlySharedMemoryBase: Q$ 0
PEB64.TppWorkerpListLock: Q$ 0
PEB64.TppWorkerpList.Flink: Q$ 0
PEB64.TppWorkerpList.Blink: Q$ 0
PEB64.WaitOnAddressHashTable: Q$ 0 #128]
and PEB (PEB32) is like:
[PEB:
PEB.InheritedAddressSpace: B$ 0
PEB.ReadImageFileExecOptions: B$ 0
PEB.BeingDebugged: B$ 0
PEB.SpareBool: B$ 0
PEB.Mutant: D$ 0
PEB.ImageBaseAddress: D$ 0
PEB.LdrData: D$ 0
PEB.ProcessParameters: D$ 0
PEB.SubSystemData: D$ 0
PEB.ProcessHeap: D$ 0
PEB.FastPebLock: D$ 0
PEB.FastPebLockRoutine: D$ 0
PEB.FastPebUnlockRoutine: D$ 0
PEB.EnvironmentUpdateCount: D$ 0
PEB.KernelCallbackTable: D$ 0
PEB.EventLogSection: D$ 0
PEB.EventLog: D$ 0
PEB.FreeList: D$ 0
PEB.TlsExpansionCounter: D$ 0
PEB.TlsBitmap: D$ 0
PEB.TlsBitmapBits: D$ 0 #2
PEB.ReadOnlySharedMemoryBase: D$ 0
PEB.ReadOnlySharedMemoryHeap: D$ 0
PEB.ReadOnlyStaticServerData: D$ 0
PEB.AnsiCodePageData: D$ 0
PEB.OemCodePageData: D$ 0
PEB.UnicodeCaseTableData: D$ 0
PEB.NumberOfProcessors: D$ 0
PEB.NtGlobalFlag: D$ 0
PEB.Spare2: B$ 0 #4
PEB.CriticalSectionTimeout: Q$ 0
PEB.HeapSegmentReserve: D$ 0
PEB.HeapSegmentCommit: D$ 0
PEB.HeapDeCommitTotalFreeThreshold: D$ 0
PEB.HeapDeCommitFreeBlockThreshold: D$ 0
PEB.NumberOfHeaps: D$ 0
PEB.MaximumNumberOfHeaps: D$ 0
PEB.ProcessHeaps: D$ 0
PEB.GdiSharedHandleTable: D$ 0
PEB.ProcessStarterHelper: D$ 0
PEB.GdiDCAttributeList: D$ 0
PEB.LoaderLock: D$ 0
PEB.OSMajorVersion: D$ 0
PEB.OSMinorVersion: D$ 0
PEB.OSBuildNumber: W$ 0
PEB.OSCSDVersion: W$ 0
PEB.OSPlatformId: D$ 0
PEB.ImageSubSystem: D$ 0
PEB.ImageSubSystemMajorVersion: D$ 0
PEB.ImageSubSystemMinorVersion: D$ 0
PEB.ImageProcessAffinityMask: D$ 0
PEB.GdiDBuffer: D$ 0 #34
PEB.PostProcessInitRoutine: D$ 0
PEB.TlsExpansionBitmap: D$ 0
PEB.TlsExpansionBitmapBits: D$ 0 #32
PEB.SessionId: D$ 0
PEB.AppCompatFlags: Q$ 0
PEB.AppCompatFlagsUser: Q$ 0
PEB.pShimData: D$ 0
PEB.AppCompatInfo: D$ 0
PEB.CSDVersion.UnicodeStr64.Length: W$ 0
PEB.CSDVersion.UnicodeStr64MaximumLength: W$ 0
PEB.CSDVersion.UnicodeStr64Buffer: D$ 0
PEB.ActivationContextData: D$ 0
PEB.ProcessAssemblyStorageMap: D$ 0
PEB.SystemDefaultActivationContextData: D$ 0
PEB.SystemAssemblyStorageMap: D$ 0
PEB.MinimumStackCommit: D$ 0
PEB.FlsCallback: D$ 0
PEB.FlsListHead.Flink: D$ 0
PEB.FlsListHead.Blink: D$ 0
PEB.FlsBitmap: D$ 0
PEB.FlsBitmapBits: D$ 0 #4
PEB.FlsHighIndex: D$ 0
PEB.WerRegistrationData: D$ 0
PEB.WerShipAssertPtr: D$ 0
PEB.pContextData: D$ 0
PEB.pImageHeaderHash: D$ 0
PEB.TracingFlags: D$ 0
PEB.Padding4: D$ 0
PEB.CsrServerReadOnlySharedMemoryBase: Q$ 0
PEB.TppWorkerpListLock: D$ 0
PEB.TppWorkerpList.Flink: D$ 0
PEB.TppWorkerpList.Blink: D$ 0
PEB.WaitOnAddressHashTable: D$ 0 #128]
Ok, guys...managed to make RosAsm GDIView work to display some window info. Missing to understand how to do the same for other type of objects
(https://i.ibb.co/fM1Mvpw/Ful-Image1.png) (https://ibb.co/fM1Mvpw)