Author Topic: MasmBasic  (Read 39032 times)

jj2007

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
MasmBasic
« on: May 23, 2012, 10:16:07 PM »
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 and higher, e.g. version 8.0) and JWasm *). While MasmBasic is pretty stable, 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 8)

To install the library, double-click SetupMasmBasic.exe in the attached archive.

For an overview of the 180+ functions available, see \Masm32\MasmBasic\MbGuide.rtf (after extracting the archive, of course) or see the (incomplete) MasmBasic Quick Reference online.

17 November 2014: Updated archive attached below
Latest additions: 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, ...

*) Note that you need either JWasm (highly recommended) or at least ML.EXE version 6.15 to use the MasmBasic library; ML 6.14 (the old version that is included with the Masm32 SDK, see \Masm32\bin) is not sufficient, because MasmBasic contains SSE2 code (more here)
« Last Edit: November 17, 2014, 12:17:00 PM by jj2007 »

jj2007

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
Re: MasmBasic - a fast and easy-to-use library
« Reply #1 on: May 23, 2012, 10:17:30 PM »
So what exactly is MasmBasic?


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:

Code: [Select]
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  ;)

Code: [Select]
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:
« Last Edit: November 01, 2013, 02:50:01 PM by jj2007 »

jj2007

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
New MasmBasic version
« Reply #2 on: July 29, 2012, 09:12:15 AM »
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

CodeDog

  • Guest
Re: MasmBasic - a fast and easy-to-use library
« Reply #3 on: September 11, 2012, 12:01:25 PM »
Hi jj2007. Nice library. Are you not worried when you need to convert this thing to 64 bit code?  :icon_confused:

How many users worldwide is using this library?

jj2007

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
Re: MasmBasic - a fast and easy-to-use library
« Reply #4 on: September 11, 2012, 03:30:45 PM »
Hi jj2007. Nice library. Are you not worried when you need to convert this thing to 64 bit code?  :icon_confused:
Win7-64 still runs 16-bit code. Guess how old I'll be when Windows stops supporting 32-bit code :greensml:

Quote
How many users worldwide is using this library?

Be the first. It's faster than your favourite C dialect...

japheth

  • Member
  • ***
  • Posts: 359
Re: MasmBasic - a fast and easy-to-use library
« Reply #5 on: September 11, 2012, 04:43:52 PM »

There's no license info in the package. Hence MB is freeware only. You should make this fact - and perhaps also what parts of MB are redistributable - clear by some text ( "EULA", license.txt, copyright notice, ... ).

Was fällt, das soll man auch noch stoßen!

CodeDog

  • Guest
Re: MasmBasic - a fast and easy-to-use library
« Reply #6 on: September 11, 2012, 05:18:43 PM »
Can you add a game extension to the library to support useful game functionality like ai, pathfinding, projecting path's for guns and shells, laser beam, gravity and such? You could call the extension BasicGameExtension

jj2007

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
Re: MasmBasic - a fast and easy-to-use library
« Reply #7 on: September 11, 2012, 05:49:55 PM »

There's no license info in the package. Hence MB is freeware only. You should make this fact - and perhaps also what parts of MB are redistributable - clear by some text ( "EULA", license.txt, copyright notice, ... ).

Valid point, thanks. I though it was covered by point 0 and lines 41ff of \Masm32\RichMasm\ReadMeMasmBasic.txt but maybe it's not explicit enough.

jj2007

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
OLE support in MasmBasic
« Reply #8 on: September 14, 2012, 08:18:53 AM »
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

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
MasmBasic bug fix
« Reply #9 on: September 19, 2012, 08:40:38 AM »
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

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
Re: MasmBasic - a fast and easy-to-use library
« Reply #10 on: September 25, 2012, 08:01:44 AM »
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

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
MasmBasic & Unicode: wOpen added
« Reply #11 on: October 04, 2012, 09:54:11 AM »
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

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
Ascii to byte/word/dword/sdword/qword/Real4/8/10 and xmm regs
« Reply #12 on: October 14, 2012, 10:43:56 AM »
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

  • Member
  • *****
  • Posts: 3519
    • MasmBasic
Re: MasmBasic - a fast and easy-to-use library
« Reply #13 on: October 30, 2012, 10:28:00 AM »
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

  • Member
  • **
  • Posts: 203
Re: MasmBasic - a fast and easy-to-use library
« Reply #14 on: November 04, 2012, 03:24:43 AM »
Hi jj,

Does MB supports nested for loop?

Example:
Code: [Select]
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