Make application sleep

M

Morten Snedker

I open a file for input. Each line is handled individually. Every time
a line has been handled I wish to wait for ½ second before reading the
next. Am I doing it right or wrong ? (I think it's wrong):


Dim thSleep As New Thread(AddressOf AppSleep)

Sub AppSleep()
Do
Thread.Sleep(500)
Loop
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click

Dim sr As StreamReader = New StreamReader("d:\test.txt")
Dim s As String = ""

Do While sr.Peek() >= 0
s = sr.ReadLine()
Console.WriteLine(s)

If s.Substring(0, 1) = "{" Then
s = s.Substring(1, s.Length - 2)
Dim myArray() As String = Split(s, ",", ,
CompareMethod.Text)

ClickPosition()
AppSleep()

Else
TextInput = s
WriteText()
AppSleep()
End If

Loop

sr.Close()
sr.Dispose()

End Sub

The essense is that for each line either a mouse click og textline i
send to another application. For each click/text I wish for the
application to "absorb" it.

Regards /Snedker
 
S

Stephany Young

Ummmmmmmm ... It's very wrong.

The first time you call AppSleep, your UI thread will go to sleep and never
wake up again because of the Do ... Loop.
 
H

HKSHK

Dear Mr. Snedker,

As I see it your sub AppSleep is an eternal loop, because you didn't set
any condition on how to end it. So it will sleep again and again and
again and ...

So, make AppSleep look like this:

Sub AppSleep()
Thread.Sleep(500)
End Sub

Apart from that, there is the problem that the sending application
(sender) does not know if the string was processed or not. Depending on
the situation (maybe Windows is swapping or very busy) 500 ms might not
be enough. If you send the next string already, the processing order
might be that the second string is processed first. This might be a
problem if the order of the strings is important.

Perhaps another method might be better (but it would only work if you
have access to the sources of both applications):

Implement a status message into both programs. This could e.g. be done
by creating a status file (or a named pipe).

The receiver creates a status file (and if you like returns a status
message e.g. OK or error message). The sender then checks if the file
exists.

a) If the file exists and you implemented the OK/error message it opens
it and checks if the transaction was OK or an error occurred. If OK,
then the sender deletes the file and sends the next string otherwise
handle the error.

OR

b) If the file exists the sender deletes the file and sends the next string.

Best Regards,

HKSHK
 
T

teslar91

As the others said, and:

If you're using PostMessage as we recently discussed in your
ClickPosition(), you might want to use SendMessage instead - it waits
until the app processes the message before returning. Might help
reduce/eliminate the need for Sleep and speed things up.
 
M

Morten Snedker

On 12 Oct 2006 03:11:54 -0700, (e-mail address removed) wrote:


Thanks to all of you guys for your help and efforts. I've given
SendMessage a go, but it still won't do (entirely).

My test.txt contains:
{1221,12}
{50,980}
{70,867}

The idea is to move to each position and perform a click. In my case
the first position should minimize any foremost underlying
application.

Second click hits the Win-XP Start-button.

The third click should click somewhat above the the now unfolded list
above the the Start-button and hit Notepad.

In all three cases the mouse moves to the proper position.

Though, the first click doesn't minimize the underlying application
(that could be any maximized app).

The second click performs well and unfolds the Start-button.

The thirc click doesn't open the Notepad (even at the right position).

Here is my full code:

'--code begin
Imports System.Windows.Forms
Imports System.Threading
Imports System.IO
Public Class Form1

Public TextInput As String = ""
Public PosX As Integer, PosY As Integer

Dim thSleep As New Thread(AddressOf ReadFile)

#Region "Get window-name, Declares"
Dim myVal1 As Integer
Dim myVal2 As Integer

Dim intHandle As IntPtr = FindWindow("[Class Name Here]",
vbNullString)
Dim intHandle2 As IntPtr = FindWindow(vbNullString, "Lommeregner")

Private Declare Function GetForegroundWindow _
Lib "user32" () As IntPtr
Private Declare Function SetForegroundWindow _
Lib "user32" (ByVal hWnd As IntPtr) As Boolean
Private Declare Function GetWindowThreadProcessId _
Lib "user32" (ByVal hWnd As IntPtr, _
ByVal lpdwProcessId As IntPtr) As Integer
Private Declare Function AttachThreadInput _
Lib "user32" (ByVal idAttach As Integer, _
ByVal idAttachTo As Integer, ByVal fAttach As Boolean _
) As Boolean
Private Declare Function FindWindow _
Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String,
_
ByVal lpWindowName As String) As IntPtr
#End Region

