News:

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

Main Menu

MasmBasic

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

Previous topic - Next topic

jj2007

BASIC is the Best Approach to Simple and Intelligent Coding. MasmBasic is a library that allows to use BASIC syntax in assembler, i.e. it is not a "separate" language but rather a library of macros and routines, fully compatible with the latest Masm32 SDK (version 11), MASM (version 6.15 or higher) and UAsm, and thoroughly tested on Windows XP, 7, 8 and 10.

While MasmBasic is pretty stable (and pretty fast - typically twice as fast as C), it is still Assembler, therefore the usual disclaimers apply - do not use for military purposes, in hospitals and anywhere else where buggy applications could cause damage. You have been warned :cool:

To install the library, double-click SetupMasmBasic.exe in the attached archive (see step-by-step instructions).
Note that some AntiVirus programmes don't like it - see Latest batch of unsound AV scanners for reasons.

For an overview of the over 500 powerful available functions, see \Masm32\MasmBasic\MbGuide.rtf (after extracting the archive, of course) or see the (incomplete) MasmBasic Quick Reference online. See also A guide to the RichMasm editor.

28 April 2024: Updated archive attached below, now with ultrafast HexVal(), OpenAdo, ZipFiles, Json$(), RichMasm support for the Masm64 SDK, SetWatch, StackWalk, StringBuild, FastMath, Say "Hello World", ArrayIndex(array, match), _Local x$="Hello World", better UTF-8 support, MemState for finding leaks, MapView control, Math symbols in RichMasm, PrintRtf, dual 32/64-bit examples in File/New Masm source menu, and a 64-bit version of the deb macro. Older changes: For_ each x$ in My$(), improved Switch_; GetFiles returns UTF8 now; WebCam, GetProcessArray(), new GSL lib, Choose, fast MemSet, Instr_() and Sinus() added, GuiTextBox improved. Data and Read , float counters are valid in For_ ... Next, and xmm regs are preserved for all MasmBasic commands. Note that simple Windows API calls can trash them on 64-bit versions of Windows.
Latest additions: GuiXX functions, Split$, Join$, Filter$, commandline to Files$(), GfCallback, true Unicode, also in file I/O; UnzipFile, ArraySet, SetReg64 for 64-bit registry settings, ArrayMerge, Age(), GetRegArrays, unsigned LONGLONG in Str$(), ShEx, xls interface, ArraySet, ArrayPlot, AddWin$, WritePipe, Plugins, IsFolder(), wOpen, FileOpen$/FileSave$, also as Unicode versions, Extract$, Dialogs, COM support (CoInvoke, GuidsEqual(), IUnknown, VARIANT, ...), improved ANSI and Unicode commandline macros CL$()/wCL$(), improved xHelp, Launch$(), Try/Catch/Finally, ...

