Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

Thanks for taking a look :)

 

 

Right now I am using Send Keys to acomplish playing and stoping audio on one of my computers but the problem is it is the same key. So if the player has finished playing the audio and I turn off the switch the audio starts again. What I would like to do is get the window that has the play and stop buttons and "send a message" to the application telling it which button to "hit". Can this be done in .NET or would it be better to do this with vb6? My only catch is the program has to have hardware attached to it so I have to build the application install it try it and so on.

 

 

Thanks For any help you may be able to provide.

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted

Thanks

 

Is it possible to enumerate the controls of the window? Use spy++ and see if you can get the handle of the stop and play button.

 

 

Thanks, I didn't expect a response so soon. Ok well using Spy++ I couldn't get a handle on the buttons but I did get the window and the X,Y values of the mouse. So that is cool and I have figured out how to find a window and send a key to it, but how do I simulate a mouse click.

 

Here is my code.

 


   Public Structure MSG
       Public hwnd As Integer
       Public message As Integer
       Public wParam As Integer
       Public lParam As Integer
       Public time As Integer
       Public pt As Integer
   End Structure

   Private Const WM_KEYDOWN = &H100
   Private Const WM_KEYUP = &H101
   Public Const WM_CHAR = &H102
   Private Const WM_LBUTTONDOWN = &H201
   Private Const WM_LBUTTONUP = &H202

   Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
   Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Integer, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer
   Declare Function TranslateMessage Lib "user32.dll" (ByRef lpMsg As MSG) As Integer
   Declare Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As UIntPtr, ByVal lParam As IntPtr) As IntPtr
   Dim PTools_hWnd As Integer
   Dim myMsg As MSG = New MSG


   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
       'PTools_hWnd = FindWindow(vbNullString, "Untitled - NotePad")  'FindWindow("Notepad", vbNullString)
       Dim hwnd As Integer = FindWindow(vbNullString, "Untitled - NotePad") '/// assuming you have notepad open.
       PTools_hWnd = FindWindowEx(hwnd, 0, "Edit", vbNullString)
       MsgBox(PTools_hWnd)
       If Not PTools_hWnd = 0 Then
           myMsg.hwnd = PTools_hWnd
           myMsg.message = WM_KEYDOWN 
           myMsg.wParam = Keys.B
           myMsg.lParam = 0
           Dim ret As Integer
           ret = TranslateMessage(myMsg)
           textbox1.text = ret
       End If
   End Sub

 

I am using Notepad as a test bed, I'll have to build the app "Blind" before installing it and testing. If I could get the simulated mouse click to work I would be good to go. But I can't seem to find the how, I am still looking while this is going on. I did find an example but it is in c? and I am un able to translate all of it.

 

http://www.xtremedotnettalk.com/showthread.php?t=79579

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted

It's C# code, sorry =(

 

/// <summary>
/// Performs a left-button mouse click.
/// </summary>
public void Click()
{
//SetForegroundWindow();
NativeMethods.mouse_event(NativeMethods.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, IntPtr.Zero);
NativeMethods.mouse_event(NativeMethods.MOUSEEVENTF_LEFTUP, 0, 0, 0, IntPtr.Zero);
}

 

 

/// <summary>
/// Synthesizes mouse motion and button clicks.
/// </summary>
/// <param name="dwFlags">Specifies various aspects of mouse motion and button clicking.</param>
/// <param name="dx">Specifies the mouse's absolute position along the x-axis or its amount of motion since the last mouse event was generated, depending on the setting of MOUSEEVENTF_ABSOLUTE.</param>
/// <param name="dy">Specifies the mouse's absolute position along the y-axis or its amount of motion since the last mouse event was generated, depending on the setting of MOUSEEVENTF_ABSOLUTE.</param>
/// <param name="dwData">If dwFlags contains MOUSEEVENTF_WHEEL, then dwData specifies the amount of wheel movement. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user.</param>
/// <param name="dwExtraInfo">Specifies an additional value associated with the mouse event.</param>
[DllImport("user32.dll", SetLastError=true)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, IntPtr dwExtraInfo);

 

public const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
public const uint MOUSEEVENTF_LEFTUP = 0x0004;

Posted
Well I understande some of what you posted but I am not folowwing 100%. I can send keyboard strokes all day but a mouse click grrr. Still working on it though.

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted

using reflector....

Private Shared Sub Click()
     Class1.mouse_event(2, 0, 0, 0, IntPtr.Zero)
     Class1.mouse_event(4, 0, 0, 0, IntPtr.Zero)
End Sub

<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Sub mouse_event(ByVal dwFlags As UInt32, ByVal dx As UInt32, ByVal dy As UInt32, ByVal dwData As UInt32, ByVal dwExtraInfo As IntPtr)
End Sub

