Author Topic: Some questions  (Read 20390 times)

Offline avcaballero

  • Full Member
  • **
  • Posts: 132
  • Country: es
    • Abre los Ojos al Ensamblador
Some questions
« on: February 22, 2015, 03:45:16 PM »
Hello. I'm updating my win32 tuto. It has full samples on masm and fasm and I wanted to upgrading it to nasmx. It was at 90% when I realized that I was making it with v1.2 :( Never mind, let's go for v1.4.

The present message is due to that I have found an error, probably loading a dll, that doesn't allow me to progress in the SQLite example.

mainWN02.asm.
This program reads some functions from dllWN01.dll. It worked ok in v1.2, but don't in v1.4 (I have attached both, same code). In fact, I think that the subroutines in the dll works akay, and, for demonstrate that, I have incorporated a messagebox showing the calculated value in ASCIIZ. The v12 mainWN02.v12.exe works fine as you can see.


bmpWN02b.asm
I think there's something strange in BITMAPINFOHEADER structure?, because I had to change manually several things to making the program work (in v1.2 it worked fine without those changes). This is a bmp reasizable viewer program loaded into memory (just for 1 bmp file, I will upgrade it when I have time). I have used a tricky to get the addr of a local variable (is there anything available already for it?):
Code: [Select]
    mov       eax, ebp
    sub       eax, .dwBytesRead    ; Truqui para el ADDR de dwBytesRead

There are some other problems/issues that I have encountered in v1.2. that I will check for v1.4:

* The buttons2 example doesn't change the boxing globe cursor when the cursor get off from the politician button. I cannot use UDC_HyperLink in my rc file if I want the DialogBoxParam that calls this dialog box work. Everything else is working ok: double image buttons, etc.

* The SQLite example doesn't read properly the units food. I believe that some problem in local variables gestion, I will check in v1.4 that I think has changed that.

* Is it possible to define local structure variables?

* Is it possible to define a local variable similar to that?
Code: [Select]
  locals
    local  myVar[40], dword
  endlocals

* Is it possible to do something like this?
Code: [Select]
   if eax, <=, 30, &&, eax, >= 5, [and so on]
     [...]

* Is it possible to make my own subroutines?
Code: [Select]
  myProc:
    push   ebp
    mov    ebp, esp
    sub    esp, 4*5   ; Space for 5 dwords
    [...]
    mov    esp, ebp
    pop    ebp
I have used it, but I think that, at least, in v12 it is not possible to execute an "invoke" command inside, even if I push and call manually.

I keep on working on that but I go a bit slow because I just have a bit of time at weekends, so if anyone want to help...  :)would be welcome.

Regards.
« Last Edit: February 22, 2015, 03:47:00 PM by avcaballero »

Offline avcaballero

  • Full Member
  • **
  • Posts: 132
  • Country: es
    • Abre los Ojos al Ensamblador
Re: Some questions
« Reply #1 on: February 22, 2015, 05:49:34 PM »
Hello, I think that I already know where is the problem in the mainWN02.asm

Code: [Select]
    mov      esp, ebp     ; ** This is not in the resulting code **
  endproc

Regards

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Some questions
« Reply #2 on: February 23, 2015, 04:20:05 PM »
Hey, Alfonso!

I'll answer some of the simpler questions first and get back to you later regarding your source code once I get some free time and played around with it a bit.

Hello. I'm updating my win32 tuto. It has full samples on masm and fasm and I wanted to upgrading it to nasmx. It was at 90% when I realized that I was making it with v1.2 :( Never mind, let's go for v1.4.

Thank you for doing this.  Your tutorials are excellent and the Spanish translations are very beneficial.  And yes, please use v1.4 for all your examples.

I think there's something strange in BITMAPINFOHEADER structure?, because I had to change manually several things to making the program work (in v1.2 it worked fine without those changes).

The big change with 1.4 was a correction of structure alignment and size which was not 100% correct in previous versions.  Specifically, now the answer to these questions:

* Is it possible to define local structure variables?

* Is it possible to define a local variable similar to that?
Code: [Select]
  locals
    local  myVar[40], dword      ; <-- CHANGE TO THIS:   local myVar, dword, 40
                                             ;             USE SAME TECHNIQUE FOR STRUCTS
  endlocals

is yes - we officially and correctly support local and global arrays of data sets ( including structures ). 

