News:

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

STRUCT help please

Started by gavin, November 01, 2005, 11:49:55 PM

Previous topic - Next topic

gavin

Hi guys i'm having problems getting SendInput working.

I don't quite understand how to make this struct.



INPUT struct
      INPUT_KEYBOARD DW 1     
union         
wVk DD 41h
wScan DD 0
dwFlags DW 0
time DW 0
dwExtraInfo DW 0
      ends
INPUT ends     



When using my debugger i get error_invalid_parameter.
As you can see I am lost .
Btw I have to use sendinput ;)

Any help on this would be great.

Thanks.
Gavin

shuttlebug

Since your declaring initialized data in your structure,did you make sure it is in the data section of your code? If its declared anywhere else then the compiler expects uninitialized data.

.data

MyStruct struct
     nNumber  dw   5
union
    Member1   dd    0
    Member2   dd    1
ends
ends MyStruct

or anywhere else

.data?

MyStruct struct
   nNumber   dw  ?
union
  Member1   dd  ?
  Member2   dd  ?
ends
ends MyStruct

gavin

Hi.

I declared it in the .data section allright.
It assembles fine ,but obviously I'm doing something wrong .
Is my structure done correctly is the first thing?



typedef struct tagINPUT {
  DWORD type;
  union {MOUSEINPUT mi;
            KEYBDINPUT ki;
            HARDWAREINPUT hi;
           };
  }INPUT, *PINPUT;




