title: Creating Accessible UI components in Delphi
body: <p>I am trying to retrieve accessible information from a standard VCL TEdit control. The get_accName() and Get_accDescription() methods return empty strings, but get_accValue() returns the text value entered into the TEdit.</p>
  
  <p>I am just starting to try to understand the MSAA and I'm a bit lost at this point. </p>
  
  <p>Does my TEdit need to have additional published properties that would be exposed to the MSA? If so would that necessitate creating a new component that descends from TEdit and adds the additional published properties such as "AccessibleName", "AccessibleDescription", etc... ?</p>
  
  <p>Also, note, I have looked at the VTVirtualTrees component which is <em>supposed</em> to be accessible, but the MS Active Accessibility Object Inspector still does not see the AccessibleName published property even on that control. </p>
  
  <p>At this point I am at a loss and would be grateful for any advice or help in this matter.</p>
  
  <pre><code>...
  interface
  uses
     Winapi.Windows,
     Winapi.Messages,
     System.SysUtils,
     System.Variants,
     System.Classes,
     Vcl.Graphics,
     Vcl.Controls,
     Vcl.Forms,
     Vcl.Dialogs,
     Vcl.StdCtrls,
     Vcl.ComCtrls,
     Vcl.ExtCtrls,
     oleacc;
  
  const
    WM_GETOBJECT = $003D; // Windows MSAA message identifier
    OBJID_NATIVEOM = $FFFFFFF0;
  
  type
    TForm1 = class(TForm)
      lblFirstName: TLabel;
      edFirstName: TEdit;
      panel1: TPanel;
      btnGetAccInfo: TButton;
      accInfoOutput: TEdit;
      procedure btnGetAccInfoClick(Sender: TObject);
      procedure edFirstNameChange(Sender: TObject);
    private
      { Private declarations }
      FFocusedAccessibleObj: IAccessible;
      FvtChild: Variant;
      FAccProperties: TStringList;
      FAccName: string;
      FAccDesc: string;
      FAccValue: string;
      procedure DoGetAccessibleObjectFromPoint(aPoint: TPoint);
    public
     { Public declarations }
     procedure BeforeDestruction; override;
     property AccName: string read FAccName;
     property AccDescription: string read FAccName;
     property AccValue: string read FAccName;
    end;
  
  var
    Form1: TForm1;
  
  const
    cCRLF = #13#10;
  
  implementation
  
  {$R *.dfm}
  
  function AccessibleObjectFromPoint(ptScreen: TPoint;
                                     out ppacc: IAccessible;
                                     out pvarChildt: Variant): HRESULT; stdcall; external   'oleacc.dll' ;
  
  {------------------------------------------------------------------------------}
  procedure TForm1.BeforeDestruction;
  begin
    VarClear(FvtChild);
    FFocusedAccessibleObj := nil;
  end;
  
  {------------------------------------------------------------------------------}
  procedure TForm1.DoGetAccessibleObjectFromPoint(aPoint: TPoint);
  var
    pt: TPoint;
    bsName: WideString;
    bsDesc: WideString;
    bsValue: WideString;
  begin
    if (SUCCEEDED(AccessibleObjectFromPoint(aPoint, FFocusedAccessibleObj, FvtChild))) then
      try
        // get_accName  returns an empty string
        bsName := '';
        FFocusedAccessibleObj.get_accName(FvtChild, bsName);
        FAccName := bsName;
        FAccProperties.Add('Acc Name: ' + FAccName + '  |  ' + cCRLF);
  
        // Get_accDescription  returns an empty string
        bsDesc := '';
        FFocusedAccessibleObj.Get_accDescription(FvtChild, bsDesc);
        FAccDesc := bsDesc;
        FAccProperties.Add('Acc Description: ' + FAccDesc + '  |  ' + cCRLF);
  
        // this works
        bsValue := '';
        FFocusedAccessibleObj.get_accValue(FvtChild, bsValue);
        FAccValue := bsValue;
        FAccProperties.Add('Acc Value: ' + FAccValue  + cCRLF);
  
     finally
       VarClear(FvtChild);
       FFocusedAccessibleObj := nil ;
     end;
    end;
  
    {------------------------------------------------------------------------------}
    procedure TForm1.btnGetAccInfoClick(Sender: TObject);
    begin
      FAccProperties := TStringList.Create;
      DoGetAccessibleObjectFromPoint(edFirstName.ClientOrigin);
      accInfoOutput.Text := FAccProperties.Text;
    end;   
  end.
  </code></pre>