AutoWin UserLibrary
Re: AutoWin UserLibrary
Kiki, this library, as excellent as it looks, is nothing to do with me!
Sorry for the off-topic posting Thomas.
Sorry for the off-topic posting Thomas.
I may look like a mule, but I'm not a complete ass.
-
- Enthusiast
- Posts: 469
- Joined: Sun Mar 16, 2008 9:18 am
Re: AutoWin UserLibrary
Don't know if you realise it, but PureBasic can do everything that AutoWin does, natively, without the need for a library. AutoWin is mainly just a bunch of wrapper calls to the Windows API. PureBasic can control IE and Firefox in exactly the same way that AutoWin does.KIKI wrote:Purebasic dosen't allows controlling IE or Firefox, it will be very usefull to have these functionality
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: AutoWin UserLibrary
Thanks for this library, Thomas!
It's very useful for my current project.
Regards, Little John
It's very useful for my current project.
Regards, Little John
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: AutoWin UserLibrary
Hi Thomas,
in the current version 1.3, I think there is an issue with the function AW_WinWaitClose2().
As far as I understand, its return value should tell us the reason why the function had terminated, e.g.:
But if the respective window is not open anyway when the function is called, the return value also is #False. So when the return value is #False, the situation is ambiguous: It can mean that the respective Window is closed, or that the window is open, and there was a timeout. For the ease of discussion, I post the code here again:
For a consistent return value, line 6 should be:
But then, lines 5-7 are not required at all.
Regards, Little John
//edit:
Similar issue with function AW_WinWaitNotActive2():
If *param\hWnd = 0, then the respective Window is not active, and the function should return #True:
in the current version 1.3, I think there is an issue with the function AW_WinWaitClose2().
As far as I understand, its return value should tell us the reason why the function had terminated, e.g.:
Code: Select all
If AW_WinWaitClose2("My window", 5)
Debug "Window is closed."
Else
Debug "Timeout. Window is open."
EndIf
Code: Select all
ProcedureDLL AW_WinWaitClose2(title.s, timeout)
Protected time = ElapsedMilliseconds() + (timeout * 1000)
Protected timebreak
If Not AW_WinExists(title)
ProcedureReturn #False
EndIf
While AW_WinExists(title)
If timeout
If ElapsedMilliseconds() > time
timebreak = #True
Break
EndIf
EndIf
Delay(250)
Wend
If timebreak
ProcedureReturn #False
Else
ProcedureReturn #True
EndIf
EndProcedure
Code: Select all
ProcedureReturn #True
Regards, Little John
//edit:
Similar issue with function AW_WinWaitNotActive2():
Code: Select all
ProcedureDLL AW_WinWaitNotActive2(title.s, timeout)
Protected time = ElapsedMilliseconds() + (timeout * 1000)
Protected timebreak
Protected *param.AW_WinParameter
*param = AW_FindWindow(title)
If *param\hWnd
While GetForegroundWindow_() = *param\hWnd
If timeout
If ElapsedMilliseconds() > time
timebreak = #True
Break
EndIf
EndIf
Delay(250)
Wend
If timebreak
ProcedureReturn #False
Else
ProcedureReturn #True
EndIf
EndIf
EndProcedure
Code: Select all
ProcedureDLL AW_WinWaitNotActive2(title.s, timeout)
Protected time = ElapsedMilliseconds() + (timeout * 1000)
Protected timebreak
Protected *param.AW_WinParameter
*param = AW_FindWindow(title)
If *param\hWnd = 0
ProcedureReturn #True ; <---- new
EndIf
While GetForegroundWindow_() = *param\hWnd
If timeout
If ElapsedMilliseconds() > time
timebreak = #True
Break
EndIf
EndIf
Delay(250)
Wend
If timebreak
ProcedureReturn #False
Else
ProcedureReturn #True
EndIf
EndProcedure
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: AutoWin UserLibrary
Sending simulated keystrokes to other programs can be very useful. In this context, time is a critical point, and I often made the experience that a Delay() at proper places in the program is crucial -- depending on the situation maybe before sending the keystrokes, or afterwards, or somewhere inbetween. In simple programs, the Delay() can be hard coded into the PB program. However, for more advanced programs this is not satisfying.
With only small changes in the procedure AW_SendKeys(), we'll get the additional keystroke command {DELAY n}, where n denotes the number of milliseconds. Here is the changed procedure:
Regards, Little John
With only small changes in the procedure AW_SendKeys(), we'll get the additional keystroke command {DELAY n}, where n denotes the number of milliseconds. Here is the changed procedure:
Code: Select all
ProcedureDLL AW_SendKeys (keys.s)
; Sends simulated keystrokes to the active window
Protected r, s, notakey, alted, vk, ctrled, shifted
Protected vk$, s$
For r = 1 To Len(keys)
vk$ = Mid(keys, r, 1)
If vk$ = "{" ; Special key found.
s = FindString(keys, "}", r + 1) - (r + 1) ; Get length of special key.
s$ = Mid(keys, r + 1, s) ; Get special key name.
notakey = #False
Select s$ ; Get virtual key code of special key.
Case "ALTDOWN" : alted = 1 : keybd_event_(#VK_MENU, 0, 0, 0) ; Hold ALT down.
Case "ALTUP" : alted = 0 : keybd_event_(#VK_MENU, 0, #KEYEVENTF_KEYUP, 0) ; Release ALT.
Case "BACKSPACE" : vk = #VK_BACK
Case "CONTROLDOWN" : ctrled = 1 : keybd_event_(#VK_CONTROL, 0, 0, 0) ; Hold CONTROL down.
Case "CONTROLUP" : ctrled = 0 : keybd_event_(#VK_CONTROL, 0, #KEYEVENTF_KEYUP, 0) ; Release CONTROL.
Case "DELETE" : vk = #VK_DELETE
Case "DOWN" : vk = #VK_DOWN
Case "END" : vk = #VK_END
Case "ENTER" : vk = #VK_RETURN
Case "F1" : vk = #VK_F1
Case "F2" : vk = #VK_F2
Case "F3" : vk = #VK_F3
Case "F4" : vk = #VK_F4
Case "F5" : vk = #VK_F5
Case "F6" : vk = #VK_F6
Case "F7" : vk = #VK_F7
Case "F8" : vk = #VK_F8
Case "F9" : vk = #VK_F9
Case "F10" : vk = #VK_F10
Case "F11" : vk = #VK_F11
Case "F12" : vk = #VK_F12
Case "ESCAPE" : vk = #VK_ESCAPE
Case "HOME" : vk = #VK_HOME
Case "INSERT" : vk = #VK_INSERT
Case "LEFT" : vk = #VK_LEFT
Case "PAGEDOWN" : vk = #VK_NEXT
Case "PAGEUP" : vk = #VK_PRIOR
Case "PRINTSCREEN" : vk = #VK_SNAPSHOT
Case "RETURN" : vk = #VK_RETURN
Case "RIGHT" : vk = #VK_RIGHT
Case "SHIFTDOWN" : shifted = 1 : keybd_event_(#VK_SHIFT, 0, 0, 0) ; Hold SHIFT down.
Case "SHIFTUP" : shifted = 0 : keybd_event_(#VK_SHIFT, 0, #KEYEVENTF_KEYUP, 0) ; Release SHIFT.
Case "TAB" : vk = #VK_TAB
Case "UP" : vk = #VK_UP
Default
If Left(s$, 5) = "DELAY" ; ** neu (JL)
Delay(Val(Mid(s$, 6))) ; Führende Leerzeichen stören Val() nicht.
Else
notakey = #True
EndIf
EndSelect
If notakey = #False
If Left(s$, 3) <> "ALT" And Left(s$, 7) <> "CONTROL" And Left(s$, 5) <> "SHIFT" And Left(s$, 5) <> "DELAY"
keybd_event_(vk, 0, 0, 0) : keybd_event_(vk, 0, #KEYEVENTF_KEYUP, 0) ; Press the special key.
EndIf
r = r + s + 1 ; Continue getting the keystrokes that follow the special key.
Else
vk = VkKeyScanEx_(Asc(vk$), GetKeyboardLayout_(0)) ; Normal key found
keybd_event_(vk, 0, 0, 0) : keybd_event_(vk, 0, #KEYEVENTF_KEYUP, 0) ; Press the normal key.
EndIf
Else
vk = VkKeyScanEx_(Asc(vk$), GetKeyboardLayout_(0)) ; Normal key found
If (vk & $0100) <> 0 And shifted = 0 : keybd_event_(#VK_SHIFT, 0, 0, 0) : EndIf ; Due to shifted character.
If (vk & $0200) <> 0 And ctrled = 0 : keybd_event_(#VK_CONTROL, 0, 0, 0) : EndIf
If (vk & $0400) <> 0 And alted = 0 : keybd_event_(#VK_MENU, 0, 0, 0) : EndIf
keybd_event_(vk, 0, 0, 0) : keybd_event_(vk, 0, #KEYEVENTF_KEYUP, 0) ; Press the normal key.
If (vk & $0100) <> 0 And shifted = 0 : keybd_event_(#VK_SHIFT, 0, #KEYEVENTF_KEYUP, 0) : EndIf ; Due to shifted character.
If (vk & $0200) <> 0 And ctrled = 0 : keybd_event_(#VK_CONTROL, 0, #KEYEVENTF_KEYUP, 0) : EndIf
If (vk & $0400) <> 0 And alted = 0 : keybd_event_(#VK_MENU, 0, #KEYEVENTF_KEYUP, 0) : EndIf
EndIf
Next
keybd_event_(#VK_MENU, 0, #KEYEVENTF_KEYUP, 0) ; Release ALT key if user forgot.
keybd_event_(#VK_CONTROL, 0, #KEYEVENTF_KEYUP, 0) ; Release CONTROL key if user forgot.
keybd_event_(#VK_SHIFT, 0, #KEYEVENTF_KEYUP, 0) ; Release SHIFT key if user forgot.
EndProcedure
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: AutoWin UserLibrary
In the help for AW_SendKeys(), {CONTROLUP} is missing.
Re: AutoWin UserLibrary
Okay, i will have a look on this on weekend and integrate your suggest.
Greetings
Thomas
Greetings
Thomas
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Re: AutoWin UserLibrary
@Little John
Have a look at
http://www.purebasic.fr/english/viewtop ... 12&t=47802
I use also the 'newer' SendInput_() instead of the 'older' (maybe deprecated) keybd_event().
Bernd
Have a look at
http://www.purebasic.fr/english/viewtop ... 12&t=47802
I use also the 'newer' SendInput_() instead of the 'older' (maybe deprecated) keybd_event().
Bernd
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: AutoWin UserLibrary
@infratec,
thank you, I'm aware that SendInput_() is now the recommended method for simulating keystrokes. The disadvantage is, that it doesn't work on older systems. It would be best to use both functions, and call them accordingly:
Regards, Little John
thank you, I'm aware that SendInput_() is now the recommended method for simulating keystrokes. The disadvantage is, that it doesn't work on older systems. It would be best to use both functions, and call them accordingly:
Code: Select all
If #PB_Compiler_OS < #PB_OS_Windows_2000
SimulateKeystrokesBy_keybd_event("Hello")
Else
SimulateKeystrokesBy_SendInput("Hello")
EndIf
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
File2PDF
At our office, we often want to share the contents of particular Excel worksheets with some other people (e.g. by copying files into a Dropbox shared folder). In order to avoid confusion, we don't want them to change the contents of the respective Excel files -- so we give them the data in the form of PDF files.
Doing this over and over again every day is just boring. So I wrote a little AutoWin "script" that does the job. The prerequisite is, that the program PDFCreator is installed.
The code sends simulated keystrokes to German GUIs, in other languages other keys must be sent, and also some window titles will be different (see comments in the code).
With small adjustments, the program also works with other programs than Excel. Maybe it's useful for someone else, too.
Regards, Little John
//edit 2012-05-05: Code slightly improved.
Doing this over and over again every day is just boring. So I wrote a little AutoWin "script" that does the job. The prerequisite is, that the program PDFCreator is installed.
The code sends simulated keystrokes to German GUIs, in other languages other keys must be sent, and also some window titles will be different (see comments in the code).
Code: Select all
EnableExplicit
XIncludeFile <path> + "AutoWin_Include.pbi"
Procedure.s rExtract (source$, s$)
; returns all characters of source$ from 1 to the
; RIGHTMOST position of s$.
Protected p, sLen
sLen = Len(s$)
For p = Len(source$)-sLen+1 To 1 Step -1
If Mid(source$, p, sLen) = s$
ProcedureReturn Left(source$, p-1)
EndIf
Next
ProcedureReturn source$
EndProcedure
;-- Initialise
#ProgName$ = "File2PDF"
#ProgVersion$ = #ProgName$ + " 0.60"
#PdfPrinter$ = "PDFCreator"
AW_ChangeMatchMode(#AW_MatchAnySubString)
Define InFile$, InFileName$, OutDir$, OutFile$, Msg$
InFile$ = ProgramParameter(0)
OutDir$ = ProgramParameter(1)
;-- Check InFile$ and OutDir$
If InFile$ = "" Or OutDir$ = ""
Msg$ + "Usage: " + #ProgName$ + " <input file> <output directory> [/auto]" + #LF$
Msg$ + #LF$
Msg$ + "( " + #DQUOTE$ + RTrim(#PdfPrinter$) + #DQUOTE$ + " must be installed on the system. )"
MessageRequester(#ProgVersion$, Msg$)
End
EndIf
If FileSize(InFile$) < 0
MessageRequester(#ProgVersion$, "Input file '" + InFile$ + "' not found.")
End
EndIf
If FileSize(OutDir$) > -2
MessageRequester(#ProgVersion$, "Output directory '" + OutDir$ + "' not found.")
End
EndIf
;-- Get file part of input file, and create name of output file
InFileName$ = rExtract(GetFilePart(InFile$), ".")
If (OutDir$ <> "") And (Right(OutDir$, 1) <> "\")
OutDir$ + "\"
EndIf
OutFile$ = OutDir$ + InFileName$
;-- Prompt the user if required
If ProgramParameter(2) <> "/auto"
Msg$ = " Convert" + #LF$ + InFile$ + #LF$ + " to" + #LF$ + OutFile$ + ".pdf ?"
If MessageRequester(#ProgVersion$, Msg$, #PB_MessageRequester_YesNo) = #PB_MessageRequester_No
End
EndIf
EndIf
;-- Open input file with associated program
RunProgram(InFile$)
If AW_WinWaitActive(InFileName$, 30) = 0
MessageRequester(#ProgVersion$, "Error opening '" + InFile$ + "'.")
End
EndIf
;-- Type CTRL+p, and wait for the "Print" dialog become active
AW_SendKeys("{CONTROLDOWN}p{CONTROLUP}")
AW_WinWaitActive("Drucken")
;-- Start PDFCreator (*only* printer in the list here that begins with "p")
AW_SendKeys("{ALTDOWN}m{ALTUP}p{ENTER}{ENTER}") ; Excel
; AW_SendKeys("{ALTDOWN}d{ALTUP}p{ENTER}") ; Planmaker
;-- Wait for PDFCreator window become active
If AW_WinWaitActive(#PdfPrinter$, 30) = 0
MessageRequester(#ProgVersion$, "Printer '" + #PdfPrinter$ + "' not found.")
End
EndIf
;-- Close PDFCreator window and start printing
AW_SendKeys("{ENTER}")
;-- Wait for the "Save as" dialog become active
AW_WinWaitActive("Speichern unter")
;-- Save the file
AW_SendKeys(OutFile$)
AW_SendKeys("{ENTER}{ALTDOWN}j{ALTUP}") ; Overwrite? > "Yes"
;-- Give focus again to window with input file, then close it
If AW_WinActivate(InfileName$)
AW_SendKeys("{ALTDOWN}{F4}{ALTUP}")
EndIf
Regards, Little John
//edit 2012-05-05: Code slightly improved.
Last edited by Little John on Sat May 05, 2012 8:58 am, edited 1 time in total.
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: AutoWin UserLibrary
Hi Thomas,
the procedure AW_WinWaitActive2() does not work as I would expect it to do.
For instance, the following AutoIt program runs without an error (on a German Windows version):
Using PureBasic and the AutoWin library, the code looks like this:
This code snippet launches Notepad, and then immediately ends with the "Timeout" error message. It neither sends the wanted text to Notepad nor waits 30 seconds.
Looking at the current (AutoWin version 1.3) source code of AW_WinWaitActive2() explains why the procedure behaves this way:
I'd suggest to change the procedure like this:
This code works for me as expected.
(This is also the code which is used by the program in my previous post -- unfortunately I forgot to mention that.)
Regards, Little John
the procedure AW_WinWaitActive2() does not work as I would expect it to do.
For instance, the following AutoIt program runs without an error (on a German Windows version):
Code: Select all
ShellExecute("C:\Windows\notepad.exe")
If WinWaitActive("Unbenannt - Editor", "", 30) Then
Send("Hello World")
Else
MsgBox(0, "Error", "Timeout")
EndIf
Code: Select all
XIncludeFile <path> + "AutoWin_Include.pbi"
RunProgram("C:\Windows\notepad.exe")
If AW_WinWaitActive("Unbenannt - Editor", 30)
AW_SendKeys("Hello World")
Else
MessageRequester("Error", "Timeout")
EndIf
Looking at the current (AutoWin version 1.3) source code of AW_WinWaitActive2() explains why the procedure behaves this way:
Code: Select all
ProcedureDLL AW_WinWaitActive2(title.s, timeout)
Protected time = ElapsedMilliseconds() + (timeout * 1000)
Protected timebreak
Protected *param.AW_WinParameter
*param = AW_FindWindow(title)
If *param\hWnd
While GetForegroundWindow_() <> *param\hWnd
If timeout
If ElapsedMilliseconds() > time
timebreak = #True
Break
EndIf
EndIf
Delay(250)
Wend
If timebreak
ProcedureReturn #False
Else
ProcedureReturn #True
EndIf
EndIf
EndProcedure
Code: Select all
ProcedureDLL.i AW_WinWaitActive2 (title.s, timeoutSec)
; Pauses execution of the program until the requested window is active
Protected endTime, timebreak=#False
Protected *param.AW_WinParameter
endTime = ElapsedMilliseconds() + timeoutSec*1000
*param = AW_FindWindow(title)
While *param\hWnd <> GetForegroundWindow_()
If (timeoutSec > 0) And (ElapsedMilliseconds() > endTime)
timebreak = #True
Break
EndIf
Delay(250)
*param = AW_FindWindow(title)
Wend
If timebreak
ProcedureReturn 0
Else
ProcedureReturn *param\hWnd
EndIf
EndProcedure
(This is also the code which is used by the program in my previous post -- unfortunately I forgot to mention that.)
Regards, Little John
Re: AutoWin UserLibrary
Hallo Jürgen,
Update: Version 1.4
added all suggestions by Little John
Userlib update to work with PB4.60
The helpfile is untouched, i will update this in a later release.
Greetings
Thomas
Update: Version 1.4
added all suggestions by Little John
Userlib update to work with PB4.60
The helpfile is untouched, i will update this in a later release.
Greetings
Thomas
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: AutoWin UserLibrary
Thank you, Thomas.
Good night from Neukölln to Wedding.
Good night from Neukölln to Wedding.
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: AutoWin UserLibrary
Hello Thomas,
I think there is a bug in the procedure AW_FindWindow() -- also in the current version 1.4 -- when a window handle is passed as parameter.
The first following code runs as expected, that means after closing the window, hWnd will be 0. The second code still shows the same hWnd as before, even when the respective window does not exist anymore.
The problem is, that in the second example the procedure AW_FindWindow() just returns the handle that has been passed as parameter ... it does not actually search whether or not that window does exist.
I think the procdure should look somehow like this:
Best regards, Jürgen
I think there is a bug in the procedure AW_FindWindow() -- also in the current version 1.4 -- when a window handle is passed as parameter.
The first following code runs as expected, that means after closing the window, hWnd will be 0. The second code still shows the same hWnd as before, even when the respective window does not exist anymore.
Code: Select all
XIncludeFile #PB_Compiler_FilePath + "AutoWin_Include.pbi"
Define *param.AW_WinParameter, hWnd
Define msg$
hWnd = OpenWindow(0, 50, 50, 200, 100, "MyWindow")
*param = AW_FindWindow("MyWindow")
msg$ = Str(*param\hWnd) + #LF$
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
CloseWindow(0)
*param = AW_FindWindow("MyWindow")
msg$ + Str(*param\hWnd)
MessageRequester("Test", msg$)
Code: Select all
XIncludeFile #PB_Compiler_FilePath + "AutoWin_Include.pbi"
Define *param.AW_WinParameter, hWnd
Define msg$
hWnd = OpenWindow(0, 50, 50, 200, 100, "MyWindow")
*param = AW_FindWindow("MyWindow")
msg$ = Str(*param\hWnd) + #LF$
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
CloseWindow(0)
AW_ChangeMatchMode(#AW_MatchParaIsHwnd)
*param = AW_FindWindow(Str(hWnd))
msg$ + Str(*param\hWnd)
MessageRequester("Test", msg$)
I think the procdure should look somehow like this:
Code: Select all
Procedure AW_FindWindow (title.s)
Static param.AW_WinParameter
Protected hWnd, text.s{260}
ClearStructure(@param, AW_WinParameter)
If AW_MatchMode = #AW_MatchParaIsHwnd
hWnd = Val(title)
If IsWindow_(hWnd)
GetWindowText_(hWnd, @text, 260)
param\hWnd = hWnd
param\Title = text
EndIf
Else
param\Title = title
EnumWindows_(@AW_EnumWindowsProc(), @param)
EndIf
ProcedureReturn @param
EndProcedure
Re: AutoWin UserLibrary
Thx for bugreport. Download the fixed version in first post!
PS: AW_FindWindow is not a public function
Greetings - Thomas
PS: AW_FindWindow is not a public function
Greetings - Thomas
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.