I have used a tricky to get the addr of a local variable (is there anything available already for it?):
Code: [Select]
    mov       eax, ebp
    sub       eax, .dwBytesRead    ; Truqui para el ADDR de dwBytesRead

That is exactly how to do it.  The reason you need to dot prepended to the name has to do with both scoping and name mangling which occurs when complying with the calling convention in use.  Internally, all local variables you create are labelled as YOUR_FUNC_NAME.YOUR_LOCAL_VAR_NAME which subsequently allows you to re-use the same variable name in multiple functions within the same source file just like C - something not possible when using regular labels.  It is also the reason why you should not define a label within a PROC without a dot prepended to it.  Otherwise, you may encounter issues later on in your code when you attempt to get a local var.  In a nutshell - use the dot!

See this page for further info: http://www.nasm.us/xdoc/2.11.08/html/nasmdoc3.html#section-3.9

* Is it possible to do something like this?
Code: [Select]
   if eax, <=, 30, &&, eax, >= 5, [and so on]
     [...]

Unfortunately, the answer is no.  Although our macro set is quite powerful in allowing you to make use of constructs such as IF, WHILE, REPEAT, CONTINUE, BREAK, etc, we haven't implemented multiple-expression control statements.  It is a good suggestion and perhaps may appear in a future release as I can see value in that.

* Is it possible to make my own subroutines?
Code: [Select]
  myProc:
    push   ebp
    mov    ebp, esp
    sub    esp, 4*5   ; Space for 5 dwords
    [...]
    mov    esp, ebp
    pop    ebp
I have used it, but I think that, at least, in v12 it is not possible to execute an "invoke" command inside, even if I push and call manually.

You can have Nasm procedures and NASMX procedures within the same source file but you can't use most NASMX macros outside of a NASMX PROC/ENDPROC pair.  The reason has to do with calling conventions, stack, alignment, and how we use Nasm to set it all up for you.

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Some questions
« Reply #3 on: February 24, 2015, 06:04:34 PM »
OK.  Found your problem in mainWN02.asm:
Code: [Select]
            push      dword [vdSuma2]
            push      dword [vdSuma1]
            call      dword [ptrFuncName]

as well as:

Code: [Select]
            push      szContent
            push      ptrdiff_t [argv(.hwnd)]
            call      dword [ptrProcName]

are both missing "add esp, 8" after the call!

Remember that if you are calling the functions directly ( eg: not using NASMX invoke macro ) you are also responsible for stack management.  I'm sure that one probably just slipped your mind.

And no, you don't need to add the line "mov  esp, ebp" in your source code prior to ENDPROC.  I've verified that this is correctly handled by NASMX.

The program now works fine for me after this fix.


« Last Edit: February 24, 2015, 06:10:33 PM by Rob Neff »

Offline avcaballero

  • Full Member
  • **
  • Posts: 132
  • Country: es
    • Abre los Ojos al Ensamblador
Re: Some questions
« Reply #4 on: February 25, 2015, 10:06:37 AM »
Ok, you are right, I was wrong because in v1.2 semeed not be necessary to recover the stack after the call, just checking for the code to work and missed recover the stack ???. There is no need to recover esp before "endproc" because there are no local variables.

Regarding bmpWN02, according to the unassembly from OllyDbg, there are some differences between the code compiled with v1.2 and v1.4 for GetBMPSize:

