Как запросить оригинальную строку в многострочном редакторе Windows? - PullRequest
2 голосов
/ 26 апреля 2019

Я обнаружил некоторую странность в том, как работает стандартный элемент управления Windows edit.

Когда включена перенос слов, он принимает целые логические строки, но возвращает строки экрана по запросу EM_GETLINE. Тем не менее, он корректно работает при изменении размера окна и заново разделяет текст относительно исходных CR-LF.

Итак, моя идея выяснить исходные логические строки состояла в том, чтобы запросить строки экрана с помощью EM_GETLINE, одну за другой, и обнаружить CR-LF в конце последней строки экрана в блоке.

К сожалению, строки, запрошенные EM_GETLINE, вообще не содержат CR-LF.

Кажется, что элемент управления хранит CR-LF внутри, но не возвращает их на EM_GETLINE. Их можно получить только при запросе всего контрольного текста с помощью WM_GETTEXT.

Возможно, существует какой-то другой способ запрашивать фрагменты текста между смежными CR-LF, кроме как получить весь текст и разбить его?

program WindowsEditControl;

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils;

const
  IDM_EXIT = 100;
  GAP = 10;

var
  hEdit: HWND;
  hFnt: HFONT;

function GetLine(hEdit: HWND; Index: Integer): string;
var
  Text: array[0..4095] of Char;
begin
  Word((@Text)^) := Length(Text);
  SetString(Result, Text, SendMessage(hEdit, EM_GETLINE, Index, LPARAM(@Text)));
end;

function GetTxt(hEdit: HWND): string;
var
  Len: Integer;
begin
  Len := SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0);
  SetString(Result, PChar(nil), Len);
  if Len <> 0 then
  begin
    Len := Len - SendMessage(hEdit, WM_GETTEXT, Len + 1, LongWord(PChar(Result)));
    if Len > 0 then
      SetLength(Result, Length(Result) - Len);
  end;
end;

function WndFunc(h: HWND; iMessage: UINT; w: WPARAM; l: LPARAM): LRESULT; stdcall;
var
  nWidth, nHeight: NativeUInt;
  i, j, lineLength: Integer;
  s: string;
begin
  case iMessage of
    WM_CREATE: begin
      hEdit := CreateWindowEx(WS_EX_NOPARENTNOTIFY, 'edit', 'Control #1',
        WS_BORDER or WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or ES_READONLY or WS_VSCROLL, GAP, GAP,
        810 - GAP*2 - 15, 260, h, 0, hInstance, nil);
      hFnt := CreateFont(20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Calibri');
      SendMessage(h, WM_SETFONT, hFnt, MakeLong(1, 0));
      SendMessage(hEdit, WM_SETFONT, hFnt, MakeLong(1, 0));
      for i := 0 to 10 do begin
        for j := 0 to 20 do s := s + 'Item' + IntToStr(i) + '.' + IntToStr(j) + ' ';
        s := s + #13#10;
      end;
      SendMessage(hEdit, WM_SETTEXT, 0, LongWord(PWideChar(s)));

      //Attempts to query the edit control:
      //This gets the first SCREEN line of the edit control. CR-LFs aren't there.
      MessageBox(h, PWideChar('|'+GetLine(hEdit, 0)+'|'), 'Screen line 1', 0);
      //This gets the second SCREEN line of the edit control. CR-LFs aren't there.
      MessageBox(h, PWideChar('|'+GetLine(hEdit, 1)+'|'), 'Screen line 2', 0);
      //In a whole text are all the CR-LFs there
      MessageBox(h, PWideChar(GetTxt(hEdit)), 'Whole text', 0);
    end;
    WM_DESTROY: begin
      DeleteObject(hFnt);
      PostQuitMessage(0);
      Result := 0;
    end;
    WM_SIZE: begin
      nWidth := LOWORD(l);
      nHeight := HIWORD(l);
      SetWindowPos(hEdit, 0, GAP, GAP, nWidth - GAP*2, nHeight - GAP*2, 0);
      Result := 0;
    end;
    WM_COMMAND: if w = IDM_EXIT then PostMessage(h, WM_CLOSE, 0, 0);
    else
      Result := DefWindowProc(h, iMessage, w, l);
  end;
end;

var
  wndClass: TWndClass;
  h: HWND;
  msg: TMsg;

begin
  wndClass.style          := CS_HREDRAW or CS_VREDRAW;
  wndClass.lpfnWndProc    := @WndFunc;
  wndClass.cbClsExtra     := 0;
  wndClass.cbWndExtra     := 0;
  wndClass.hInstance      := hInstance;
  wndClass.hIcon          := 0;
  wndClass.hCursor        := LoadCursor(0, IDC_ARROW);
  wndClass.hbrBackground  := GetStockObject(WHITE_BRUSH);
  wndClass.lpszMenuName   := nil;
  wndClass.lpszClassName  := 'EditTest';

  if RegisterClass(wndClass) = 0 then Halt(0);

  h := CreateWindow(wndClass.lpszClassName, 'Edit Test', WS_OVERLAPPEDWINDOW, 35, 35, 810, 320, 0, 0, hInstance, nil);
  ShowWindow(h, SW_SHOW);

  while GetMessage(msg, 0, 0, 0) do begin
    TranslateMessage(msg);
    DispatchMessage(msg);
  end;
  Halt(msg.wParam);
end.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...