Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > выдрать текст из RichEdit20A


Автор: Smailik 16.5.2006, 13:17
если класс ричедита TRichEdit - все пашет
а с родными ричедитами Windows - вышибает прогу которой принадлежит ричедит. где грабли? подскажите плиз!!!

Код

procedure TForm1.Button1Click(Sender: TObject);
var
  TextRange: TGetTextEx;
  gtl : TGetTextLengthEx;
  mass : Pchar;
  tmp : integer;
  AHandle : THandle;
begin
  AHandle := FindWindow(nil,Pchar(Edit1.Text));

  enumChildWindows(AHandle, @enumListOfChildTasks, LongInt(Self)); //возвращает handle ричедита - проверял верно работает 

  getmem(mass,4048);

  if EditHandle = 0 then begin
    ShowMessage('not found.');
  end
  else begin
    Memo1.Lines.Clear;
      with gtl do begin
        flags := GTL_DEFAULT;
        codepage := CP_ACP;
      end;


    with TextRange do begin
      cb := 0;
      flags := GT_DEFAULT;
      codepage := cp_ACP;
      lpDefaultChar := nil;
      lpUsedDefChar := nil;
    end;

// вот тут аварийно завершается прога которой принадлежит ричедит, например WordPad
    tmp := SendMessage(EditHandle, EM_GETTEXTEX, integer(@textrange), integer(mass)); 
    Memo1.Lines.Add(string(mass));
//    tmp := SendMessage(EditHandle, EM_GETTEXTLENGTHEX , integer(@gtl), 0); //количество букв
    ShowMessage(inttostr(tmp));
  end;

  freemem(mass);
end;
 

Автор: RA 16.5.2006, 17:38
Там нужно не сенд месаджи слать а GetWindowText

Добавлено @ 17:40 
Хотя сендмесаджем нужно проверить длинну данных. 

Автор: Yanis 16.5.2006, 19:45
Цитата(RAdmin @  16.5.2006,  18:38 Найти цитируемый пост)
Там нужно не сенд месаджи слать а GetWindowText

Ну можно же WM_GETTEXT+SendMessage использовать smile 

Автор: Smailik 17.5.2006, 06:28
Цитата(RAdmin @  16.5.2006,  17:38 Найти цитируемый пост)
Там нужно не сенд месаджи слать а GetWindowText


у ричедита нет title и caption


Цитата(Yanis @  16.5.2006,  19:45 Найти цитируемый пост)
Ну можно же WM_GETTEXT+SendMessage использовать   



только для edit работает

 smile  

Автор: RA 17.5.2006, 09:44
Цитата(Smailik @  17.5.2006,  06:28 Найти цитируемый пост)
у ричедита нет title и caption



GetwindowText возвращает не только заголовки окон.

Добавлено @ 09:51 
Точнее сказать будет - GetwindowText возвращает текст окон.
если окно формы то её caption, если окно рича то текст рича.

Вот правда на счёт рича не знаю возвратит она форматированный текст или Plain.

 

Автор: Yanis 17.5.2006, 12:07
Посмотрел сейчас через WIS - текст RichEdit нельзя получить через GetwindowText.

Цитата(RAdmin @  17.5.2006,  10:44 Найти цитируемый пост)
Вот правда на счёт рича не знаю возвратит она форматированный текст или Plain.
См. выше. А вообще текст возвращается как plain.
 

Автор: RA 17.5.2006, 12:36
а в форме с двумя ричами можно  smile  
Код

procedure TForm1.Button1Click(Sender: TObject);
var text : array [0..255] of Char;
begin
Windows.GetWindowText(RichEdit1.Handle,text,100);
RichEdit2.lines.add(text);
end;


ЗЫ: Таже CustomEdit, тьфу. 

Автор: Rouse_ 17.5.2006, 14:46
Прежде нужно учить матчасть и разбираться в каком АП выделен буффер, куда будет ложиться данные и как обойти границу адресных пространств двух и более процессов. Сколько раз уже повторял - читайте Рихтера, там все по полкам разложено.


Smailik, код конкретно для твоей задачи с комментариями:

Код

unit MainUnit;

interface

uses
  Windows, Graphics, Controls, Forms, ComCtrls,
  StdCtrls, Classes, SysUtils, Dialogs;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Memo1: TMemo;
    Edit2: TEdit;
    procedure Button1Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

uses RichEdit;

{$R *.dfm}

function SetDebugPriv: Boolean;
var
  Token: THandle;
  tkp: TTokenPrivileges;
begin
  Result := False;
  if OpenProcessToken(GetCurrentProcess,
    TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token) then
  begin
    if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'),
      tkp.Privileges[0].Luid) then
    begin
      tkp.PrivilegeCount := 1;
      tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      Result := AdjustTokenPrivileges(Token, false,
        tkp, 0, PTokenPrivileges(nil)^, PDWord(nil)^);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
{$DEFINE DEBUG_FIND}
var
  MainWindowHandle, RichEditWHandle: THandle;
  ProcessID : Cardinal;
  ProcessHandle : THandle;
  StructTextEx: TGetTextEx;
  StructTextLength: TGetTextLengthEx;
  PStructTextLength, PStructTextEx, PTextBuffer: Pointer;
  BytesWriten, RichEditTextLength: DWORD;
  TextBuffer: array of Char;
