News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

MasmBasic

Started by jj2007, October 06, 2009, 08:24:57 PM

Previous topic - Next topic

jj2007

New version attached at the end of the first post (some lines above Dave's post).

What's new?

Quoteinclude \masm32\MasmBasic\MasmBasic.inc      ; include this library
      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$(1)      ; there is no retval, so we have to test for errors
      Exit      ; do a clean exit, inter alia FreeLibrary
[/color]
end start

Dll "name" loads a dll with LoadLibrary
Declare dllfunction, #args defines a macro that can be used e.g. as mov eax, MyFunc(1, eax, 3)
Housekeeping (FreeLibrary) is done with the Exit statement
The example above needs a Unicode filename, therefore wCL$().
See reply 155 for the PopCount and Rand() functions.

Antariy

Jochen, for Dll macro, I guess, you can return index of the DLL in EDX, in addition to EAX's handle.

jj2007

Quote from: Antariy on November 23, 2010, 11:46:30 PM
Jochen, for Dll macro, I guess, you can return index of the DLL in EDX, in addition to EAX's handle.

Old:
MbDllCt = -4
Dll MACRO name
  invoke LoadLibrary, repargA(name)
  MbDllCt = MbDllCt + 4
  mov DllTable[MbDllCt], eax
ENDM


New:
MbDllCt = -4
Dll MACRO name
  invoke LoadLibrary, repargA(name)
  MbDllCt = MbDllCt + 4
  mov edx, MbDllCt  ; <-------------------- like this?
  mov DllTable[MbDllCt], eax
ENDM


Like this? But how would you use this value?

Antariy

Quote from: jj2007 on November 24, 2010, 07:22:10 AM
Like this? But how would you use this value?

Well, this can be convenient, can be. (maybe I'll want to replace handle of dll in the table) :P

:bg

jj2007

Bugfix: CL$() returned the commandline correctly but unfortunately did not correct the stack properly :red
Use version 27.11.2010 on top of thread. It has also a slight improvement of the Declare macro.
The snippet below g-zips the file obtained from the commandline.

Quoteinclude \masm32\MasmBasic\MasmBasic.inc
   Init
   Dll
"\masm32\RichMasm\zLib\zlib1.dll"  ; make sure zlib1.dll is present
   Declare gzopen, C:2
   Declare gzwrite, C:3
   Declare gzclose, C:1
   mov ebx, gzopen("TheTest.gz", "wb6")
   Let esi=FileRead$(CL$())
   mov ecx, gzwrite(ebx, esi, Len(esi))
   Inkey Str$("retval=%i, ", gzclose(ebx)), Str$("compressed=%i\n", ecx)
   Exit
end start

dedndave

oops !
glad you fixed it, Jochen

Z sends a K - no tongue  :P

jj2007

Quote from: dedndave on November 27, 2010, 03:02:30 AM
Z sends a K - no tongue  :P
Hey, you are not jealous, are you?

@Alex: Set RetDllCt = 1 to get in edx the handle offset (mov DllTable[edx], eax)

QuoteRetDllCt = 0  ; default: don't return the offset
[/b]Dll [/color]MACRO name
  invoke LoadLibrary, repargA(name)
  test eax, eax
  ExternDef MbError0:NEAR
  je MbError0
  MbDllCt = MbDllCt + 4
  if RetDllCt
   push MbDllCt
   pop edx
   mov DllTable[edx], eax
  else
   mov DllTable[MbDllCt], eax
  endif
ENDM

Declare allows now C calling convention and variable # of args:
Quote   Declare gzwrite, C:3   ; C calling convention, three args
Quote   Dll "msvcrt"
   Declare sprintf, C:?   ; C calling convention, variable # of args
   void sprintf(offset msgtext, "%016I64u", i64)      ; low & high dword of i64 managed by macro
   Print offset msgtext, 13, 10
   ; Masm32 syntax for static link: invoke crt_sprintf, offset msgtext, offset format, i64
void means discard the retval (which is a rather useless "# of chars written" for sprintf).

jj2007

Update (attached on top of thread):

Quoteinclude \masm32\MasmBasic\MasmBasic.inc
   Init
   GetFiles
\masm32\m32lib\*.asm
   ZipFiles "The_Masm32_lib"
   UnZipFiles "The_Masm32_lib", "\masm32\ZipTest"
   Inkey "Archive zipped & unzipped, everything ok?"
   Exit
end start

This full-fledged Windows console application assembles fine with Masm 6.15 and higher or JWasm, and
- zips the whole \masm32\m32lib\*.asm folder
- and unzips it to \masm32\ZipTest\masm32\m32lib\*.asm
Compression is roughly 10:1, with 53,775 bytes for The_Masm32_lib (for comparison: WinZip "Maximum portable": 182,884 bytes)

For options, see MbGuide.rtf in the MasmBasic package.

jj2007

Update (attached on top of thread): New AddFiles, AddFolders, SendData functions.

GetFiles has got companions, and has learnt to recurse into subdirectories:
QuoteGetFiles, AddFiles
   GetFiles filter [, startpattern] [, endpattern or lines matching] [, case sensitivity and full mode]
   GetFiles *.inc      ; fill the Files$() array with *.inc files of the current directory
   AddFiles Help\*.hlp
|*.chm   ; add to the Files$() array hlp or chm files from the Help subfolder
   mov ebx, eax      ; eax=# of files found
   Print Str$("\nFound %i files matching *.inc:", ebx)
   For_ n=0 To ebx-1
      Print CrLf$, Files$(n)
   Next

QuoteGetFolders, AddFolders
   GetFolders         ; fill the Files$() array with folders and subfolders starting with the current directory
   AddFolders \Masm32\include\*      ; add to the Files$() array folders and subfolders of the specified directory
Rem[/color]   - returns # of created lines in eax and MbGetFileCount
   - can be combined with GetFiles/AddFiles

ZipFiles
   GetFiles[/color] \masm32\m32lib\*.asm
   ZipFiles "The Masm32 lib"   ; the minimum: just the name of the *.arc archive
   
; with archive name, file count, show, Launch console mode:
   ZipFiles "The_Masm32_lib", 10, SW_MINIMIZE,
CREATE_NEW_CONSOLE   ; use first 10 files and a minimised new console
Rem[/color]   - requires FreeArc in its default location (e.g. C:\Program Files\FreeArc\bin\Arc.exe)
   - creates archive in *.arc format
   - return value: see Launch
   - use MbZipLog = 1 to see the command lines in ZipLog.txt
Key   -

UnZipFiles

   
UnZipFiles "The_Masm32_lib"      ; unzip The_Masm32_lib.arc, restoring the tree on the current drive
   ; with archive name, a new destination folder, show, Launch console mode:
   UnZipFiles[/color] "The_Masm32_lib", "\masm32\ZipTest", SW_MINIMIZE, CREATE_NEW_CONSOLE   ; unzip the tree to new folder
Rem[/color]   - requires FreeArc in its default location (e.g. C:\Program Files\FreeArc\bin\Arc.exe)
   - creates archive in *.arc format
   - return value: see Launch
   - use MbZipLog = 1 to see the command lines in ZipLog.txt

For Inter-Process Communication, the SendData/CopyData$() pair is easy to use:
QuoteCopyData$()
   SetWin$ hEdit="Just received:"+CrLf$+CopyData$()+CrLf$+"--- end of data ---"      ; use directly to set a window content
   Let My$="Just received:"+CrLf$+CopyData$()+CrLf$+"--- end of data ---"      ; store away for later use
Rem[/color]   - for receiving data from other apps; for use inside a WM_COPYDATA message handler, for example:
  SWITCH uMsg
  CASE WM_COPYDATA
      Let My$=CopyData$()+CrLf$+"received "+Time$

For sending data, use SendData

SendData
   SendData
"MyClient", Win$(hEdit)
   SendData "MyClient", "How are you?"
Rem[/color]   - returns DWORD in eax: 0=no client found
   - can also be used from a Win32 console application

jj2007

With bugfixes, version 141210b is attached on top of thread. Note the syntax for Timer has changed - before it was Timer(), but I have now found a way to convince MASM 6.15, 9.0 and JWasm to accept that there are no brackets. In general, I try to avoid useless trailing brackets; there are a few exceptions, such as
Let My$=Clip$()    ; get all available text from clipboard
Let My$=Clip$(100) ; get up to 100 bytes

Let My$=CL$(0)     ; get arg #0, i.e. the current executable
Let My$=CL$()      ; get first arg of the commandline (i.e. #1 is the default arg)
Let My$=CL$(2)     ; get second arg of the commandline


The Server/Client example for IPC with SendData/CopyData$ has been improved, too.

Alex (Antariy) asked me if GetFiles checks for maximum recursion depth. Actually, it doesn't, and tests seem to prove that it doesn't matter. There is an old thread discussing this:

Quote from: zooba on June 24, 2007, 01:02:16 PM
The stack reserves the size specified by the linker but it doesn't commit it until you try and access it. It detects attempted accesses using a guard page, so the first time you attempt to access a page that hasn't been committed, Windows will catch an exception and commit it. However, it only guards one page, which is the next uncommitted page. Attempting to access the page beyond the guard page will cause an access violation exception.

The critical sentence here is "Attempting to access the page beyond the guard page will cause an access violation exception". A recursive FindFirstFile proc allocates a few hundred bytes per recursion, and thus will never throw an exception. Attached is a zip archives that extracts two zero byte files to a 48 levels deep folder ("use folder names" option in WinZip required). Test it with this snippet:

include \masm32\MasmBasic\MasmBasic.inc ; http://www.masm32.com/board/index.php?topic=12460
Init
GetFiles \masm32\RichMasm\*.rt ; recurse until you find files with extension *.rt
push eax
For_ n=0 To eax-1
PrintLine Str$("#%i\t", n), Files$(n)
Next
pop eax
Inkey Str$("\n%i files found", eax)
Exit
end start


The test also reveiled that WinXP stops at a total names length of 256 bytes, i.e. even when using single letter folder names, the theroretical maximum recursion level is apparently 256.

dedndave

Jochen,
i know, with XP, you can't go as deep with
CD c:\a\a\a\a...\a\a\a
as you can with
CD c:\a
CD a
CD a
CD a
...
CD a
CD a
CD a

the point being, it matters if it is root-relative or current-relative

jj2007

Unzip the archive to C:\, then go to the last level and try an mkdir dedndave...

Re Client/Server example: If you want some fun, try (in \masm32\RichMasm\Res\Server.asc):
case IdEdit
  push esi
  Let esi=Win$(hEdit)+CrLf$+FileRead$("\Masm32\include\Windows.inc")+FileRead$("\Masm32\include\WinExtra.inc")
  SendData "MyClient", esi, hWnd
  Clr$ esi
  pop esi


Type something while MyClient is active... it feels like Microsoft Word :green

Antariy

Quote from: jj2007 on December 14, 2010, 10:00:36 PM
Alex (Antariy) asked me if GetFiles checks for maximum recursion depth. Actually, it doesn't, and tests seem to prove that it doesn't matter. There is an old thread discussing this:

Quote from: zooba on June 24, 2007, 01:02:16 PM
The stack reserves the size specified by the linker but it doesn't commit it until you try and access it. It detects attempted accesses using a guard page, so the first time you attempt to access a page that hasn't been committed, Windows will catch an exception and commit it. However, it only guards one page, which is the next uncommitted page. Attempting to access the page beyond the guard page will cause an access violation exception.

The critical sentence here is "Attempting to access the page beyond the guard page will cause an access violation exception".

My point was not trying to access beyond guard page, untill you did'n allocate more than 4 KB this would not occur. With using of your macro for clearing local variables, this will not occur even with over 4 KB buffers.
My point is: you just can reach end of all space allocated for stack, if recursive function take too many data as local variables. At least, WFD structure have size over 300 bytes, and for each level of recursion this will increase linearly. If proc have other fat local data, then you just *can* reach end of the stack, with funny exception (and probably without any Windows "Error reporting" message) :lol

dedndave

the stack has a lot of room to work in win 32   :bg

Antariy

Quote from: dedndave on December 15, 2010, 01:32:06 AM
the stack has a lot of room to work in win 32   :bg

Dave, this discussion is not interesting. I dislike to to rend the air with such conversations.
BUT, for example, imagine that your recursive function have 600 (only 600!!!) bytes of local variables. And >300 from them - the WFD structure only.
So, for 128 levels (for example) of recursion, you will grab 128*600=75 KB of the stack space. At point of 1 meg default linking stack space, this is not so small. You shouldn't decise that "almost all stack is mine". In some relatively deep call you will get a stack overflow, and exit without any "error message", since SEH cannot work in this case.
Of course, you "will get a stack overflow" only for 50/50, dependedly from case and application. But this lottery should not pleasing you.

:P

P.S. TotalCommander in near back have funny stack overflows by many cases, if you don't trust me :P