Oxygen Basic

Programming => Example Code => General => Topic started by: Arnold on March 21, 2018, 02:27:32 AM

Title: theForger's Tutorials revised
Post by: Arnold on March 21, 2018, 02:27:32 AM
Hello,

when I started to learn about OxygenBasic, one of my first projects was to explore theForger's Win32 API Programming Tutorial:

http://www.winprog.org/tutorial/

By reading the tutorials and porting the examples to Oxygen I not only learned about C (although I probably will never be able to code correctly in this language), but also about the Win32 Api and about using Oxygenbasic. Although I tried to use a more C-like syntax, the examples could also be coded e.g. in a more Freebasic-like style to some extent.

Oxygenbasic has evolved very much since my first attempt. By using corewin.inc there was only one function left which I had to define separately. (ZeroMemory, which in fact is not necessary in OxygenBasic).

Maybe there are some people who are interested in exploring the tutorials and the examples. I think they are very instructive and can also be further extended. If the folder of theForger_o2 is stored as a subfolder of e.g. \examples or of projectA\B\C then the accompanying batch files should work as expected. The .o2bas files are coded to create 64-bit executables. But they could also be created as 32-bit exes.

As I am not able to do this, perhaps there is someone else who would like to code at least the first two examples in another Basic like syntax. It would be interesting to see to what extent this is possible in Oxygenbasic.

My next step will be to apply Oxygen's own library functions with some of these examples.

Roland
Title: Re: theForger's Tutorials revised
Post by: chrisc on March 21, 2018, 04:22:29 AM
Thanxx a lot Roland
this is a very good contribution
Title: Re: theForger's Tutorials revised
Post by: jack on March 21, 2018, 04:45:05 AM
thank you Arnold :)
Title: Re: theForger's Tutorials revised
Post by: Aurel on March 21, 2018, 10:53:17 AM
Thanks Arnold

I know for this site but i never look in this example:

App_four .... did you tried compile as 32bit exe ?
Why I ask ?
Maybe you know ..i have lot of trouble to force A043/progress to compile
properly my AurelEdit  .. toolbar & scintilla control problem.
With old release and using awinh with bind all works as it should be but now not.
So i see in this App_four that have toolbar and have this :

Code: [Select]
ZeroMemory(&tbb, SizeOf(tbb) * spanof(tbb))
            tbb[1].iBitmap = STD_FILENEW
            tbb[1].fsState = TBSTATE_ENABLED
            tbb[1].fsStyle = TBSTYLE_BUTTON
            tbb[1].idCommand = ID_FILE_NEW

            tbb[2].iBitmap = STD_FILEOPEN
            tbb[2].fsState = TBSTATE_ENABLED
            tbb[2].fsStyle = TBSTYLE_BUTTON
            tbb[2].idCommand = ID_FILE_OPEN

            tbb[3].iBitmap = STD_FILESAVE
            tbb[3].fsState = TBSTATE_ENABLED
            tbb[3].fsStyle = TBSTYLE_BUTTON
            tbb[3].idCommand = ID_FILE_SAVEAS

            SendMessage(hTool, TB_ADDBUTTONS, spanof(tbb), &tbb)

last LINE  is new for me ...
In old version i use just sizeof() ..not spanof()
maybe there is whole trick how to use this way to sand message to Toolbar control.
So i will study it again ..
thnx

Aurel
Title: Re: theForger's Tutorials revised
Post by: Aurel on March 21, 2018, 11:27:14 AM
This is UDT what is exactly i use before with toolbar control

type TBBUTTON
  int       iBitmap
  int       idCommand
  byte      fsState
  byte      fsStyle
  byte      bReserved[2]
  dword     dwData
  int       iString
end type


Arnol i compile this example app_four.o2bas
and toolbar is properly created...
so i know what I need to do in my own.

IF WE AGREE that we must TEST OxygenbasicProgress... right?

Aurel
Title: Re: theForger's Tutorials revised
Post by: José Roca on March 21, 2018, 11:33:11 AM
Be warned that that structure definition is only valid for 32 bit.
Title: Re: theForger's Tutorials revised
Post by: Aurel on March 21, 2018, 11:44:30 AM
Hi Jose

Yes I know that ...thanks  :)
my structure different and i am not sure how work with old version.
it is here:

TYPE TBBUTTON
   iBitmap    as long
   idCommand  as long
   fsState    as byte
   fsStyle    as byte
        bReserved[0] as byte
        bReserved[1] as byte
   dwData     as long
    iString     as sys
END TYPE


Jose
You probably mean on second member of
bReserved[1] as byte is needed for 64bit.... is that right?

For example from dlib Structure Viewer is :

