Jump to content
Sign in to follow this  
dickep

.Net and checkbox

Recommended Posts

dickep

I have tried the DotNetIdentification.au3 UDF to figure out if a checkbox is checked or not. However, I am not having any luck.

I can get the control ID but the status does not seem to want to come in.

What command can I use with the DotNetIdentification tool to get the actual checked/unchecked status?

Thanks

E

Share this post


Link to post
Share on other sites
zfisherdrums

I have tried the DotNetIdentification.au3 UDF to figure out if a checkbox is checked or not. However, I am not having any luck.

I can get the control ID but the status does not seem to want to come in.

What command can I use with the DotNetIdentification tool to get the actual checked/unchecked status?

Thanks

E

The functions contained within DotNetIdentification.au3 were written ( well, actually, I ported ) to allow one to retrieve the control ID only. From there, the user can pass the control ID to the native AutoIt functions, e.g. ControlClick, ControlCommand, etc.

That the check box does not return a checked/unchecked status is not surprising. It depends if the control responds to that particular message, which I can't guarantee on this side of the conversation. Could you supply your script so I can see what you're doing.

Zach Fisher...

Share this post


Link to post
Share on other sites
dickep

The functions contained within DotNetIdentification.au3 were written ( well, actually, I ported ) to allow one to retrieve the control ID only. From there, the user can pass the control ID to the native AutoIt functions, e.g. ControlClick, ControlCommand, etc.

That the check box does not return a checked/unchecked status is not surprising. It depends if the control responds to that particular message, which I can't guarantee on this side of the conversation. Could you supply your script so I can see what you're doing.

Zach Fisher...

Here is a snippet of what I am trying to do. Just not getting what I thought it should return

Again, thanks for your tool

$control = NET_ControlGetHandleByName("Power Saver Advanced","",$label)
    $temp = ControlCommand("Power Saver Advanced","",$control,"UnCheck","")
    MsgBox(0,$temp,$control)

Share this post


Link to post
Share on other sites
susall

Here is a snippet of what I am trying to do. Just not getting what I thought it should return

Again, thanks for your tool

$control = NET_ControlGetHandleByName("Power Saver Advanced","",$label)
    $temp = ControlCommand("Power Saver Advanced","",$control,"UnCheck","")
    MsgBox(0,$temp,$control)
We're seeing the same issue here. I'd be interested in knowing if this is a bug in AutoIT3 and if there is a workaround.

-su

Share this post


Link to post
Share on other sites
zfisherdrums

We're seeing the same issue here. I'd be interested in knowing if this is a bug in AutoIT3 and if there is a workaround.

-su

Short Story: It appears that the Check and UnCheck control commands initially query the control to determine its current state. If the current state is equal to the desired state, then no further action is taken. When queried for status, a WinForms ( .NET ) checkbox does not return a valid result; it is always 0x0 ( which appears to correspond to "unchecked" ). That is probably why consecutive calls to Check will cause the .NET control to alternate between check and unchecked, and conversely why no action is ever taken when UnCheck is called.

As AutoIt has never claimed to fully support controls of the WinForms variety, it stands to reason that this is not an error on AutoIT's part. So what to do?

One workaround off the top of my head is to use Pixel commands to determine if the check mark is present in the control's display. However, this approach could be problematic if the control was hidden or obscured by other windows; standard defensive coding practices apply.

Edited by zfisherdrums

Share this post


Link to post
Share on other sites
zfisherdrums

Long Story:

Using .Reflector against the WinForm class definition for Checkbox appears to confirm that at no point in the WndProc routines in the inheritance chain - is there a case that handles a mesage of "0xf0". That seems somewhat odd as the result from this message appears to provide the checked state of the control. Yes, I am aware of the checked property, but I believe I'd have to do some heavy duty process injection to obtain said properties from WinForms while in the context of AutoIT. Perhaps this lack of message handling is an oversight of the Framework designers or was allowed for reasons beyond my current comprehension. Either way, a workaround is provided in the following post.

