News:

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

Main Menu

Try RichEditCtrl and syntaxhighlight

Started by minor28, June 11, 2014, 06:22:49 AM

Previous topic - Next topic

minor28

The GDI handle leak is fixed but I have abandoned the solution to paint the client rect with text. It is a fast way of loading files or paste text to an empty richedit. But that's it.

I have concluded that the best solution is to use RTF syntax. The solution works well for documents of less than about 1000 rows.

I use windows.inc as a yardstick. To scan through the file and convert it to rtf takes less than 2 seconds, but RichEdit need at least 30 seconds to paint the converted text. RichEdit20 control is extremely slow to load files.

If you instead use RichEdit50W (msftedit.dll) the whole procedure will be executed in about 2 sec. It is an acceptable time to load windows.inc.

Undo and Redo are problems remaining to work with.

jj2007

Hi,

When trying to save the colour options, it crashes in ntdll.dll. I tried to rebuild it but get "fatal error A1000: cannot open file : Automation.inc".

Lines 29+30 in RichEditor.inc can be commented out, but still, while building succeeds then, the dialog does not show up under WinXP SP3. Your original exe works, though.

When saving, be aware that EM_STREAMOUT is broken ("disk space saving feature"). Use EM_GETTEXTEX instead.

Re speed, see http://www.masmforum.com/board/index.php?topic=13089.0
RichMasm loads Windows.inc in 0.55 seconds on my trusty old Celeron.

qWord

Quote from: minor28 on July 13, 2014, 06:43:36 PM
The GDI handle leak is fixed
it is not fixed - you can check that (for example) with the program GDIView.

You should remarks that you can delete GDI object only if they are currently not selected into a DC. Also DeleteDC does not destroy selected objects. For that reason:

  • create the GDI object
  • select it into the DC and save the returned handle
  • do the drawing operation/s
  • select the previously returned handle back in the DC and delete(if wished) the returned object

(Furthermore there are the functions SaveDC and RestoreDC, which might be used for simplification under certain circumstances)
MREAL macros - when you need floating point arithmetic while assembling!

minor28

Thank you both for testing.

About the leakage. I do not understand what you mean. In my previous version, I noted that more memory was used when the client rect was repainted. I checked all gdi handles was deleted and after that there was no increase in memory usage.

I this new version there is no increase of memory. I downloaded GDIView but I can not interpret the results. I can not see that my program differs from any of the other running programs. Please could you explain how to detect the leakage.

dedndave

not sure about how to use that tool
rather than messing with that, heed qWord's notes about how to avoid GDI handle leaks   :t

generally, when i create a GDI object, i do so in the WM_CREATE code
and - i "mirror" that creation with a DeleteObject call in WM_DESTROY

there are exceptions to this
one exception might be that i want the handle for window class registration
in that case, i mirror the creation with a DeleteObject in WinMain (before ExitProcess)

another exception is that i might create a GDI object during WM_PAINT
i generally try to avoid this, but a compatible HBITMAP meets this requirement
in such a case, i mirror the creation with a DeleteObject in WM_PAINT

in order for a GDI object to be deleted, it must not be currently selected into a DC

also, when you create a memory DC (applies to any DC, for that matter), you should restore the
originally selected objects before deleting or releasing the DC

if you follow those rules, you shouldn't have any GDI leaks
typically, i notice a GDI leaks by running a program several times (assemble/test/assemble/test, etc)
after a while, windows runs out of GDI handle space and funky things start happening - lol
things like windows not redrawn correctly or at all,
maybe windows explorer not working correctly, desktop icons not redrawn, and so on

minor28

Quote
1. create the GDI object
2. select it into the DC and save the returned handle
3. do the drawing operation/s
4. select the previously returned handle back in the DC and delete(if wished) the returned object
Isn't this what I do?


MainDlgProc proc:

.if uMsg==WM_INITDIALOG
invoke CreateFontIndirect,offset CodeFont
mov hCodeFont,eax
invoke SendMessage,hRED1,WM_SETFONT,eax,TRUE
.elseif uMsg==WM_CLOSE
invoke DeleteObject,hCodeFont


DrawLineNumbers proc: call from richedit WM_PAINT

invoke GetDC,hRED1
mov hDC,eax
invoke CreateCompatibleDC,hDC
mov mDC,eax
invoke CreateCompatibleBitmap,hDC,rect.right,rect.bottom
mov hBitmap,eax
invoke SelectObject,mDC,hBitmap
mov hBitmapObj,eax