Code: [Select]
CPU Disasm
Address   Hex dump          Command                                  Comments
004010EE  /$  55            PUSH EBP
004010EF  |.  89E5          MOV EBP,ESP
004010F1  |.  895D FC       MOV DWORD PTR SS:[LOCAL.1],EBX
004010F4  |.  8975 F8       MOV DWORD PTR SS:[LOCAL.2],ESI
004010F7  |.  83EC 08       SUB ESP,8
004010FA  |.  8B1D 34214000 MOV EBX,DWORD PTR DS:[402134]
00401100  |.  B8 0E000000   MOV EAX,0E                         [b]; Look at this for example, in v1.4 is 10[/b]
00401105  |.  01D8          ADD EAX,EBX
00401107  |.  A3 38214000   MOV DWORD PTR DS:[402138],EAX
0040110C  |.  89C6          MOV ESI,EAX
0040110E  |.  8B43 0A       MOV EAX,DWORD PTR DS:[EBX+0A]
00401111  |.  01D8          ADD EAX,EBX
00401113  |.  A3 3C214000   MOV DWORD PTR DS:[40213C],EAX
00401118  |.  31C0          XOR EAX,EAX
0040111A  |.  31DB          XOR EBX,EBX
0040111C  |.  833E 0C       CMP DWORD PTR DS:[ESI],0C
0040111F  |.  75 0A         JNE SHORT 0040112B
00401121  |.  66:8B46 04    MOV AX,WORD PTR DS:[ESI+4]
00401125  |.  66:8B5E 06    MOV BX,WORD PTR DS:[ESI+6]
00401129  |.  EB 0D         JMP SHORT 00401138
0040112B  |>  8B46 04       MOV EAX,DWORD PTR DS:[ESI+4]
0040112E  |.  8B5E 08       MOV EBX,DWORD PTR DS:[ESI+8]
00401131  |.  83FB 01       CMP EBX,1
00401134  |.  7F 02         JG SHORT 00401138
00401136  |.  F7DB          NEG EBX
00401138  |>  A3 48214000   MOV DWORD PTR DS:[402148],EAX
0040113D  |.  891D 4C214000 MOV DWORD PTR DS:[40214C],EBX
00401143  |.  83C4 08       ADD ESP,8
00401146  |.  5E            POP ESI
00401147  |.  5B            POP EBX
00401148  |.  89EC          MOV ESP,EBP
0040114A  |.  5D            POP EBP
0040114B  \.  C3            RETN

Code: [Select]
CPU Disasm
Address   Hex dump          Command                                  Comments
004010EA  /$  55            PUSH EBP
004010EB  |.  53            PUSH EBX
004010EC  |.  56            PUSH ESI
004010ED  |.  8B1D 34214000 MOV EBX,DWORD PTR DS:[402134]
004010F3  |.  B8 10000000   MOV EAX,10                         [b]; Look at this for example, in v1.2 is 0E[/b]
004010F8  |.  01D8          ADD EAX,EBX
004010FA  |.  A3 38214000   MOV DWORD PTR DS:[402138],EAX
004010FF  |.  89C6          MOV ESI,EAX
00401101  |.  8B43 0C       MOV EAX,DWORD PTR DS:[EBX+0C]
00401104  |.  01D8          ADD EAX,EBX
00401106  |.  A3 3C214000   MOV DWORD PTR DS:[40213C],EAX
0040110B  |.  31C0          XOR EAX,EAX
0040110D  |.  31DB          XOR EBX,EBX
0040110F  |.  833E 0C       CMP DWORD PTR DS:[ESI],0C
00401112  |.  75 0A         JNE SHORT 0040111E
00401114  |.  66:8B46 04    MOV AX,WORD PTR DS:[ESI+4]
00401118  |.  66:8B5E 06    MOV BX,WORD PTR DS:[ESI+6]
0040111C  |.  EB 0D         JMP SHORT 0040112B
0040111E  |>  8B46 04       MOV EAX,DWORD PTR DS:[ESI+4]
00401121  |.  8B5E 08       MOV EBX,DWORD PTR DS:[ESI+8]
00401124  |.  83FB 01       CMP EBX,1
00401127  |.  7F 02         JG SHORT 0040112B
00401129  |.  F7DB          NEG EBX
0040112B  |>  A3 48214000   MOV DWORD PTR DS:[402148],EAX
00401130  |.  891D 4C214000 MOV DWORD PTR DS:[40214C],EBX
00401136  |.  5E            POP ESI
00401137  |.  5B            POP EBX
00401138  |.  5D            POP EBP
00401139  \.  C3            RETN

Thank you for your time, Rob. It seems to be scarced for all of us :)

The source code for bmpWN02, same for v1.2 and v1.4. I wanted to attach a zip file, but it seems that it is not possible on a sended post.
Code: [Select]
; ----------------------------------------------------------------------------
; -       TITULO  : Ejemplo de load-bmp en ventana W-NASMX v1.4              -
; -----                                                                  -----
; -       AUTOR   : Alfonso Víctor Caballero Hurtado                         -
; -----                                                                  -----
; -       VERSION : 1.0                                                      -
; -----                                                                  -----
; -      (c) 2015. Abre los Ojos al Ensamblador                              -
; ----------------------------------------------------------------------------

%include '..\..\windemos.inc'

cdXPos                EQU  128
cdYPos                EQU  128
cdXSize               EQU  320
cdYSize               EQU  200
cdColFondo            EQU  COLOR_BTNFACE + 1
cdVIcono              EQU  IDI_APPLICATION
cdVCursor             EQU  IDC_ARROW
cdVBarTipo            EQU  NULL
cdVBtnTipo            EQU  WS_VISIBLE+WS_OVERLAPPEDWINDOW    ; Botones de minimizar, maximizar y cerrar
DIB_RGB_COLORS        equ  0

