IAccessible Implementation - 仅在控制窗口中的可访问名称?

时间:2014-02-26 13:57:56

标签: winforms delphi delphi-xe2 ui-automation

我目前正在尝试在自定义控件中实现IAccessible接口,以便能够自动测试我的GUI。 我能够实现接口,并为我不想改变的所有属性/功能创建和使用StdAccessibleObject作为代理。但是,它并没有像我想要的那样真正起作用。

MSAA访问的每个控件都有自己的Window-Control,它包含控件本身。在我的例子中,只有这个窗口获取我应用的name属性,真正的控件(在我的例子中是TCustomEdit的派生)具有标准值。

enter image description here

有人有一个想法如何将可访问的名称附加到控件和控制窗口,甚至只是控件本身?

提前感谢您的时间。

在我的代码下面。


我创建了一个自己的类,其中包含IAccessible的函数,这个类的一个实例是在创建Handle之后在我的Edit中创建的。

TXCustomEdit = class(TCustomMaskEdit, IXControl, ... , IAccessible)

...

strict private
  FAccessible: IAccessible;
  ...
  procedure WMGetMSAAObject(var Message : TMessage); message WM_GETOBJECT;
  ...
private
  procedure CreateHandle(); override;
  ...
protected
  property Accessible: IAccessible read FAccessible implements IAccessible;
  ...
end;

implementation
...

procedure TXCustomEdit.CreateHandle;
begin
  inherited CreateHandle;
  FAccessible := TXControlEigenschaften.Create(Self);
end;

procedure TXCustomEdit.WMGetMSAAObject(var Message: TMessage);
begin
  if Assigned(FAccessible) then
    (FAccessible as TXControlEigenschaften).WMGetMSAAObject(Message);
end;

我班的宣言:

TXControlEigenschaften = class (TInterfacedObject, IAccessible)
strict private
  FControl: IXControl;
  FAccessible: IAccessible;

  // IAccessible
  function Get_accParent(out ppdispParent: IDispatch): HResult; stdcall;
  function Get_accChildCount(out pcountChildren: Integer): HResult; stdcall;
  function Get_accChild(varChild: OleVariant; out ppdispChild: IDispatch): HResult; stdcall;
  function Get_accName(varChild: OleVariant; out pszName: WideString): HResult; stdcall;
  function Get_accValue(varChild: OleVariant; out pszValue: WideString): HResult; stdcall;
  function Get_accDescription(varChild: OleVariant; out pszDescription: WideString): HResult; stdcall;
  function Get_accRole(varChild: OleVariant; out pvarRole: OleVariant): HResult; stdcall;
  function Get_accState(varChild: OleVariant; out pvarState: OleVariant): HResult; stdcall;
  function Get_accHelp(varChild: OleVariant; out pszHelp: WideString): HResult; stdcall;
  function Get_accHelpTopic(out pszHelpFile: WideString; varChild: OleVariant;
                                                      out pidTopic: Integer): HResult; stdcall;
  function Get_accKeyboardShortcut(varChild: OleVariant; out pszKeyboardShortcut: WideString): HResult; stdcall;
  function Get_accFocus(out pvarChild: OleVariant): HResult; stdcall;
  function Get_accSelection(out pvarChildren: OleVariant): HResult; stdcall;
  function Get_accDefaultAction(varChild: OleVariant; out pszDefaultAction: WideString): HResult; stdcall;
  function accSelect(flagsSelect: Integer; varChild: OleVariant): HResult; stdcall;
  function accLocation(out pxLeft: Integer; out pyTop: Integer; out pcxWidth: Integer;
                                           out pcyHeight: Integer; varChild: OleVariant): HResult; stdcall;
  function accNavigate(navDir: Integer; varStart: OleVariant; out pvarEndUpAt: OleVariant): HResult; stdcall;
  function accHitTest(xLeft: Integer; yTop: Integer; out pvarChild: OleVariant): HResult; stdcall;
  function accDoDefaultAction(varChild: OleVariant): HResult; stdcall;
  function Set_accName(varChild: OleVariant; const pszName: WideString): HResult; stdcall;
  function Set_accValue(varChild: OleVariant; const pszValue: WideString): HResult; stdcall;

  function GetIDsOfNames(const IID: TGUID; Names: Pointer;
    NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
  function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
    Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;

public
  constructor Create(aControl: IXControl);

  procedure WMGetMSAAObject(var Message : TMessage); message WM_GETOBJECT;
end;

重要的实施:

constructor TXControlEigenschaften.Create(aControl: IXControl);
var
  p: Pointer;
begin
  inherited Create();
  FControl := aControl;
  CreateStdAccessibleObject((FControl.GetOwnControl as TWinControl).Handle, OBJID_CLIENT, IID_IAccessible, p);
  FAccessible := IAccessible(p);
end;

procedure TXControlEigenschaften.WMGetMSAAObject(var Message: TMessage);
begin
  if (Message.Msg = WM_GETOBJECT) then
    Message.Result := LresultFromObject(IID_IAccessible, Message.WParam, Self)
  else
    Message.Result := DefWindowProc((FControl.GetOwnControl as TWinControl).Handle, Message.Msg, Message.WParam, Message.LParam);
end;

function TXControlEigenschaften.Get_accName(varChild: OleVariant; out pszName: WideString): HResult;
begin
  pszName := FControl.Name;
  Result := S_OK;
end;

界面的所有其他功能都是通过我的“代理”实现的,例如:

function TXControlEigenschaften.Get_accParent(out ppdispParent: IDispatch): HResult;
begin
  Result := FAccessible.Get_accParent(ppdispParent);
end;

1 个答案:

答案 0 :(得分:1)

刚刚发现,仅在窗口控件中具有名称是没有问题的,因为UI测试生成器始终在两个MSAA对象中搜索以识别控件。这就是为什么这个问题不必要的原因。

如果有人知道这个问题的真正答案,我会接受它,但没有必要解决这个问题,因为这对我的用例没有问题。