Installation hints for Windows 8 ... 10 (on Win7 & XP it's simpler):
- click on SetupMasmBasicDayMonthYear.zip below
- depending on your browser and zip application, choose open in xyZip or Save as...
- if it doesn't open in 7-zip or WinZip or whatever, locate the zip file and open it
- once you see SetupMasmBasic.exe, open it (double-click or select and Enter)
- you should see an extraction dialog, and shortly after a box "Windows Protected Your PC - Windows SmartScreen prevented..."
- do NOT click OK; instead, click on the tiny green link "More info"
- you will see Program SetupMasmBasic.exe and "unknown publisher"; click "Run Anyway"
- the screen will darken, and you see a box "Do you want to allow .. changes to your computer?"
- type the administrator password and click Yes
- you should see now a big box "MasmBasic - a fast library..." with a EULA; read it, then click "Accept & Install"

** if anything goes wrong, have a look at our AV Software sh*t list subforum, then disable your antivirus for the \Masm32 folder and try again; if that doesn't help, reply to this thread **

jj2007

#1
Various extras, JBasic for dual 64-/32-bit assembly

The attached JBasic (SetupJBasic*.zip) builds on your existing Masm32 and MasmBasic installation. Just run the JBasic*.exe installer.



-------- Maps in MasmBasic: --------
In the RichMasm editor, click on File/New Masm source to see a green box with code templates.
Two of them called Gdi+ and maps (in the middle to the right) require a map of Europe. Extract the two files in the attachment to \Masm32\MasmBasic\Res\europe.* to make these templates work.

jj2007

#2


This snippet (a full-fledged Windows console application  :biggrin:) produces the following output:
Введите строку, которую вы хотите найти в папке \Masm32\Include: bitmap
#1      \Masm32\Examples\advanced\wrep\result.asm
#2      LOCAL tbab   :TBADDBITMAP
#3      \Masm32\Examples\advanced\wrep\richedit.asm
#4      LOCAL tbab   :TBADDBITMAP
#5      \Masm32\Examples\Bill_Cravener\calender\calendar.asm
...
#96     \Masm32\Examples\exampl02\appack\toolbar.asm
#97     LOCAL tbab  :TBADDBITMAP
#98     ; The toolbar bitmap
#99     ; You must supply a bitmap for the toolbar that ha
#100    \Masm32\Examples\exampl02\appack\rsrc.rc
ok


As the example shows,
    1. MasmBasic is not BASIC: No BASIC dialect understands mov ebx, 400
    2. MasmBasic is assembly, i.e. it will flawlessly assemble with Microsoft Macro Assembler (MASM, version 6.15 upwards) or, better, with Jwasm

Here is a more complex application. It opens Windows.inc, converts all hexadecimal equates into decimal ones, and writes it back to disk:

include \masm32\MasmBasic\MasmBasic.inc

Init
call Convert
Exit

Convert proc
LOCAL pos, posAfter, MyTimer, MyCounter
  and MyCounter, 0
  mov MyTimer, Timer
  Recall "\Masm32\include\Windows.inc", L$() ; load an array of strings from file
  mov ebx, eax
  For_ n=0 To ebx-1
mov pos, Instr_(1, L$(n), "equ", 5) ; start in pos 1, 1=case-insensitive + 4=full word
.if pos
mov esi, Val(Mid$(L$(n), pos+3, 99)) ; get the numeric value of the string behind equ
.if signed edx<0 ; edx returns the number of usable chars; a
neg edx ; negative number indicates a hex$ or bin$ was found
add edx, pos
add edx, 3
mov posAfter, edx
inc MyCounter
Let L$(n)=Left$(L$(n), pos-1)+"EQU "+Str$(esi)+Mid$(L$(n), posAfter)
.endif
.endif
  Next
  Store "MyWindows.inc", L$() ; write all strings back to file
  sub MyTimer, Timer
  Print Str$("\nConverting %i hex equates in Windows.inc to decimals", MyCounter), Str$(" took %i ms\n", 0-MyTimer)
  ret
Convert endp

end start


Output:
Converting 7676 hex equates in Windows.inc to decimals took 31 ms

MasmBasic comes with RichMasm. The editor is configured to give context-sensitive help with the F1 key, and to expand many instructions. For example,
opo [space] will expand to Open "O", #1,
mb becomes MsgBox 0, "¨", "Hi", MB_OK
for_ becomes For_ n=0 To ebx-1 ... Next
ism becomes invoke SendMessage,
etc.; more in \masm32\MasmBasic\MbGuide.rtf (in RichMasm:  File/MasmBasic Guide)

Last but not least an ultra-short Win32 application  ;)

include \masm32\MasmBasic\MasmBasic.inc
Init
Credits
Exit
end start


Let me know who is missing  :biggrin:

I wrote this library for my own use and pleasure, but since many forum members contributed to it, through good advice and even better algos, I think it is just fair to release it here. Thanks to everybody :icon14:

For the xHelp project, I had to add a few functions - sorry if you tried to assemble xHelp.asc with the June version. Among others, these features have been included:

Launch$
   Init
   ; the line below launches Arc.exe with option v and returns what SdtOut produces:
   Let esi=Launch$(ExpandEnv$(Chr$(34, "%ProgramFiles%\FreeArc\bin\Arc.exe", 34, " v Lib32.arc")))   ; see FreeArc
   StringToArray esi, FreeArc$()   ; translate linear output to an array
   For_ ebx=0 To eax-1
      PrintLine Str$(ebx), Tb$, FreeArc$(ebx)
   Next