entry Entrada

[section .bss]
  hInstance:    reserve(ptrdiff_t) 1
  CommandLine:  reserve(ptrdiff_t) 1
  hWnd:         reserve(ptrdiff_t) 1
  hdc:          reserve(ptrdiff_t) 1
  hBitmap:      reserve(ptrdiff_t) 1
  hMemDC:       reserve(ptrdiff_t) 1
  hMemory:      reserve(ptrdiff_t) 1
  pBMPbuf:      reserve(ptrdiff_t) 1
  pBMPi:        reserve(ptrdiff_t) 1
  pBMPBits:     reserve(ptrdiff_t) 1
  vdXCliente:   reserve(ptrdiff_t) 1
  vdYCliente:   reserve(ptrdiff_t) 1
  vdXBMP:       reserve(ptrdiff_t) 1
  vdYBMP:       reserve(ptrdiff_t) 1
  vbRedimens:   reserve(ptrdiff_t) 1
  ; dwHighSize:   reserve(ptrdiff_t) 1
  ; dwBytesRead:  reserve(ptrdiff_t) 1
               
[section .data]
  NombreClase:    declare(NASMX_TCHAR) NASMX_TEXT("SimpleWinClass"), 0
  MsgCabecera:    declare(NASMX_TCHAR) NASMX_TEXT("Ejemplo de load-bmp en ventana (NasmX)"), 0
  MsgError:       declare(NASMX_TCHAR) NASMX_TEXT("Carga inicial fallida."),0
  Cantload:       declare(NASMX_TCHAR) NASMX_TEXT("No se puede cargar el BMP-fichero"),0
  vsBMPFilePath:  declare(NASMX_TCHAR) NASMX_TEXT("Ejemplo.bmp"),0

    NASMX_ISTRUC rect, RECT
    NASMX_IENDSTRUC

    NASMX_ISTRUC ps, PAINTSTRUCT
    NASMX_IENDSTRUC

    NASMX_ISTRUC wc, WNDCLASSEX
        NASMX_AT cbSize,           WNDCLASSEX_size
        NASMX_AT style,            CS_VREDRAW + CS_HREDRAW
        NASMX_AT lpfnWndProc,      NULL
        NASMX_AT cbClsExtra,       NULL
        NASMX_AT cbWndExtra,       NULL
        NASMX_AT hInstance,        NULL
        NASMX_AT hIcon,            NULL
        NASMX_AT hCursor,          NULL
        NASMX_AT hbrBackground,    COLOR_BTNFACE + 1
        NASMX_AT lpszMenuName,     NULL
        NASMX_AT lpszClassName,    NULL
        NASMX_AT hIconSm,          NULL
    NASMX_IENDSTRUC

  NASMX_ISTRUC message, MSG
      NASMX_AT hwnd,     NULL
      NASMX_AT message,  NULL
      NASMX_AT wParam,   NULL
      NASMX_AT lParam,   NULL
      NASMX_AT time,     NULL
      NASMX_ISTRUC pt, POINT
          NASMX_AT x,       NULL
          NASMX_AT y,       NULL
      NASMX_IENDSTRUC
  NASMX_IENDSTRUC