Private Const MOUSEEVENTF_LEFTDOWN As UInt32 = 2
Private Const MOUSEEVENTF_LEFTUP As UInt32 = 4

 

and import the System.Runtime.InteropServices namespace.

Posted
using reflector....

Private Shared Sub Click()
     Class1.mouse_event(2, 0, 0, 0, IntPtr.Zero)
     Class1.mouse_event(4, 0, 0, 0, IntPtr.Zero)
End Sub

<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Sub mouse_event(ByVal dwFlags As UInt32, ByVal dx As UInt32, ByVal dy As UInt32, ByVal dwData As UInt32, ByVal dwExtraInfo As IntPtr)
End Sub

Private Const MOUSEEVENTF_LEFTDOWN As UInt32 = 2
Private Const MOUSEEVENTF_LEFTUP As UInt32 = 4

 

and import the System.Runtime.InteropServices namespace.

 

 

Cool now I am getting mouse click but it will only click where the mouse is I need to set the x & y and get the click to happen there. If I set the x & y values it still only clicks under the mouse. Also this is only done on the screen not on a specific window. How can this be sent to a window. I found this "MOUSEEVENTF_ABSOLUTE" but no example of how to use it or what it's value is. So I am still hunting away.

 

here is the spy++ capture

00020534 S WM_SetCursor hwnd:00020532 nHittest:HTMENU wMouseMsg:WM_LBUTTONDOWN

 

does this help?

 

Thanks for your help

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted
try using Cursor.Position to set the mouse position' date=' and then using mouse_event to emulate the clicking.[/quote']

 

 

Thanks for this clip of info. I was able to move the cursor and then get a mouse click. This works great to a point. My app will be in the systray waiting for input and the window that the play controls are on is movable. So this could cause a problem. I was looking into trying to use Keys.Lbutton but again the use of this is not really clear. I have tried this in my "key Press" code but nothing happens. Now if find windows could give me the x,y of the found window/child window I could make this work. It's the holidays so my searching will be limited this comming weekend.

 

Any more thoughts,

 

Thanks

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted

Thanks for the links. I was trying this.

 

   Declare Function GetWindowRect Lib "user32" Alias "GetWindowRect" (ByRef hwnd As Integer, ByRef lpRect As RECT) As Integer
  

 

But I could only get it to return zero values for the four side of a rectangle. I'll check those out later on tonight.

 

Thanks again,

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted

reflectored c# code

<DllImport("user32.dll", SetLastError:=True)> _
Public Shared Function GetWindowRect(ByVal hwnd As IntPtr, <Out> ByRef rectangle As Rectangle) As Boolean
End Function

<STAThread> _
Private Shared Sub Main(ByVal args As String())
     Dim rectangle1 As Rectangle
     If Not Class1.GetWindowRect(New IntPtr(658582), rectangle1) Then
           Throw New Win32Exception
     End If
End Sub

 

658582 was the handle of an instance of notepad I had. Include the following namespaces.

 

System;

System.Runtime.InteropServices;

System.Drawing;

 

and the dll

System.Drawing

 

and a valid handle to a win32 window and it should work.

Posted

argh

 

Thanks for your help with this, here is my code as of now.

 

'The Imports

Imports System
Imports System.Runtime.InteropServices
Imports System.Drawing

'Structure

   Public Structure MSG
       Public hwnd As IntPtr
       Public message As Integer
       Public wParam As Integer
       Public lParam As Integer
       Public time As Integer
       Public pt As Integer
   End Structure

'Declare Functions

   Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr

   Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As IntPtr, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As IntPtr

   Declare Function GetWindowRect Lib "user32" Alias "GetWindowRect" (ByRef hwnd As IntPtr, ByRef lpRect As Rectangle) As Boolean

   Declare Function TranslateMessage Lib "user32.dll" (ByRef lpMsg As MSG) As Integer

   Declare Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As UIntPtr, ByVal lParam As IntPtr) As IntPtr

Declare Sub mouse_event Lib "user32.dll" (ByVal dwFlags As Integer, ByVal dx As Integer, ByVal dy As Integer, ByVal dwData As Integer, ByVal dwExtraInfo As IntPtr)

'Const

Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Public Const WM_CHAR = &H102

'Variables

Dim PTools_hWnd As IntPtr
Dim myMsg As MSG = New MSG