Declare Auto Function WindowFromPoint Lib "user32" (ByVal xPoint
As Integer, ByVal yPoint As Integer) As IntPtr
Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal
wParam As Integer, ByVal lParam As Integer) As Integer

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles Button1.Click
Me.WindowState = FormWindowState.Minimized
ReadFile()
End Sub
Sub ReadFile()

Dim sr As StreamReader = New StreamReader("d:\test.txt")
Dim s As String = ""

Do While sr.Peek() >= 0
s = sr.ReadLine()
Console.WriteLine(s)

If s.Substring(0, 1) = "{" Then
s = s.Substring(1, s.Length - 2)
Dim myArray() As String = Split(s, ",", ,
CompareMethod.Text)
PosX = myArray(0)
PosY = myArray(1)

ClickPosition()
Thread.Sleep(500)
Else
'TextInput = s
'WriteText()
'Thread.Sleep(500)
End If
Loop

sr.Close()
sr.Dispose()

End Sub
Sub ClickPosition()
Dim wnd As IntPtr
Dim pt As Point

pt.X = PosX
pt.Y = PosY
Windows.Forms.Cursor.Position = pt

Const WM_ACTIVATEAPP = &H1C
Const WM_LBUTTONUP = &H202 '//LButton up
Const WM_LBUTTONDOWN = &H201 '//LButton down

wnd = WindowFromPoint(PosX, PosY)
Call SendMessage(wnd, WM_ACTIVATEAPP, 0, 0)
Call SendMessage(wnd, WM_LBUTTONDOWN, 0, 0)
Call SendMessage(wnd, WM_LBUTTONUP, 0, 0)
End Sub

Sub WriteText()
SendKeys.SendWait(TextInput)
End Sub

End Class
'--code end

Regards /Snedker
 
C

Chris Dunaway

Morten said:
The third click should click somewhat above the the now unfolded list
above the the Start-button and hit Notepad.

What if the position of Notepad in the start menu changes? What if the
machine the program is running on does not have Notepad in the start
menu?

What are you trying to accomplish? Just starting Notepad (or some
other app?) Why not use the Process class to start notepad directly?
 
N

NickP

Hi Morten,

This won't really help with your app but I can see a few strange things
going on there..

When you call a method to operate on a variable it's best to send that
variable to the method as a parameter, i.e.

Sub WriteText(Byval iTextInput As String)
SendKeys.SendWait(iTextInput)
End Sub

That way SendKeys will always send each value. If the value of
TextInput were to change after calling the method it would not act as
expected.

Same goes for your click method, I would create a parameter for the
position to click, but this would be relative to the screen coordinates.
You have to bare in mind that if you are obtaining the handle to a window
and sending the click message to it then X, and Y will be relative to it's
current location, so it might not even be clicking inside of it.

BTW, what are you trying to achieve? Scripting clicking a few buttons I
presume to remove something annoying from the screen? ;-)

Nick.

Morten Snedker said:
On 12 Oct 2006 03:11:54 -0700, (e-mail address removed) wrote:


Thanks to all of you guys for your help and efforts. I've given
SendMessage a go, but it still won't do (entirely).

My test.txt contains:
{1221,12}
{50,980}
{70,867}

The idea is to move to each position and perform a click. In my case
the first position should minimize any foremost underlying
application.

Second click hits the Win-XP Start-button.

The third click should click somewhat above the the now unfolded list
above the the Start-button and hit Notepad.

In all three cases the mouse moves to the proper position.

Though, the first click doesn't minimize the underlying application
(that could be any maximized app).

The second click performs well and unfolds the Start-button.

The thirc click doesn't open the Notepad (even at the right position).

Here is my full code:

'--code begin
Imports System.Windows.Forms
Imports System.Threading
Imports System.IO
Public Class Form1

Public TextInput As String = ""
Public PosX As Integer, PosY As Integer

Dim thSleep As New Thread(AddressOf ReadFile)

#Region "Get window-name, Declares"
Dim myVal1 As Integer
Dim myVal2 As Integer