Title: Re: theForger's Tutorials revised
Post by: Aurel on March 21, 2018, 12:00:47 PM
Here is how look MDI app
Title: Re: theForger's Tutorials revised
Post by: José Roca on March 21, 2018, 12:22:10 PM
> is that right?

What I mean is that, for 64 bit, bReserved must be 6 bytes, and dwData and iString must be 64 bit pointers, not LONG as you're using in dwData.
Title: Re: theForger's Tutorials revised
Post by: José Roca on March 21, 2018, 12:24:16 PM
Code: [Select]
typedef struct {
  int       iBitmap;
  int       idCommand;
  BYTE      fsState;
  BYTE      fsStyle;
#ifdef _WIN64
  BYTE      bReserved[6];
#else
#if defined(_WIN32)
  BYTE      bReserved[2];
#endif
#endif
  DWORD_PTR dwData;
  INT_PTR   iString;
} TBBUTTON, *PTBBUTTON, *LPTBBUTTON;

See: https://msdn.microsoft.com/es-es/library/windows/desktop/bb760476(v=vs.85).aspx
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky on March 21, 2018, 01:15:35 PM
Aurel,

In OxygenBasic terms, the two bottom-most members should be declared as SYS because both of them are pointers as per MSDN, and pointers are automatically sensitive to system bitness, i.e. 32 bits on x86, and 64 bits, on x64.

Besides, there are certain things that O2 allows you to do with a 32-bit SYS but would silently refuse to do with an ordinary int, long, or DWORD. It may become your constant PITA if you fail to memorize it once and for all to avoid bugs that are difficult to isolate and cure.
Title: Re: theForger's Tutorials revised
Post by: José Roca on March 21, 2018, 01:30:31 PM
Former VBer's use LONG and BYVAL AS STRING (sorry, Long and ByVal As String) a lot. This is because VB had not support for DWORD, pointers and null terminated strings. Together with the use of mixed case in keywords, it is a distinctive mark.
Title: Re: theForger's Tutorials revised
Post by: Aurel on March 21, 2018, 02:14:41 PM
Quote
It may become your constant PITA if you fail to memorize it once and for all to avoid bugs that are difficult to isolate and cure.

Mike
Can be ,,but is not
because some internal o2 changes ... that is why my programs written in older version not work properly.
I understand very well what is SYS ..it is Long Integer Pointer ...there are so many twisted types...
But here is problem with structures..
In older version such a structures are accepted and now not.And this is not first time.
Long time before you come here we ..me & peter and some others fight with similar stuff..
of course that was o2 just a new born baby with lot of quirks with strings and other suff.
for example:
if sys is a lpInt so logical way should be that he can hold address of any other variable

sys a
string b ="o2"

so if we try
a = @b

that's not work
but this yes :

@a = b

looking little but unlogical but thats the way things work.
I don't want to patronize and i accept that.

Charles explained in your topic;


To keep the rules simple:

Use @ explicitly when passing numeric primitives, their arrays, and procedures byref. Indirection is correctly resolved

Use strptr for all types of string passed byval . This is optional but more efficient.

UDTs and class objects (passed byref) do not require @, but you may do so for clarity.

Use @@ for Virtual objects passed byref
Title: Re: theForger's Tutorials revised
Post by: José Roca on March 21, 2018, 03:08:46 PM
> I understand very well what is SYS ..it is Long Integer Pointer

Really? I thought that it was a sort of place holder to store 32 bit or 64 bit values depending of if you compile the application as 32 or 64 bit. Guess it will be a LONG in 32 bit and a signed QUAD in 64 bit, but not a pointer.
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky on March 21, 2018, 03:18:22 PM
Aurel,

You seem to confuse different and irrelevant topics.

1. DWORD, int, long will stay 32-bit on any platform and will thus misalign your structure declaration on 64 bits if you use such declarations for the fields that are designed by MS (not by you or me or Charles) to store pointers. OTOH Oxygen's SYS will automatically expand to 64 bits on x64 and will keep the structure aligned exactly as MS requires. Get used to writing MS-compliant code to avoid booby traps you otherwise install for yourself throughout your own scripts.

2. There are certain operations that are valid only for SYS but not for other integer types. And this doesn't depend upon how long ago you came to this forum. You success here depends entirely on what your background knowledge was when you first came here, and how quickly you're prepared to learn from the mistakes you make.

3. I do not question Charles' rules and I really need none of your nuzzling. If you don't understand why I'm really putting my questions to Charles, then ask, and I will tell you: I'm evaluating if Charles' recent mods to Oxygen are sufficient to invest my time and effort in writing apps for the O2 environment it obviously needs -- in the style I find most efficient. Otherwise I need really little help in finding my way around floats, integers and pointers in any language.

