Home All Groups Group Topic Archive Search About

Make application sleep

Author
12 Oct 2006 7:33 AM
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

Author
12 Oct 2006 8:07 AM
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.



Show quoteHide quote
"Morten Snedker" <morten_spammenot_ATdbconsult.dk> wrote in message
news:7arri2dqvf1gtljjumsvbngpdn5tb0f8pm@4ax.com...
>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
Author
12 Oct 2006 8:47 AM
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


Morten Snedker wrote:
Show quoteHide quote
> 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
Author
12 Oct 2006 10:11 AM
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.
Author
12 Oct 2006 12:10 PM
Morten Snedker
On 12 Oct 2006 03:11:54 -0700, tesla***@hotmail.com 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
Author
12 Oct 2006 1:27 PM
Chris Dunaway
Morten Snedker wrote:

> 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?
Author
12 Oct 2006 1:56 PM
Morten Snedker
On 12 Oct 2006 06:27:09 -0700, "Chris Dunaway" <dunaw***@gmail.com>
wrote:

>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
Author
12 Oct 2006 1:48 PM
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.

Show quoteHide quote
"Morten Snedker" <morten_spammenot_ATdbconsult.dk> wrote in message
news:dkbsi218ov4g0hotsfj1i3os3fpv9lgosa@4ax.com...
> On 12 Oct 2006 03:11:54 -0700, tesla***@hotmail.com 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
Author
12 Oct 2006 2:01 PM
Morten Snedker
On Thu, 12 Oct 2006 14:48:07 +0100, "NickP" <a@a.com> wrote:

>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
Author
12 Oct 2006 2:27 PM
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.
Author
13 Oct 2006 8:48 AM
Morten Snedker
On 12 Oct 2006 07:27:38 -0700, tesla***@hotmail.com wrote:

Show quoteHide quote
>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! :-)

Show quoteHide quote
>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
Author
13 Oct 2006 10:27 PM
teslar91
Morten Snedker wrote:
> Thank you for helping me out. =B-)

Sure thing.  Your colleague is gonna looove you. :)
Author
12 Oct 2006 8:51 PM
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/microsoft.public.vb.winapi/tree/browse_frm/thread/5c87c565a02eb525/26f09645b8f1219e?rnum=1&q=vb+minimize+windows&_done=%2Fgroup%2Fmicrosoft.public.vb.winapi%2Fbrowse_frm%2Fthread%2F5c87c565a02eb525%2F4cbafa5ecf39b93a%3Flnk%3Dst%26q%3Dvb+minimize+windows%26rnum%3D3%26#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