News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

MasmBasic

Started by jj2007, May 23, 2012, 10:16:07 PM

Previous topic - Next topic

jj2007

#420
MasmBasic 25 December 2017 features ClearFileCache for timings and benchmarks involving disk I/O, uMirror$(), plus a number of new controls. Here are 75 lines of code showing 18 controls in action (screenshot below, source & exe attached; drag a text file over the exe):

GuiParas equ "Controls", x660, y50, w500, h320, m4, b RgbCol(160, 255, 255)    ; position, margins, background
GuiMenu equ @File, &Open, &Save, -, E&xit, @Edit, Undo, Copy, Paste    ; define a menu (functions not implemented)
include \masm32\MasmBasic\Res\MbGui.asm
  SetGlobals ticks=rv(GetTickCount), f$="some text to find", r$="Доброе утро!!!!"     ; set global variables; note that they use ebx under the hood
  SetGlobals                                                    ; initialise them
  GuiControl ListBox, "listbox", x700, w300, h1000-80, WS_EX_CLIENTEDGE, +WS_BORDER or LBS_NOINTEGRALHEIGHT     ; start at 70% width, use 30% width, full height; + means defstyle or ...
  GuiControl MyDt, "syslink", "Date+Time (MSDN):", x700, w300, y1000-72, h0+18
  GuiControl MyTime, "time", x700, w300, y1000-53, h0+25
  GuiControl MyDate, "date", x700, w300, y1000-26, h0+25
  GuiGroup "Controls can be grouped:", w0+246, h0+75, bgcol RgbCol(255, 255, 200)
    GuiControl StatFind, "static", "Find:",        h0+22, w0+55              ; general syntax:
    GuiControl StatRepl, "static", "Replace:", h0+22, w0+55, y 0+24            ; guicontrol ID, "class", args "text", x, y, w, h, style
    GuiControl EditFind, "edit", f$, x 0+62, w0+100, h0+22, WS_EX_CLIENTEDGE   ; args have a variable part plus an optional fixed one, example:
    GuiControl EditRepl, "edit", r$, x 0+62, w0+100, h0+22, WS_EX_CLIENTEDGE, y 0+28   ; x1000-90 means "at right border, i.e. 100.0%, minus 90 pixels"
    GuiControl Cis, "button", BS_AUTOCHECKBOX, h0+22, x0+170, w0+60, "Case"    ; args may appear in no particular order, e.g. "Case" at the end
    GuiControl Fw, "button", text "Full word", h0+22, x0+170, w0+64, y0+28, BS_AUTOCHECKBOX
  GuiGroup end
  GuiControl BigEdit, "richedit", y0+120, h1000-120, w700      ; y at fixed 120px, h at full height minus 100px; width 70.0%
  If_ Exist(CL$()) Then <SetWin$ hBigEdit=FileRead$(Exist$)>    ; OPT_Arg1      \Masm32\MasmBasic\Res\MbSnippets.asc
  GuiControl Ok, "button", "Reset", x0+257, w0+80, h0+24, BS_DEFPUSHBUTTON
  GuiControl Progress, "progressbar", y0+88, h0+29, w700        ; , style PBS_SMOOTH    ; no effect if manifest is active
  GuiControl Status, "statusbar", "MasmBasic is pure assembly!!!!"
  GuiControl TimeMs, "static", x0+260, y0+32, h0+17, w0+75
  GuiControl InstallMB, "syslink", x0+260, y0+50, h0+17, w0+80, "MasmBasic"     ; RichMasm: copy a URL, select a word, press Ctrl K
  GuiControl Track, "trackbar", x0+257, y0+68, h0+17, w0+75, style TBS_AUTOTICKS or TBS_ENABLESELRANGE
  StringToArray cfm$("These\nare\nsome\nentries\nin\na\nlittle\nlistbox"), lbox$()      ; create an array (use Recall to load a textfile)
  SetListbox lbox$()                   ; fill the listbox