My response isn't intended as flaming. We had pretty nuff of that in the past. You were curious why your structures are so lopsided -- I answered. Jose presupposes you can read C prototypes but I know you can't. That's why I'm trying to explain where everybody else would just RTFM you.

If you don't want, or aren't prepared, to listen to my explanations -- well, then just keep on pouring your sorrows out into the majestic silence. Good riddance.
Title: Re: theForger's Tutorials revised
Post by: José Roca on March 21, 2018, 03:31:41 PM
The default alignment for structures in 32 bit is 4 bytes (a DWORD). This is why after

Code: [Select]
   fsState    as byte
   fsStyle    as byte

we need to fill two bytes more (bReserved) to keep the 4 bytes alignment.

But in 64 bit, the default alignment is 8 bytes (a QUAD). Therefore bReserved must be 6 bytes to keep the 8 bytes alignment.

BTW the worst thing that you can do to translate C++ structures or API functions is to use VB declares as a guide. VB was not designed for API coders.

Title: Re: theForger's Tutorials revised
Post by: Aurel on March 21, 2018, 03:36:46 PM
Quote
You were curious why your structures are so lopsided -- I answered.

No you don't know because I don't show what i use in original version.

And i really don't know about what kind of f**** C prototypes you think  :o
If you think that i don't know to read  and translate some simple C code about win32
then you wrong.
And you constantly talk about things i know.
Of course i don't want to argue with you at all but please ignore my posts..
so ok?
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky on March 21, 2018, 03:39:32 PM
Got it Aurel. And keep on holding back your sources. You know why.

Out.
Title: Re: theForger's Tutorials revised
Post by: Aurel on March 21, 2018, 03:40:28 PM
Thanks Jose  :)

Do you see Mike who know how to explain things!
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 21, 2018, 03:47:57 PM
Hi  Aurel,

I used the beta release of OxygenBasic. I compiled each program with a 32-bit computer as 32-bit and with a 64-bit computer as 64-bit. If you use corewin.inc with A43, this is a little bit like using sparks of a Porsche in a Mercedes Benz car.

José is very right with the TBBUTTON structure. With my first attempt I only tried to create 32-bit exes and this time I forgot to check the types, which I must catch up. At that time I also did not know about mode64bit:

Code: [Select]
type TBBUTTON
  int       iBitmap
  int       idCommand
  byte      fsState
  byte      fsStyle
#ifdef mode64bit
  byte      bReserved[6]
#else 
  byte      bReserved[2]
#endif
  sys       dwData   
  sys       iString
end type

I am not quite sure about iString, but I think it is a pointer. Perhaps dwData too. It must be tested. That the structure worked in 64-bit happened by chance, I did not use dwData or iString in the example. There are some more structures which must be examined.

Roland

Edit: José, you were faster than me with dwData. Thank you.

Title: Re: theForger's Tutorials revised
Post by: José Roca on March 21, 2018, 03:59:07 PM
Despite the name used, dwData is also a pointer, so you should also use sys instead of dword.
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge on March 21, 2018, 04:15:32 PM
José, Just to clarify:

Sys is a generic integer type, as you say. It is not specifically a pointer, but is wide enough to hold one on either platform. Generally speaking, it's sign can be disregarded. Due to twos-complement arithmetic, you can safely add and subtract values from the pointer.

The C member alignment rules, which I endeavour to follow, require that 8 bit members have 8bit alignment, 16bit members have 16bit alignment and so forth.

When a structure is inherited, it is aligned in the main structure according to its largest primitive member. For example: if the inherited structure contains a double as its largest primitive, then the structure must align to 64 bits within the main structure.

Oxygen also supports packed types, using 'packed' as a prefix.
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 21, 2018, 06:04:17 PM
Hi Charles,

in examples\WINGUI\Toolbar1.o2bas I found this solution:

Code: OxygenBasic
  1. % _WIN32
  2.  
  3. typedef struct {
  4.   sys     hInst;
  5.   sys     nID;
  6. } TBADDBITMAP, *LPTBADDBITMAP;
  7.  
  8. #ifdef _WIN32
  9.  %n 2
  10. #else
  11.  %n 6
  12. #endif
  13.  
  14. typedef struct {
  15.   int       iBitmap;
  16.   int       idCommand;
  17.   BYTE      fsState;
  18.   BYTE      fsStyle;
  19.   BYTE      bReserved[n];
  20.   sys   dwData;
  21.   sys   iString;
  22. } TBBUTTON, *PTBBUTTON, *LPTBBUTTON;
  23.  

Can my way of using mode64bit be applied too?  It looks so smart.