Dim intHandle As IntPtr = FindWindow("[Class Name Here]",
vbNullString)
Dim intHandle2 As IntPtr = FindWindow(vbNullString, "Lommeregner")

Private Declare Function GetForegroundWindow _
Lib "user32" () As IntPtr
Private Declare Function SetForegroundWindow _
Lib "user32" (ByVal hWnd As IntPtr) As Boolean
Private Declare Function GetWindowThreadProcessId _
Lib "user32" (ByVal hWnd As IntPtr, _
ByVal lpdwProcessId As IntPtr) As Integer
Private Declare Function AttachThreadInput _
Lib "user32" (ByVal idAttach As Integer, _
ByVal idAttachTo As Integer, ByVal fAttach As Boolean _
) As Boolean
Private Declare Function FindWindow _
Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String,
_
ByVal lpWindowName As String) As IntPtr
#End Region

Declare Auto Function WindowFromPoint Lib "user32" (ByVal xPoint
As Integer, ByVal yPoint As Integer) As IntPtr
Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal
wParam As Integer, ByVal lParam As Integer) As Integer

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles Button1.Click
Me.WindowState = FormWindowState.Minimized
ReadFile()
End Sub
Sub ReadFile()

Dim sr As StreamReader = New StreamReader("d:\test.txt")
Dim s As String = ""

Do While sr.Peek() >= 0
s = sr.ReadLine()
Console.WriteLine(s)

If s.Substring(0, 1) = "{" Then
s = s.Substring(1, s.Length - 2)
Dim myArray() As String = Split(s, ",", ,
CompareMethod.Text)
PosX = myArray(0)
PosY = myArray(1)

ClickPosition()
Thread.Sleep(500)
Else
'TextInput = s
'WriteText()
'Thread.Sleep(500)
End If
Loop

sr.Close()
sr.Dispose()

End Sub
Sub ClickPosition()
Dim wnd As IntPtr
Dim pt As Point

pt.X = PosX
pt.Y = PosY
Windows.Forms.Cursor.Position = pt

Const WM_ACTIVATEAPP = &H1C
Const WM_LBUTTONUP = &H202 '//LButton up
Const WM_LBUTTONDOWN = &H201 '//LButton down

wnd = WindowFromPoint(PosX, PosY)
Call SendMessage(wnd, WM_ACTIVATEAPP, 0, 0)
Call SendMessage(wnd, WM_LBUTTONDOWN, 0, 0)
Call SendMessage(wnd, WM_LBUTTONUP, 0, 0)
End Sub

Sub WriteText()
SendKeys.SendWait(TextInput)
End Sub

End Class
'--code end

Regards /Snedker
 
M

Morten Snedker

What if the position of Notepad in the start menu changes? What if the
machine the program is running on does not have Notepad in the start
menu?

Not an issue - the described situation is just for test. Just to see
it work.
What are you trying to accomplish? Just starting Notepad (or some
other app?) Why not use the Process class to start notepad directly?

Notepad is just an example. The end-purpose is to make flexible
navigation in any given program.

The kickstart is my collegue who has a special application to make
complicated calculations. That takes several clicks and input of data.
Then it calculates for 5-6 minutes. That he sometimes does a hundred
times - and it's a kiling job.

So we wish for this application to take care of itself.

Regards /Snedker
 
M

Morten Snedker

Hi Morten,

This won't really help with your app but I can see a few strange things
going on there..

When you call a method to operate on a variable it's best to send that
variable to the method as a parameter, i.e.

Sub WriteText(Byval iTextInput As String)
SendKeys.SendWait(iTextInput)
End Sub

Initially that's what I had. Just found it more convenient to have
just one variable...but I agree.
Same goes for your click method, I would create a parameter for the
position to click, but this would be relative to the screen coordinates.
You have to bare in mind that if you are obtaining the handle to a window
and sending the click message to it then X, and Y will be relative to it's
current location, so it might not even be clicking inside of it.

Aha. That indeed may be where I'm going wrong. But if I send a
doubleclick to an Excel-shortcut on the desktop, still Excel doesn't
open...?

Thanks for input.

Regards /Snedker
 
T

teslar91

Sigh.

In your thread "How to find my information", you inquired into a means
of simulating a mouse click *without* moving the mouse, which I
provided with a warning that not all controls respond uniformly. You
said you'd follow up in that thread if you had problems.