Rem   args as in Launch above; returns string in eax

Output:
0       FreeArc 0.666 listing archive: Lib32.arc
1       Listing archive: Lib32.arc
2       Date/time              Attr     Size          Packed      CRC Filename
3       ----------------------------------------------------------------------
4       2000-06-02 16:24:14 .......     1364           10002 c2249beb Masm32\m32lib\a2dw.asm
5       2004-05-21 07:38:48 .......     3399               0 50c16759 Masm32\m32lib\a2dw_ex.asm
...
41      2003-12-06 08:43:10 .......     4843            1097 b83a653e Masm32\m32lib\ascdump.asm
42      ----------------------------------------------------------------------
43      38 files, 77,396 bytes, 11,099 compressed


ExeFromWin$
   Let esi="Recent Unread Topics"
   Print esi, " was launched by ", ExeFromWin$(WinByTitle(esi))   ; by firefox.exe, of course ;-)
Rem   returns full path of executable that created a window

SetGlobals   
; declares global variables relative to ebx, syntax as in LOCAL
.data?
   whatever   dd ?
   SetGlobals hMain, hStatic, hEdit
   SetGlobals hMenu, hM1, hM2, rc:RECT
   SetGlobals msg:MSG, wc:WNDCLASSEX, exeBuffer[MAX_PATH]:BYTE, gBuffer[1024]:BYTE
   .code
   ; no args: set ebx to the right offset; must be used in Init part and all callbacks (WndProc, SubEdit, ...)
   SetGlobals

Rem   variables return [ebx+x]

Enum      
; create a list of IDs
   Enum   IdMenuNew, IdMenuSave, IdMenuCopy, IdTimer
   Enum   20:IdEdit, IdButton1, 30:IdButton2, IdStatic, IdFind, IdFindStatic
Rem   - variables return [ebx+x]
   - default start is 10, but different start values can be specified

jj2007

Version 14 September features two new macros for use with COM, GuidFromString and GuidsEqual.
I hope the sample below is self-explanatory for the COM fans ;-)

.code
CLSID_WebBrowser   GuidFromString(8856F961-340A-11D0-A96B-00C04FD705A2)      ; ExDisp.h
IID_IWebBrowser2     GuidFromString(D30C1661-CDAF-11D0-8A3E-00C04FC9E26E)   ; OleIdl.h
IID_IUnknown      GuidFromString(00000000-0000-0000-C000-000000000046)
IID_IOleObject      GuidFromString(00000112-0000-0000-C000-000000000046)     ; MSDN
IID_IOleClientSite      GuidFromString(00000118-0000-0000-C000-000000000046)
IID_IOleWindow      GuidFromString(00000114-0000-0000-C000-000000000046)
IID_IOleInPlaceSite   GuidFromString(00000119-0000-0000-C000-000000000046)

MyQuery proc pRefID, pRet
  xor edx, edx
  .if GuidsEqual(pRefID, IID_IUnknown)
           mov edx, pWB2   ; return this
  .else
  .if GuidsEqual(pRefID, IID_IOleClientSite)
           mov edx, MyClientSite   ; return ptr to a handler
  .else
  .if GuidsEqual(pRefID, IID_IOleWindow)
           mov edx, MySite
  .else
  .if GuidsEqual(pRefID, IID_IOleInPlaceSite)
           mov edx, MySite
  .endif
  .endif
  .endif
  .endif
  mov eax, pRet
  mov [eax], edx   ; return result
  xor eax, eax      ; S_OK
  .if !edx
           mov eax, E_NOINTERFACE   ; flag failure
  .endif
  ret
MyQuery endp

jj2007

Versions earlier than 19 Sept had a problem with Declare, it's fixed now:

include \masm32\MasmBasic\MasmBasic.inc      ; download
      Init            ; initialise the app
      Dll "shimgvw"      ; load the shell image view dll aka Windows Picture and Fax Viewer Library
      Declare ImageView_Fullscreen, 4      ; ImageView_Fullscreen expects 4 dwords
      void ImageView_Fullscreen(0, 0, wCL$(1), SW_SHOW)   ; we need the wide version of the commandline arg
      