Below are tests conducted against a custom .NET control to determine which messages are being sent from the control's perspective. Commented below the commands are the console outs from the control and from AutoIt. I place this here in the hopes that others may get ideas into how they might troubleshoot ( what might appear to be ) AutoIt failures.

Custom .NET Checkbox C# Code ( for Test 1 and 2 )

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace TestApp
{
    public class MyCheckbox : CheckBox 
    {
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            Console.WriteLine(DateTime.Now.ToString("hh:mm:ss") + "\t" + m.ToString());
        }
    }
}

Test 1 : IsChecked Command against .NET control ( Checkbox initally unchecked )

Dim $checkbox = NET_ControlGetHandleByName( "TestApp", "", "checkbox1" )
;~  01:09:59    msg=0xc1c1 hwnd=0x40692 wparam=0x400 lparam=0x3fe0000 result=0xa
;~  @@ Debug(5) : $checkbox  = 0x00040692
;~  >Error code: 0

ControlFocus( "TestApp", "", $checkbox )
;~  01:10:01    msg=0x0 (WM_NULL) hwnd=0x40692 wparam=0x0 lparam=0x0 result=0x0
;~  01:10:01    msg=0xe (WM_GETTEXTLENGTH) hwnd=0x40692 wparam=0x0 lparam=0x0 result=0x8
;~  01:10:01    msg=0xd (WM_GETTEXT) hwnd=0x40692 wparam=0x9 lparam=0x1db4b8 result=0x8
;~  01:10:01    msg=0x202b (WM_REFLECT + WM_DRAWITEM) hwnd=0x40692 wparam=0x40692 lparam=0x3e5e330 result=0x0
;~  01:10:01    msg=0x7 (WM_SETFOCUS) hwnd=0x40692 wparam=0x1c0684 lparam=0x0 result=0x0
;~  01:10:01    msg=0xf (WM_PAINT) hwnd=0x40692 wparam=0x0 lparam=0x0 result=0x0

Dim $status = ControlCommand( "TestApp", "", $checkbox, "IsChecked", "" )
;~  01:10:03    msg=0xf0 hwnd=0x40692 wparam=0x0 lparam=0x0 result=0x0   <--- observe the result. This is accidentally correct.
;~  @@ Debug(12) : $status = 0
;~  >Error code: 0

Test 2: IsChecked Command against .NET control ( Checkbox initally checked )

Dim $checkbox = NET_ControlGetHandleByName( "TestApp", "", "checkbox1" )
;~  01:12:06    msg=0xc1c1 hwnd=0x40692 wparam=0x400 lparam=0x3ff0000 result=0xa
;~  @@ Debug(5) : $checkbox  = 0x00040692
;~  >Error code: 0

ControlFocus( "TestApp", "", $checkbox )
;~  01:12:08    msg=0x0 (WM_NULL) hwnd=0x40692 wparam=0x0 lparam=0x0 result=0x0
;~  01:12:08    msg=0xe (WM_GETTEXTLENGTH) hwnd=0x40692 wparam=0x0 lparam=0x0 result=0x8
;~  01:12:08    msg=0xd (WM_GETTEXT) hwnd=0x40692 wparam=0x9 lparam=0x1db418 result=0x8
;~  01:12:08    msg=0x202b (WM_REFLECT + WM_DRAWITEM) hwnd=0x40692 wparam=0x40692 lparam=0x3e5e330 result=0x0
;~  01:12:08    msg=0x7 (WM_SETFOCUS) hwnd=0x40692 wparam=0xa0688 lparam=0x0 result=0x0
;~  01:12:08    msg=0xf (WM_PAINT) hwnd=0x40692 wparam=0x0 lparam=0x0 result=0x0

Dim $status = ControlCommand( "TestApp", "", $checkbox, "IsChecked", "" )
;~  01:12:10    msg=0xf0 hwnd=0x40692 wparam=0x0 lparam=0x0 result=0x0   <--- observe the result; Message is not being handled as expected
;~  @@ Debug(12) : $status = 0
;~  >Error code: 0

