jarmo / RAutomation

RAutomation
MIT License
100 stars 33 forks source link

ButtonHelper.set? always returns false #32

Closed leviwilson closed 11 years ago

leviwilson commented 11 years ago

I've pulled the latest sources and am running them on Windows 7. It looks like everything that uses ButtonHelper.set? is failing as BM_GETSTATE is always returning 0 (according to Spy). Here is my output from rake (only the fail information):

Failures:

  1) RAutomation::Window#activate & #active?
     Failure/Error: window.should be_active
       expected active? to return true, got false
     # ./spec/window_spec.rb:69:in `block (2 levels) in <top (required)>'

  2) Win32::Checkbox#set? & #set
     Failure/Error: checkbox.set
     RAutomation::WaitHelper::TimeoutError:
       timed out after 15 seconds
     # ./lib/rautomation/wait_helper.rb:20:in `wait_until'
     # ./lib/rautomation/adapter/win_32/control.rb:33:in `click'
     # ./lib/rautomation/adapter/win_32/button_helper.rb:18:in `set'
     # ./spec/adapter/win_32/checkbox_spec.rb:16:in `block (2 levels) in <top (required)>'

  3) Win32::Checkbox#clear
     Failure/Error: checkbox.set
     RAutomation::WaitHelper::TimeoutError:
       timed out after 15 seconds
     # ./lib/rautomation/wait_helper.rb:20:in `wait_until'
     # ./lib/rautomation/adapter/win_32/control.rb:33:in `click'
     # ./lib/rautomation/adapter/win_32/button_helper.rb:18:in `set'
     # ./spec/adapter/win_32/checkbox_spec.rb:27:in `block (2 levels) in <top (required)>'

  4) Win32::RadioButton#set? & #set
     Failure/Error: radio.set
     RAutomation::WaitHelper::TimeoutError:
       timed out after 15 seconds
     # ./lib/rautomation/wait_helper.rb:20:in `wait_until'
     # ./lib/rautomation/adapter/win_32/control.rb:33:in `click'
     # ./lib/rautomation/adapter/win_32/button_helper.rb:18:in `set'
     # ./spec/adapter/win_32/radio_spec.rb:17:in `block (2 levels) in <top (required)>'

Finished in 2 minutes 17.41 seconds
85 examples, 4 failures

Failed examples:

rspec ./spec/window_spec.rb:66 # RAutomation::Window#activate & #active?
rspec ./spec/adapter/win_32/checkbox_spec.rb:12 # Win32::Checkbox#set? & #set
rspec ./spec/adapter/win_32/checkbox_spec.rb:25 # Win32::Checkbox#clear
rspec ./spec/adapter/win_32/radio_spec.rb:13 # Win32::RadioButton#set? & #set
enkessler commented 11 years ago

Yep, that sounds about right. I looked into it some months back and never could figure out why it was always returning 0. The MsUia adapter should be good to go though if you don't have a particular need to use the Win32 one.

leviwilson commented 11 years ago

I don't have a problem using MsUia. Wanted to make sure I wasn't crazy that the specs were not passing :-) This post talks about the problem that I'm seeing as well. I'll keep digging to see if there's an alternative way to get this using Win32.

enkessler commented 11 years ago

That post also supposedly found a solution and posted it. I'll have to try it out later unless you want to beat me to it. I've got a few deadlines that will keep me from doing it for about a week otherwise. Thanks for the research.

leviwilson commented 11 years ago

Yeah, it looked like the solution was to go through IAccessible, which it looks like it is already using. I'll poke around some more.

jarmo commented 11 years ago

I have to chime in by saying that i have investigated this problem too in the past and couldn't figure out the reason behind it. It would be awesome if we could solve this problem at last!

leviwilson commented 11 years ago

I messed around with it a lot last night but to no avail. I added debug messages to IAccessibleDLL.dll to see what was going on, but could not gather info about the checked state :-( The focus would be returned in the get_accState result, but not the STATE_SYSTEM_CHECKED flag.

I noticed that the HMODULE is not being freed and neither is the IAccessible * in that method, but fixing that had no effect (not that I thought it would).

__declspec( dllexport ) long get_button_state(HWND buttonHwnd) {
  HMODULE hModule = LoadLibraryA("oleacc.dll");
  LPFNACCESSIBLEOBJECTFROMWINDOW lpfnAccessibleObjectFromWindow = (LPFNACCESSIBLEOBJECTFROMWINDOW)GetProcAddress(hModule, "AccessibleObjectFromWindow");

  IAccessible   *pIAccessible ;
  HRESULT hr = lpfnAccessibleObjectFromWindow(buttonHwnd, OBJID_CLIENT, IID_IAccessible, (void**)&pIAccessible) ;

  VARIANT varChildId;
  VariantInit(&varChildId);
  varChildId.vt = VT_I4;
  varChildId.lVal = CHILDID_SELF ;

  VARIANT varState;
  pIAccessible->get_accState(varChildId, &varState);

  FreeLibrary(hModule);
  pIAccessible->Release();

  return varState.lVal;
}

I was going to poke around to see if building the WindowsForms.exe with a different .NET platform would make a difference or maybe changing a property of the checkbox would help.

leviwilson commented 11 years ago

Changing the FlatStyle property of the CheckBox control to System fixed the spec. I had to do the same thing for the RadioButton as well. Using FlatStyle.System allows the operating system to handle the drawing of the control. I'm guessing in this instance, the .NET CheckBox control does not subclass the default control, so it behaves as expected?

I've issued a pull request for this.

jarmo commented 11 years ago

Closed by @leviwilson pull request. Awesome discovery!