Err$(0)         ; there is no retval, so we have to test for errors
      Exit         ; do a clean exit, inter alia FreeLibrary
end start

I seized the occasion to tune up the dialog examples. Here is a nice one:

include \masm32\MasmBasic\MasmBasic.inc   ; download (version 19 Sept 2012)
  Init
  Let ecx=NoTag$(FileRead$("http://masm32.com/why.htm"))   ; get some wise words from the World Wide Web
  DlgDefine "... but nothing beats Basic, hehe:", 0, 0, 325, 90
  DlgControl dcStatic, "\Masm32\examples\exampl04\car\car.jpg", SS_BITMAP, 80, 5   ; any Masm32 installation has this JPG
  DlgControl dcStatic, "\masm32\RichMasm\icons\Smiley.ico", SS_ICON, 30, 1   ; x, y [, width, height]
  Let ecx="... "+Mid$(ecx, Instr_(ecx, "and contrary"), 109)
  DlgControl dcStatic, wChr$(ecx), SS_LEFT, 5, 18, 70, 70      ; x, y, width, height
  DlgShow
  Exit
end start

Full source and exe attached ;)

jj2007

Extract$   extracts a substring based on left and right matches
   ; simple example:
   Let esi='This is a link to <a href="http://www.google.com">Google</a> that can be extracted'
   Print "The URL for ", Extract$(esi, Chr$(34, 62), "</a>"), " is "   ; 34, 62 = ">
   Inkey Extract$(esi, "http://", Chr$(34), xsIncL)         ; you could use '"' (single/double/single quote) instead of Chr$(34)
   ; result: The URL for Google is http://www.google.com

   ; syntax: Extract$(pSrc, "left match" [, "right match"] [, xsFlags] [, maxlines*)] [, startIndex])
   ; right match: if omitted, end of line is assumed
   ; xsFlags: if omitted, search for left match is case-sensitive, left and right matches are excluded
   ; maxlines: default is 1, i.e. right match must be in same line; for extracting structures etc, put a reasonable value, e.g. 100
   ; startIndex: default is 1, i.e. beginning of string; if xsLoop is set, search for the left match restarts where the last right match
   was found; see also the options for Instr_ - Extract$ uses Instr_ for the left match
   xsCaseI   ; case-insensitive search for left match (right: always case-sensitive)
   xsIs       ; intellisense; search is case-insensitive for 1st char only, i.e. Hello = hello
   xsI1c   ; ignore 1st char in left match, e.g. ?:\Masm32\...
   xsFullW   ; full word (left match only)
   xsIncL   ; include left pattern (e.g. http://)
   xsIncR   ; include right pattern
   xsExcL   ; exclude left pattern, e.g. {url= ... }
   xsExcR   ; exclude right pattern
   xsTrimL   ; trim left side, i.e. strip everything <=ASCII 39 aka single quote
   xsTrimR   ; trim right side (after excluding right match if xsExcL is set)
   xsTrim=xsTrimL or xsTrimR   ; trim both sides
   xsLineL   ; include line of the left match
   xsLineR   ; include rest of line after the right match (must include right match...)
   xsLoop   ; let Instr_ start behind the last position, for using in loops
    *) if the right pattern contains a linefeed (LF, Ascii 10), the maxlines counter will never stop the pattern search
   ----------------------------------------------------------
   The last flag, xsLoop, is used in the following demo, a Windows console application that extracts
   all structures from the two main Masm32 include files. Do not use the result for work, as there are
   problems with nested structures (e.g. unions ending with ends) and some structures ending with
   lowercase ends.
   
include \masm32\MasmBasic\MasmBasic.inc   ; download
   Init
   ; First, let's get some useful source string:
   Let ecx=FileRead$("\Masm32\include\Windows.inc")+FileRead$("\Masm32\include\WinExtra.inc")
   Open "O", #1, "Structures.txt"   ; open a file for output
   xor ebx, ebx   ; reset counter
   .While 1
      inc ebx
      .Break .if !Extract$(ecx, "STRUCT", 'ENDS', xsFullW or xsLineL or xsIncR or xsLoop, 100)
      Print #1, eax, CrLf$
   .Endw
   Close #1   ; file #1 closed
   Inkey Str$("%i structures found\n", ebx)
   Exit