Custom .NET Checkbox C# Code ( for Test 3 )

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace TestApp
{
    public class MyCheckbox : CheckBox 
    {
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0xf0)
            {
                Console.WriteLine("---Interception!---");
                m.Result = this.Checked ? new IntPtr(1) : IntPtr.Zero;
            }
            else
            {
                base.WndProc(ref m);
            }
 
            Console.WriteLine(DateTime.Now.ToString("hh:mm:ss") + "\t" + m.ToString());
        }
    }
}

Test 3: IsChecked Command against .NET control ( Checkbox initally unchecked, IsChecked message is intercepted in the override WndProc )

Dim $checkbox = NET_ControlGetHandleByName( "TestApp", "", "checkbox1" )
;~  01:16:48    msg=0xc1c1 hwnd=0x90602 wparam=0x400 lparam=0x3ff0000 result=0xa
;~  @@ Debug(5) : $checkbox  = 0x00090602
;~  >Error code: 0

ControlFocus( "TestApp", "", $checkbox )
;~  01:16:50    msg=0x0 (WM_NULL) hwnd=0x90602 wparam=0x0 lparam=0x0 result=0x0
;~  01:16:50    msg=0xe (WM_GETTEXTLENGTH) hwnd=0x90602 wparam=0x0 lparam=0x0 result=0x8
;~  01:16:50    msg=0xd (WM_GETTEXT) hwnd=0x90602 wparam=0x9 lparam=0x1db418 result=0x8
;~  01:16:50    msg=0x202b (WM_REFLECT + WM_DRAWITEM) hwnd=0x90602 wparam=0x90602 lparam=0x3e5e32c result=0x0
;~  01:16:50    msg=0x7 (WM_SETFOCUS) hwnd=0x90602 wparam=0x7069e lparam=0x0 result=0x0
;~  01:16:50    msg=0xf (WM_PAINT) hwnd=0x90602 wparam=0x0 lparam=0x0 result=0x0

Dim $status = ControlCommand( "TestApp", "", $checkbox, "IsChecked", "" )
;~  ---Interception!---
;~  01:16:52    msg=0xf0 hwnd=0x90602 wparam=0x0 lparam=0x0 result=0x0   <--- observe the result. This is correct
;~  @@ Debug(12) : $status = 0
;~  >Error code: 0

Dim $status2 = ControlCommand( "TestApp", "", $checkbox, "Check", "" )
;~  ---Interception!---
;~  01:16:54    msg=0xf0 hwnd=0x90602 wparam=0x0 lparam=0x0 result=0x0   <--- observe the result. This is correct
;~  01:16:54    msg=0x201 (WM_LBUTTONDOWN) hwnd=0x90602 wparam=0x1 lparam=0x80025 result=0x0
;~  01:16:54    msg=0x84 (WM_NCHITTEST) hwnd=0x90602 wparam=0x0 lparam=0x690187 result=0x1
;~  01:16:54    msg=0xf (WM_PAINT) hwnd=0x90602 wparam=0x0 lparam=0x0 result=0x0
;~  01:16:54    msg=0xf1 hwnd=0x90602 wparam=0x1 lparam=0x0 result=0x0
;~  01:16:54    msg=0x14 (WM_ERASEBKGND) hwnd=0x90602 wparam=0x6901111e lparam=0x0 result=0x1
;~  01:16:54    msg=0xf (WM_PAINT) hwnd=0x90602 wparam=0x0 lparam=0x0 result=0x0
;~  01:16:54    msg=0x215 (WM_CAPTURECHANGED) hwnd=0x90602 wparam=0x0 lparam=0x0 result=0x0
;~  01:16:54    msg=0x202 (WM_LBUTTONUP) hwnd=0x90602 wparam=0x0 lparam=0x80025 result=0x0
;~  @@ Debug(17) : $status2 = 0
;~  >Error code: 0

