SendKeys alternatives - CopyMemory woes

T

Turtle

I've been using SendKeys to automate a small utility which doesn't expose an
automation interface, but ran into a problem, for which I found the
suggestion that I use the WinAPI SendInput call instead. In trying to
implement this, most of the sample code I've found has been in VB6, so I'm
trying to deal with that, too.
The code requires a call to CopyMemory to pack information into the right
structures for the SendInput call, and that's where it gets really hairy.
The VB declaration for CopyMemory uses two arguments declared as ANY, which
my VB.NET compiler doesn't like.
Anybody have any ideas on how this should look?
I feel I'm in way over my head on this, so please ask me what information I
need to be posting to get the answers I need to get this thing going.
Or if I'd be better off in another newsgroup, I'd appreciate a reference on
that, too.

TIA
- Turtle
 
T

Tom Shelton

I've been using SendKeys to automate a small utility which doesn't expose an
automation interface, but ran into a problem, for which I found the
suggestion that I use the WinAPI SendInput call instead. In trying to
implement this, most of the sample code I've found has been in VB6, so I'm
trying to deal with that, too.
The code requires a call to CopyMemory to pack information into the right
structures for the SendInput call, and that's where it gets really hairy.
The VB declaration for CopyMemory uses two arguments declared as ANY, which
my VB.NET compiler doesn't like.
Anybody have any ideas on how this should look?
I feel I'm in way over my head on this, so please ask me what information I
need to be posting to get the answers I need to get this thing going.
Or if I'd be better off in another newsgroup, I'd appreciate a reference on
that, too.

TIA
- Turtle

CopyMemory is usually a bad idea in .NET apps, and is usually not
needed. Can you post the code (or a link to) the code your trying to
convert? It would be much easier to help with that as a reference :)
 
T

Turtle

Thanks so much for your response!

Here's a snippet - one function of what I'm trying to convert.
You can see that CopyMemory is being used to load the InputEvents xi
member, which is then passed to the SendInput API.
I haven't included all the constant definitions - let me know if you
need them:

Public Sub PressKey(KeyCode As Integer)

'special handler for mouse buttons
Select Case KeyCode
Case vbKeyRButton
PressMouseButton MOUSEEVENTF_RIGHTDOWN
Case vbKeyLButton
PressMouseButton MOUSEEVENTF_LEFTDOWN
Case vbKeyMButton
PressMouseButton MOUSEEVENTF_MIDDLEDOWN

Case Else 'now do regular keyboard things

Dim InputEvents(0 To 0) As INPUT_TYPE ' holds information about
each event
Dim keyevent As KEYBDINPUT ' temporarily hold keyboard
input info

' Press the key
With keyevent
.wVk = KeyCode ' the key to release
.wScan = 0 ' not needed
.dwFlags = 0 ' press the key down
.time = 0 ' use the default
.dwExtraInfo = 0 ' not needed
End With
InputEvents(0).dwType = INPUT_KEYBOARD
CopyMemory InputEvents(0).xi(0), keyevent, Len(keyevent)

' Now that all the information for the two input events has been
placed
' into the array, finally send it into the input stream.
Dim X As Long
X = SendInput(1, InputEvents(0), Len(InputEvents(0)))

End Select

End Sub
 
T

Tom Shelton

Thanks so much for your response!

Here's a snippet - one function of what I'm trying to convert.
You can see that CopyMemory is being used to load the InputEvents xi
member, which is then passed to the SendInput API.
I haven't included all the constant definitions - let me know if you
need them:

Public Sub PressKey(KeyCode As Integer)

'special handler for mouse buttons
Select Case KeyCode
Case vbKeyRButton
PressMouseButton MOUSEEVENTF_RIGHTDOWN
Case vbKeyLButton
PressMouseButton MOUSEEVENTF_LEFTDOWN
Case vbKeyMButton
PressMouseButton MOUSEEVENTF_MIDDLEDOWN

Case Else 'now do regular keyboard things

Dim InputEvents(0 To 0) As INPUT_TYPE ' holds information about
each event
Dim keyevent As KEYBDINPUT ' temporarily hold keyboard
input info

' Press the key
With keyevent
.wVk = KeyCode ' the key to release
.wScan = 0 ' not needed
.dwFlags = 0 ' press the key down
.time = 0 ' use the default
.dwExtraInfo = 0 ' not needed
End With
InputEvents(0).dwType = INPUT_KEYBOARD
CopyMemory InputEvents(0).xi(0), keyevent, Len(keyevent)

' Now that all the information for the two input events has been
placed
' into the array, finally send it into the input stream.
Dim X As Long
X = SendInput(1, InputEvents(0), Len(InputEvents(0)))

End Select

End Sub

Oky, doky... Here is a little bit of untested code :) I'm not sure how
you are declaring your INPUT_TYPE, but I would do it like this:

Public Structure MOUSEINPUT
Public dx As Integer
Public dy As Integer
Public mouseData As Integer
Public dwFlags As Integer
Public time As Integer
Public dwExtraInfo As IntPtr
End Structure

Public Structure KEYBDINPUT
Public wVk As Short ' according to msdn, these are word (short)
Public wScan As Short
Public dwFlags As Integer
Public time As Integer
Public dwExtraInfo As IntPtr
End Structure

Public Structure HARDWAREINPUT
Public uMsg As Integer
Public wParamL As Short
Public wParamH As Short
End Structure

<StructLayout (LayoutKind.Explicit)> _
Public Structure INPUT_UNION
<FieldOffset (0)> _
Public mi As MOUSEINPUT
<FieldOffset (0)> _
Public ki As KEYBDINPUT
<FieldOffset (0)> _
Public hi AS HARDWAREINPUT
End Structure

Public Structure INPUT_TYPE
Public dwType As Integer
Public union As INPUT_UNION
End Structure

Public Declare Function SendInput Lib "user32.dll" _
(ByVal nInputs As Integer, _
ByRef pInputs As INPUT_TYPE, _
ByVal cbSize As Integer) As Integer

Then... You can use it like this:

Public Sub PressKey(KeyCode As Short)
'special handler for mouse buttons
Select Case KeyCode
Case vbKeyRButton
PressMouseButton MOUSEEVENTF_RIGHTDOWN
Case vbKeyLButton
PressMouseButton MOUSEEVENTF_LEFTDOWN
Case vbKeyMButton
PressMouseButton MOUSEEVENTF_MIDDLEDOWN
Case Else 'now do regular keyboard things
Dim InputEvent As INPUT_TYPE ' holds information about each event

' Press the key
With InputEvent
.dwType = INPUT_KEYBOARD
.union.ki.wVk = KeyCode ' the key to release
.union.ki.wScan = 0 ' not needed
.union.ki.dwFlags = 0 ' press the key down
.union.ki.time = 0 ' use the default
.union.ki.dwExtraInfo = New IntPtr (0) ' not needed
End With

' Now that all the information for the two input events has been placed
' into the array, finally send it into the input stream.
Dim X As Integer
X = SendInput(1, InputEvents(0), Len(InputEvents(0)))

End Select
End Sub

HTH
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top