Author Topic: theForger's Tutorials revised  (Read 11706 times)

0 Members and 3 Guests are viewing this topic.

Arnold

  • Guest
Re: theForger's Tutorials revised
« Reply #45 on: March 28, 2018, 06:47:50 AM »
It is a pity. I tried:

% TTN_FIRST (-520 and 0xFFFFFFFF)
% TTN_NEEDTEXT (TTN_FIRST)

and some combinations, but tooltips only show in Win32. Until now in Win64 only this worked:
dword TTN_NEEDTEXT = -520  or
uint TTN_NEEDTEXT = -520

But with this in mind, it should actually be possible to deal with these situations.

Charles Pegge

  • Guest
Re: theForger's Tutorials revised
« Reply #46 on: March 28, 2018, 07:48:53 AM »
The problem goes right down to machine-code level. The CPU will sign-extend any number, in any operation where bit 31 is set, except when loading a quad number in immediate mode. I will have to think this through very carefully to find a leak-proof solution.

Mike Lobanovsky

  • Guest
Re: theForger's Tutorials revised
« Reply #47 on: March 28, 2018, 08:13:26 AM »
The problem is the contrary, Mike. ... From our point of view, this is unexpected. ... The Windows-side should not be evaluating the upper bits when it apparently doesn't use them.

Yes Charles, it seems you're correct while I ain't. Alas, I have to withdraw my guesswork assumptions. It looks like there's really too much auto-correction going on in both Oxygen and Windows that's reshaping our ANSI windows on the fly into Unicode-only stuff allowed on its modern platforms. ???

Using a global variable for dodgy negative equates like this, is the only option at present. I would also recommend using global variables for floating-point number equates, since the FPU cannot load numbers directly anyway.

Can we have your gentlemanly word and thus be absolutely sure that at least your own WinAPI-related include files observe these rules and list all of the dodgy equates as their DWORD/uint palliations?

O2 is eager to sign-extend its numbers ...

Yes, to the point where neither explicit 0xFFFFFDF8, nor 0xFFFFFFFF | (-520), nor 0x00000000FFFFFDF8, nor quad TTN_NEEDTEXT = 0xFFFFFDF8, nor quad TTN_NEEDTEXT =  0x00000000FFFFFFFF | 0xFFFFFDF8 would seem to work as expected. ;)

Quote
I will have to think this through very carefully to find a leak-proof solution.

Great! :)

Quote
... but this API seems to expect a 32bit integer, with the upper 32 bits set to zero.

Not really a classical interpretation of x86 bitness but the idea is understandable.

__________________________________

One more thing to note while we're at it, Roland. I've fiddled with your app_four1.o2bas for quite a while and I'd say the app leaks memory. Get your Task Manager running and watch the app's Working Set (Memory) grow as you add a dozen or two new child windows to your MDI. Now close them one by one via their [X] buttons and see the Working Set (Memory) stay at the same level. The GDI Objects count decreases to prove the app doesn't leak its GDI resources but the overall process RAM stays disproportionately high.  :-\

Charles Pegge

  • Guest
Re: theForger's Tutorials revised
« Reply #48 on: March 28, 2018, 09:51:02 AM »
To express the problem in Assembler, and machine script:

' dword -520
mov rax,0xfffffdf8 'not correct (gets sign extended)

o2 48 b8 hq00000000fffffdf8 'immediate quad mov to rax (not supported by assembler yet)

'but only mov available for immediate quads. It cannot be done with add, sub, and or ...
'it has to be done indirectly:

o2 48 b9 hq00000000fffffdf8  'immediate quad mov to rcx

'then other ops can be performed:
add rax,rcx
sub rax,rcx
and rax,rcx
or rax,rcx

...

José Roca

  • Guest
Re: theForger's Tutorials revised
« Reply #49 on: March 28, 2018, 09:54:56 AM »
Does a syntax like this work with O2?

% TTN_FIRST Convert Ulong (-520)

In FreeBasic, the problem was solved using

const TTN_FIRST = culng(0u - 520u)

Mike Lobanovsky

  • Guest