invoke CreateFontIndirect,offset NumFont
push eax
invoke SelectObject,mDC,eax
mov hFontObj,eax
invoke CreateSolidBrush,numBKcolor
push eax
invoke FillRect,mDC,addr rect,eax


;solid brush
pop eax
invoke DeleteObject,eax
;numbers font
pop eax
invoke DeleteObject,eax                   ;This object was not deleted!!!
invoke DeleteObject,hFontObj
invoke DeleteObject,hBitmapObj
invoke DeleteObject,hBitmap           ;This object was not deleted!!!
invoke DeleteDC,mDC
invoke ReleaseDC,hRED1,hDC


ColorsTabProc proc:

.elseif uMsg == WM_CTLCOLORSTATIC
invoke GetClassName,lParam,addr buffer,sizeof buffer
invoke lstrcmp,addr buffer,offset szColorStatic
.if eax==0
.if OptionColor==-1
invoke GetDlgCtrlID,lParam
mov eax,optTbl[eax*4]
mov edx,colToken[eax*4]
invoke CreateSolidBrush,edx
.else
invoke CreateSolidBrush,OptionColor
mov OptionColor,-1
.endif
ret
.endif


FillFontData proc:

invoke GetDC,hRED1
mov hDC,eax
invoke GetDeviceCaps,hDC,LOGPIXELSY


invoke ReleaseDC,hRED1,hDC


I'm still interested in how GDIView should be interpreted. I would appreciate if someone could enlighten me.

guga

Minor28
from maindialog. Perhaps you are missing create a Dc for the main window handle to the hCodeFont be properly selected (then after using it you may delete the object)

DidnĀ“t saw your code, but, perhaps something like this will avoid the GDI leaking you are facing:


.if uMsg==WM_INITDIALOG
invoke CreateFontIndirect,offset CodeFont
mov hCodeFont,eax
-------------------------------------------------------------------------------
        invoke GetDC YourMainWindow
        mov hEditFontDC, eax
        invoke SetMapMode eax, MM_TEXT <---If you need it)
        invoke SelectObject hEditFontDC, hCodeFont

invoke SendMessage,hRED1,WM_SETFONT, hCodeFont,TRUE
-------------------------------------------------------------------------------
.elseif uMsg==WM_CLOSE
invoke DeleteObject,hCodeFont
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

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

jj2007

SelectObject returns the previously selected object. Before deleting the new one, you must de-select it by selecting the old one:

invoke CreateFontIndirect,offset NumFont
push eax
invoke SelectObject,mDC,eax
mov hFontObj,eax   ; OLD font
...
;numbers font
invoke SelectObject, mDC, hFontObj  ; re-select OLD font, thus freeing new font
pop eax  ; NEW font
invoke DeleteObject,eax                   ;This object was not deleted!!!
; NO, it's not yours: invoke DeleteObject,hFontObj

qWord

minor28,

GDIView shows you what kind and how many GDI object a process currently use. To detected a handle leak, enable auto refresh due to the menu, start your program and take a look at the handle counts of the corresponding process. When scrolling loaded text you will see that the count continually increase.

Quote from: minor28 on July 14, 2014, 05:50:49 PM
Quote
1. create the GDI object
2. select it into the DC and save the returned handle
3. do the drawing operation/s
4. select the previously returned handle back in the DC and delete(if wished) the returned object
Isn't this what I do?
no, you don't deselect the objects. For example, see DrawLineNumbers:

invoke CreateCompatibleDC,hDC
mov mDC,eax
invoke CreateCompatibleBitmap,hDC,rect.right,rect.bottom
mov hBitmap,eax
invoke SelectObject,mDC,hBitmap
mov hBitmapObj,eax

invoke CreateFontIndirect,offset NumFont
invoke SelectObject,mDC,eax
mov hFontObj,eax

; ...

invoke DeleteObject,hFontObj
invoke DeleteObject,hBitmapObj
invoke DeleteDC,mDC
invoke ReleaseDC,hRED1,hDC

it should be:
invoke CreateCompatibleDC,hDC
mov mDC,eax
invoke CreateCompatibleBitmap,hDC,rect.right,rect.bottom
invoke SelectObject,mDC,eax
mov hBitmapObj,eax

invoke CreateFontIndirect,offset NumFont
invoke SelectObject,mDC,eax
mov hFontObj,eax

; ...

invoke SelectObject,mDC,hFontObj ; deselect (restore default object)
invoke DeleteObject,eax

