| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224 |
- 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;
- procedure CallNotifyWinEvent(event: DWORD; hwnd: HWND; idObject: DWORD;
- idChild: Longint);
- function InitializeOleAcc: Boolean;
- var
- LresultFromObjectFunc: function(const riid: TGUID; wParam: WPARAM;
- pUnk: IUnknown): LRESULT; stdcall;
- AccessibleObjectFromWindowFunc: function(hwnd: HWND; dwId: DWORD;
- const riid: TGUID; out ppvObject: Pointer): HRESULT; stdcall;
- { For debugging purposes only: }
- ViewAccObjectInstances: Integer = 0;
- ItemViewerAccObjectInstances: Integer = 0;
- implementation
- uses
- {$IFDEF JR_D6} Variants, {$ENDIF} ActiveX, Menus, TB2Common;
- 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;
- NotifyWinEventInited: BOOL;
- NotifyWinEventFunc: procedure(event: DWORD; hwnd: HWND; idObject: DWORD;
- idChild: Longint); stdcall;
- procedure CallNotifyWinEvent(event: DWORD; hwnd: HWND; idObject: DWORD;
- idChild: Longint);
- begin
- if not NotifyWinEventInited then begin
- NotifyWinEventFunc := GetProcAddress(GetModuleHandle(user32), 'NotifyWinEvent');
- InterlockedExchange(Integer(NotifyWinEventInited), Ord(True));
- end;
- if Assigned(NotifyWinEventFunc) then
- NotifyWinEventFunc(event, hwnd, idObject, idChild);
- end;
- var
- OleAccInited: BOOL;
- OleAccAvailable: BOOL;
- function InitializeOleAcc: Boolean;
- var
- M: HMODULE;
- begin
- if not OleAccInited then begin
- M := {$IFDEF JR_D5} SafeLoadLibrary {$ELSE} LoadLibrary {$ENDIF} ('oleacc.dll');
- if M <> 0 then begin
- LresultFromObjectFunc := GetProcAddress(M, 'LresultFromObject');
- AccessibleObjectFromWindowFunc := GetProcAddress(M, 'AccessibleObjectFromWindow');
- if Assigned(LresultFromObjectFunc) and
- Assigned(AccessibleObjectFromWindowFunc) then
- OleAccAvailable := True;
- end;
- InterlockedExchange(Integer(OleAccInited), Ord(True));
- end;
- Result := OleAccAvailable;
- end;
- function AccObjectFromWindow(const Wnd: HWND; out ADisp: IDispatch): Boolean;
- var
- P: Pointer;
- begin
- if Assigned(AccessibleObjectFromWindowFunc) and
- (AccessibleObjectFromWindowFunc(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.
|