Event Timer
  sub rv(GetTickCount), ticks
  invoke SendMessage, hProgress, PBM_SETPOS, eax, 0
  SetWin$ hTimeMs=fTime$(0, "HH:mm:ss.fff")     ; shows milliseconds (check CPU usage in Task Manager!)
Event Message
  .if uMsg_==WM_HSCROLL                 ; horizontal trackbar sends this message
        mov eax, lParam_
        .if eax==hTrack
                mov ticks, rv(GetTickCount)             ; try to sync with progressbar ;-)
                shl rv(SendMessage, lParam_, TBM_GETPOS, 0, 0), 9
                sub ticks, eax
        .endif
  .elseif uMsg==WM_CLOSE
        if 0                                    ; put 0 for testing (Escape quits), 1 for the release version
               MsgBox 0, "Save settings?", "Hi", MB_YESNOCANCEL
                sub eax, IDCANCEL
                je @RetEax                      ; return 0, i.e. do NOT close
                .if eax==IDYES-IDCANCEL
                                MsgBox 0, "Add your 'save settings' etc here", "Hi", MB_OK
                .endif
        endif
  .endif
Event Key
  .if VKey==VK_A
        MsgBox 0, "You pressed 'A'", "Hi", MB_OK                ; negative VK_ codes indicate the key was hit in an edit control
  .endif
Event Command
  Switch_ MenuID                                        ; menu entries start with 0, controls return their IDs here
  Case_ 0, Ok
        SetWin$ hStatus="You clicked the Open menu or the Reset button"
        mov ticks, rv(GetTickCount)
  Case_ 1: call MySave                          ; your own functions may appear after EndOfEvents
  Case_ 2: invoke SendMessage, hWnd, WM_CLOSE, 0, 0     ; the Exit menu entry
  Case_ 3 .. 9 : <MsgBox 0, Str$("You clicked MenuID #%i", MenuID), "Menu clicked:", MB_OK>
  Case_ EditFind, EditRepl, Cis, Fw
        wSetWin$ hStatus=wStr$("You clicked inside the group on item %i with text '", MenuID)+wWin$(rv(GetDlgItem, hWnd, MenuID))+"'"      ; Unicode is possible
  Endsw_
  .if NotifyCode==DTN_DATETIMECHANGE && (wParam==MyDate || wParam==MyTime)
        SetWin$ hStatus=Cat$(Win$(hMyDate)+", "+Win$(hMyTime))  ; 11.12.2013, 12:34:56
  .endif
  If_ NotifyCode==NM_CLICK && (word ptr wParam==InstallMB || word ptr wParam==MyDt) Then <wShEx Link$()>  ; open a web page
  If_ NotifyCode==LBN_SELCHANGE && word ptr wParam==ListBox Then SetWin$ hStatus=LbSel$         ; LbSel$ returns the text of the current listbox entry
EndOfEvents
MySave proc    ; your procs go below EndOfEvents
  SetWin$ hStatus="You clicked the Save menu"
  ret
MySave endp
GuiEnd


P.S.: You may try other types of controls, see Current UI Automation Control Types for an overview. Let me know what you tried and if it worked; if not, I may be able to implement the missing bits. Btw there is no "control" that allows to pick colours. Instead, use the MasmBasic RgbCol macro with ?, for example: invoke someapi, RgbCol(?). Just for fun, here an "add-on" for the source above: SetWin$ hStatus="You clicked the Open menu or the Reset button"
mov ticks, rv(GetTickCount)
invoke DeleteObject, hcGroupBx   ; internal handles for the groupbox (not documented)
mov hcGroupBx[4], RgbCol(?)
mov hcGroupBx, rv(CreateSolidBrush, eax)
invoke InvalidateRect, hcGroupBx[8], 0, 1

jack

hi jj2007
I installed the masm32 sdk without problems but trying to install MasmBasic trows Wndows Defender into panic, I forgot the trojans name that it purportedly found, any advise?

jj2007

Just tested the current package on Jotti, details here, but "0/18 scanners reported malware". Quite unusual, actually :icon_mrgreen:

Similar for VirusTotal (results) - the Baidu AV reported "WisdomEyes", whatever that is, but 60 others say it's clean.

The Forum is on a safe server, and the MasmBasic package gets built with an automated procedure. There is no chance of a trojan creeping in. But many AV produce false positives - we even have a dedicated sub-forum AV Software sh*t list  :bgrin:

Assembler produces by its nature suspicious code: The virus scanners expect C/C++ initialisation routines, CRT, SEH, etc; if they don't find them, they shout foul. Sometimes they shout foul because they see a pushad ... popad sequence, which is very unusual in C code, so it's "suspicious". Everything that is non-standard looks dangerous to them. Well, we are all proud here to produce non-standard software, so evidently there is a certain tension between assembler programmers and the AV brigade. And to be honest, there is also a community of assembler programmers who do produce malware, but we usually smell them from a distance if they appear here and ask for advice. The forum rules are very strict, and for valid reasons.

If you cannot ignore or override the message, try if there is an option to exclude certain folders, e.g. \Masm32\, from the scan. In the last five ten years or so, we had one case of a virus introduced here in this forum by a young member (who apparently had an infected machine without knowing it), and it was spotted by experienced members, not by their antivirus software...

jack

ok thanks, I suspected it was a false positive.

jj2007

Just remembered the Test your AV software thread, which I launched two years ago because I couldn't explain why Windows Defender never tried to defend me from really suspicious software ;)

jj2007

Sometimes you may want to know in which line of a string array a certain text is found. The standard way of doing this is a loop: or ecx, -1
.Repeat
inc ecx
.Until Instr_(L$(ecx), Match$, 2) || ecx>ebx


Attached is a new MatchLine(L$(), "text", mode) macro that does the same but a factor 9*) faster:

include \masm32\MasmBasic\MasmBasic.inc         ; download
include MatchLine.mac   ; the new macro
  Init
  PrintCpu 0
  Match$ equ <"duplicate include">      ; see Windows.inc, line 26900: echo WARNING Duplicate include file windows.inc
  Recall "\Masm32\include\Windows.inc", L$()
  xchg eax, ebx
  PrintLine "new fast MatchLine:"
  push 9                                ; ten iterations
  .Repeat
        NanoTimer()
        PrintLine Str$("Match in line %i found in ", MatchLine(L$(), Match$, 2)), NanoTimer$()
        dec stack
  .Until Sign?

  PrintLine cfm$("\nold loop method:")
  push 9                                ; ten iterations
  .Repeat
        NanoTimer()
        or ecx, -1
        .Repeat
                inc ecx
        .Until Instr_(L$(ecx), Match$, 2) || ecx>ebx
        PrintLine Str$("Match in line %i found in ", ecx), NanoTimer$()
        dec stack
  .Until Sign?
EndOfCode


Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz
new fast MatchLine:
Match in line 26899 found in 215 µs
Match in line 26899 found in 205 µs
Match in line 26899 found in 204 µs
Match in line 26899 found in 202 µs
Match in line 26899 found in 202 µs
Match in line 26899 found in 202 µs
Match in line 26899 found in 203 µs
Match in line 26899 found in 202 µs
Match in line 26899 found in 202 µs
Match in line 26899 found in 202 µs

old loop method:
Match in line 26899 found in 1742 µs
Match in line 26899 found in 1753 µs
Match in line 26899 found in 1831 µs
Match in line 26899 found in 1774 µs
Match in line 26899 found in 1728 µs
Match in line 26899 found in 1721 µs
Match in line 26899 found in 1722 µs
Match in line 26899 found in 1722 µs
Match in line 26899 found in 2017 µs
Match in line 26899 found in 1740 µs


Usage of MatchLine() is restricted to:
- unmodified text arrays obtained with Recall
- Instr_ modes 0 (=case-sensitive) and 2 (=intellisense, case of first char ignored)