end start

Rem   - Extract$ returns pointer in eax, and len of result in edx
   - can be used with Print and Let even if no match found, i.e. eax=0; in this case, Extract$ will print as ?
RichMasm Key   ex$

jj2007

As a complement to MasmBasic's new file dialog understanding Unicode file names,
I added the capacity to use these file names for opening files:

      wOpen "O", #1, wRes$(ResID)   ; file name from a resource string, e.g. Добро пожаловать.txu
... wPrint to this file ...

   .if wFileOpen$("Unicode text=*.txu")
      wPrint wCrLf$, "You selected ", wFileOpen$(), wCrLf$
      wOpen "I", #1, wFileOpen$()   ; use the filename
      lea ecx, [Lof(#1)-2]   ; required: length of file minus 2 bytes BOM
      Let esi=New$(ecx)   ; create a string with the required length
      Input #1, esi, 2   ; discard the Unicode BOM
      Input #1, esi, ecx   ; read rest of file into buffer
      Close
      wPrint "The content of the selected file: [", esi, "]", wCrLf$
      ; the console may have problems with Chinese etc, a MessageBox shouldn't:
      wMsgBox 0, esi, "The content of the selected file:"
   .endif


Version 4 October is available on top of this thread. Full example in \masm32\RichMasm\Res\SkelFileIO_Unicode.asc - open in RichMasm and hit F6.

jj2007

Version 14 October 2012 has some improvements under the hood, inter alia regarding JWasm compatibility and handling of more data types for ebx-relative global variables. Here is an example, a more complete one will be in \masm32\RichMasm\SetGlobalsQword.asc after extracting the MasmBasic archive.

include \masm32\MasmBasic\MasmBasic.inc   ; download
   SetGlobals MyR4:REAL4, MyR8:REAL8, MyR10:REAL10, MyPoint:POINT, MyQ:QWORD
   SetGlobals MySD:SDWORD, MyD, MyW:WORD, MyB:BYTE, MyRect:RECT

   Init
   SetGlobals   ; short code through ebx-relative addressing
   MovVal MyB, "123"
   MovVal MyW, "12345"
   MovVal MySD, "-123456789"   ; signed dword
   MovVal MyD, "123456789"   ; both versions work
   mov MyD, Val("123456789")   ; Val is for DWORD destinations only
   MovVal MyR4, "12345.6789"
   MovVal MyR8, "123456789012345678"
   MovVal MyR10, "12345678901234567890"
   MovVal MyQ, "123456789012345678"
   MovVal xmm0, "123456789012345678"
   MovVal f:xmm1, "123456789012345678"

   MovVal MyPoint.y, "987654321"   ; structure elements
   mov MyPoint.x, Val("123456789")   ; Val is for DWORD destinations only
   MovVal  MyRect.left, "111111111"
   mov MyRect.bottom, Val("999999999")

   deb 4, "SetGlobals", MyB, MyW, MyD, MySD, MyQ, MyR4, MyR8, MyR10, xmm0, f:xmm1
   deb 4, "POINT & RECT", MyPoint.x, MyPoint.y, MyRect.left, MyRect.bottom
   Inkey
   Exit
end start



Output:
SetGlobals
MyB             123
MyW             12345
MyD             123456789
MySD            -123456789
MyQ             123456789012345678
MyR4            12345.68
MyR8            1.234567890123457e+17
MyR10           1.23456789012345679e+19
xmm0            123456789012345678
f:xmm1          1.234567890123457e+17

POINT & RECT
MyPoint.x       123456789
MyPoint.y       987654321
MyRect.left     111111111
MyRect.bottom   999999999

jj2007

Update 30 October 2012 (attached to 1st post above):

- RichMasm editor has learned to warn the user when doing stupid things

- Launch$("proggie.exe") has been enhanced with ExitCode():

   Let My$=Launch$("GetInfo.exe")      ; imagine a little proggie that writes something useful to console ...
   mov eax, ExitCode()      ; ... and  finishes with a Yes/No/Cancel MsgBox plus invoke ExitProcess, eax
   .if eax==IDYES
      ... do something with My$ ...
   .endif
Rem   - returns a global variable containing the para passed with ExitProcess, i.e. the DOS-style errorlevel
   - for Launch "whatever", this value is also returned in edx

anta40

Hi jj,

Does MB supports nested for loop?

Example:

include \masm32\MasmBasic\MasmBasic.inc

Init

For_ ebx=1 To 3
    For_ ecx=1 To (4-ebx)
        Print Str$(edx," ")
    Next
    Print CrLf$
Next

Exit

end start


I tried to assemble using jwasm and ML. Both failed.

jwasm
Quote
JWasm v2.09pre, Oct 29 2012, Masm-compatible assembler.
Portions Copyright (c) 1992-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.

forloop.asm(6) : Error A2227: Missing right parenthesis in expression
MbFor(46)[MasmBasic.inc]: Macro called from
  forloop.asm(6): Main line code
forloop.asm(6) : Error A2227: Missing right parenthesis in expression
MbFor(60)[MasmBasic.inc]: Macro called from
  forloop.asm(6): Main line code
forloop.asm(6) : Error A2209: Syntax error: )
MbFor(74)[MasmBasic.inc]: Macro called from
  forloop.asm(6): Main line code
invalid Str$
forloop.asm: 14 lines, 1 passes, 109 ms, 0 warnings, 3 errors

ML
Quote
Microsoft (R) Macro Assembler Version 11.00.50522.1
Copyright (C) Microsoft Corporation.  All rights reserved.

Assembling: forloop.asm
forloop.asm(6) : error A2006:undefined symbol : atVt
MbFor(49): Macro Called From
  forloop.asm(6): Main Line Code
invalid Str$
forloop.asm(7) : error A2207:missing right parenthesis in expression
MbFor(3): Macro Called From
  forloop.asm(6): Main Line Code
forloop.asm(7) : error A2207:missing right parenthesis in expression
MbFor(10): Macro Called From
  forloop.asm(6): Main Line Code
forloop.asm(7) : error A2208:missing left parenthesis in expression
MbFor(11): Macro Called From
  forloop.asm(6): Main Line Code
forloop.asm(7) : error A2052:forced error
Str$(3): Macro Called From
  Print(0): Macro Called From
   forloop.asm(7): Main Line Code

jj2007

Quote from: anta40 on November 04, 2012, 03:24:43 AM
Hi jj,

Does MB supports nested for loop?

Example:

include \masm32\MasmBasic\MasmBasic.inc

Init

For_ ebx=1 To 3
    For_ ecx=1 To (4-ebx)
        Print Str$(edx," ")
    Next
    Print CrLf$
Next

Exit

end start


Hi Anta,

No brackets for 4-ebx, and Str$() has a different syntax:

   For_ ebx=1 To 3
      For_ ecx=1 To 4-ebx   
         Print Str$(ecx), " "
      Next
      Print CrLf$
   Next

anta40

Ah, a small typo :redface:

Thanks jj, now it works as expected  :t

jj2007

Great ;-)

Version 5 Nov 2012 is out:
- FileOpen$() keeps user's folder changes
- IsFolder() macro
- Dll & Declare speedup: see example here

frktons

Hi jj.

MasmBasic is really a nice project. If I had enough knowledge I'd started
a similar project myself. Unfortunately I'm not able to do much with it for the time
being.

It remains, however, one of my goal to learn and use some MasmBasic as soon
as I've enough capacity to do it.

Carry on this optimal work.

Frank
There are only two days a year when you can't do anything: one is called yesterday, the other is called tomorrow, so today is the right day to love, believe, do and, above all, live.

Dalai Lama

jj2007

Thanks a lot, Frank.

Version 3 December features an improved xHelp, now included in the MasmBasic package.
Inter alia, xHelp has learned how to add F1 context-sensitive help to qEditor. After extraction of the package (the archive in post #1 of this thread) with "use folder names", launch \Masm32\InstallXhelp.exe. Afterwards, you can select some text, e.g. CreateWindowEx in qEditor, and press F1. Compliments to Hutch who made such a great plugin interface for the Masm32 editor :t

And apologies that I stole the idea to create a plugin interface for RichMasm, too - PM me for details ;-)