Dim $status3 = ControlCommand( "TestApp", "", $checkbox, "IsChecked", "" )
;~  ---Interception!---
;~  01:16:56    msg=0xf0 hwnd=0x90602 wparam=0x0 lparam=0x0 result=0x1   <--- observe the result. This is our expected result.
;~  @@ Debug(22) : $status3  = 1
;~  >Error code: 0
Edited by zfisherdrums

Share this post


Link to post
Share on other sites
zfisherdrums

Here is a snippet of what I am trying to do. Just not getting what I thought it should return

Again, thanks for your tool

$control = NET_ControlGetHandleByName("Power Saver Advanced","",$label)
    $temp = ControlCommand("Power Saver Advanced","",$control,"UnCheck","")
    MsgBox(0,$temp,$control)
Here's a workaround. Give it a try and let me know if it works out:

Opt( "PixelCoordMode", 2 )

Dim $control = NET_ControlGetHandleByName("Power Saver Advanced","",$label)
Dim $hWnd = WinGetHandle( "Power Saver Advanced" )
Dim $pos = ControlGetPos( "Power Saver Advanced", "", $control )
Dim $IsChecked = ( Hex( PixelGetColor( $pos[0] + 6, $pos[1] + 9, $hWnd ), 6 ) = Hex(0,6)); Get the pixel color inside the checkbox itself

If $IsChecked Then ControlCommand("Power Saver Advanced","",$control,"Check","")

This will fail if the checkbox is obscured or is off screen.

Edited by zfisherdrums

Share this post


Link to post
Share on other sites
dickep

Here's a workaround. Give it a try and let me know if it works out:

Opt( "PixelCoordMode", 2 )

Dim $control = NET_ControlGetHandleByName("Power Saver Advanced","",$label)
Dim $hWnd = WinGetHandle( "Power Saver Advanced" )
Dim $pos = ControlGetPos( "Power Saver Advanced", "", $control )
Dim $IsChecked = ( Hex( PixelGetColor( $pos[0] + 6, $pos[1] + 9, $hWnd ), 6 ) = Hex(0,6)); Get the pixel color inside the checkbox itself

If $IsChecked Then ControlCommand("Power Saver Advanced","",$control,"Check","")

This will fail if the checkbox is obscured or is off screen.

I have been trying to do this and put in some message boxes to see what is happening.

$IsChecked is FALSE when it is either checked or unchecked.

$pos data I need to know how to map the display to see where it is finding the $control and I do not know how to do that.

So, my testing is inconclusive but leaning towards not doing what I need yet.

Thanks.

Edited by dickep

Share this post


Link to post
Share on other sites
zfisherdrums

I have been trying to do this and put in some message boxes to see what is happening.

$IsChecked is FALSE when it is either checked or unchecked.

$pos data I need to know how to map the display to see where it is finding the $control and I do not know how to do that.

So, my testing is inconclusive but leaning towards not doing what I need yet.

Thanks.

Use the Window Info Tool with these settings:

Options -> Freeze (On)

Options -> Coord Mode -> Window

Options -> Color Mode -> RGB

Options -> Magnify (On)

Drag the Finder Tool over the checkbox and line the crosshairs up with the check inside the checkbox.

Make note of the values under Control Tab: ControlClick Coords. Use these as offsets in PixelGetColor.

In my example, the offsets are 6 and 9.

It is possible that these offsets will be different if the control is custom or rendered in a special way.

One thing that helped me as well was to get the colors for each pixel in the control's region. I would

output this to console or clipboard and paste it into Excel. Then I'd adjust the cells so that they were

square, then zoom out to 40% or less. This gave me a map of the control that I could "deal with" and

determining the target pixel was as easy as counting the columns and rows ( starting at 0 for each ).

Here's a quick script that will place the pixel color info in your clipboard. Hope any of this helps.

Opt( "PixelCoordMode", 2 )

Dim $appTitle = "Form1"
Dim $appControl = "Button1"
Dim $pos = ControlGetPos( $appTitle, "", $appControl )
Dim $hwnd = WinGetHandle( $appTitle )
Dim $output = ""