'The Code

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
       Try
           Dim ret As Integer
           Dim Rec1 As Rectangle = New Rectangle
           'Find Window

           Dim hwnd As IntPtr = FindWindow(vbNullString, "Untitled - NotePad") 'Using Notepad as example to real program
           PTools_hWnd = FindWindowEx(hwnd, 0, "Edit", vbNullString) 'finds child windows

           'Set the send message Structure, works great for keystrokes
           myMsg.hwnd = PTools_hWnd
           myMsg.message = WM_KEYDOWN
           myMsg.wParam = Keys.L
           myMsg.lParam = 0

           ret = TranslateMessage(myMsg)

           'Get Left, Right, Top and Bottom of Form1
           GetWindowRect(hwnd, Rec1)

           'GetWindowRect returning zero values
           'Tried both hwnd & PTools_hWnd

           MoveCursor((Rec1.Left + 25), (Rec1.Top + 25))
           mouse_event(2, 0, 0, 0, IntPtr.Zero)
           mouse_event(4, 0, 0, 0, IntPtr.Zero)

       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

   Private Sub MoveCursor(ByVal Fx As Integer, ByVal Fy As Integer)
       If Me.Cursor.Equals(Cursors.Default) Then
           Me.Cursor = New Cursor(Cursor.Current.Handle)
           Cursor.Position = New Point(Fx, Fy)
           Me.Cursor = Cursors.Default
       End If
   End Sub

 

Using the code above I get the letter "l" enter in notepad and the mouse moved to the upper left hand corner and a mouse click. If the rec1 had values it would click "file" on the notepad menu.

 

any thoughts

 

Thanks

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted (edited)

Ok, here's code I created in a console app

Imports System
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports System.Windows.Forms
Imports System.ComponentModel