typedef struct tagKEYBDINPUT {
    WORD wVk;
    WORD wScan;
    DWORD dwFlags;
    DWORD time;
    ULONG_PTR dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT;



My structure

INPUT struct
      INPUT_KEYBOARD DW 1     
union         
wVk DD 41h
wScan DD 0
dwFlags DW 0
time DW 0
dwExtraInfo DW 0
      ends
INPUT ends 


Thanks.

Jimg

It looks like the first entry should be a double and you declared it as a word.  You also need to convert each of the items in the union to a masm structure-

INPUTRECORD struct
   type dd ?
   union
     mi MOUSEINPUT <>
     ki  KEYBDINPUT <>
     hi  HARDWAREINPUT <>
   ends
INPUTRECORD ends

where MOUSEINPUT=
typedef struct tagMOUSEINPUT {
    LONG dx;
    LONG dy;
    DWORD mouseData;
    DWORD dwFlags;
    DWORD time;
    ULONG_PTR dwExtraInfo;
}

KEYBOARDINPUT=
typedef struct tagKEYBDINPUT {
    WORD wVk;
    WORD wScan;
    DWORD dwFlags;
    DWORD time;
    ULONG_PTR dwExtraInfo;
}

HARDWAREINPUT =
typedef struct tagHARDWAREINPUT {
    DWORD uMsg;
    WORD wParamL;
    WORD wParamH;
}

These last three also need to be translated to masm.


gavin

Hi Jimg.



    INPUT struct
       dtype WORD 1             
       union
          wVk          WORD  ?
          wScan        WORD  ?
          dwFlags      DWORD ?
          time         DWORD ?
          dwExtraInfo  DWORD ?
       ends
    INPUT ends 


I don't quite understand what your saying.
I read about unions and structs but so far thisis the best i can do without more help.
So all i do is code this in the .data section and then i can use it from sendinput right?


Thanks for your help so far.

hutch--

Gavin,

Do you have a reference version of the structure in C ? It would make it a lot easier to convert if we knew what it was supposed to do.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Jimg

Not quite.  First word is a dword.  And in this case, since you are only doing the keyboard, you wouldn't use union.  If you were going to define the mouse and hardware inputs you would use union so they would all be in the same memory location.

    INPUT struct
       dtype DWORD ?
          wVk          WORD  ?
          wScan        WORD  ?
          dwFlags      DWORD ?
          time         DWORD ?
          dwExtraInfo  DWORD ?
    INPUT ends 

I think that should answer your question, but here is a bunch more info to confuse you-


The long form, with all three kinds of input defined would be:

The documentation on the microsoft site http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/sendinput.aspsays the syntax for the SendInput API is:
QuoteSyntax

UINT SendInput(     

    UINT nInputs,
    LPINPUT pInputs,
    int cbSize
);

Parameters

    nInputs
        [in] Specifies the number of structures in the pInputs array.
    pInputs
        [in] Pointer to an array of INPUT structures. Each structure represents an event to be inserted into the keyboard or mouse input stream.
    cbSize
        [in] Specifies the size, in bytes, of an INPUT structure. If cbSize is not the size of an INPUT structure, the

The format of pInputs would be:

INPUTS struct        ;; or any name you want.  I'm gunshy of using input for a structure name.
   dtype dword ?
   union
     mi MOUSEINPUT <>
     ki  KEYBDINPUT <>
     hi  HARDWAREINPUT <>
   ends
INPUTS ends


but before that you have to define the internal structures.  I don't speak C so I may have converted these incorrectly, if so, someone will speak up.

, so these come first before the INPUTS structure above-

MOUSEINPUT struc
    dx LONG ?
    dy LONG ?
    mouseData DWORD ?
    dwFlags DWORD ?
    time DWORD ?
    dwExtraInfo DWORD ?     ;;;***  I don't know for sure what a ULONG_PTR is but I'm guessing a dword.
MOUSEINPUT ends

KEYBOARDINPUT struc
          wVk          WORD  ?
          wScan        WORD  ?
          dwFlags      DWORD ?
          time           DWORD ?
          dwExtraInfo  DWORD ?
KEYBOARDINPUT ends

HARDWAREINPUT struct
typedef struct tagHARDWAREINPUT {
    uMsg DWORD ?
    wParamL WORD ?
    wParamH WORD ?
HARDWAREINPUT ends

gavin

#7
Hey .

Thanks so much for your help Jimg.
I never knew word was a dword. hmm
But after you spending so time on my questions it shows i need to learn a little c ,
since asm is dependant on at least some knowledge of it.(espcially structures :)

I am not sure either what it means by a pointer to an array of input structures.
But i'm going to search around and see if i can find out for myself.
Sometimes i feel bad posting questions here.
Thanks for all your help man.
I'll post back if i can't sort this thing out as my head is wrecked  :dazzled:
Thanks again i learned alot from the post ;)

Update i think most of this is correct.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    .486                       ; create 32 bit code
    .model flat, stdcall       ; 32 bit memory model
    option casemap :none       ; case sensitive

    include \masm32\include\windows.inc
    include \masm32\include\masm32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc


    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib


.data

    window_class db 'Valve001',0
    handle dd ?
    thread_id dd ?
   
.data?

    KEYBOARDINPUT struc
          dtype        DWORD ?
          wVk          WORD  ?
          wScan        WORD  ?
          dwFlags      DWORD ?
          time         DWORD ?
          dwExtraInfo  DWORD ?
     KEYBOARDINPUT ends

keys KEYBOARDINPUT <>
   
.code

start:

    invoke FindWindow,
    addr window_class,
    NULL

    mov handle,eax

    invoke GetWindowThreadProcessId,
    handle,
    thread_id
 
    mov thread_id,eax

    invoke SetForegroundWindow,
    handle

    mov [keys.dtype],1
    mov [keys.wVk],41h
    mov [keys.wScan],41h
    mov [keys.dwFlags],0
    mov [keys.time],0
    mov [keys.dwExtraInfo],0
   
    invoke SendInput,
    1,
    ADDR keys,                        ;pointer to an array of input structures
    SIZEOF KEYBOARDINPUT

invoke ExitProcess,NULL

end start


I'm still getting the invalid parameter after i call sendinput.



Jimg

Here's an alternate method I've used successfully.  I use this program every day with no problems. 

.686p
.model  flat, stdcall
option  casemap :none   ; case sensitive
.nolist
include windows.inc

inv equ Invoke

uselib  MACRO   libname
    include     libname.inc
    includelib  libname.lib
ENDM
uselib user32
uselib kernel32
uselib masm32
uselib debug

.listall

.data?
Phase     dd ?
CurrWnd   dd ?
TaskName  db 100 dup (?)

.data
MedVed    db 'Default Portfolio - Medved QuoteTracker',0
PortFolio db 'Portfolios and Alerts',0

.code

Program:

    mov Phase,1

DoitStart:
    inv FindWindow,0,0      ; get starting window
    mov CurrWnd,eax

DoitLoop:
    cmp eax,0
    je DoitDone
    inv GetWindowTextLength,CurrWnd
    .if eax>0
        inv GetWindowText,CurrWnd,addr TaskName,99
        ;PrintString TaskName
        mov ecx,offset TaskName
        .if Phase==1
            mov edx,offset MedVed
        .else
            mov edx,offset PortFolio
        .endif
    @@:
        mov al,[edx]    ; compare window found against what we want
        cmp al,0
        je @f           ; found all we wanted
        cmp al,[ecx]
        jne NextWindow  ; not this one, go look for next window name
        inc ecx
        inc edx
        jmp @b
    @@:
        .if Phase==1
            inv IsIconic,CurrWnd            ; if minimized
            .IF eax!=0
                inv OpenIcon,CurrWnd        ; restore
                ;inv ShowWindow,CurrWnd,SW_RESTORE
            .ENDIF
            inv SetForegroundWindow,CurrWnd
            inv keybd_event, VK_MENU, 0, 0, 0   ;Send Alt key 'down'
            inv Sleep, 40
            inv keybd_event, VK_P, 0, 0, 0 ;Send P key 'down'
            inv Sleep, 40           
            inv keybd_event, VK_P, 0, KEYEVENTF_KEYUP, 0 ;Send P key 'up'
            inv Sleep, 40
            inv keybd_event, VK_MENU, 0, KEYEVENTF_KEYUP, 0 ;Send Alt key 'up'
            inv Sleep, 40
            inv keybd_event, VK_E, 0, 0, 0 ;Send E key 'down'
            inv Sleep, 40
            inv keybd_event, VK_E, 0, KEYEVENTF_KEYUP, 0 ;Send E key 'up'
            inc Phase
            jmp DoitStart
        .else   ; Phase 2, move the window
        inv Sleep,40
            inv MoveWindow, CurrWnd, 425, 0, 600, 436, TRUE
            jmp DoitDone
        .endif
    .endif

NextWindow:
    inv GetWindow,CurrWnd,GW_HWNDNEXT
    mov CurrWnd,eax
    jmp DoitLoop
       
DoitDone:
    inv ExitProcess, 0

end Program

gavin

Nice program Jimg  :U

But i cannot use the keybd_event as i am trying to make a bot for my game.

The game uses directinput and keybd_event won't work with that.

:'(


Jimg

Ok, I converted my program to sendinput and got it working.  Try this structure.

KEYBOARDINPUT struc
      dtype        DWORD ?
      wVk          WORD  ?
      wScan        WORD  ?
      dwFlags      DWORD ?
      time         DWORD ?
      dwExtraInfo  DWORD ?
      dummy1 db 8 dup (?)
KEYBOARDINPUT ends


Apparently the extra 8 bytes that would be needed for mouseinput are required even though unused.  I found also I had to do a larger delay between keystrokes using sendinput rather than keybd_event.


Jimg

And after a little trial and error, the way sendinput was meant to be used, with multiple keys.  This is just my previous program converted to sendinput.

; Bring up portfolio edit in Medved QuoteTracker   

.686p
.model  flat, stdcall
option  casemap :none   ; case sensitive
.nolist
include windows.inc

inv equ Invoke

uselib  MACRO   libname
    include     libname.inc
    includelib  libname.lib
ENDM
uselib user32
uselib kernel32
uselib masm32
uselib debug

.listall

.data?
Phase     dd ?
CurrWnd   dd ?
TaskName  db 100 dup (?)

KEYBOARDINPUT struc
dtype        DWORD ?
wVk          WORD  ?
wScan        WORD  ?
dwFlags      DWORD ?
time         DWORD ?
dwExtraInfo  DWORD ?
dummy1 db 8 dup (?)
KEYBOARDINPUT ends

KSize equ sizeof KEYBOARDINPUT

kdata equ [edx].KEYBOARDINPUT  ; how to get to data using edx as base register                   

Keys db 10*KSize dup (?)  ; set aside enough for 10 events (280 bytes)

.data

MedVed    db 'Default Portfolio - Medved QuoteTracker',0
PortFolio db 'Portfolios and Alerts',0

.code

Program:

    mov Phase,1

mov edx,offset Keys
mov ecx,10 ; setup 10 keys
@@:
    mov kdata.dtype,INPUT_KEYBOARD
    mov kdata.wScan,0
    mov kdata.dwFlags,0
    mov kdata.time,0
    mov kdata.dwExtraInfo,0
    add edx,KSize
dec ecx
jnz @b


DoitStart:
    inv FindWindow,0,0      ; get starting window
    mov CurrWnd,eax

DoitLoop:
    cmp eax,0
    je DoitDone
    inv GetWindowTextLength,CurrWnd
    .if eax>0
        inv GetWindowText,CurrWnd,addr TaskName,99
        ;PrintString TaskName
        mov ecx,offset TaskName
        .if Phase==1
            mov edx,offset MedVed
        .else
            mov edx,offset PortFolio
        .endif
    @@:
        mov al,[edx]    ; compare window found against what we want
        cmp al,0
        je @f           ; found all we wanted
        cmp al,[ecx]
        jne NextWindow  ; not this one, go look for next window name
        inc ecx
        inc edx
        jmp @b
    @@:
        .if Phase==1
            inv IsIconic,CurrWnd            ; if minimized
            .IF eax!=0
                inv OpenIcon,CurrWnd        ; restore
                ;inv ShowWindow,CurrWnd,SW_RESTORE
            .ENDIF
            inv SetForegroundWindow,CurrWnd
           
;           inv keybd_event, VK_MENU, 0, 0, 0   ;Send Alt key 'down'
;           inv keybd_event, VK_P, 0, 0, 0 ;Send P key 'down'
;           inv keybd_event, VK_P, 0, KEYEVENTF_KEYUP, 0 ;Send P key 'up'
;           inv keybd_event, VK_MENU, 0, KEYEVENTF_KEYUP, 0 ;Send Alt key 'up'
;           inv keybd_event, VK_E, 0, 0, 0 ;Send E key 'down'
;           inv keybd_event, VK_E, 0, KEYEVENTF_KEYUP, 0 ;Send E key 'up'

            ; now setup actual keys used in this test
            mov edx,offset Keys
            mov kdata.wVk,VK_MENU
            add edx,KSize
            mov kdata.wVk,VK_P
            add edx,KSize
            mov kdata.wVk,VK_P
            mov kdata.dwFlags,KEYEVENTF_KEYUP
            add edx,KSize
            mov kdata.wVk,VK_MENU
            mov kdata.dwFlags,KEYEVENTF_KEYUP
            add edx,KSize
            mov kdata.wVk,VK_E
            add edx,KSize
            mov kdata.wVk,VK_E
            mov kdata.dwFlags,KEYEVENTF_KEYUP

            inv SendInput,6,addr Keys,sizeof KEYBOARDINPUT
           
            inc Phase
            jmp DoitStart
        .else   ; Phase 2, move the window
        inv Sleep,40
            inv MoveWindow, CurrWnd, 425, 0, 600, 436, TRUE
            jmp DoitDone
        .endif
    .endif

NextWindow:
    inv GetWindow,CurrWnd,GW_HWNDNEXT
    mov CurrWnd,eax
    jmp DoitLoop
       
DoitDone:
    inv ExitProcess, 0

end Program


There is a timing problem somewhere I havn't figured out.  If I doubleclick on the .exe, it doesn't work.  If I make a shortcut to the .exe on the desktop and doubleclick the shortcut, it seems to work fine.  Makes me a little nervous though.  Perhaps I need to insert sleeps after some of the keys to give the program a chance to respond.  Or perhaps, there is some way to use generate a pause by sending a keystroke or mouse move or hardware input?

gavin

Hiya Jimg.
Thanks man.
I had the same timing problems and had to use the Sleep function for the keys.
The speed of sendinput is really fast man.
I'm using mine for an online game ,so i had to use sleep after i show the window.
But thanks to you i got it going allright.
About the pause i have not used it yet but

time         DWORD ? maybe could be used?

I am not sure , and your problem seems very strange.
I just tried your code and changed the window to a.txt and open a.txt and it works fine man.