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

Quote from: 2B||!2B on September 10, 2023, 11:32:07 AMNice looking rounded buttons. Do you use GDI+ or D2D?

Thanks. It's Gdi+

jj2007

MasmBasic & RichMasm were updated: Now most if not all sources in...

\Masm32\Examples
\Masm64\Examples

... will assemble & link out of the box just by hitting F6 in RichMasm. No individual batch file is needed, since the IDE will autodetect if a) resources are needed and b) if it's a console or GUI application.

Please let me know if you find an example does not build flawlessly. Actually, I found one: \Masm64\Examples\Advanced\tEdit\tEdit.asm needs an OPT_Assembler ml64 to build properly, in a comment or at the end of the source (Hutch put the masm64rt.ìnc in an include file instead of the main source...).

Plus minor improvements, such as the icon option for static controls (project attached, it's just two tiny files):

GuiParas equ "Hello Ida", w104, h222, b BlueGreen, style 0, icon Butterfly    ; width+height, background colour, icon for caption
include \masm32\MasmBasic\Res\MbGui.asm
  GuiControl MyStatic, "static",  icon IDI_APPLICATION
GuiEnd
Rsrc
#include "resource.h"
01 RT_MANIFEST    "\\Masm32\\MasmBasic\\Res\\XpManifest.xml"
IDI_APPLICATION ICON        "Ida.ico"
Rsrc

You may note that in RichMasm, the resources can be integrated into the main source. This is often handy, as you can edit quickly e.g. a resource ID in both the asm and the rc file without opening two files. When hitting the build button F6, the section between the two Rsrc lines gets exported to [filename].rc before the assembly starts.

mstram

I just installed this on the sdk from http://masm32.masmcode.com/masm32/masm32v11r.zip (had to use Edge and bypass the "can't be downloaded securely).

When I click on File / Build and run get :

\masm32\bin\UAsm32' is not recognized as an internal or external command,
operable program or batch file.
*** Assembly error ***

jj2007

#603
Hi mstram,

Check https://www.terraspace.co.uk/uasm.html#p2

There are UAsm64.exe and UAsm32.exe. Are you using a 32-bit version of Windows?

mstram


jj2007

Update 11 October 2023 (download):

1. Clean$(pString, leftMatch, rightMatch, mode):
  include \masm32\MasmBasic\MasmBasic.inc
  Init        ; select and hit F6
  Let esi="index.php?PHPSESSID=74e64f1f&topic="
  PrintLine "before: [", esi, "]"
  PrintLine "after:  [", Clean$(esi, "PHPSESSID=", "&", 0), "]"    ; string, left, right match, mode
EndOfCode

Output:
before: [index.php?PHPSESSID=74e64f1f&topic=]
after:  [index.php?topic=]

It's the counterpart to Extract$():
- "cleans" a given string depending on left and right matches
- mode as in Instr_()
- if no right match is given, Cr$ is assumed, i.e. until end of line

2. GuiControl allows now to set the background colour with e.g. Ini$() - see CheckNewPosts:
  .if !Ini$()  ; if [filename].ini not found, create it and set defaults:
    SetIni$ "upperBgColour", Str$(LiteBlueGreen)
    SetIni$ "lowerBgColour", Str$(LiteGrey)
  .endif
  GuiControl TheDesc, "RichEdit", y=0+26, h=0+230, font -16, bcol <Val(Ini$("upperBgColour"))>, text hover$
  GuiControl TheLinks, "RichEdit", y0+228, h1000-228, font -14, bcol <Val(Ini$("lowerBgColour"))>

jj2007

Update 28 October 23:

a) ZipFiles adjusted, see here

b) CoInvoke:
Sometimes you see things like this on the web:
hResult = pISD->namespace(vFile, &pToFolder)
To make the translation to Assembly easier, you can now use
Local vDest:VARIANT
  mov vDest.vt, VT_BSTR ; the type
  mov vDest.bstrVal, rv(SysAllocStringLen, ecx, eax) ; put a filename
  CoInvoke pISD, IShellDispatch.NameSpace, vFile, &pFolder