[section .text]

  proc LoadBMP2Mem, dword pstrFileName
    ;  Propósito: Cargamos un BMP en memoria dinámica
    ;  Entrada  : pstrFileName: la ruta del BMP-fichero a cargar
    ;  Salida   : EAX: El puntero al bmp cargado en memoria
    ;  Destruye : Ninguna
    uses ebx
    locals
      local     bSuccess,dword          ; Local2= ebp-4*2
      local     dwFileSize,dword        ; Local3= ebp-4*3
      local     dwHighSize,dword
      local     dwBytesRead,dword
      local     hFile,dword             ; Local4= ebp-4*4
      local     lpBMPbuf,dword          ; Local5= ebp-4*5
    endlocals
    invoke    CreateFileA, dword [argv(.pstrFileName)], GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0       ; Abrimos fichero para lectura
    mov       dword [var(.hFile)], EAX                      ; Guardamos el file-handle
    cmp       EAX, INVALID_HANDLE_VALUE                     ; Comprobamos si ha ido bien
    je        .LBM_Fin_Error
    mov       eax, ebp
    sub       eax, .dwHighSize                              ; Truqui para el ADDR de dwHighSize
    invoke    GetFileSize, dword [var(.hFile)], eax         ; Obtenemos el tamaño del BMP-fichero
    mov       dword [var(.dwFileSize)], eax                 ; y lo guardamos
    or        dword [var(.dwHighSize)], 0                   ; Comprobamos si hubo éxito, dwHighSize no NULL
    jz      .Next1
        invoke    CloseHandle, dword [var(.hFile)]
        jmp       .LBM_Fin_Error
    .Next1:
    invoke    GlobalAlloc,GMEM_MOVEABLE + GMEM_ZEROINIT, dword [var(.dwFileSize)]   ; Reservamos memoria para dwFileSize
    mov       dword [hMemory], EAX                          ; Guardamos la memoria-handle
    invoke    GlobalLock, dword [hMemory]                   ; Bloquea la memoria reservada
    mov       dword [var(.lpBMPbuf)], EAX                   ; Y devuelve un puntero al primer byte: BITMAPFILEHEADER
    mov       EBX, EAX                                      ; Lo guardamos también en EBX
    or        dword [var(.lpBMPbuf)], 0                     ; Si falló
    jne       .Next2
        invoke    CloseHandle, dword [var(.hFile)]          ; cerramos el bmp-fichero y salimos
        jmp       .LBM_Fin_Error
    .Next2:
    mov       eax, ebp
    sub       eax, .dwBytesRead                             ; Truqui para el ADDR de dwBytesRead
    invoke    ReadFile, dword [var(.hFile)], dword [var(.lpBMPbuf)], dword [var(.dwFileSize)], eax, 0
    ; hFile:Handle del fichero a leer, lpBMPbuf:Dirección del búfer que recibirá los datos,
    ; dwFileSize:número de bytes a leer, dwBytesRead:número de bytes leídos, 0:lpOverlapped
    mov       dword [var(.bSuccess)], EAX                   ; Si hubo éxito devuelve un valor noCero
    invoke    CloseHandle, dword [var(.hFile)]              ; Cerramos el bmp-fichero
    mov       EAX, dword [var(.dwBytesRead)]                ; Los bytes efectivamente leídos
    mov       CX, word [BITMAPFILEHEADER.bfType+ebx]        ; Obtenemos el tipo de fichero de la cabecera: (2bytes) BM
    xchg      cl, ch                                        ; ¿Es necesario?
    mov       EDX, dword [BITMAPFILEHEADER.bfSize+EBX]            ; Tamaño en bytes del bmp
    ; Comprobamos que es un fichero correcto
    or        dword [var(.bSuccess)], 0
    je        .Next3
    cmp       eax, dword [var(.dwFileSize)]
    jne       .Next3
    cmp       cx, "MB"
    jne       .Next3
    cmp       edx, dword [var(.dwFileSize)]
    jne       .Next3
    jmp       .Next4
    .Next3:
        invoke    GlobalUnlock, dword [var(.lpBMPbuf)]       ; Desbloqueamos la memoria reservada
        invoke    GlobalFree, dword [hMemory]                ; y la liberamos
    .Next4:
    mov       eax, dword [var(.lpBMPbuf)]
    jmp       .LBM_Fin
    .LBM_Fin_Error:
    mov       eax, 0
    .LBM_Fin:
  endproc
 
  proc GetBMPSize
      ;  Propósito: Obtiene el tamaño del bmp así como los punteros
      ;  Entrada  : pBMPbuf: puntero al bmp-búfer
      ;  Salida   : pBMPi: puntero a la bmp-información, pBMPBits: puntero al vigente BMP pixel bits
      ;             vdXBMP: anchura del bmp, vdYBMP: altura del BMP
      ;  Destruye : EAX
      uses      ebx, esi
      locals    none
      ; Obtiene los punteros a la estructura de información Get pointers to the info structure & the bits
      MOV       EBX, dword [pBMPbuf]             ; Guardamos en EBX el puntero a la cabecera del bmp en el búfer
      MOV       EAX, BITMAPFILEHEADER_size       ; Si sumamos el tamaño de la cabecera
      ADD       EAX, EBX                         ; con la dirección de ésta,
      MOV       dword [pBMPi], EAX               ; Obtenemos el puntero a la bmp-información
      MOV       ESI, EAX                         ; Lo guardamos en ESI también
      MOV       EAX, [EBX+BITMAPFILEHEADER.bfOffBits]; Recogemos de la cabecera la dirección de los bits
      ADD       EAX, EBX                         ; Sumándole la dirección de la cabecera
      MOV       dword [pBMPBits], EAX            ; Obtenemos un puntero al vigente BMP pixel bits
      XOR       EAX, EAX                         ; Lo inicializamos primero
      XOR       EBX, EBX                         ; para asegurarnos de borrar la parte superior
      ; Obtenemos la anchura y altura del BMP
      CMP      dword [ESI+BITMAPINFOHEADER.biSize], BITMAPCOREHEADER_size    ; Ancho y alto son WORDs
      JNE      .L_SBMPS_Sino
          MOV       AX, word [ESI+BITMAPCOREHEADER.bcWidth]       ; Anchura del BMP
          MOV       BX, word [ESI+BITMAPCOREHEADER.bcHeight]      ; Altura del BMP
          JMP       .L_SBMPS_Exit
      .L_SBMPS_Sino:                                          ; Ancho y alto son DWORDs
          MOV       EAX, dword [ESI+BITMAPINFOHEADER.biWidth]      ; Anchura del BMP
          MOV       EBX, dword [ESI+BITMAPINFOHEADER.biHeight]     ; Altura del BMP
          CMP       EBX, 1
          JG        .L_SBMPS_Exit
              NEG       EBX                                  ; Obtenemos el valor absoluto
      .L_SBMPS_Exit:                                          ; Ancho y alto son DWORDs
      MOV       dword [vdXBMP], EAX
      MOV       dword [vdYBMP], EBX
  endproc

  proc   WndProc, ptrdiff_t hwnd, dword uMsg, size_t wParam, size_t lParam
    ;  Propósito: Procesa los mensajes provenientes de las ventanas
    ;  Entrada  : hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    ;  Salida   : Ninguna
    ;  Destruye : Ninguna
    locals none
    mov       eax, ptrdiff_t [argv(.uMsg)]
    cmp       eax, WM_PAINT
    jz        .wmPaint
    cmp       eax, WM_CREATE
    jz        .wmCreate
    cmp       eax, WM_SIZE
    jz        .wmSize
    cmp       eax, WM_DESTROY
    jz        .wmDestroy

    .wmDefault:
        invoke   DefWindowProcA, ptrdiff_t [argv(.hwnd)], ptrdiff_t [argv(.uMsg)], ptrdiff_t [argv(.wParam)], ptrdiff_t [argv(.lParam)]
        jmp      .wmFin
    .wmSize:
        ; Recogemos en las variables la anchura y altura de la ventana
        mov      byte [vbRedimens], 1       ; avch: este flag tampoco es necesario en MASM
        MOV      EAX, ptrdiff_t [argv(.lParam)]
        AND      EAX, 0FFFFh        ; Nos quedamos con el word bajo
        MOV      [vdXCliente], EAX
        MOV      EAX, ptrdiff_t [argv(.lParam)]
        SHR      EAX, 16            ; Nos quedamos con el word alto: 2^16=10000h
        MOV      [vdYCliente], EAX
        jmp      .wmPaint
        ; avch. Atención, ESTO ES IMPORTANTE. Ha sido necesario redireccionar a "wm_paint" porque cuando se
        ; redimensiona la ventana cliente a mayor, se produce un suceso "wm_paint", pero cuando se redimensionaba
        ; a menor, no. Por lo tanto se escalaba el bmp sólo cuando se agrandaba, no cuando se achicaba.
        ; Sin embargo, en MASM esto no era necesario ???
        jmp      .wmFin
    .wmCreate:
        invoke   LoadBMP2Mem, vsBMPFilePath      ; Carga en memoria el fichero bmp
        mov      dword [pBMPbuf], eax            ; Devuelve el puntero en memoria para el bitmapbuffer
        or       dword [pBMPbuf], 0              ; Si no se pudo cargar en memoria
        jnz      .Next2
            invoke   MessageBox, ptrdiff_t [argv(.hwnd)], Cantload, MsgCabecera, 0
            mov      EAX, MB_ICONEXCLAMATION + MB_OK
            jmp      .wmFin
        .Next2:
        ; invoke   InvalidateRect, [hwnd], NULL, TRUE   ;Invalidate client area for later update
        call     GetBMPSize         ; Obtiene el tamaño del bmp y los punteros pBMPBits y pBMPi
        jmp      .wmFin
    .wmPaint:
        invoke   BeginPaint,ptrdiff_t [argv(.hwnd)],ps
        mov      dword [hdc],eax
        or       dword [pBMPbuf], 0
        jz       .Next3
            invoke    SetStretchBltMode, [hdc], COLORONCOLOR
            invoke    StretchDIBits, [hdc], 0,0, [vdXCliente], [vdYCliente], 0,0,[vdXBMP],[vdYBMP], \
                                 [pBMPBits], [pBMPi], DIB_RGB_COLORS, SRCCOPY
            or        byte [vbRedimens], 0                   ; avch: Ninguna de estas líneas para invalidateRect son necesarias en MASM
            jz        .Next3
              invoke    InvalidateRect, ptrdiff_t [argv(.hwnd)], NULL, TRUE   ; Invalidate client area for later update
              mov       byte [vbRedimens], 0
        .Next3:
        invoke   EndPaint,ptrdiff_t [argv(.hwnd)],ps
        jmp      .wmFin
    .wmDestroy:
        cmp      dword [pBMPbuf], 0
        jz       .Next1
            invoke    GlobalUnlock, [pBMPbuf]          ; Desbloquea la memoria asignada
            invoke    GlobalFree, [hMemory]            ; Libera la memoria asignada
        .Next1:
        invoke   PostQuitMessage,0
    .wmFin:
  endproc
 
  proc   WinMain, ptrdiff_t hinst, ptrdiff_t hpinst, ptrdiff_t cmdln, dword dwshow
    locals none

    invoke LoadIcon, NULL, IDI_APPLICATION
    mov    __CX, wc
    mov    ptrdiff_t [__CX + WNDCLASSEX.hIcon], __AX
    mov    ptrdiff_t [__CX + WNDCLASSEX.hIconSm], __AX
    mov    ptrdiff_t [__CX + WNDCLASSEX.lpfnWndProc], WndProc
    mov    ptrdiff_t [__CX + WNDCLASSEX.lpszClassName], NombreClase
    mov    __AX, ptrdiff_t [argv(.hinst)]
    mov    ptrdiff_t [__CX + WNDCLASSEX.hInstance], __AX

    invoke RegisterClassEx, __CX
    invoke CreateWindowEx, cdVBarTipo, NombreClase, MsgCabecera, \
                cdVBtnTipo,\
                cdXPos, cdYPos, cdXSize, cdYSize, NULL, NULL, \
                ptrdiff_t [wc + WNDCLASSEX.hInstance], NULL
    mov    ptrdiff_t [hWnd], __AX
    invoke ShowWindow, hWnd, dword [argv(.dwshow)]
    invoke UpdateWindow, hWnd

    .msgloop:
        invoke GetMessage, message, NULL, NULL, NULL
        cmp    eax, dword 0
        je     .exit
        invoke TranslateMessage, message
        invoke DispatchMessage, message
    jmp    .msgloop

    .exit:
    mov    eax, dword [message + MSG.wParam]
  endproc

  proc    Entrada, ptrdiff_t argcount, ptrdiff_t cmdline
      locals none
      invoke GetModuleHandle, NULL
      mov    ptrdiff_t [hInstance], __AX
      invoke WinMain, hInstance, NULL, NULL, SW_SHOWNORMAL
      invoke ExitProcess, NULL
  endproc
