如何获得字符串的值?

时间:2014-04-17 17:50:02

标签: delphi exception window controls delphi-xe2

{ *
  * 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

2 个答案:

答案 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;