Looks unnecessary? Yes, but the "v" in vFile stands for VARIANT, and to do that properly by hand, you would need this:
CoInvoke pISD, IShellDispatch.NameSpace, VT_BSTR, 0, vFile.bstrVal, 0, addr pFolder
It's easy to get a little bit confused here, especially if the COM call expects several VARIANTs, as e.g. in Folder.CopyHere :cool:

jj2007

Update 2 December 23:

As shown in the Assembly uses Python thread, it may happen that a DLL doesn't work as expected because, well, it can't find its components. Python3.dll loads six more DLLs, and since it's a bit dumb, it looks for them
a) in the current folder (i.e. the executable's folder)
b) in C:\Windows\System32

No luck, folks, if the executable sits elsewhere. So I had to invent the SetDllFolder macro:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  SetDllFolder "\Python"            ; adjust to your setup; downloaded from here
  Dll "python38"                          ; depends on six more DLLs
  Declare void Py_Initialize
  Declare void PyRun_SimpleString, C:1    ; requires python38.dll
  SetDllFolder                     ; no args=go back to previous folder after declaring the functions
  Py_Initialize()
  PyRun_SimpleString("MyLong=123456789")    ; use the interpreter
  Inkey "ok"
EndOfCode

The good news is that with SetDllFolder you don't need the full path for Dll "Python3" :cool:

Overall, Python is a horrible mess:
- Python 3 is absolutely incompatible with Python 2
- dll hell, see SetDllFolder above
- there is Python3.dll in the downloaded folder, but it does not pass on all the functions of the main DLL, which is (in this case) Python38.dll
- so you often must hardcode the version in your code, and force the user to install a specific version (3.8 is the last one that works on Win7 btw)
- there are three distinct methods to access Python from Assembly:
  1. C API (probably the fastest)
  2. PyRun_SimpleString
  3. PyObject_CallMethod
- my guess is that three quarters of the over 1,600 functions exported by Python38.dll are either for typecasting or simply redundant

TimoVJL

#608
Idea for hunting down correct Python3x.dll, but not reliable, as that string is missing many import Python3.dlls, like in version 3.10.0
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "user32.lib")
// https://docs.python.org/3/c-api/
typedef void (PY_INITIALIZE)(void);
typedef PY_INITIALIZE *LPPY_INITIALIZE;
// PyRun_SimpleString
typedef int PYRUN_SIMPLESTRING(char *);
typedef PYRUN_SIMPLESTRING *LPPYRUN_SIMPLESTRING;

int __cdecl main(void)
{
    static LPPY_INITIALIZE Py_Initialize;
    static LPPYRUN_SIMPLESTRING PyRun_SimpleString;
    char szVersion[50];
    char szPythonDll[260] = "bin64/Python3.dll";
    HMODULE hMod = LoadLibrary(szPythonDll);    //
    if (hMod) {
        int nLen = GetModuleFileName(hMod, szPythonDll, 260);
        LoadString(hMod, 1000, szVersion, 50);
        printf("%s\n", szVersion);
        FreeLibrary(hMod);
        szPythonDll[nLen-5] = szVersion[0];
        szPythonDll[nLen-4] = szVersion[2];
        szPythonDll[nLen-3] = 0;
        printf("%s\n", szPythonDll);
        hMod = LoadLibrary(szPythonDll);
    }
    if (hMod) {
        printf("%s loaded\n", szPythonDll);
        Py_Initialize = (LPPY_INITIALIZE)GetProcAddress(hMod, "Py_Initialize");
        if (Py_Initialize) {
            Py_Initialize();
            PyRun_SimpleString = (LPPYRUN_SIMPLESTRING)GetProcAddress(hMod, "PyRun_SimpleString");
            if (PyRun_SimpleString) {
                PyRun_SimpleString("print('Python Print test')");
            } else printf("PyRun_SimpleString not found\n");
        } else printf("Py_Initialize not found\n");
        FreeLibrary(hMod);
    } else printf("Python3x.dll not loaded\n");
    return 0;
}
This works with 3.10
    char szVersion[50];
    char szPythonDll[260] = "bin64_310/Python3.dll";
    HMODULE hMod = LoadLibrary(szPythonDll);
    if (hMod) {
        int nLen = GetModuleFileName(hMod, szPythonDll, 260);
        printf("%s\n",GetVersionInfo(hMod, "FileVersion", szVersion, sizeof(szVersion)));
        FreeLibrary(hMod);
        szPythonDll[nLen-5] = szVersion[0];
        szPythonDll[nLen-4] = szVersion[2];
        if (szVersion[3] != '.') szPythonDll[nLen-3] = szVersion[3]; else szPythonDll[nLen-3] = 0;
        szPythonDll[nLen-2] = 0;
        printf("%s\n", szPythonDll);
        hMod = LoadLibrary(szPythonDll);
    }