Roland
Title: Re: theForger's Tutorials revised
Post by: Aurel on March 21, 2018, 09:47:21 PM
Arnold

I use OxygenBasicProgress not A043 just because i want to try CoreWin.inc
Also i use 32bit on win7 and i don't care to much about 64bit yet.
My problems start when i remove  bind()  from awinh035 and declare api function in usual way.
So combination of o2 internal changes and removing things create problem in controls creation.

thanks again
and all best

 :)

Title: Re: theForger's Tutorials revised
Post by: Charles Pegge on March 21, 2018, 11:21:32 PM
Hi Roland,

The n padding is not required because sys will automatically align upward to a 32bit or 64bit block within the structure, depending on its width.

Many thanks for the tutorials. I have not had a chance to look at them yet.
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 22, 2018, 01:21:52 AM
Hi Charles,

I tried this little code and I am not quite sure how I should interpret the results:

Code: [Select]
$ filename "TBBUTTON.exe"

'uses RTL32
'uses RTL64

use console

type TBBUTTON
  int       iBitmap
  int       idCommand
  byte      fsState
  byte      fsStyle
'#ifdef mode64bit 
  byte      bReserved[6]
'#else 
''  byte      bReserved[2]
'#endif
  sys       dwData   
  sys       iString
end type

printl "sizeof  TBBUTTON " sizeof(TBBUTTON)
printl "spanof  TBBUTTON " spanof(TBBUTTON)
printl "countof TBBUTTON " countof(TBBUTTON)
printl
TBBUTTON tbb[3]
printl "sizeof  tbb " sizeof(tbb)
printl "spanof  tbb " spanof(tbb)
printl "countof tbb " countof(tbb)
printl

type TBBUTTON
  int       iBitmap
  int       idCommand
  byte      fsState
  byte      fsStyle
'#ifdef mode64bit 
''  byte      bReserved[6]
'#else 
  byte      bReserved[2]
'#endif
  sys       dwData   
  sys       iString
end type

printl "sizeof  TBBUTTON " sizeof(TBBUTTON)
printl "spanof  TBBUTTON " spanof(TBBUTTON)
printl "countof TBBUTTON " countof(TBBUTTON)
printl
TBBUTTON tbb[3]
printl "sizeof  tbb " sizeof(tbb)
printl "spanof  tbb " spanof(tbb)
printl "countof tbb " countof(tbb)
printl

type TBBUTTON
  int       iBitmap
  int       idCommand
  byte      fsState
  byte      fsStyle
#ifdef mode64bit 
  byte      bReserved[6]
#else 
  byte      bReserved[2]
#endif
  sys       dwData   
  sys       iString
end type

printl "sizeof  TBBUTTON " sizeof(TBBUTTON)
printl "spanof  TBBUTTON " spanof(TBBUTTON)
printl "countof TBBUTTON " countof(TBBUTTON)
printl
TBBUTTON tbb[3]
printl "sizeof  tbb " sizeof(tbb)
printl "spanof  tbb " spanof(tbb)
printl "countof tbb " countof(tbb)
printl

printl "Enter ... " : waitkey

I used a)bReserved[6], b)bReserved[2], c)distinguish 32/64 bit.
In particular I am not sure if I will get the correct position of dwData, iString in each case? (I have not yet tried this)

I assume it does not harm if I differentiate between 32/64 bit? There are some more structures where MSDN makes a difference between 32/64 bit.

Roland
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge on March 22, 2018, 02:49:29 AM
Hi Roland,

You can inspect the compiler's view of TBBUTTON using #recordof. It takes a little interpretation:

Code: [Select]
'2018-03-22 T 10:42:52
'MEMBER PADDING 32BIT/64BIT
$filename "t.exe"
'uses rtl64
type TBBUTTON
  int       iBitmap
  int       idCommand
  byte      fsState
  byte      fsStyle
'#ifdef mode64bit
'  byte      bReserved[6]
'#else
'  byte      bReserved[2]
'#endif
  sys       dwData   
  sys       iString
end type
#recordof "T.TXT"  TBBUTTON

t.txt
Code: [Select]
-3
--------
20
--------
0
--------
0
--------
0
--------
4
--------
0
--------
0
--------
tbbutton
--------
ibitmap 4 0 0 1 AA , int
idcommand 4 4 0 1 AA , int
fsstate 1 8 0 1 AA , byte
fsstyle 1 9 0 1 AA , byte
dwdata 4 12 0 1 AA , sys
istring 4 16 0 1 AA , sys

--------

--------

--------

Title: Re: theForger's Tutorials revised
Post by: Arnold on March 23, 2018, 08:28:18 AM
Hi Charles,