« Last Edit: February 25, 2015, 10:36:42 AM by avcaballero »

Offline avcaballero

  • Full Member
  • **
  • Posts: 132
  • Country: es
    • Abre los Ojos al Ensamblador
Re: Some questions
« Reply #5 on: February 25, 2015, 10:21:28 AM »
Only 2000 chars allowed , attach zip

* bmpWN02.asm. This is the same and "correct" code for v1.2 and v1.4. I have included the v1.2 exe file and v1.4. I include the unassembly source from OllyDbg for both. You can see, for example, that in v1.2 is "MOV EAX, 0E" and in v1.4 is "MOV EAX, 10".

* bmpWN02b.asm. With this code v1.4 works fine. You can compare with the previous one with a comparer text tool.

Sorry for inconveniences and thanks for the time

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Some questions
« Reply #6 on: February 25, 2015, 03:19:56 PM »
* bmpWN02.asm. This is the same and "correct" code for v1.2 and v1.4. I have included the v1.2 exe file and v1.4. I include the unassembly source from OllyDbg for both. You can see, for example, that in v1.2 is "MOV EAX, 0E" and in v1.4 is "MOV EAX, 10".

The problem is that in your personal windemos.inc file you probably have the definition of BITMAPFILEHEADER without alignment packing instructions.  If you look in /nasmx/inc/win32/windows.inc you will see the following:

Code: [Select]
NASMX_PRAGMA PACK, PUSH, 2
NASMX_STRUC BITMAPFILEHEADER
    NASMX_RESERVE bfType,      short_t, 1
    NASMX_RESERVE bfSize,      int32_t, 1
    NASMX_RESERVE bfReserved1, short_t, 1
    NASMX_RESERVE bfReserved2, short_t, 1
    NASMX_RESERVE bfOffBits,   int32_t, 1
NASMX_ENDSTRUC
NASMX_PRAGMA PACK, POP

By default, without the pragma PACK, PUSH, 2 option, NASMX will align structure variables and size the structure according to the rules of natural alignment.  The alignment for that structure would be 4 (DWORD) which would make the bfSize member at offset 4 thus increasing the size of the structure from 0x0E to 0x10.

However, for this specific structure Microsoft forces WORD alignment thus we have to comply with that.  Subsequently, in NASMX, we enclose that structure with PACK 2 to do the same.  The WORD alignment now puts bfSize at offset 2 and the size of the structure is now 0x0E.  You'll simply need to update your own windemos.inc file similarly.

Had you used windows.inc you'd not have experienced this.  That's the trade-off of rolling your own include file: speed of assembly time vs. compatibility.  Trust me when I say I know the pain of pulling in all those headers and use a custom version myself.  Having pre-compiled headers sure would make things much better.