WinActivate( $appTitle )

For $i = 0 to $pos[3]
    For $j = 0 to $pos[2]
        Dim $hexColor = Hex( PixelGetColor( $pos[0] + $j, $pos[1] + $i, $hwnd ), 6 )
        $output &= ( $hexColor & @TAB )
    Next 
    $output &= @CRLF 
Next

ClipPut( $output )

MsgBox(0, @ScriptName, "Done!")
Edited by zfisherdrums

Share this post


Link to post
Share on other sites
dickep

Use the Window Info Tool with these settings:

Options -> Freeze (On)

Options -> Coord Mode -> Window

Options -> Color Mode -> RGB

Options -> Magnify (On)

Drag the Finder Tool over the checkbox and line the crosshairs up with the check inside the checkbox.

Make note of the values under Control Tab: ControlClick Coords. Use these as offsets in PixelGetColor.

In my example, the offsets are 6 and 9.

It is possible that these offsets will be different if the control is custom or rendered in a special way.

One thing that helped me as well was to get the colors for each pixel in the control's region. I would

output this to console or clipboard and paste it into Excel. Then I'd adjust the cells so that they were

square, then zoom out to 40% or less. This gave me a map of the control that I could "deal with" and

determining the target pixel was as easy as counting the columns and rows ( starting at 0 for each ).

Here's a quick script that will place the pixel color info in your clipboard. Hope any of this helps.

Opt( "PixelCoordMode", 2 )

Dim $appTitle = "Form1"
Dim $appControl = "Button1"
Dim $pos = ControlGetPos( $appTitle, "", $appControl )
Dim $hwnd = WinGetHandle( $appTitle )
Dim $output = ""

WinActivate( $appTitle )

For $i = 0 to $pos[3]
    For $j = 0 to $pos[2]
        Dim $hexColor = Hex( PixelGetColor( $pos[0] + $j, $pos[1] + $i, $hwnd ), 6 )
        $output &= ( $hexColor & @TAB )
    Next 
    $output &= @CRLF 
Next

ClipPut( $output )

MsgBox(0, @ScriptName, "Done!")
I tried putting this in and now am getting a compile error "subscript used with non-Array variable:" and it points to $pos. What??

thanks

Share this post


Link to post
Share on other sites
zfisherdrums

I tried putting this in and now am getting a compile error "subscript used with non-Array variable:" and it points to $pos. What??

thanks

$appTitle and $appControl need to point to your application window and the checkbox control respectively. If that is not the issue, could you please post your version of the code? Thanks!

Zach...

Share this post


Link to post
Share on other sites
dickep

$appTitle and $appControl need to point to your application window and the checkbox control respectively. If that is not the issue, could you please post your version of the code? Thanks!

Zach...

I guess I was not clear. The error I described was using your "utility". It says that $pos is NOT an array. But, it is populated by the ControlGetPos which is supposed to bring up an array.

Yes, my $appTitle and $appControl does point to the application/window that is open and in focus.

I also tried this using the example from the help file and got the same error/result.

So, what am I now missing to get this working to try it out? I am stumped.

THanks

P.S. here is my code that I modified from your example

Opt("PixelCoordMode", 2)

Dim $appTitle = "Power Saver Advanced"
Dim $appControl = "checkBoxOOpenLid"
Dim $pos = ControlGetPos($appTitle, "", $appControl)
dim $hWnd = WinGetHandle($appTitle)
Dim $output = ""

WinActivate($appTitle)

for $i = 0 to $pos[3]
    for $j = 0 to $pos[2]
        Dim $hexColor = Hex( PixelGetColor( $pos[0] + $j, $pos[1] +$i,$hWnd), 6)
        $output &= ($hexColor & @TAB)
    Next
    $output &= @CRLF
Next

ClipPut( $output )

MsgBox(9,@ScriptName, "Done!")
Edited by dickep

Share this post


Link to post
Share on other sites
zfisherdrums