Thank you for pointing to the #recordof command. Hopefully I have understood it a little bit. But I can see if I use bReserved[2] or comment out the bReserved[] statements that I will find dwData at the same position in Win32 and at the same position in Win64. So if I respect the types and use the Win32 values for padding then I should have no problems with Win64.

Oddly enough I did not find more structures of this kind although I was sure there are some. I only found structures with different member types when using Win32 or Win64. But this could be checked when this case will occur.

Roland
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 23, 2018, 11:41:36 AM
These are the first two examples of theForger in short form. There should be no problem to understand them.

simple_window1.o2bas:
Code: OxygenBasic
  1. $ filename "simple_window1.exe"
  2.  
  3. 'uses rtl32
  4. uses rtl64
  5.  
  6. uses WinUtil
  7.  
  8.  
  9. MainWindow 240,120,WS_OVERLAPPEDWINDOW
  10.  
  11.  
  12. function WndProc(sys hwnd, uMsg, wParam, lParam) as sys callback
  13.  
  14.     select uMsg
  15.    
  16.         case WM_CLOSE
  17.             DestroyWindow(hwnd)
  18.        
  19.         case WM_DESTROY
  20.             PostQuitMessage(0)
  21.        
  22.         case else
  23.             return DefWindowProc(hwnd, uMsg, wParam, lParam)
  24.            
  25.     end select
  26.    
  27.     return 0
  28. end function
  29.  

window_click1.o2bas:
Code: OxygenBasic
  1. $ filename "window_click1.exe"
  2.  
  3. 'uses rtl32
  4. uses rtl64
  5.  
  6. uses WinUtil
  7.  
  8. sys hInstance=inst
  9.  
  10. MainWindow 240,120,WS_OVERLAPPEDWINDOW
  11.  
  12.  
  13. function WndProc(sys hwnd, Msg, wParam, lParam) as sys callback
  14.  
  15.     select Msg
  16.    
  17.         case WM_LBUTTONDOWN
  18.             zstring szFileName[MAX_PATH]
  19.  
  20.             GetModuleFileName(hInstance, szFileName, MAX_PATH)
  21.             MessageBox(hwnd, szFileName, "This program is:", MB_OK or MB_ICONINFORMATION)
  22.    
  23.         case WM_CLOSE
  24.             DestroyWindow(hwnd)
  25.        
  26.         case WM_DESTROY
  27.             PostQuitMessage(0)
  28.        
  29.         case else
  30.             return DefWindowProc(hwnd, Msg, wParam, lParam)
  31.            
  32.     end select
  33.    
  34.     return 0
  35. end function
  36.  

Edit: I noticed that copying the code into an editor works, so I only attach the batch files
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 24, 2018, 06:57:57 AM
Hi Charles,

I am trying to code theForger example 7:dlg_one using winutil.inc and a in-memory dialog. This does work quite nice in JIT mode, but if I try to compile the example to exe, I will get this error:

Linker found unidentified names: ::guistate level 0

I explored the files of Oxygenbasic for guistate, but I can only find it in winutil.inc. As there are some more examples which include winutil.inc, I do not know what I am doing wrong. Can I satisfy Oxygenbasic in some way?

Roland

Edit: Incredible. I was so happy to apply namespace, and now that it is necessary, I forgot about it. But now the example works fine. I can also create Menus à la resource. Oxygen is great!