Module Module1

   <DllImport("user32.dll", SetLastError:=True)> _
   Public Function FindWindowA(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
   End Function

   <DllImport("user32.dll", SetLastError:=True)> _
   Public Function SetForegroundWindow(ByVal hWnd As IntPtr) As Boolean
   End Function

   <DllImport("user32.dll", SetLastError:=True)> _
  Public Sub BringWindowToTop(ByVal window As IntPtr)
   End Sub

   <DllImport("user32.dll", SetLastError:=True)> _
   Public Function FindWindowExA(ByVal hWnd1 As IntPtr, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As IntPtr
   End Function

   <DllImport("user32.dll", SetLastError:=True)> _
   Public Function GetWindowRect(ByVal hwnd As IntPtr, <Out()> ByRef rectangle As Rectangle) As Boolean
   End Function

   <DllImport("user32.dll", SetLastError:=True)> _
   Public Function TranslateMessage(ByRef lpMsg As Message) As Integer
   End Function

   <DllImport("user32.dll", SetLastError:=True)> _
   Public Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As UIntPtr, ByVal lParam As IntPtr) As IntPtr
   End Function

   <DllImport("user32.dll", SetLastError:=True)> _
   Public Sub mouse_event(ByVal dwFlags As Integer, ByVal dx As Integer, ByVal dy As Integer, ByVal dwData As Integer, ByVal dwExtraInfo As IntPtr)
   End Sub

   Private Const WM_KEYDOWN = &H100
   Private Const WM_KEYUP = &H101
   Public Const WM_CHAR = &H102

   <STAThread()> _
   Sub Main()
       Try
           Dim ret As Integer
           Dim Rec1 As Rectangle = New Rectangle
           'Find Window

           Dim hwnd As IntPtr = FindWindowA(vbNullString, "Untitled - NotePad") 'Using Notepad as example to real program
           Dim PTools_hWnd As IntPtr = FindWindowExA(hwnd, 0, "Edit", vbNullString) 'finds child windows

           Dim myMsg As Message = New Message
           'Set the send message Structure, works great for keystrokes
           myMsg.HWnd = PTools_hWnd
           myMsg.Msg = WM_KEYDOWN
           myMsg.WParam = New IntPtr(Keys.L)
           myMsg.LParam = IntPtr.Zero

           ret = TranslateMessage(myMsg)

           'Get Left, Right, Top and Bottom of Form1
           Dim success As Boolean = GetWindowRect(hwnd, Rec1)
           Debug.WriteLine(String.Format("Rec1={0}", Rec1))

           If Not success Then
               Throw New Win32Exception
           End If

           'GetWindowRect returning zero values
           'Tried both hwnd & PTools_hWnd

           MoveCursor((Rec1.Left + 25), (Rec1.Top + 25))
           If Not SetForegroundWindow(hwnd) Then
               Throw New Win32Exception
           End If
           mouse_event(2, 0, 0, 0, IntPtr.Zero)
           mouse_event(4, 0, 0, 0, IntPtr.Zero)

       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try
   End Sub

   Private Sub MoveCursor(ByVal Fx As Integer, ByVal Fy As Integer)
       Dim newPoint As Point = New Point(Fx, Fy)
       Debug.WriteLine(String.Format("Old mouse position = {0}.", Cursor.Position))
       Debug.WriteLine(String.Format("Moving mouse to {0}.", newPoint))
       Cursor.Position = newPoint
       Debug.Assert(newPoint.Equals(Cursor.Position), "The cursor position was not set to the desired location.")
   End Sub

End Module

 

There are a few differences between your code and mine, the most important being the declaration of the native methods such as GetWindowRect. Note that I declare my methods using <DLLImport> and use the SetLastError attribute because all of those imported functions modify the error code (according to the msdn documentation). I needed to use BringWindowToTop to make sure the notepad window was visible before doing any mouse clicking otherwise the click could be sent to the wrong screen.

 

I also use the Message Structure instead of the MSG structure you declared. Nothing major, but it's less code that needs to be maintained =]

 

I also use Debug.WriteLine to write debug info to any listeners (the output window in vs.net always listens) and I use Debug.Assert to make sure the cursor position was moved to the desired location.

Edited by HJB417
Posted

THANK YOU!

 

I was able to get it to work in a console app, just like you you created. Now when moving it over to a Form based app I am getting this error.

 

System.InvalidProgramException: Error: PInvoke item (field,method) must be Static.

'Full message

System.InvalidProgramException: Error: PInvoke item (field,method) must be Static.
  at ProToolsController.Form1.FindWindowA(String lpClassName, String lpWindowName)
  at ProToolsController.Form1.Button1_Click(Object sender, EventArgs e) in C:\Local Documents\VB .NET Projects\ProToolsController\ProToolsController\Form1.vb:line 145

'Line Causing the error,

Dim hwnd As IntPtr = FindWindowA(vbNullString, "Untitled - NotePad") 'Using Notepad as example to real program

 

I just wanted to give you an update I am currently looking into the error. If you have any thoughts feel free to let me know.

 

Thank you again,

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted

I was able to fix the errors by changing the Public Functions to Shared Functions and all works great. Thank you again HJB417 for your help. I have learned alot from this process. Thank you again.

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted

Crude small problem, this works great if my window caption never changes but it will be. I was think of that while driving today. So is it possible to grab a window by part of the caption? I'll be reading and looking into this a bit tomorrow.

 

Thanks for any more help you may give.

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted
The caption may change but the handle of/to the window will most likely be the same for the life of the application, so try to use handles whenever possible - or - you can enumerate all of the child windows and compare the title with what you're looking for.
Posted

I could do that, now when you say life of the application do you mean from the time the shortcut is clicked and the program is running or untill the app is uninstalled. I am thinking it's the ladder of the two but I wan to be sure. The reason I ask is this will be used by other people and if they close the app that I am looking for and the handle is reset well then my "add-on won't work.

 

Thanks for your help

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted
The former (until the window is destroyed).

 

Damn, well he is my current thought process, I haven'y been able to test this but. I'm thinking that if I can find the program in the task manager get it's PID number I should be able to find the window and any child windows. Since I'm not at the computer with VB.Net on it I can't try anything but I don't see why that wouldn't be possible, I'll be doing some research on it. I know i reads something about get process ID or something of that nature. I'll hunt through the MNSD site tonight. Plaease feel free to comment on my thought process above and it you think it would work or if you have a better direction to go.

 

Thanks again

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted

Ok well here is what I found and I think if I incorporate this into the other code it'll work just fine.

 

Imports System.Diagnostics

   Dim returnValue() As Diagnostics.Process

   Dim Handle As IntPtr

   returnValue = Process.GetProcessesByName("notepad")

   Handle = returnValue(0).Handle

 

Any thoughts about doing it this way?

 

Thanks

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted

Opps I had to change this line.

 


Handle = returnValue(0).Handle

to

Handle = returnValue(0).MainWindowHandle

 

Again Thanks for you help

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Posted

New Problem

 

Ok Eveything is great but, The window I need to grab is 1, a child window and 2, it has no caption. I have been lookinig into this,

 

C# Code

[DllImport("User32.dll")]
public static extern Boolean EnumChildWindows(int hWndParent,Delegate lpEnumFunc,int lParam);

 

but I can't seem to get it to work while trying to convert it to VB.NET

 

   <DllImport("user32.dll", SetLastError:=True)> _
   Shared Function EnumChildWindows(ByVal hWndParent As IntPtr, ByVal lpEnumFunc As ?Not Sure?, ByVal lParam As Integer) As IntPtr
   End Function

 

I have seen some examples but nothing it working for me. I am still reading up on it to learn more but any help is welcome.

 

Thanks

 

ZeroEffect

If you can't find it, Build It.

 

There is no place Like 127.0.0.1 also don't forget 1 + 1 = 10

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...