| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177 | unit TB2Acc;{  Toolbar2000  Copyright (C) 1998-2005 by Jordan Russell  All rights reserved.  The contents of this file are subject to the "Toolbar2000 License"; you may  not use or distribute this file except in compliance with the  "Toolbar2000 License". A copy of the "Toolbar2000 License" may be found in  TB2k-LICENSE.txt or at:    http://www.jrsoftware.org/files/tb2k/TB2k-LICENSE.txt  Alternatively, the contents of this file may be used under the terms of the  GNU General Public License (the "GPL"), in which case the provisions of the  GPL are applicable instead of those in the "Toolbar2000 License". A copy of  the GPL may be found in GPL-LICENSE.txt or at:    http://www.jrsoftware.org/files/tb2k/GPL-LICENSE.txt  If you wish to allow use of your version of this file only under the terms of  the GPL and not to allow others to use your version of this file under the  "Toolbar2000 License", indicate your decision by deleting the provisions  above and replace them with the notice and other provisions required by the  GPL. If you do not delete the provisions above, a recipient may use your  version of this file under either the "Toolbar2000 License" or the GPL.  $jrsoftware: tb2k/Source/TB2Acc.pas,v 1.7 2005/01/06 03:56:50 jr Exp $  This unit is used internally to implement the IAccessible interface on  TTBView and TTBItemViewer for Microsoft Active Accessibility support.}interface{$I TB2Ver.inc}uses  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  TB2Item;type  { Our declaration for IAccessible }  ITBAccessible = interface(IDispatch)    ['{618736E0-3C3D-11CF-810C-00AA00389B71}']    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 pvarID: 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 pvarEnd: OleVariant): HRESULT; stdcall;    function accHitTest(xLeft: Integer; yTop: Integer; out pvarID: OleVariant): HRESULT; stdcall;    function accDoDefaultAction(varChild: OleVariant): HRESULT; stdcall;    function put_accName(varChild: OleVariant; const pszName: WideString): HRESULT; stdcall;    function put_accValue(varChild: OleVariant; const pszValue: WideString): HRESULT; stdcall;  end;  TTBCustomAccObject = class(TTBBaseAccObject, IUnknown, IDispatch)  private    FPrevious, FNext: TTBCustomAccObject;  public    constructor Create;    destructor Destroy; override;  end;  TTBViewAccObject = class(TTBCustomAccObject, IUnknown, IDispatch, ITBAccessible)  private    FView: TTBView;    function Check(const varChild: OleVariant; var ErrorCode: HRESULT): Boolean;    { ITBAccessible }    function accDoDefaultAction(varChild: OleVariant): HRESULT; stdcall;    function accHitTest(xLeft: Integer; yTop: Integer; out pvarID: 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 pvarEnd: OleVariant): HRESULT; stdcall;    function accSelect(flagsSelect: Integer; varChild: OleVariant): HRESULT; stdcall;    function get_accChild(varChild: OleVariant; out ppdispChild: IDispatch): HRESULT; stdcall;    function get_accChildCount(out pcountChildren: Integer): HRESULT; stdcall;    function get_accDefaultAction(varChild: OleVariant; out pszDefaultAction: WideString): HRESULT; stdcall;    function get_accDescription(varChild: OleVariant; out pszDescription: WideString): HRESULT; stdcall;    function get_accFocus(out pvarID: 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_accName(varChild: OleVariant; out pszName: WideString): HRESULT; stdcall;    function get_accParent(out ppdispParent: IDispatch): HRESULT; stdcall;    function get_accRole(varChild: OleVariant; out pvarRole: OleVariant): HRESULT; stdcall;    function get_accSelection(out pvarChildren: OleVariant): HRESULT; stdcall;    function get_accState(varChild: OleVariant; out pvarState: OleVariant): HRESULT; stdcall;    function get_accValue(varChild: OleVariant; out pszValue: WideString): HRESULT; stdcall;    function put_accName(varChild: OleVariant; const pszName: WideString): HRESULT; stdcall;    function put_accValue(varChild: OleVariant; const pszValue: WideString): HRESULT; stdcall;  public    constructor Create(AView: TTBView);    destructor Destroy; override;    procedure ClientIsDestroying; override;  end;  TTBItemViewerAccObject = class(TTBCustomAccObject, IUnknown, IDispatch, ITBAccessible)  private    FViewer: TTBItemViewer;    function Check(const varChild: OleVariant; var ErrorCode: HRESULT): Boolean;    function IsActionable: Boolean;    function IsAvailable: Boolean;    function IsFocusable: Boolean;    { ITBAccessible }    function accDoDefaultAction(varChild: OleVariant): HRESULT; stdcall;    function accHitTest(xLeft: Integer; yTop: Integer; out pvarID: 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 pvarEnd: OleVariant): HRESULT; stdcall;    function accSelect(flagsSelect: Integer; varChild: OleVariant): HRESULT; stdcall;    function get_accChild(varChild: OleVariant; out ppdispChild: IDispatch): HRESULT; stdcall;    function get_accChildCount(out pcountChildren: Integer): HRESULT; stdcall;    function get_accDefaultAction(varChild: OleVariant; out pszDefaultAction: WideString): HRESULT; stdcall;    function get_accDescription(varChild: OleVariant; out pszDescription: WideString): HRESULT; stdcall;    function get_accFocus(out pvarID: 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_accName(varChild: OleVariant; out pszName: WideString): HRESULT; stdcall;    function get_accParent(out ppdispParent: IDispatch): HRESULT; stdcall;    function get_accRole(varChild: OleVariant; out pvarRole: OleVariant): HRESULT; stdcall;    function get_accSelection(out pvarChildren: OleVariant): HRESULT; stdcall;    function get_accState(varChild: OleVariant; out pvarState: OleVariant): HRESULT; stdcall;    function get_accValue(varChild: OleVariant; out pszValue: WideString): HRESULT; stdcall;    function put_accName(varChild: OleVariant; const pszName: WideString): HRESULT; stdcall;    function put_accValue(varChild: OleVariant; const pszValue: WideString): HRESULT; stdcall;  public    constructor Create(AViewer: TTBItemViewer);    destructor Destroy; override;    procedure ClientIsDestroying; override;    procedure HandleAccSelect(const AExecute: Boolean);  end;var  { For debugging purposes only: }  ViewAccObjectInstances: Integer = 0;  ItemViewerAccObjectInstances: Integer = 0;implementationuses  Variants, ActiveX, Menus, TB2Common, Winapi.oleacc, Types;const  { Constants from OleAcc.h }  ROLE_SYSTEM_MENUBAR = $2;  ROLE_SYSTEM_CLIENT = $a;  ROLE_SYSTEM_MENUPOPUP = $b;  ROLE_SYSTEM_MENUITEM = $c;  ROLE_SYSTEM_SEPARATOR = $15;  ROLE_SYSTEM_TOOLBAR = $16;  ROLE_SYSTEM_PUSHBUTTON = $2b;  ROLE_SYSTEM_BUTTONMENU = $39;  STATE_SYSTEM_HASPOPUP = $40000000;  NAVDIR_UP         = 1;  NAVDIR_DOWN       = 2;  NAVDIR_LEFT       = 3;  NAVDIR_RIGHT      = 4;  NAVDIR_NEXT       = 5;  NAVDIR_PREVIOUS   = 6;  NAVDIR_FIRSTCHILD = 7;  NAVDIR_LASTCHILD  = 8;  SELFLAG_TAKEFOCUS = 1;type  TControlAccess = class(TControl);  TTBViewAccess = class(TTBView);  TTBCustomItemAccess = class(TTBCustomItem);  TTBItemViewerAccess = class(TTBItemViewer);var  LastAccObject: TTBCustomAccObject;  { last object in the linked list }  LastAccObjectCritSect: TRTLCriticalSection;function AccObjectFromWindow(const Wnd: HWND; out ADisp: IDispatch): Boolean;var  P: Pointer;begin  if AccessibleObjectFromWindow(Wnd, OBJID_WINDOW, IDispatch, P) = S_OK then begin    ADisp := IDispatch(P);    IDispatch(P)._Release;    Result := True;  end  else    Result := False;end;procedure DisconnectAccObjects;{ This procedure calls CoDisconnectObject() on all acc. objects still  allocated. This is needed to prevent potential AV's when TB2k is compiled  into a DLL, since a DLL may be freed by the application while an MSAA  client still holds acc. object references. }var  Obj, PrevObj: TTBCustomAccObject;begin  Obj := LastAccObject;  while Assigned(Obj) do begin    { Make a copy of Obj.FPrevious since CoDisconnectObject may cause Obj      to be freed }    PrevObj := Obj.FPrevious;    { CoDisconnectObject should cause remote MSAA clients to release all      references to the object, thus destroying it (assuming the local      application doesn't have references of its own). }    CoDisconnectObject(Obj, 0);    Obj := PrevObj;  end;end;function GetAltKeyName: String;{ This silly function is needed since ShortCutToText(VK_MENU) fails on Delphi  and C++Builder versions <= 4 }var  ScanCode: UINT;  KeyName: array[0..255] of Char;begin  ScanCode := MapVirtualKey(VK_MENU, 0) shl 16;  if (ScanCode <> 0) and     (GetKeyNameText(ScanCode, KeyName, SizeOf(KeyName)) > 0) then    Result := KeyName  else    Result := 'Alt';  { shouldn't get here, but just in case... }end;{ TTBCustomAccObject }constructor TTBCustomAccObject.Create;begin  inherited Create;  { Add Self to linked list of objects }  EnterCriticalSection(LastAccObjectCritSect);  try    FPrevious := LastAccObject;    if Assigned(FPrevious) then      FPrevious.FNext := Self;    LastAccObject := Self;  finally    LeaveCriticalSection(LastAccObjectCritSect);  end;end;destructor TTBCustomAccObject.Destroy;begin  { Remove Self from linked list of objects }  EnterCriticalSection(LastAccObjectCritSect);  try    if LastAccObject = Self then      LastAccObject := FPrevious;    if Assigned(FPrevious) then      FPrevious.FNext := FNext;    if Assigned(FNext) then      FNext.FPrevious := FPrevious;  finally    LeaveCriticalSection(LastAccObjectCritSect);  end;  inherited;end;{ TTBViewAccObject }constructor TTBViewAccObject.Create(AView: TTBView);begin  inherited Create;  FView := AView;  InterlockedIncrement(ViewAccObjectInstances);end;destructor TTBViewAccObject.Destroy;begin  InterlockedDecrement(ViewAccObjectInstances);  if Assigned(FView) then begin    TTBViewAccess(FView).FAccObjectInstance := nil;    FView := nil;  end;  inherited;end;procedure TTBViewAccObject.ClientIsDestroying;begin  FView := nil;end;function TTBViewAccObject.Check(const varChild: OleVariant;  var ErrorCode: HRESULT): Boolean;begin  if FView = nil then begin    ErrorCode := E_FAIL;    Result := False;  end  else if (VarType(varChild) <> varInteger) or (varChild <> CHILDID_SELF) then begin    ErrorCode := E_INVALIDARG;    Result := False;  end  else    Result := True;end;function TTBViewAccObject.accDoDefaultAction(varChild: OleVariant): HRESULT;begin  Result := S_FALSE;end;function TTBViewAccObject.accHitTest(xLeft, yTop: Integer;  out pvarID: OleVariant): HRESULT;var  ViewWnd, W: HWND;  R: TRect;  P: TPoint;  D: IDispatch;  V: TTBItemViewer;begin  try    if FView = nil then begin      Result := E_FAIL;      Exit;    end;    ViewWnd := FView.Window.Handle;    GetWindowRect(ViewWnd, R);    P.X := xLeft;    P.Y := yTop;    if PtInRect(R, P) then begin      P := FView.Window.ScreenToClient(P);      W := ChildWindowFromPointEx(ViewWnd, P, CWP_SKIPINVISIBLE);      if (W <> 0) and (W <> ViewWnd) then begin        { Point is inside a child window (most likely belonging to a          TTBControlItem) }        if AccObjectFromWindow(W, D) then begin          pvarID := D;          Result := S_OK;        end        else          Result := E_UNEXPECTED;      end      else begin        V := FView.ViewerFromPoint(P);        if Assigned(V) then          pvarID := V.GetAccObject        else          pvarID := CHILDID_SELF;        Result := S_OK;      end;    end    else      Result := S_FALSE;  except    Result := E_UNEXPECTED;  end;end;function TTBViewAccObject.accLocation(out pxLeft, pyTop, pcxWidth,  pcyHeight: Integer; varChild: OleVariant): HRESULT;var  R: TRect;begin  try    if not Check(varChild, Result) then      Exit;    GetWindowRect(FView.Window.Handle, R);    pxLeft := R.Left;    pyTop := R.Top;    pcxWidth := R.Right - R.Left;    pcyHeight := R.Bottom - R.Top;    Result := S_OK;  except    Result := E_UNEXPECTED;  end;end;function TTBViewAccObject.accNavigate(navDir: Integer; varStart: OleVariant;  out pvarEnd: OleVariant): HRESULT;var  I: Integer;begin  try    if not Check(varStart, Result) then      Exit;    Result := S_FALSE;    case navDir of      NAVDIR_FIRSTCHILD: begin          for I := 0 to FView.ViewerCount-1 do            if FView.Viewers[I].IsAccessible then begin              pvarEnd := FView.Viewers[I].GetAccObject;              Result := S_OK;              Break;            end;        end;      NAVDIR_LASTCHILD: begin          for I := FView.ViewerCount-1 downto 0 do            if FView.Viewers[I].IsAccessible then begin              pvarEnd := FView.Viewers[I].GetAccObject;              Result := S_OK;              Break;            end;        end;    end;  except    Result := E_UNEXPECTED;  end;end;function TTBViewAccObject.accSelect(flagsSelect: Integer;  varChild: OleVariant): HRESULT;begin  Result := DISP_E_MEMBERNOTFOUND;end;function TTBViewAccObject.get_accChild(varChild: OleVariant;  out ppdispChild: IDispatch): HRESULT;var  I, J: Integer;  Viewer: TTBItemViewer;  Ctl: TControl;begin  try    if FView = nil then begin      Result := E_FAIL;      Exit;    end;    if VarType(varChild) <> varInteger then begin      Result := E_INVALIDARG;      Exit;    end;    I := varChild;    if I = CHILDID_SELF then begin      ppdispChild := Self;      Result := S_OK;    end    else begin      { Convert a one-based child index (I) into a real viewer index (J) }      J := 0;      while J < FView.ViewerCount do begin        if FView.Viewers[J].IsAccessible then begin          if I = 1 then Break;          Dec(I);        end;        Inc(J);      end;      if J >= FView.ViewerCount then begin        { 'I' was either negative or too high }        Result := E_INVALIDARG;        Exit;      end;      Viewer := FView.Viewers[J];      if Viewer.Item is TTBControlItem then begin        { For windowed controls, return the window's accessible object instead          of the item viewer's }        Ctl := TTBControlItem(Viewer.Item).Control;        if (Ctl is TWinControl) and TWinControl(Ctl).HandleAllocated then begin          if AccObjectFromWindow(TWinControl(Ctl).Handle, ppdispChild) then            Result := S_OK          else            Result := E_UNEXPECTED;          Exit;        end;      end;      ppdispChild := Viewer.GetAccObject;      Result := S_OK;    end;  except    Result := E_UNEXPECTED;  end;end;function TTBViewAccObject.get_accChildCount(out pcountChildren: Integer): HRESULT;var  Count, I: Integer;begin  try    if Assigned(FView) then begin      Count := 0;      for I := 0 to FView.ViewerCount-1 do        if FView.Viewers[I].IsAccessible then          Inc(Count);      pCountChildren := Count;      Result := S_OK;    end    else      Result := E_FAIL;  except    Result := E_UNEXPECTED;  end;end;function TTBViewAccObject.get_accDefaultAction(varChild: OleVariant;  out pszDefaultAction: WideString): HRESULT;begin  Result := S_FALSE;end;function TTBViewAccObject.get_accDescription(varChild: OleVariant;  out pszDescription: WideString): HRESULT;begin  Result := S_FALSE;end;function TTBViewAccObject.get_accFocus(out pvarID: OleVariant): HRESULT;begin  Result := S_FALSE;end;function TTBViewAccObject.get_accHelp(varChild: OleVariant;  out pszHelp: WideString): HRESULT;begin  Result := S_FALSE;end;function TTBViewAccObject.get_accHelpTopic(out pszHelpFile: WideString;  varChild: OleVariant; out pidTopic: Integer): HRESULT;begin  pidTopic := 0;  { Delphi doesn't implicitly clear Integer 'out' parameters }  Result := S_FALSE;end;function TTBViewAccObject.get_accKeyboardShortcut(varChild: OleVariant;  out pszKeyboardShortcut: WideString): HRESULT;begin  try    if not Check(varChild, Result) then      Exit;    if vsMenuBar in FView.Style then begin      pszKeyboardShortcut := GetAltKeyName;      Result := S_OK;    end    else      Result := S_FALSE;  except    Result := E_UNEXPECTED;  end;end;function TTBViewAccObject.get_accName(varChild: OleVariant;  out pszName: WideString): HRESULT;var  S: String;begin  try    if not Check(varChild, Result) then      Exit;    if Assigned(FView.ParentView) and Assigned(FView.ParentView.OpenViewer) then      S := StripAccelChars(TTBItemViewerAccess(FView.ParentView.OpenViewer).GetCaptionText);    if S = '' then      S := TControlAccess(FView.Window).Caption;    pszName := S;    Result := S_OK;  except    Result := E_UNEXPECTED;  end;end;function TTBViewAccObject.get_accParent(out ppdispParent: IDispatch): HRESULT;begin  try    if Assigned(FView) then begin      if Assigned(FView.ParentView) and Assigned(FView.ParentView.OpenViewer) then begin        ppdispParent := FView.ParentView.OpenViewer.GetAccObject;        Result := S_OK;      end      else begin        if AccObjectFromWindow(FView.Window.Handle, ppdispParent) then          Result := S_OK        else          Result := E_UNEXPECTED;      end;    end    else      Result := E_FAIL;  except    Result := E_UNEXPECTED;  end;end;function TTBViewAccObject.get_accRole(varChild: OleVariant;  out pvarRole: OleVariant): HRESULT;begin  try    if not Check(varChild, Result) then      Exit;    if FView.IsPopup then      pvarRole := ROLE_SYSTEM_MENUPOPUP    else begin      if vsMenuBar in FView.Style then        pvarRole := ROLE_SYSTEM_MENUBAR      else        pvarRole := ROLE_SYSTEM_TOOLBAR;    end;    Result := S_OK;  except    Result := E_UNEXPECTED;  end;end;function TTBViewAccObject.get_accSelection(out pvarChildren: OleVariant): HRESULT;begin  Result := S_FALSE;end;function TTBViewAccObject.get_accState(varChild: OleVariant;  out pvarState: OleVariant): HRESULT;begin  try    if not Check(varChild, Result) then      Exit;    pvarState := 0;    Result := S_OK;  except    Result := E_UNEXPECTED;  end;end;function TTBViewAccObject.get_accValue(varChild: OleVariant;  out pszValue: WideString): HRESULT;begin  Result := S_FALSE;end;function TTBViewAccObject.put_accName(varChild: OleVariant;  const pszName: WideString): HRESULT;begin  Result := S_FALSE;end;function TTBViewAccObject.put_accValue(varChild: OleVariant;  const pszValue: WideString): HRESULT;begin  Result := S_FALSE;end;{ TTBItemViewerAccObject }constructor TTBItemViewerAccObject.Create(AViewer: TTBItemViewer);begin  inherited Create;  FViewer := AViewer;  InterlockedIncrement(ItemViewerAccObjectInstances);end;destructor TTBItemViewerAccObject.Destroy;begin  InterlockedDecrement(ItemViewerAccObjectInstances);  if Assigned(FViewer) then begin    TTBItemViewerAccess(FViewer).FAccObjectInstance := nil;    FViewer := nil;  end;  inherited;end;procedure TTBItemViewerAccObject.ClientIsDestroying;begin  FViewer := nil;end;function TTBItemViewerAccObject.Check(const varChild: OleVariant;  var ErrorCode: HRESULT): Boolean;begin  if FViewer = nil then begin    ErrorCode := E_FAIL;    Result := False;  end  else if (VarType(varChild) <> varInteger) or (varChild <> CHILDID_SELF) then begin    ErrorCode := E_INVALIDARG;    Result := False;  end  else    Result := True;end;function TTBItemViewerAccObject.IsActionable: Boolean;{ Returns True if 'doDefaultAction' may be performed on the viewer, i.e. if  it's visible/off-edge/clipped, enabled & selectable, and the view is  focusable. }begin  Result := FViewer.IsAccessible and IsAvailable and IsFocusable;end;function TTBItemViewerAccObject.IsAvailable: Boolean;{ Returns True if the viewer's item is enabled and selectable }begin  Result := FViewer.Item.Enabled and    (tbisSelectable in TTBCustomItemAccess(FViewer.Item).ItemStyle);end;function TTBItemViewerAccObject.IsFocusable: Boolean;{ Returns True if viewers on the view can be 'focused' (i.e. the view's window  doesn't have the csDesigning state, the window is visible and enabled, and  the application is active). }  function IsWindowAndParentsEnabled(W: HWND): Boolean;  begin    Result := True;    repeat      if not IsWindowEnabled(W) then begin        Result := False;        Break;      end;      W := GetParent(W);    until W = 0;  end;var  ViewWnd, ActiveWnd: HWND;begin  Result := False;  if csDesigning in FViewer.View.Window.ComponentState then    Exit;  ViewWnd := FViewer.View.Window.Handle;  if IsWindowVisible(ViewWnd) and IsWindowAndParentsEnabled(ViewWnd) then begin    if vsModal in FViewer.View.State then      Result := True    else begin      ActiveWnd := GetActiveWindow;      if (ActiveWnd <> 0) and         ((ActiveWnd = ViewWnd) or IsChild(ActiveWnd, ViewWnd)) then        Result := True;    end;  end;end;procedure TTBItemViewerAccObject.HandleAccSelect(const AExecute: Boolean);begin  if Assigned(FViewer) and     ((AExecute and IsActionable) or (not AExecute and IsFocusable)) then begin    FViewer.View.Selected := FViewer;    FViewer.View.ScrollSelectedIntoView;    if vsModal in FViewer.View.State then begin      if AExecute then        FViewer.View.ExecuteSelected(False);    end    else if (FViewer.View.ParentView = nil) and (GetCapture = 0) then begin      if AExecute then        FViewer.View.EnterToolbarLoop([tbetExecuteSelected, tbetFromMSAA])      else        FViewer.View.EnterToolbarLoop([tbetFromMSAA]);    end;  end;end;function TTBItemViewerAccObject.accDoDefaultAction(varChild: OleVariant): HRESULT;begin  try    if not Check(varChild, Result) then      Exit;    { NOTE: This must be kept in synch with get_accDefaultAction }    if IsActionable then begin      Result := S_OK;      if FViewer.View.OpenViewer = FViewer then begin        FViewer.View.CancelChildPopups;        { Like standard menus, cancel the modal loop when a top-level menu          is closed }        if (vsModal in FViewer.View.State) and not FViewer.View.IsPopup then          FViewer.View.EndModal;      end      else begin        FViewer.View.Selected := FViewer;        FViewer.View.ScrollSelectedIntoView;        TTBItemViewerAccess(FViewer).PostAccSelect(True);      end;    end    else      { Note: Standard menus return DISP_E_MEMBERNOTFOUND in this case but        that doesn't make much sense. The member is there but just isn't        currently available. }      Result := E_FAIL;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.accHitTest(xLeft, yTop: Integer;  out pvarID: OleVariant): HRESULT;var  P: TPoint;begin  try    if FViewer = nil then begin      Result := E_FAIL;      Exit;    end;    P := FViewer.View.Window.ScreenToClient(Point(xLeft, yTop));    if PtInRect(FViewer.BoundsRect, P) then begin      pvarID := CHILDID_SELF;      Result := S_OK;    end    else      Result := S_FALSE;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.accLocation(out pxLeft, pyTop, pcxWidth,  pcyHeight: Integer; varChild: OleVariant): HRESULT;var  R: TRect;  P: TPoint;begin  try    if not Check(varChild, Result) then      Exit;    R := FViewer.BoundsRect;    P := FViewer.View.Window.ClientToScreen(Point(0, 0));    OffsetRect(R, P.X, P.Y);    pxLeft := R.Left;    pyTop := R.Top;    pcxWidth := R.Right - R.Left;    pcyHeight := R.Bottom - R.Top;    Result := S_OK;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.accNavigate(navDir: Integer; varStart: OleVariant;  out pvarEnd: OleVariant): HRESULT;var  I, J: Integer;  View: TTBView;begin  try    if not Check(varStart, Result) then      Exit;    Result := S_FALSE;    if (navDir = NAVDIR_FIRSTCHILD) or (navDir = NAVDIR_LASTCHILD) then begin      { Return the child view's acc. object }      View := FViewer.View.OpenViewerView;      if Assigned(View) then begin        pvarEnd := View.GetAccObject;        Result := S_OK;      end;    end    else begin      I := FViewer.View.IndexOf(FViewer);      if I >= 0 then begin        case navDir of          NAVDIR_UP, NAVDIR_LEFT, NAVDIR_PREVIOUS:            for J := I-1 downto 0 do              if FViewer.View.Viewers[J].IsAccessible then begin                pvarEnd := FViewer.View.Viewers[J].GetAccObject;                Result := S_OK;                Break;              end;          NAVDIR_DOWN, NAVDIR_RIGHT, NAVDIR_NEXT:            for J := I+1 to FViewer.View.ViewerCount-1 do              if FViewer.View.Viewers[J].IsAccessible then begin                pvarEnd := FViewer.View.Viewers[J].GetAccObject;                Result := S_OK;                Break;              end;        end;      end;    end;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.accSelect(flagsSelect: Integer;  varChild: OleVariant): HRESULT;begin  try    if not Check(varChild, Result) then      Exit;    if flagsSelect <> SELFLAG_TAKEFOCUS then begin      Result := E_INVALIDARG;      Exit;    end;    if IsFocusable and (FViewer.Show or FViewer.Clipped) then begin      FViewer.View.Selected := FViewer;      FViewer.View.ScrollSelectedIntoView;      if not(vsModal in FViewer.View.State) and         (FViewer.View.ParentView = nil) then        TTBItemViewerAccess(FViewer).PostAccSelect(False);    end    else      Result := E_FAIL;      { ^ what Office XP returns when you try focusing an off-edge item }  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.get_accChild(varChild: OleVariant;  out ppdispChild: IDispatch): HRESULT;var  View: TTBView;begin  try    if FViewer = nil then begin      Result := E_FAIL;      Exit;    end;    Result := E_INVALIDARG;    if VarType(varChild) = varInteger then begin      if varChild = CHILDID_SELF then begin        ppdispChild := Self;        Result := S_OK;      end      else if varChild = 1 then begin        { Return the child view's acc. object }        View := FViewer.View.OpenViewerView;        if Assigned(View) then begin          ppdispChild := View.GetAccObject;          Result := S_OK;        end;      end;    end;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.get_accChildCount(out pcountChildren: Integer): HRESULT;begin  try    if FViewer = nil then begin      Result := E_FAIL;      Exit;    end;    { Return 1 if the viewer has a child view }    if FViewer.View.OpenViewer = FViewer then      pCountChildren := 1    else      pCountChildren := 0;    Result := S_OK;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.get_accDefaultAction(varChild: OleVariant;  out pszDefaultAction: WideString): HRESULT;begin  try    if not Check(varChild, Result) then      Exit;    if IsActionable then begin      { I'm not sure if these should be localized, or even if any screen        readers make use of this text...        NOTE: This must be kept in synch with accDoDefaultAction }      if FViewer.View.OpenViewer = FViewer then        pszDefaultAction := 'Close'      else if tbisSubmenu in TTBCustomItemAccess(FViewer.Item).ItemStyle then        pszDefaultAction := 'Open'      else if FViewer.View.IsPopup or (vsMenuBar in FViewer.View.Style) then        pszDefaultAction := 'Execute'      else        pszDefaultAction := 'Press';      Result := S_OK;    end    else      Result := S_FALSE;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.get_accDescription(varChild: OleVariant;  out pszDescription: WideString): HRESULT;begin  Result := S_FALSE;end;function TTBItemViewerAccObject.get_accFocus(out pvarID: OleVariant): HRESULT;begin  try    if FViewer = nil then begin      Result := E_FAIL;      Exit;    end;    if (vsModal in FViewer.View.State) and       (FViewer.View.Selected = FViewer) then begin      pvarID := CHILDID_SELF;      Result := S_OK;    end    else      Result := S_FALSE;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.get_accHelp(varChild: OleVariant;  out pszHelp: WideString): HRESULT;begin  Result := S_FALSE;end;function TTBItemViewerAccObject.get_accHelpTopic(out pszHelpFile: WideString;  varChild: OleVariant; out pidTopic: Integer): HRESULT;begin  pidTopic := 0;  { Delphi doesn't implicitly clear Integer 'out' parameters }  Result := S_FALSE;end;function TTBItemViewerAccObject.get_accKeyboardShortcut(varChild: OleVariant;  out pszKeyboardShortcut: WideString): HRESULT;var  C: Char;begin  try    if not Check(varChild, Result) then      Exit;    Result := S_FALSE;    if TTBItemViewerAccess(FViewer).CaptionShown then begin      C := FindAccelChar(TTBItemViewerAccess(FViewer).GetCaptionText);      if C <> #0 then begin        CharLowerBuff(@C, 1);  { like standard menus, always use lowercase... }        if FViewer.View.IsPopup then          pszKeyboardShortcut := C        else begin          { Prefix 'Alt+' }          pszKeyboardShortcut := GetAltKeyName + '+' + C;        end;        Result := S_OK;      end;    end;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.get_accName(varChild: OleVariant;  out pszName: WideString): HRESULT;var  C, S: String;begin  try    if not Check(varChild, Result) then      Exit;    C := StripAccelChars(TTBItemViewerAccess(FViewer).GetCaptionText);    if not FViewer.IsToolbarStyle then      S := FViewer.Item.GetShortCutText;    if S = '' then      pszName := C    else      pszName := C + #9 + S;    Result := S_OK;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.get_accParent(out ppdispParent: IDispatch): HRESULT;begin  try    if Assigned(FViewer) then begin      ppdispParent := FViewer.View.GetAccObject;      Result := S_OK;    end    else      Result := E_FAIL;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.get_accRole(varChild: OleVariant;  out pvarRole: OleVariant): HRESULT;begin  try    if not Check(varChild, Result) then      Exit;    pvarRole := TTBItemViewerAccess(FViewer).GetAccRole;    Result := S_OK;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.get_accSelection(out pvarChildren: OleVariant): HRESULT;begin  Result := S_FALSE;end;function TTBItemViewerAccObject.get_accState(varChild: OleVariant;  out pvarState: OleVariant): HRESULT;var  Flags: Integer;begin  try    if not Check(varChild, Result) then      Exit;    Flags := 0;    if FViewer.View.Selected = FViewer then begin      Flags := Flags or STATE_SYSTEM_HOTTRACKED;      if vsModal in FViewer.View.State then        Flags := Flags or STATE_SYSTEM_FOCUSED;      if FViewer.View.MouseOverSelected and FViewer.View.Capture then        { ^ based on "IsPushed :=" code in TTBView.DrawItem }        Flags := Flags or STATE_SYSTEM_PRESSED;    end;    if tbisSubmenu in TTBCustomItemAccess(FViewer.Item).ItemStyle then      Flags := Flags or STATE_SYSTEM_HASPOPUP;    if FViewer.Show or FViewer.Clipped then begin      if IsFocusable then        Flags := Flags or STATE_SYSTEM_FOCUSABLE;    end    else begin      { Mark off-edge items as invisible, like Office }      Flags := Flags or STATE_SYSTEM_INVISIBLE;    end;    if not IsAvailable then      Flags := Flags or STATE_SYSTEM_UNAVAILABLE;    if FViewer.Item.Checked then      Flags := Flags or STATE_SYSTEM_CHECKED;    pvarState := Flags;    Result := S_OK;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.get_accValue(varChild: OleVariant;  out pszValue: WideString): HRESULT;begin  try    if not Check(varChild, Result) then      Exit;    if TTBItemViewerAccess(FViewer).GetAccValue(pszValue) then      Result := S_OK    else begin      pszValue := '';      Result := S_FALSE;    end;  except    Result := E_UNEXPECTED;  end;end;function TTBItemViewerAccObject.put_accName(varChild: OleVariant;  const pszName: WideString): HRESULT;begin  Result := S_FALSE;end;function TTBItemViewerAccObject.put_accValue(varChild: OleVariant;  const pszValue: WideString): HRESULT;begin  Result := S_FALSE;end;{ Note: This COM initialization code based on code from DBTables }var  SaveInitProc: Pointer;  NeedToUninitialize: Boolean;procedure InitCOM;begin  if SaveInitProc <> nil then TProcedure(SaveInitProc);  NeedToUninitialize := SUCCEEDED(CoInitialize(nil));end;initialization  InitializeCriticalSection(LastAccObjectCritSect);  if not IsLibrary then begin    SaveInitProc := InitProc;    InitProc := @InitCOM;  end;finalization  DisconnectAccObjects;  if NeedToUninitialize then    CoUninitialize;  DeleteCriticalSection(LastAccObjectCritSect);end.
 |