dlg_one1.o2bas
Code: OxygenBasic
  1. $ filename "dlg_one1.exe"
  2.  
  3.  
  4. 'uses rtl32
  5. uses rtl64
  6.  
  7. '% review
  8.  
  9. uses winutil
  10. uses dialogs
  11. namespace
  12.  
  13. # autodim off
  14.  
  15. % DS_MODALFRAME=128
  16.  
  17.  
  18. #ifndef IDC_STATIC
  19. #define IDC_STATIC (-1)
  20. #endif
  21.  
  22. #define IDR_MYMENU      101
  23. #define IDD_ABOUT       102
  24. #define ID_FILE_EXIT    40001
  25. #define ID_HELP_ABOUT   40002
  26.  
  27.  
  28. declare sub initMenu(sys hWnd)
  29.  
  30.  
  31. MainWindow 240, 120,WS_OVERLAPPEDWINDOW
  32.  
  33.  
  34. function DialogProc(sys hDlg, Message, wParam, lParam) as bool callback
  35.  
  36.   select case Message
  37.  
  38.     case WM_INITDIALOG
  39.       return true
  40.  
  41.     case WM_COMMAND
  42.        select case loword(wParam)
  43.          case IDOK
  44.             EndDialog( hDlg, null)
  45.             MessageBox(null, "Dialog exited with IDOK.", "Notice",
  46.                        MB_OK or MB_ICONINFORMATION)                    
  47.          case IDCANCEL
  48.             EndDialog( hDlg, null )
  49.             MessageBox(null, "Dialog exited with IDCANCEL.", "Notice",
  50.                        MB_OK or MB_ICONINFORMATION)
  51.        end select
  52.      
  53.     case WM_CLOSE
  54.        EndDialog( hDlg, null )
  55.                
  56.   end select
  57.  
  58.   return 0
  59. end function    
  60.  
  61.  
  62. function WndProc(sys hwnd, Message, wParam, lParam) as sys callback
  63.  
  64.     select Message
  65.         case WM_CREATE
  66.            initMenu(hwnd)
  67.            SetWindowText (hWnd, "The title of my window")
  68.        
  69.         case WM_COMMAND
  70.  
  71.             select loword(wParam)                            
  72.             case ID_HELP_ABOUT                
  73.                sys lpdt
  74.                dyn::init(lpdt) '1024
  75.  
  76.                dyn::Dialog( 4,  0, 0, 239, 66, "My About Box", lpdt,
  77.                        DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_POPUP | WS_SYSMENU or DS_SETFONT,
  78.                        8, "MS Sans Serif" )
  79.                dyn::DEFPUSHBUTTON   "OK", IDOK, 174, 18, 50, 14, 0, WS_EX_LEFT
  80.                dyn::PUSHBUTTON      "Cancel", IDCANCEL, 174, 35, 50, 14, 0, WS_EX_LEFT
  81.                dyn::GROUPBOX        "About this program...", IDC_STATIC, 7, 7, 225, 52, 0, WS_EX_LEFT
  82.                dyn::CTEXT           "An example program showing how to use" cr "Dialog Boxes" cr+cr  "by theForger", IDC_STATIC, 16, 18, 144, 33, SS_CENTER, WS_EX_LEFT
  83.  
  84.                dyn::CreateModalDialog( hWnd, @DialogProc, 0, lpdt )
  85.                
  86.             case ID_FILE_EXIT                
  87.                SendMessage(hWnd, WM_CLOSE,0,0)              
  88.             end select
  89.        
  90.         case WM_CLOSE
  91.             DestroyWindow(hwnd)
  92.        
  93.         case WM_DESTROY
  94.             PostQuitMessage(0)
  95.        
  96.         case else
  97.             return DefWindowProc(hwnd, Message, wParam, lParam)
  98.    
  99.     end select
  100.    
  101.     return 0
  102. end function
  103.  
  104.  
  105. ==================================
  106.  
  107. sub initMenu(sys hWnd)
  108.    sys hMenu
  109.    
  110.    dyn::MENU(hMenu)
  111.    dyn::POPUP "&File"
  112.    dyn::BEGIN
  113.        dyn::MENUITEM "E&xit", ID_FILE_EXIT
  114.    dyn::ENDMenu
  115.    dyn::POPUP "&Help"
  116.    dyn::BEGIN
  117.        dyn::MENUITEM "&About...", ID_HELP_ABOUT
  118.    dyn::ENDMenu
  119.  
  120.    if SetMenu( hWnd, hMenu ) = 0 then
  121.      mbox "SetMenu hMenu failed!"
  122.    end if
  123. end sub
  124.  
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge on March 24, 2018, 11:35:39 AM
Hi Roland,

Very briefly, you need to close the dialog namespace by uncommenting 'namespace

Code: [Select]
uses winutil
uses dialogs
namespace
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 24, 2018, 02:54:57 PM
Thank you Charles. Sometimes I miss the simplest solutions. I replaced the code in reply #29. The example works very fine now with Win32 and Win64.

Roland
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge on March 24, 2018, 05:32:47 PM

I'm glad we caught that one, Roland. I will ensure that namespaces automatically close before a program performs its epilog.
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 26, 2018, 01:35:33 AM
Hi Charles,

I am trying to convert theForger's app_four.o2bas using MainWindow of WinUtil.inc. This works if I use WM_NCCREATE. The app would work fine, but there is a problem with using Ctrl-F6 and Ctrl-F4 for the mdi child windows. I tried to use MessageLoopProcesses, but this seems not to work.
So as a test I modified in WinUtil.inc:

...
    #endif
    '
if not TranslateMDISysAccel(g_hMDIClient, &wm) then
    TranslateMessage @wm
    DispatchMessage @wm
end if
  wend 'GetMessage / PeekMessage
...

