我目前正在尝试在自定义控件中实现IAccessible接口,以便能够自动测试我的GUI。
我能够实现接口,并为我不想改变的所有属性/功能创建和使用StdAccessibleObject
作为代理。但是,它并没有像我想要的那样真正起作用。
MSAA访问的每个控件都有自己的Window-Control,它包含控件本身。在我的例子中,只有这个窗口获取我应用的name属性,真正的控件(在我的例子中是TCustomEdit
的派生)具有标准值。
有人有一个想法如何将可访问的名称附加到控件和控制窗口,甚至只是控件本身?
提前感谢您的时间。
在我的代码下面。
我创建了一个自己的类,其中包含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;
答案 0 :(得分:1)
刚刚发现,仅在窗口控件中具有名称是没有问题的,因为UI测试生成器始终在两个MSAA对象中搜索以识别控件。这就是为什么这个问题不必要的原因。
如果有人知道这个问题的真正答案,我会接受它,但没有必要解决这个问题,因为这对我的用例没有问题。