Instead, you started a new thread, "Trouble with mouse click", where
you posted code where you're *moving* the mouse, then using the
technique I provided for simulating a click *without moving* the mouse,
thus combining the disadvantages of both. There I advised you use the
more conventional, reliable method of simulating clicks if you were
going to move the mouse anyway, and provided code.

When you started this thread I wasn't sure if you'd seen my previous
response, but now that you've posted ClickPosition code, it appears
that you did not; if you had, it would be working already.

Seriously. One problem, one thread, makes things so much easier. :)

This will work just fine on your minimize button, start menu, shortcut,
and whatever else you throw at it:

Const MOUSEEVENTF_LEFTDOWN = &H2
Const MOUSEEVENTF_LEFTUP = &H4
Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Int32, ByVal dX
As Int32, ByVal dy As Int32, ByVal cButtons As Int32, ByVal dwExtraInfo
As Int32)

Sub ClickPosition()
Dim wnd As IntPtr
Dim pt As Point

pt.X = PosX
pt.Y = PosY
Windows.Forms.Cursor.Position = pt

mouse_event(MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
End Sub

Want a double-click? Just issue that mouse_event twice, back to back,
no delay necessary.
 
H

HKSHK

Dear Mr. Snedker,
The idea is to move to each position and perform a click. In my case
the first position should minimize any foremost underlying
application.

If you want to minimize windows, then maybe you would like to use this
method (which minimizes ALL visible windows, taken from
http://groups.google.com/group/micr...minimize+windows&rnum=3&#doc_050a39c3d24b89a3):

Private Const WM_COMMAND As Int32 = &H111
Private Const MIN_ALL As Int32 = 419
Private Const MIN_ALL_UNDO As Int32 = 416

Private Declare Function FindWindow Lib "USER32" Alias "FindWindowA"
(ByVal lpClassName As String, ByVal lpWindowName As String) As Int32

Private Declare Function SendMessage Lib "USER32" Alias "SendMessageA"
(ByVal hWnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32,
lParam As Any) As Int32

'--------------------------


Dim TrayHandle as Int32, r As Int32

'Minimize all windows
TrayHandle = FindWindow("Shell_TrayWnd", Chr(0))
r = SendMessage(TrayHandle, WM_COMMAND, MIN_ALL, 0&)



'Restore all windows
r = SendMessage(TrayHandle, WM_COMMAND, MIN_ALL_UNDO, 0&)

Best Regards,

HKSHK
 
M

Morten Snedker

Sigh.

In your thread "How to find my information", you inquired into a means
of simulating a mouse click *without* moving the mouse, which I
provided with a warning that not all controls respond uniformly. You
said you'd follow up in that thread if you had problems.

Instead, you started a new thread, "Trouble with mouse click", where
you posted code where you're *moving* the mouse, then using the
technique I provided for simulating a click *without moving* the mouse,
thus combining the disadvantages of both. There I advised you use the
more conventional, reliable method of simulating clicks if you were
going to move the mouse anyway, and provided code.

When you started this thread I wasn't sure if you'd seen my previous
response, but now that you've posted ClickPosition code, it appears
that you did not; if you had, it would be working already.

Seriously. One problem, one thread, makes things so much easier. :)

I apologize for my poor newsgroup behaviour. I _will_ improve in the
future! :)
This will work just fine on your minimize button, start menu, shortcut,
and whatever else you throw at it:

Const MOUSEEVENTF_LEFTDOWN = &H2
Const MOUSEEVENTF_LEFTUP = &H4
Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Int32, ByVal dX
As Int32, ByVal dy As Int32, ByVal cButtons As Int32, ByVal dwExtraInfo
As Int32)

Sub ClickPosition()
Dim wnd As IntPtr
Dim pt As Point

pt.X = PosX
pt.Y = PosY
Windows.Forms.Cursor.Position = pt

mouse_event(MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
End Sub

Want a double-click? Just issue that mouse_event twice, back to back,
no delay necessary.

That all did the trick.

Although the solution seems simple I find reaching it difficult. Then
again, I haven't spend as much time with .Net as I'd like to, so I
guess it'll some bleeding knees before riding the bike.

Thank you for helping me out. =B-)


Regards /Snedker
 

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