Now mdi.o2bas works fine, but I know this cannot be applied. In other apps there are also other combinations possible e.g.:

       ' Check for accelerator keystrokes
       if TranslateAccelerator(
                hDlg,               // handle to receiving window
                hAccelTable,        // handle to active accelerator table
                &Msg) = 0 then      // message data
       if not IsDialogMessage(hFindDialog, &Msg) then
       if not IsDialogMessage(hFindReplaceDialog, &Msg) then
       if not IsDialogMessage(hDlg, &Msg) then
         TranslateMessage(&Msg)
         DispatchMessage(&Msg)
       end if
       end if
       end if
       end if

Would it be possible to replace :
 
TranslateMessage @wm
DispatchMessage @wm

somehow with an own block or could I use % MessageLoopProcesses in some way?

Roland

Edit: Code deleted. There is no need to use WM_NCCREATE
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge on March 26, 2018, 02:44:04 AM
Hi Roland,

I think this will fit into the system if you provide a macro defining InMessageLoop which will give you full control over the contents.

Code: [Select]
    #ifdef InMessageLoop
      InMessageLoop ''CUMSTOMISED MESSAGE PROCESSING
    #else
      #ifdef MessageLoopProcesses
        MessageLoopProcesses
      #endif
      '
      TranslateMessage @wm
      DispatchMessage @wm
    #endif
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 26, 2018, 04:02:15 AM
Thank you again Charles. I used InMessageLoop this way:

$ filename "mdi.exe"

'uses rtl32
'uses rtl64

% InMessageLoop
sys g_hMDIClient = null
macro InMessageLoop
  if not TranslateMDISysAccel(g_hMDIClient, &wm) then     
     TranslateMessage(&wm)
     DispatchMessage(&wm)
  end if           
end macro

uses winutil
uses dialogs
namespace
...

I know I must be careful when using InMessageLoop in order to avoid endless loops and freezing the app, but the macro offers a lot of valuable usage.

After applying some more O2  library functions in app_four.o2bas I will upload my results.

Roland
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 28, 2018, 01:59:49 AM
This is theForger example A4: app_four1.o2bas, using WinUtil.inc which Charles provided in reply #34. It will run as a 64-bit and as a 32-bit exe. I added tooltips for the toolbar, shortcuts for the menu items and arranged menus a la resource file.

App_four is remarkable in my opinion. Although coded long ago, it is still usable in the days of Windows 10. It could be easily extended with adding statusbar statements, goto line, find / findreplace, checking for modified files, in order to get a working editor. A richedit control could be used. Some routines could be added to run Oxygenbasic programs.

But I will not do this. (at least not at this point)

Roland
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 28, 2018, 02:14:57 AM
Hi Charles,

for app_four1.o2bas I must use the constant:
% TTN_NEEDTEXT = -520

This works fine in Win32 but in Win64 this is read as 4294966776. I used the constant in sub showToolTips:
...
   if lpttt.hdr.code = TTN_NEEDTEXT then
     select lpttt.hdr.idFrom   
...


lpttt.hdr.code will not fire in Win64. So I used this definition to get tooltips to work:
dword TTN_NEEDTEXT = -520

Are there other options possible in order to use: % TTN_NEEDTEXT = -520 ?

Roland
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky on March 28, 2018, 02:24:40 AM
Hi Roland,

Prefer to use HEX notation when defining Win32 equates. That'll automatically dismiss the sign problem caused by using longs in place of DWORDs. HEX values are treated as unsigned ints on default. (hopefully this applies to O2 too)
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 28, 2018, 03:14:08 AM
Hi Mike,

I tried to use:
% TTN_NEEDTEXT = 0xFFFFFDF8

but for me this does also only work in Win32. As lpttt.hdr.code is derived from NMHDR structure (WinData.inc) I suppose I must do a cast somewhere? (or use dword for the declaration, which I would like to avoid)

Roland
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge on March 28, 2018, 04:04:37 AM
Hi Roland & Mike,

The problem is that o2 integer equates are typeless, and so are the prototypes. You can use a uint or dword variable instead. Then sign extension into the upper bits will not occur.
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky on March 28, 2018, 04:26:03 AM
Hi Charles,

Quote
Then sign extension into the upper bits will not occur.

But I think it should occur by all means!

There are a few Win32 constants that the C headers would #define as signed integers rather than HEX DWORDs. I think to overcome this glitch in Oxygen, equates could be treated internally as SYSes. This would extend their sign, if any, from 32 to 64 bits automatically, so that % TTN_NEEDTEXT = -520 would always amount to -520 regardless of platform bitness.

Does OxygenBasic treat its equates as PP macros rather than variables? If yes then DWORD or uint vars would be a memory consuming palliation rather than a full replacement IMO...
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge on March 28, 2018, 04:56:21 AM
The problem is the contrary, Mike.