Try this:

Opt("PixelCoordMode", 2)

Dim $appTitle = "Power Saver Advanced"
Dim $appControl = NET_ControlGetHandleByName("Power Saver Advanced","","checkBoxOOpenLid")
Dim $pos = ControlGetPos($appTitle, "", $appControl)
dim $hWnd = WinGetHandle($appTitle)
Dim $output = ""

WinActivate($appTitle)

for $i = 0 to $pos[3]
    for $j = 0 to $pos[2]
        Dim $hexColor = Hex( PixelGetColor( $pos[0] + $j, $pos[1] +$i,$hWnd), 6)
        $output &= ($hexColor & @TAB)
    Next
    $output &= @CRLF
Next

ClipPut( $output )

MsgBox(9,@ScriptName, "Done!")

Share this post


Link to post
Share on other sites
dickep

I tried your newly revised code and now the error is not there.

However, I am not getting what I expected.

Upon finishing, I put the data into an Excel spreadsheet and it is ALL FFFFFF in all cells.

I tried hard coding a value for the x and y spots starting with 100 in each and get the bottom part of the desktop and the taskbar.

So, I am confused on PixelGetColor and what it really does (or in this case, does not do). Or is it me - probably more than AutoIt

Thanks.

Share this post


Link to post
Share on other sites
zfisherdrums

I tried your newly revised code and now the error is not there.

However, I am not getting what I expected.

Upon finishing, I put the data into an Excel spreadsheet and it is ALL FFFFFF in all cells.

I tried hard coding a value for the x and y spots starting with 100 in each and get the bottom part of the desktop and the taskbar.

So, I am confused on PixelGetColor and what it really does (or in this case, does not do). Or is it me - probably more than AutoIt

Thanks.

Okay, so here's what we know:

1 - Your installation of AutoIt is functioning correctly

2 - The calls to the .NET control appear to be valid because the ControlGetPos call returns a valid array.

3 - All "0xFFFFFF" values leads me to believe that the coordinates are not being interpreted correctly OR that the control is obscured by another window.

PixelGetColor is a function that allows one to obtain the color of a pixel in a specific area of the screen. The script I sent you breaks down like this:

1 - Get the handle for the .NET Checkbox

2 - Obtain the control's coordinates

3 - Get all the color values from all pixels inside the area of the control, placing them into the clipboard

My desire was to obtain a kind a proof that the control handle is valid and that we can inspect its state via pixel colors ( very fragile, but can work ).

If I may ask, what GUICoordMode option are you using?

Share this post


Link to post
Share on other sites
dickep

Okay, so here's what we know:

1 - Your installation of AutoIt is functioning correctly

2 - The calls to the .NET control appear to be valid because the ControlGetPos call returns a valid array.

3 - All "0xFFFFFF" values leads me to believe that the coordinates are not being interpreted correctly OR that the control is obscured by another window.

PixelGetColor is a function that allows one to obtain the color of a pixel in a specific area of the screen. The script I sent you breaks down like this:

1 - Get the handle for the .NET Checkbox

2 - Obtain the control's coordinates

3 - Get all the color values from all pixels inside the area of the control, placing them into the clipboard

My desire was to obtain a kind a proof that the control handle is valid and that we can inspect its state via pixel colors ( very fragile, but can work ).

If I may ask, what GUICoordMode option are you using?

Thanks again for your perseverance with this - I really appreciate it.

I just copied your script as is. So, I did not set the GUICoordMode - suppose it is in the default.

I did try MouseCoordMode of 0 and 2 but got the same result.

I also tried this on the Power Meter window. I could not get it to focus on it so got the background in the coords it was showing.

I put in a MouseMove so that I could see where it was getting the pixel. the mousemove tracked the same coords as the pixelGetColor but got only F's.

One more test I just did and got the text BEHIND the window. I use WinActivate for the window, but it does not seem to be in the front. suggestions???

So, I am not sure what to do now.

Thanks.

Edited by dickep

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.