GetVersionInfo.c
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winver.h>
#include <stdio.h>

#pragma comment(lib, "version.lib")
#pragma comment(lib, "user32.lib")

LPSTR GetVersionInfo(HMODULE hMod, TCHAR *szValue, TCHAR *szBuffer, ULONG nLength)
{
    LPSTR csRet;

    csRet = NULL;
    HRSRC hVersion = FindResource(hMod, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
    DWORD dwSize = SizeofResource(hMod, hVersion);
    if (hVersion != NULL)
    {
        HGLOBAL hGlobal = LoadResource(hMod, hVersion);

        if (hGlobal != NULL)
        {
            //LPVOID ver = LockResource(hGlobal);
            LPVOID ver = LocalAlloc(LPTR, dwSize*2);

            if (ver != NULL)
            {
                memcpy(ver, hGlobal, dwSize);
                DWORD *codepage;
                UINT len;
                char fmt[0x40];
                PVOID ptr = 0;
                if (VerQueryValue(ver, "\\VarFileInfo\\Translation", (LPVOID) & codepage, &len))
                {
                    //wsprintf(fmt, "\\StringFileInfo\\%04x%04x\\%s", (*codepage) & 0xFFFF, (*codepage) >> 16, csEntry);
                    wsprintf(fmt, "\\StringFileInfo\\%08x\\%s", (*codepage) << 16 | (*codepage) >> 16, szValue);
                    if (VerQueryValue(ver, fmt, &ptr, &len))
                    {
                        lstrcpyn(szBuffer, (TCHAR*)ptr, min(nLength, len));
                        csRet = szBuffer;
                    }
                }
                LocalFree(ver);
            }
            FreeResource(hGlobal);
        }
    }
    return csRet;
}
EDIT 2023-12-03:
api-ms-win-core-path-l1-1-0.dll for Windows 7

Windows API function AddDllDirectory() is useful with
LoadLibraryEx(szPythonDll, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_USER_DIRS);
char szVersion[50];
char szPythonDll[260] = "bin64_310/Python3.dll";
wchar_t wszPath[260];
HMODULE hMod = LoadLibrary(szPythonDll);
if (hMod) {
int nLen = GetModuleFileNameW(hMod, wszPath, 260);
while (wszPath[--nLen] != '\\');
if (nLen) wszPath[nLen+1] = 0;
AddDllDirectory(wszPath);
nLen = GetModuleFileName(hMod, szPythonDll, 260);
printf("%s\n",GetVersionInfo(hMod, "FileVersion", szVersion, sizeof(szVersion)));
FreeLibrary(hMod);
szPythonDll[nLen-5] = szVersion[0];
szPythonDll[nLen-4] = szVersion[2];
if (szVersion[3] != '.') szPythonDll[nLen-3] = szVersion[3]; else szPythonDll[nLen-3] = 0;
szPythonDll[nLen-2] = 0;
printf("%s\n", szPythonDll);
//hMod = LoadLibrary(szPythonDll);
//if (!hMod)
hMod = LoadLibraryEx(szPythonDll, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_USER_DIRS);
}
May the source be with you

jj2007

Thanks, Timo.

This works, it checks for the first Python3?.dll whose name is more than 11 chars long:

include \masm32\MasmBasic\MasmBasic.inc
  SetGlobals ffd:WIN32_FIND_DATA
  Init
  SetDllFolder "\Python" ; adjust to your setup; downloaded from here
  GetFiles python3*.dll
  or ecx, -1
  .Repeat
inc ecx
  .Until Len(Files$(ecx))>11 || ecx>=9
  .if Zero?
MsgBox 0, "Dll not found", "Hi", MB_OK
Exit
  .endif
  Dll Files$(ecx) ; python3?.dll offers twice as many functions
  Declare void Py_Initialize
  Declare Py_GetBuildInfo
  push ecx
  SetDllFolder ; no args=go back to previous folder after declaring the functions
  pop ecx
  Py_Initialize()
  Let edi=Py_GetBuildInfo()
  Inkey "Version ", edi, " loaded from ", Files$(ecx)
EndOfCode

Output: Version tags/v3.13.0a1:ad056f0, Oct 13 2023, 09:34:45 loaded from python313.dll

jj2007

Quote from: TimoVJL on December 03, 2023, 08:18:40 AMWindows API function AddDllDirectory() is useful with
LoadLibraryEx(szPythonDll, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_USER_DIRS);

  LOAD_LIBRARY_SEARCH_USER_DIRS=400h
  LOAD_LIBRARY_SEARCH_DEFAULT_DIRS=1000h
  Dll "kernelbase"
  Declare void AddDllDirectory, 1
  AddDllDirectory(wRec$("\Python"))
  Dll "python313", LOAD_LIBRARY_SEARCH_DEFAULT_DIRS or LOAD_LIBRARY_SEARCH_USER_DIRS

Thanks, Timo, it works, but it's quite an effort. The SetDllFolder macro is straightforward, too.

TimoVJL

With different API function:
int nLen = GetModuleFileNameW(hMod, wszPath, 260);
while (wszPath[--nLen] != '\\');
if (nLen) wszPath[nLen+1] = 0;
SetEnvironmentVariableW(L"PATH", wszPath);
May the source be with you

jj2007

MasmBasic version 20 March 2024 comes with an improved SetAccels macro:
  SetAccels F1: 0
  SetAccels Ctrl F2: Hlp        ; no args
  SetAccels Alt F2: Hlp1(22)
  SetAccels Ctrl Shift F2: Hlp2(33:var444)    ; see console
  SetAccels Ctrl Shift F3: Hlp3(44:Hello$)        ; a MsgBox
  SetAccels Ctrl F1, Ctrl Shift T
  SetAccels Alt F1
  SetAccels Shift F1
  SetAccels a, Shift B, c, D    ; lowercase a, c, d work, B needs a shift
  SetAccels Ctrl O: CtrlOpen
  SetAccels Ctrl VK_SPACE: MyConSpace
  SetAccels Ctrl Z: NoUndo
  SetAccels x: LowercaseX, Shift X: UppercaseX

F1:123 means "let F1 trigger an Event Accel"
F1:someproc means "jump to someproc" - with no, one, or two arguments.

Full code attached. Please report if anything is unexpected :cool:

Archer-Dante

Hello again

I'm trying to compile simpliest code

include C:\masm32\MasmBasic\masmbasic.inc
includelib "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt\x86\ucrt.lib"
includelib C:\masm32\MasmBasic\MasmBasic.lib

.data

.code


DllEntryPoint proc

call DLLStartup
ret

DllEntryPoint endp



DLLStartup proc
 MsgBox 0, Str$(eax), "-1 is less than 99:", MB_OK
 ret

DLLStartup endp


End DllEntryPoint

output:

1234.asm(30) : error A2006: undefined symbol : dw2aTable
 Str$(20): Macro Called From
  MsgBox(0): Macro Called From
   1234.asm(30): Main Line Code

by trying I found that it's caused by Str$(eax)
If i replace it with regular string everything works fine
How can i fix this?  :undecided:

jj2007

Quote from: Archer-Dante on May 13, 2024, 11:12:49 PMerror A2006: undefined symbol : dw2aTable

This symbol gets normally defined by the Init macro. It seems you are not using Init (maybe it's not possible in a DLL, I have to check that).

You can "heal" the problem with ExternDef dw2aTable:DWORD right after the include line.

P.S.: include C:\masm32\MasmBasic\masmbasic.inc will not assemble on a machine where Masm32 is installed on drive D:
It is better to use include \masm32\MasmBasic\masmbasic.inc instead.