Offline avcaballero

  • Full Member
  • **
  • Posts: 132
  • Country: es
    • Abre los Ojos al Ensamblador
Re: Some questions
« Reply #7 on: February 25, 2015, 03:35:32 PM »
Yes, you were right once again, now it works. Thank you for your time, Rob. Remind me that I owe you a beer  ;D.

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Some questions
« Reply #8 on: February 25, 2015, 04:04:21 PM »
And I will say thank you for your efforts as well.  I'd love to get together and share a few beers with you one day!  :)

Offline avcaballero

  • Full Member
  • **
  • Posts: 132
  • Country: es
    • Abre los Ojos al Ensamblador
Re: Some questions
« Reply #9 on: February 25, 2015, 05:56:53 PM »
That's would be a pleasure. Don't believe that I'll be in the USA, but if you were in Spain sometime, it would be very nice to lower the foam a few beers with you. In fact, it would be nice to make an encounter of asm programmers... sometime... somewhere  8).

By the way, if you are interested, I attach a review of demo17 in a better code. The dib section is created in the "create" section, in such a way that in the Paint section you just need to calculate the floor data and bitblt it to the memory.

Regards

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Some questions
« Reply #10 on: February 26, 2015, 12:48:54 AM »
Now THAT is some beautiful Win32 NASMX assembly code right there.  Neat, clean, and easy to understand.  Good refactoring too.   8)

« Last Edit: February 26, 2015, 12:55:24 AM by Rob Neff »

Offline avcaballero

  • Full Member
  • **
  • Posts: 132
  • Country: es
    • Abre los Ojos al Ensamblador
Re: Some questions
« Reply #11 on: February 28, 2015, 07:23:20 PM »
Hello, again.

Programs are working now. In the case of SQLite example I had to apply some trickies to get it working: I had to remove local variables in a subroutine and use global ones. And a few others. Never mind, it works. Let's say that you have a few friends and want to invite them to watch a football match and want to know how much will waste according the prize and units to consum for each of them saved in a SQLite DB. (program attached)

As for the loading dll example.
Quote
Remember that if you are calling the functions directly ( eg: not using NASMX invoke macro ) you are also responsible for stack management
It depends on the call convention:
- C. You have to balance the stack after the call.
- Pascal/stdcall. The subroutine called is in charge of balancing the stack before leaving. And we are in stdcall convention, are we? That's why I didn't balanced the stack after the call.

Seing at the dll code:
Code: [Select]
proto  cdecl, addLongs, dword uno, dword dos
proto  cdecl, MuestraMensaje, ptrdiff_t hWnd, dword content

I wondered what was such "cdecl" :), now I know: the declaration of call convention c-alike. So, looking at the dll dissasembly code there is no "RET 8", but just "RET". Dsssshh. Nearly.

Well, that's all for me. Thank you and up to another.