O2 is eager to sign-extend its numbers, but this API seems to expect a 32bit integer, with the upper 32 bits set to zero. 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.
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 28, 2018, 05:46:38 AM
Hi Charles,

in commctrl.h of mingw32 there are these definitions:

#define TTN_FIRST   ((UINT)-520)

#define TTN_GETDISPINFOA    (TTN_FIRST - 0)
#define TTN_GETDISPINFOW    (TTN_FIRST - 10)
#define TTN_NEEDTEXTA   TTN_GETDISPINFOA
#define TTN_NEEDTEXTW   TTN_GETDISPINFOW

Should I use a method like this? Then I would prefer to use: dword/uint TTN_NEEDTEXT = -520. But could this approach be used generally? As Mike stated there are some more negative WinApi constants. I had no problem using them in Win32 but until now I did not use them in Win64.

Roland
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge on March 28, 2018, 06:03:34 AM
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. It is faster and uses less machine code.
Title: Re: theForger's Tutorials revised
Post by: Arnold 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.
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge 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.
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky 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.  :-\
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge 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

...
Title: Re: theForger's Tutorials revised
Post by: José Roca 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)
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky 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.  :-[
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge 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
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky 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  :( )
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge 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
Title: Re: theForger's Tutorials revised
Post by: Arnold 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
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky 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 (https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-instructions):
Quote
Ordinary MOV operations into 32-bit subregisters automatically zero extend to 64 bits, so there is no MOVZXD instruction.
Title: Re: theForger's Tutorials revised
Post by: Charles Pegge 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
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky on March 29, 2018, 05:54:25 AM
Actually it ... does! :D

Thank you, Charles!
Title: Re: theForger's Tutorials revised
Post by: Arnold 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
Title: Re: theForger's Tutorials revised / for Mike
Post by: Arnold 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.  
Title: Re: theForger's Tutorials revised
Post by: Aurel on March 29, 2018, 10:25:23 AM
Arnold
when i compile this with oxygenBasicProgress
i get only this error:

looks like is only wndProc exposed 
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 29, 2018, 12:24:54 PM
Hi Aurel,

I used OxygenBasicProgress of March 29. I loaded the file SimpleMDI.o2bas with Oxide, used F5 for compiling and this creates the exe without error message. If I apply: uses RTL64  instead of: uses RTL32 then it will create the SimpleMDI.exe for 64-bit Windows.

If you use the files of the previous Oxygenbasic installation, then you must use winutil.inc of reply #34. But I have not tested this.

Roland
Title: Re: theForger's Tutorials revised
Post by: Mike Lobanovsky on March 29, 2018, 01:13:07 PM
Hi Roland,

I used OxygenBasicProgress of March 29.

Yes, Charles seems to compliment his OxygenProgress with the matching OxygenBasicProgress distros that may contain other WIP files he may wish to update accordingly. I always try to load the both zips and use them together. It practically never fails for me.

Quote
Do you see a problematic place in the code, where memory leaks could arise? I am insecure what could be missing.

No, I see no flaws in your code. There seem to be no apparent pitfalls that the memory leak may be attributed to.

Upon some brooding over this phenomenon, I can only say I used to see a similar process memory behavior only in the C++ apps that make use of C++ std::vector facilities. C++ uses its own memory allocation and garbage collection engine, and you can't reallocate or partially free the memory used by its overgrown std::vectors once you don't need the respective vector elements any longer. The C++ memory allocator preserves the memory (though not the objects stored in that memory) just in case you might need it later. You can only delete the entire std::vector using a known hack (https://stackoverflow.com/posts/10465032/revisions) or let it go out of scope and thus get garbage collected.

Which makes me think that the entire MDI engine itself may well be implemented using C++ to take advantage of its template library whereby the MDI child window data would be stored internally to the engine in a set of std::vectors.
Title: Re: theForger's Tutorials revised
Post by: jcfuller on March 29, 2018, 02:04:45 PM
I always rename my current OxgenBasic Folder adding the date -> OxygenBasic_03232018 then unzip the new one.
I then use Winmerge and load both folders for a comparison. I can copy from old to new or compare files from one folder to the other.

James
Title: Re: theForger's Tutorials revised
Post by: Arnold on March 30, 2018, 01:12:16 AM
Thank you Mike, for your info. This phenomen was new to me and unexpected. I tested some other editors (also Scite which only applies tabs) and the behaviour seems to be similar. But after terminating the app, the memory seems to be released. (I think)

I like the new feature of InMessageLoop in winutil.inc very much. If applied carefully, there is so much possible now with using the MainWindow function.

Roland