invoke SelectObject,mDC,hBitmapObj ; deselect (restore default object)
invoke DeleteObject,eax

invoke DeleteDC,mDC
invoke ReleaseDC,hRED1,hDC


BTW: the windows task manger can also show the total GDI handle count...
BTW2: jj was a bit faster :-D
MREAL macros - when you need floating point arithmetic while assembling!

minor28



Brushbitmapfonttotal
Open app21411
file loaded1713862Scrolling, resizing no change
Open option dlg18141167
Close option18141167why not decreasing?
Open again18141470
Close again18141470
Open again18141773increases with 3 each opening

The only font I use is hCodeFont created in MainDlgProc and deleted in MainDlgProc WM_CLOSE event.

The font is sent to 22 richedit control in option dlg. Is it OK when font is increasing each time the option dlg is opened and why remains the GDI handles after closing the option dlg?


ColorsTabProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.if uMsg==WM_INITDIALOG
;...

xor ecx,ecx
mov eax,7
.while ecx<23
inc colorindex
invoke CreateWindowEx,0,offset szColorStatic,0,50800000h,80,eax,40,12,hWin,colorindex,hInstance,0

mov edx,colorindex
add edx,100
pop eax
invoke CreateWindowEx,0,ASTR("RichEdit50W"),0,50010800h,125,eax,150,12,hWin,edx,hInstance,0
mov hRtf,eax

invoke SendMessage,hRtf,EM_SETBKGNDCOLOR,0,codeBKcolor
invoke SendMessage,hRtf,WM_SETFONT,hCodeFont,TRUE

;.....

.endw

.elseif uMsg==WM_LBUTTONUP


dedndave

it's ok to create and destroy the font object over and over
but - if it's something that's used a lot, i would create and delete it in WndMain
that means it uses some memory during the life of the process instance - that's ok

minor28

Quote
When trying to save the colour options, it crashes in ntdll.dll. I tried to rebuild it but get
"fatal error A1000: cannot open file : Automation.inc".

Lines 29+30 in RichEditor.inc can be commented out ..
I did some testings with IRichEdit interface and belonging dispinterfaces. I forgot to delete
those lines.

Quote
, but still, while building succeeds then, the dialog does not show up under WinXP SP3.
Your original exe works, though.
I don't have WinXP so I cannot test why the dialog not show up.

Quote
When saving, be aware that EM_STREAMOUT is broken ("disk space saving feature").
Use EM_GETTEXTEX instead.
This only happens if you save your text in RTF mode, isn't it? I save in plan text mode.

Quote
RichMasm loads Windows.inc in 0.55 seconds on my trusty old Celeron.
It is difficult to compare the speeds when you do not know the circumstances. In my case
each token will be compared in the dictionary that consists of words (keys) with the total
amount of about 1.5 MBytes. This and converting to RTF takes about two seconds. Loading the
converted text takes "no time".

Quote
it's ok to create and destroy the font object over and over
but - if it's something that's used a lot, i would create and delete it in WndMain
The code font I create in MainDlg proc and delete it when the app is closed. The number font is
created and deleted one time on each richedit WM_PAINT message. No increase of font handles here.

But when I open option dialog the font handles increases every time I open the dialog, even though
I do not create a font but use the font created in MainDlgProc. Isn't this a leak?

qWord

Quote from: minor28 on July 17, 2014, 02:16:23 AMBut when I open option dialog the font handles increases every time I open the dialog, even though
I do not create a font but use the font created in MainDlgProc. Isn't this a leak?
yes, it is a leak. The problem is that you use EndDilaog for modeless dialog boxes, whereas DestroyWindow is required. The result of this is that the option-dialog is only hidden, but not destroyed.
To fix that, replace the code in OptionsDlgProc->WM_CLOSE with a single call to DestroyWindow(hWin) and change WM_CLOSE to WM_DESTROY in ColorsTabProc.
MREAL macros - when you need floating point arithmetic while assembling!

minor28

Thanks qWord. Now it seems to be without any GDI leakage.

jj2007

Quote from: minor28 on July 17, 2014, 02:16:23 AM
Quote
When saving, be aware that EM_STREAMOUT is broken ("disk space saving feature").
Use EM_GETTEXTEX instead.
This only happens if you save your text in RTF mode, isn't it? I save in plan text mode.

I discovered this "feature" because the assembler threw errors. So it was plain text.
However, it only happens for medium-sized sources, i.e. several thousand lines.