begin

  {$IFDEF DEBUG_FIND}
    // Заполняем данные для отладки
    // В качестве примера работаем с WordPad-ом
    Edit1.Text := 'Document - WordPad';
    Edit2.Text := 'RICHEDIT50W';
  {$ENDIF}

  // Ищем окно
  MainWindowHandle := FindWindow(nil , PChar(Edit1.Text));
  if MainWindowHandle = 0 then RaiseLastOSError;
  RichEditWHandle := FindWindowEx(MainWindowHandle, 0, PChar(Edit2.Text), nil);
  if RichEditWHandle = 0 then RaiseLastOSError;

  // Включаем отладочные привилегии
  if SetDebugPriv then
  begin

    // Узнаем ID процесса
    GetWindowThreadProcessId(MainWindowHandle, @ProcessID);
    if ProcessID = 0 then RaiseLastOSError;

    // Открываем процесс
    ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, True, ProcessID);
    if ProcessHandle = 0 then RaiseLastOSError;
    try

      // Выделяем в нем память под структуру TGetTextLengthEx
      PStructTextLength := VirtualAllocEx(ProcessHandle, nil,
        SizeOf(TGetTextLengthEx), MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
      if PStructTextLength = nil then RaiseLastOSError;
      try

        // Подготавливаем структуру...
        StructTextLength.flags := GTL_NUMBYTES or GTL_USECRLF;
        StructTextLength.codepage := CP_ACP;

        // ...и пишем ее в память процесса
        if not WriteProcessMemory(ProcessHandle, PStructTextLength,
          @StructTextLength, SizeOf(TGetTextLengthEx),
          BytesWriten) then RaiseLastOSError;
        if BytesWriten <> SizeOf(TGetTextLengthEx) then RaiseLastOSError;

        // Отправляем сообщение удаленному RichEdit,
        // чтобы узнать необходимый размер буффера
        RichEditTextLength := SendMessage(RichEditWHandle,
          EM_GETTEXTLENGTHEX , Integer(PStructTextLength), 0);
        
      finally
        // Освобождаем выделенную под TGetTextLengthEx память
        VirtualFreeEx(ProcessHandle, PStructTextLength, 0, MEM_RELEASE);
      end;

      // Выделяем память под структуру TGetTextEx
      PStructTextEx := VirtualAllocEx(ProcessHandle, nil,
        SizeOf(TGetTextEx), MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
      if PStructTextEx = nil then RaiseLastOSError;
      try

        // Подготавливаем структуру...
        ZeroMemory(@StructTextEx, SizeOf(TGetTextEx));
        StructTextEx.flags := GT_USECRLF;
        StructTextEx.cb := RichEditTextLength;

        // ...и пишем ее в память процесса
        if not WriteProcessMemory(ProcessHandle, PStructTextEx,
          @StructTextEx, SizeOf(TGetTextEx),
          BytesWriten) then RaiseLastOSError;
        if BytesWriten <> SizeOf(TGetTextEx) then RaiseLastOSError;

        // Выделяем память под текстовый буффер
        PTextBuffer := VirtualAllocEx(ProcessHandle, nil,
        RichEditTextLength, MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
        if PTextBuffer = nil then RaiseLastOSError;
        try

          // отправляем сообщение
          SendMessage(RichEditWHandle, EM_GETTEXTEX, Integer(PStructTextEx),
            Integer(PTextBuffer));

          // Читаем, то, что у нас скопировалось
          SetLength(TextBuffer, RichEditTextLength);
          if not ReadProcessMemory(ProcessHandle, PTextBuffer, @TextBuffer[0],
            RichEditTextLength, BytesWriten) then RaiseLastOSError;

          Memo1.Text := String(TextBuffer);

        finally
          // Освобождаем выделенную под тестовый буффер память
          VirtualFreeEx(ProcessHandle, PTextBuffer, 0, MEM_RELEASE);
        end;

      finally
        // Освобождаем выделенную под TGetTextEx память
        VirtualFreeEx(ProcessHandle, PStructTextEx, 0, MEM_RELEASE);
      end;

    finally
      // Закрываем процесс
      CloseHandle(ProcessHandle);
    end;
  end;
end;

end.
 

Автор: Rouse_ 17.5.2006, 16:55
Кстати, RAdmin, по поводу GetWindowText. Неаккуратненько как то давать такие советы smile

Цитата

The GetWindowText function copies the text of the specified window's title bar (if it has one) into a buffer. If the specified window is a control, the text of the control is copied. However, GetWindowText cannot retrieve the text of a control in another application.
 

Автор: RA 18.5.2006, 09:47
Мда, не отмерил 7 раз, а сразу отрезал.  smile  

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)