Re: theForger's Tutorials revised
« Reply #50 on: March 28, 2018, 10:00:53 AM »
No Jose, surprisingly it doesn't. It wouldn't even compile -- though it would be exactly what Convert implies as opposed to a simpler Cast:-[

Charles Pegge

  • Guest
Re: theForger's Tutorials revised
« Reply #51 on: March 28, 2018, 10:04:27 AM »
José,

My intention is that this should work in 64bit:

% TTN_FIRST = dword -520

recognizing and giving special treatment to:
negative literals cast as dwords or uints
literals larger then 0x7fffffff

Mike Lobanovsky

  • Guest
Re: theForger's Tutorials revised
« Reply #52 on: March 28, 2018, 10:06:23 AM »
' dword -520
mov rax,0xfffffdf8 'not correct (gets sign extended)...

What about movzx? Is it supported in 64 bit asm? (I'm completely profane as far as 64 bit assembly is concerned  :( )

Charles Pegge

  • Guest
Re: theForger's Tutorials revised
« Reply #53 on: March 28, 2018, 10:18:13 AM »
Yes, Mike. o2 does that for variables: we have movzx and movsx according to type.

But there is only movsxd, and we need a mozxd equivalent
« Last Edit: March 28, 2018, 11:03:24 AM by Charles Pegge »

Arnold

  • Guest
Re: theForger's Tutorials revised
« Reply #54 on: March 28, 2018, 10:43:39 AM »
Hi Mike,

thank you for pointing me to the memory-leaks. This happens as well in app_four.o2bas as in app_four1.o2bas. Although I use the task manager as a matter of routine I did not realize this misbehaviour. I must check for the reason.

Roland

Mike Lobanovsky

  • Guest
Re: theForger's Tutorials revised
« Reply #55 on: March 28, 2018, 11:36:12 AM »
' dword -520
mov rax,0xfffffdf8 'not correct (gets sign extended)

Why not use mov eax,0xfffffdf8 instead -- platform conditionally, so to speak, and then use rax directly in subsequent asm operations? It should preserve its upper bytes empty without undue sign extension, I think.

Dixit Microsoft:
Quote
Ordinary MOV operations into 32-bit subregisters automatically zero extend to 64 bits, so there is no MOVZXD instruction.
« Last Edit: March 28, 2018, 07:38:14 PM by Mike Lobanovsky »

Charles Pegge

  • Guest
Re: theForger's Tutorials revised
« Reply #56 on: March 29, 2018, 02:04:30 AM »
This should do it.

Use uint or dword to clip negative numbers to their 32bit representation, thus

% TTN_FIRST dword -520

This release also supports quad literal mov in assembler:

In 64bit, you can load a general CPU register with quad literals, but not a memory location directly. (this is a Pentium limitation):

mov rcx,0x123456789ABCDEF0

https://github.com/Charles-Pegge/OxygenBasic/blob/master/OxygenProgress.zip

Mike Lobanovsky

  • Guest
Re: theForger's Tutorials revised
« Reply #57 on: March 29, 2018, 05:54:25 AM »
Actually it ... does! :D

Thank you, Charles!

Arnold

  • Guest
Re: theForger's Tutorials revised
« Reply #58 on: March 29, 2018, 09:03:06 AM »
Hi Charles,

I downloaded the latest OxygenBasicProgress.zip and everything works fine with me so far.
Almost every week, OxygenBasic gets better and better. And I am impressed again and again.

Roland

Arnold

  • Guest
Re: theForger's Tutorials revised / for Mike
« Reply #59 on: March 29, 2018, 10:03:30 AM »
Hi Mike,

I tried WM_CLOSE, WM_MDIDESTROY for closing childwindows of a MDI, but this seems not to release the memory. But I found this situation with some other programs too, like MDIDemo.exe by Charles Petzold, or RadAsm by Ketilo, or with my PSPAD editor.

Searching in Internet for "MDI memory leaks", it seems that there some more people who are confused about this issue. I also read somewhere, that task manager would not be reliable in this case.

I created a simple MDI demo using the latest winutil.inc, which only creates new (Ctrl-N) and closes (Ctrl-F4) child windows. Do you see a problematic place in the code, where memory leaks could arise? I am insecure what could be missing.

Roland

SimpleMDI.o2bas:
Code: OxygenBasic
  1. $ filename "SimpleMDI.exe"
  2.  
  3. uses rtl32
  4. 'uses rtl64
  5.  
  6. 'winutil.inc
  7. % InMessageLoop          
  8.  
  9. sys hMDIClient=null             'must be declared before using the macro
  10. sys hAccel                      'must be declared before using the macro
  11.  
  12. macro InMessageLoop             'must be declared before including winutil.inc
  13.  'must use MSG structure of winutil.inc
  14.  if not TranslateMDISysAccel(hMDIClient, &wm) then      
  15.   if TranslateAccelerator( hWnd, hAccel, @wm ) = 0 then
  16.      TranslateMessage(&wm)
  17.      DispatchMessage(&wm)
  18.   end if  
  19.   end if            
  20. end macro
  21.  
  22.  
  23. '% review 'Dialogs.inc, when using console
  24.  
  25. uses winutil
  26. uses dialogs
  27. 'namespace
  28.  
  29. # autodim off
  30.  
  31. 'additional constants
  32. % COLOR_3DFACE = 15
  33. % MDIS_ALLCHILDSTYLES = 1
  34. % MDITILE_VERTICAL=0
  35. % MDITILE_HORIZONTAL=1
  36. % WM_MDICREATE = 544
  37. % WM_MDIDESTROY=545
  38. % WM_MDITILE = 550
  39. % WM_MDICASCADE = 551
  40. % WM_MDIICONARRANGE=552
  41. % WM_MDIGETACTIVE = 553
  42.  
  43.  
  44. type CLIENTCREATESTRUCT
  45.   sys  hWindowMenu
  46.   uint idFirstChild
  47. end type
  48.  
  49. type MDICREATESTRUCT
  50.   sys szClass                      
  51.   sys szTitle
  52.   sys hOwner
  53.   int x
  54.   int y
  55.   int cx
  56.   int cy
  57.   dword style
  58.   sys lParam
  59. end type
  60.  
  61.  
  62. 'Menu IDs
  63. #define IDM_NEW            1000
  64. #define IDM_CLOSE          1001
  65. #define IDM_EXIT           1002
  66. #define IDM_CASCADE        1003
  67. #define IDM_TILEHORZ       1004
  68. #define IDM_TILEVERT       1005
  69. #define IDM_ARRANGE        1006
  70. % ID_MDI_FIRSTCHILD = 2000
  71.  
  72. string MDICHILDCLASS = "MdiChild"
  73.  
  74. declare sub SetupMenu(sys hWnd)
  75. declare function SetUpMDIChildWindowClass() as bool
  76. declare function CreateNewMDIChild(sys hMDIClient) as sys
  77.  
  78. sys hInstance=inst                  'Winutil.inc
  79. dyn::init_common_controls(0x00ff)   'Dialogs.inc, ICC_WIN95_CLASSES
  80.  
  81. 'winutil.inc      
  82. MainWindow 480, 320,WS_OVERLAPPEDWINDOW
  83.  
  84.  
  85. function WndProc(sys hwnd, uMsg, wParam, lParam) as sys callback
  86.  
  87.     select uMsg
  88.  
  89.         case WM_CREATE
  90.             SetupMenu(hwnd)
  91.             SendMessage(hWnd, WM_SETTEXT, 0, "Simple MDI Demo")
  92.  
  93.             'Register Child Window Class
  94.            if not SetUpMDIChildWindowClass() then    
  95.               return 0
  96.             end if        
  97.  
  98.             CLIENTCREATESTRUCT ccs
  99.  
  100.             ' Create MDI Client
  101.            ' Find window menu where children will be listed
  102.            ccs.hWindowMenu  = GetSubMenu(GetMenu(hwnd), 1)
  103.             ccs.idFirstChild = ID_MDI_FIRSTCHILD
  104.  
  105.             hMDIClient = CreateWindowEx(WS_EX_CLIENTEDGE, "mdiclient", null,
  106.                 WS_CHILD or WS_VSCROLL or WS_HSCROLL or WS_VISIBLE,
  107.                 0,0,0,0,
  108.                 hwnd, 0, hInstance, &ccs)
  109.  
  110.             if hMDIClient = null then
  111.                 MessageBox(hwnd, "Could not create MDI client.", "Error", MB_OK or MB_ICONERROR)
  112.             end if    
  113.  
  114.  
  115.         case WM_COMMAND
  116.             select loword(wParam)            
  117.             case IDM_EXIT
  118.                 PostMessage(hwnd, WM_CLOSE, 0, 0)
  119.             case IDM_NEW
  120.                 CreateNewMDIChild(hMDIClient)                                
  121.             case IDM_CLOSE                
  122.                 sys hChild = SendMessage(hMDIClient, WM_MDIGETACTIVE,0,0)
  123.                 if hChild then
  124.                     SendMessage(hChild, WM_CLOSE, 0, 0)
  125.                     SendMessage(hChild, WM_MDIDESTROY, 0, 0)
  126.                 end if
  127.  
  128.             case IDM_TILEHORZ
  129.                 SendMessage(hMDIClient, WM_MDITILE, MDITILE_HORIZONTAL, 0)                
  130.             case IDM_TILEVERT
  131.                 SendMessage(hMDIClient, WM_MDITILE, MDITILE_VERTICAL, 0)                
  132.             case IDM_CASCADE
  133.                 SendMessage(hMDIClient, WM_MDICASCADE, 0, 0)                                
  134.             case IDM_ARRANGE
  135.                 SendMessage(hMDIClient, WM_MDIICONARRANGE, 0, 0)                
  136.  
  137.             case else                
  138.                 if loword(wParam) >= ID_MDI_FIRSTCHILD then
  139.                     DefFrameProc(hwnd, hMDIClient, WM_COMMAND, wParam, lParam)
  140.                 else
  141.                     sys hChild = SendMessage(hMDIClient, WM_MDIGETACTIVE,0,0)
  142.                     if hChild then
  143.                         SendMessage(hChild, WM_COMMAND, wParam, lParam)
  144.                     end if
  145.                 end if
  146.  
  147.             end select              
  148.    
  149.         case WM_CLOSE
  150.             DestroyAcceleratorTable( hAccel )        
  151.             DestroyWindow(hwnd)
  152.        
  153.         case WM_DESTROY
  154.             PostQuitMessage(0)
  155.        
  156.         case else
  157.             return DefFrameProc(hwnd, hMDIClient, uMsg, wParam, lParam)
  158.  
  159.     end select
  160.    
  161.     return 0
  162. end function
  163.  
  164. function SetUpMDIChildWindowClass() as bool
  165.     'Register Child Window Class
  166.    WNDCLASSEX wc
  167.  
  168.     'fill only necessary items
  169.    wc.cbSize         = sizeof(WNDCLASSEX)
  170.     wc.lpfnWndProc    = @MDIChildWndProc
  171.     wc.hbrBackground  = COLOR_3DFACE+1
  172.     wc.lpszClassName    = strptr "MdiChild" 'strptr(MDICHILDCLASS)
  173.  
  174.     if not RegisterClassEx(&wc) then
  175.         MessageBox(0, "Could Not Register Child Window", "Oh Oh...",
  176.             MB_ICONEXCLAMATION or MB_OK)
  177.         return FALSE
  178.     else
  179.         return TRUE
  180.     end if    
  181.        
  182. end function
  183.  
  184. function CreateNewMDIChild(sys hMDIClient) as sys
  185.  
  186.     MDICREATESTRUCT mcs
  187.     sys hChild
  188.     string text, num
  189.     static int untitled
  190.    
  191.     untitled+=1 : num=str(untitled) : if untitled<10 then num="0" & num
  192.     text="Untitled " & num
  193.     mcs.szTitle = strptr text
  194.     mcs.szClass = strptr"MdiChild"
  195.     mcs.hOwner  = hInstance
  196.     mcs.x = mcs.cx = CW_USEDEFAULT
  197.     mcs.y = mcs.cy = CW_USEDEFAULT
  198.     mcs.style = MDIS_ALLCHILDSTYLES
  199.  
  200.     hChild = SendMessage(hMDIClient, WM_MDICREATE, 0, &mcs)
  201.     if not hChild then    
  202.         MessageBox(hMDIClient, "MDI Child creation failed.", "Oh Oh...",
  203.                      MB_ICONEXCLAMATION or MB_OK)
  204.     end if
  205.  
  206.     return hChild
  207. end function
  208.  
  209.  
  210. function MDIChildWndProc(sys hwnd, msg, wParam, lParam) as sys callback
  211.     return DefMDIChildProc(hwnd, msg, wParam, lParam)
  212. end function
  213.  
  214. ====================================
  215.  
  216. sub SetupMenu(sys hWnd)
  217.    sys hMenu  
  218.  
  219.    MENU(hMenu)
  220.    POPUP "&File"
  221.    BEGIN
  222.        MENUITEM "&New" tab "Ctrl-N", IDM_NEW
  223.        MENUITEM "&Close",            IDM_CLOSE
  224.        MENUITEM "SEPARATOR"
  225.        MENUITEM "E&xit" tab "ALT-F4",IDM_EXIT
  226.    ENDMenu
  227.    POPUP "&Window"
  228.    BEGIN
  229.        MENUITEM "&Cascade",         IDM_CASCADE
  230.        MENUITEM "Tile &horizontal", IDM_TILEHORZ
  231.        MENUITEM "Tile &vertical",   IDM_TILEVERT
  232.        MENUITEM "&Arrange Icons",   IDM_ARRANGE              
  233.    ENDMenu
  234.  
  235.    if SetMenu( hWnd, hMenu ) = 0 then
  236.      mbox "SetMenu hMenu failed!"
  237.    end if
  238.  
  239.    'Accelerators
  240.   indexbase 0
  241.    
  242.    ACCEL accl[0] = {
  243.    {FVIRTKEY | FCONTROL, asc("N"), IDM_NEW }
  244.    }
  245.  
  246.    hAccel = CreateAcceleratorTable( @accl, 1 )
  247.  
  248. end sub
  249.