*)
MatchLine() is about 9x as fast as the loop method for a small file like Windows.inc - and it is probably irrelevant if the search takes 0.2 or 1.8 milliseconds. My tests with a much bigger file, 12MB and 164,000 lines (i.e. too big to be cached) still show a factor 4 improvement.

Macro and exe are attached - grateful for some timings on other CPUs.

2B||!2B

There is a bug in the Dim directive. It uses a call to HeapAlloc with NULL as the heap which leads to crash.

jj2007

Quote from: 2B||!2B on April 17, 2018, 09:47:41 PM
There is a bug in the Dim directive. It uses a call to HeapAlloc with NULL as the heap which leads to crash.

Can you post your code please? Since I use Dim very often, and without such problems, I suspect that you forgot to use Init at the beginning. I am afraid the documentation is a bit misleading there - Init is not optional, some commands will simply not work. Sorry for that, it will be corrected once I find time to post a new version.

2B||!2B

#428
Quote from: jj2007 on April 17, 2018, 10:17:22 PM
Quote from: 2B||!2B on April 17, 2018, 09:47:41 PM
There is a bug in the Dim directive. It uses a call to HeapAlloc with NULL as the heap which leads to crash.

Can you post your code please? Since I use Dim very often, and without such problems, I suspect that you forgot to use Init at the beginning. I am afraid the documentation is a bit misleading there - Init is not optional, some commands will simply not work. Sorry for that, it will be corrected once I find time to post a new version.

Hi man,

Yes you are right. Have forgot the Init actually sorry about that.

Added it before Dim and now it works fine.

Awesome work man.

2B||!2B

I have a question. Why do you use FPU/MMX/SSE instructions set so often? are there any advantages by using them rather than using the standard x86 instructions set? like faster execution, smaller code size maybe?

jj2007

There are no MMX instructions in MasmBasic (MMX code is inefficient, and there are conflicts with the FPU).

For calculations, the FPU is generally being used; it's not faster (and not slower) than the corresponding SSE* instructions, but internally it gives REAL10 precision, while SSE* offers only double precision, i.e. REAL8.

SSE* code is generally not shorter than ordinary x86 (but there are exceptions). However, it's often a lot faster. Take a simple example, getting the length of a zero-delimited string. There is a little thread here showing how the Masm32 team developed the current MasmBasic Len() macro. The thread has 149 replies, meaning it took a while to find the fastest option. Check yourself how fast it is, compared to the strlen function of the C runtime library (remember C is the fastest language on Earth :P):

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Recall "\Masm32\include\Windows.inc", L$() ; get a string array
  push eax ; #elements
  xor ebx, ebx
  xor edi, edi
  NanoTimer()
  .Repeat
invoke crt_strlen, L$(ebx)
add edi, eax ; calculate total len
inc ebx
  .Until ebx>=stack
  Print "The CRT needs ", NanoTimer$(), Str$(" for calculating the length of %i strings", ebx), Str$(", a total of %i bytes\n", edi)
  xor ebx, ebx
  xor edi, edi
  NanoTimer()
  .Repeat
add edi, Len(L$(ebx)) ; calculate total len
inc ebx
  .Until ebx>=stack
  pop edx
  Inkey " MB Len needs ", NanoTimer$(), Str$(" for calculating the length of %i strings", ebx), Str$(", a total of %i bytes\n", edi)
EndOfCode


Note that Windows.inc has relatively short strings. The difference between the speed of Len vs crt_strlen is much bigger for long strings. For example, if you apply the code above to a bible.txt file, with longer strings, the difference is twice as much. I won't tell you how much because there a C/C++ coders here in the forum, and they might fall into a deep depression if they see the results :icon_cool: 

Attached a full example, comparing also the Instr() performances of MasmBasic and the CRT (if that sounds interesting, see Benchmark 2: Alice in Wonderland for a CRT strstr vs Boyer-Moore comparison)

2B||!2B

