{ *
* AControl: Control handle determined by Spy++ (e.g. 0037064A)
* ANewText: Text to assign to control
* AWinTitle: Window Title/Caption
* }
function ControlSetText(const AControl, ANewText, AWinTitle: string): boolean;
function EnumChildren(AWindowHandle: HWND; ALParam: lParam): bool; stdcall;
begin
ShowMessage(AControl); // if commented out - code works fine
TStrings(ALParam).Add(IntToStr(GetDlgCtrlID(AWindowHandle)));
Result := true;
end;
var
_MainWindowHandle: HWND;
_WindowControlList: TStringlist;
i: integer;
_ControlHandle: integer;
begin
Result := false;
_MainWindowHandle := FindWindow(nil, PWideChar(AWinTitle));
if _MainWindowHandle <> 0 then
begin
_WindowControlList := TStringlist.Create;
try
if TryStrToInt('$' + Trim(AControl), _ControlHandle) then
try
EnumChildWindows(_MainWindowHandle, @EnumChildren,
UINT_PTR(_WindowControlList));
for i := 0 to _WindowControlList.Count - 1 do
begin
if (StrToInt(_WindowControlList[i]) = _ControlHandle)
then
begin
SendMessage(StrToInt(_WindowControlList[i]), WM_SETTEXT, 0,
integer(PCHAR(ANewText)));
Result := true;
end;
end;
except
on E: Exception do
MessageDlg(E.Message, TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0)
end;
finally
FreeAndNil(_WindowControlList);
end;
end;
end;
调试器使用消息
引发异常---------------------------调试器异常通知----------------- ----------
项目Default_project.exe引发了异常类$ C0000005,并显示消息“访问冲突” 0x00406fae:写入地址0x00408dbb'。
它打破了:
for i := 0 to _WindowControlList.Count - 1 do
我称之为:
ControlSetText('00070828', 'New TEdit text', 'Delphi_test_app');
我正在计划更新,因此,不仅可以传递控制句柄,还可以控制类型+标识符,例如'EDIT1'。
编辑:
我要做的是实施http://www.autohotkey.com/docs/commands/ControlSetText.htm
答案 0 :(得分:4)
问题是你的回调是一个本地嵌套函数。那就是它嵌套在ControlSetText
里面。它必须在全球范围内声明。
必须通过lParam
参数传递任何额外的状态信息。
我也觉得奇怪的是你在字符串中存储整数和指针。将它们存储为整数或指针。
事实上,它不仅仅是奇怪的。您将控件ID放在列表中,作为字符串,但然后将它们用作窗口句柄。因此,一旦您通过崩溃,代码将无法正常工作。我不想在这个问题上进行调试。
答案 1 :(得分:1)
崩溃的根本原因是你正在使用内部函数作为EnumChildWindows()
回调,并且它正在引用来自其外部函数的参数,这将无效(以及当你注释掉它时它为什么会起作用)访问该参数)。调用堆栈帧不是EnumChildWindows()
所期望的。你需要让内部函数成为一个独立的函数。
话虽如此,您的代码中还有另一个错误。即使上述方法有效,您的代码仍会失败,因为您在TStringList
中存储了控件ID ,但之后使用它们就好像它们是 HWND
值< / strong>相反。他们不是!
尝试更像这样的事情:
uses
..., System.Generics.Collections;
{ *
* AControl: Control handle determined by Spy++ (e.g. 0037064A)
* ANewText: Text to assign to control
* AWinTitle: Window Title/Caption
* }
type
THWndList = TList<HWND>;
function EnumChildren(AWindowHandle: HWND; AParam: LPARAM): BOOL; stdcall;
begin
THWndList(AParam).Add(AWindowHandle);
Result := TRUE;
end;
function TryStrToHWnd(const AStr: String; var Wnd: HWND): Boolean;
begin
{$IFDEF WIN64}
Result := TryStrToInt64(AStr, Int64(Wnd));
{$ELSE}
Result := TryStrToInt(AStr, Integer(Wnd));
{$ENDIF}
end;
function ControlSetText(const AControl, ANewText, AWinTitle: String): Boolean;
var
_MainWindowHandle: HWND;
_WindowControlList: THWndList;
i: integer;
_ControlHandle: HWND;
EnumInfo: TEnumInfo;
begin
Result := False;
_MainWindowHandle := FindWindow(nil, PChar(AWinTitle));
if _MainWindowHandle <> 0 then
begin
_WindowControlList := THWndList;
try
if TryStrToHWnd('$' + Trim(AControl), _ControlHandle) then
try
EnumChildWindows(_MainWindowHandle, @EnumChildren, LPARAM(_WindowControlList));
for i := 0 to _WindowControlList.Count - 1 do
begin
if (_WindowControlList[i] = _ControlHandle) then
begin
Result := SendMessage(_WindowControlList[i], WM_SETTEXT, 0, LPARAM(PChar(ANewText))) = 1;
Break;
end;
end;
except
on E: Exception do
MessageDlg(E.Message, TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0);
end;
finally
FreeAndNil(_WindowControlList);
end;
end;
end;
可替换地:
{ *
* AControl: Control handle determined by Spy++ (e.g. 0037064A)
* ANewText: Text to assign to control
* AWinTitle: Window Title/Caption
* }
type
PEnumInfo = ^TEnumInfo;
TEnumInfo = record
Control: HWND;
Found: Boolean;
end;
function EnumChildren(AWindowHandle: HWND; AParam: LPARAM): BOOL; stdcall;
begin
PEnumInfo(AParam).Found := (AWindowHandle = PEnumInfo(AParam).Control);
Result := not PEnumInfo(AParam).Found;
end;
function TryStrToHWnd(const AStr: String; var Wnd: HWND): Boolean;
begin
{$IFDEF WIN64}
Result := TryStrToInt64(AStr, Int64(Wnd));
{$ELSE}
Result := TryStrToInt(AStr, Integer(Wnd));
{$ENDIF}
end;
function ControlSetText(const AControl, ANewText, AWinTitle: String): Boolean;
var
_MainWindowHandle: HWND;
_ControlHandle: HWND;
EnumInfo: TEnumInfo;
begin
Result := False;
_MainWindowHandle := FindWindow(nil, PChar(AWinTitle));
if _MainWindowHandle <> 0 then
begin
if TryStrToHWnd('$' + Trim(AControl), _ControlHandle) then
try
EnumInfo.Control := _ControlHandle;
EnumInfo.Found := False;
EnumChildWindows(_MainWindowHandle, @EnumChildren, LPARAM(@EnumInfo));
if EnumInfo.Found then
begin
Result := SendMessage(_ControlHandle, WM_SETTEXT, 0, LPARAM(PChar(ANewText))) = 1;
end;
except
on E: Exception do
MessageDlg(E.Message, TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0);
end;
end;
end;
或者只是摆脱EnumChilWindows()
并让Windows验证您尝试发送到的HWND
:
{ *
* AControl: Control handle determined by Spy++ (e.g. 0037064A)
* ANewText: Text to assign to control
* }
function TryStrToHWnd(const AStr: String; var Wnd: HWND): Boolean;
begin
{$IFDEF WIN64}
Result := TryStrToInt64(AStr, Int64(Wnd));
{$ELSE}
Result := TryStrToInt(AStr, Integer(Wnd));
{$ENDIF}
end;
function ControlSetText(const AControl, ANewText: String): Boolean;
var
_ControlHandle: HWND;
begin
Result := TryStrToHWnd('$' + Trim(AControl), _ControlHandle) and
(SendMessage(_ControlHandle, WM_SETTEXT, 0, LPARAM(PChar(ANewText))) = 1);
end;