Ah ok i got it now thanks for clarifying that. Actually i used some FPU instructions for floating point result (like progress bar 0.# for example) but have never used SSE instructions.  :biggrin:

Quote from: jj2007 on April 19, 2018, 05:32:39 PM
I won't tell you how much because there a C/C++ coders here in the forum, and they might fall into a deep depression if they see the results :icon_cool: 

Lol, they can still use inline ASM though  :biggrin:

jj2007

include \masm32\MasmBasic\MasmBasic.inc         ; download
  SetGlobals MyR4:REAL4, MyW:WORD=-123, MyDw:DWORD=-123
  Init
  PrintLine cfm$("number\tFloor(number)\tCeil(number)")
  PrintLine Str$("%4f", MyW), Str$("\t%5f", Floor(MyW)v), Str$("  \t%5f", Ceil(MyW)v), " (WORD size integer)"
  PrintLine Str$("%4f", MyDw), Str$("\t%5f", Floor(MyDw)v), Str$("  \t%5f", Ceil(MyDw)v), " (DWORD size integer)"
  For_ ecx=0 To 29
        Rand(-99.9, +99.9, MyR4)
        PrintLine Str$("%4f ", MyR4), Str$("\t%5f", Floor(MyR4)v), Str$("  \t%5f", Ceil(MyR4)v)
  Next
EndOfCode


Output:number  Floor(number)   Ceil(number)
-123.0  -123.00         -123.00 (WORD size integer)
-123.0  -123.00         -123.00 (DWORD size integer)
-9.629  -10.0000        -9.0000
-85.50  -86.000         -85.000
-72.59  -73.000         -72.000
72.67   72.000          73.000
31.14   31.000          32.000
64.07   64.000          65.000
-55.86  -56.000         -55.000
57.42   57.000          58.000
-95.26  -96.000         -95.000
3.386   3.0000          4.0000
12.49   12.000          13.000
-27.00  -28.000         -27.000
15.36   15.000          16.000
35.19   35.000          36.000
-49.67  -50.000         -49.000
-70.70  -71.000         -70.000
17.82   17.000          18.000
-7.807  -8.0000         -7.0000
37.56   37.000          38.000
95.73   95.000          96.000
27.80   27.000          28.000
-67.03  -68.000         -67.000
68.09   68.000          69.000
-75.14  -76.000         -75.000
-53.27  -54.000         -53.000
55.16   55.000          56.000
75.63   75.000          76.000
90.65   90.000          91.000
88.01   88.000          89.000
-21.09  -22.000         -21.000


Not included in the current (December '17) release, therefore attached as FloorCeil.inc; you may add it to your MasmBasic.inc.

Note the red v after the Str$("format", Numberv): Floor() and Ceil() always return ST(0) for further processing; if you just print the value, it needs to be popped via fstp st from the FPU. That's what the v does. Of course, you can also pop it directly into another variable, specified as second argument:

  Floor(123.456, MyDw)
  Print Str$("dw(123.456)=%i", MyDw)


The first argument can be an immediate (interpreted as double) or a DWORD, WORD, REAL4 ... REAL10 variable.

tenkey

The second example in the MasmBasic guide fails to assemble due to missing DualWin.inc file. I see LibUsed$() example is also using JBasic.inc instead of MasmBasic.inc. MasmBasic Version 25 Dec 2017.

jj2007

Thanks for the feedback. Did you get any error messages?

Please tell me if the following files are present (this helps me to understand what went wrong):
  \Masm32\MasmBasic\Res\GetPT.exe
  \Masm32\MasmBasic\Res\StructInfo.txt

- Extract the attached files to \Masm32\MasmBasic\Res
- Try again to build the example; if that doesn't work, try to run \Masm32\MasmBasic\Res\GetPT.bat

Note that the 64-bit examples build also with MASM; to do so, add an OPTion as follows:
include \masm32\MasmBasic\Res\JBasic.inc ; OPT_Assembler ML

However, RichMasm prefers UAsm and will try to install it if it's not present at \Masm32\bin\Uasm64.exe
You can do that manually, too: install UAsm64, i.e. extract \Masm32\bin\Uasm64.exe

Let me know if it works, please.