library AttachLib;

uses Windows, Messages, SysUtils, PsAPI, TlHelp32;

var ThreadID  : DWORD;
    Wnds      : array of HWnd;
    hEdit     : HWnd;

// Формування переліку вікон для потоку
function EnumThreadsF(Wnd: HWnd; lP: LPARAM): boolean; stdcall;
begin
  SetLength(Wnds, Length(Wnds) + 1);
  Wnds[High(Wnds)] := Wnd;
end;

// Формування переліку дочірніх вікон для батьківського вікна
function EnumChilds(Wnd: HWnd; lP: LPARAM): boolean; stdcall;
var Cs: array[0..255] of Char;
begin
  GetClassName(Wnd, Cs, 255);
  if Cs = 'Edit' then hEdit := Wnd;
end;

// Функція потоку
function ThreadFunc(Ptr: Pointer): LongInt; stdcall;
var hSS : Thandle;
    TE : TThreadEntry32;
    EdText : PChar;
    PID    : DWORD;
    Flag   : boolean;
begin
  // Обчислення ідентифікатора викликаючого процесу
  PID := GetCurrentProcessID;

  // Формування переліку вікон верхнього рівня для
  // поточного процесу. Перше вікно цього переліку
  // Wnds[0] буде головним вікном редактора "Блокнот"
  hSS := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
  TE.dwSize := SizeOf(TE);
  Wnds := nil;
  if Thread32First(hSS, TE) then
    repeat
      if TE.th32OwnerProcessID = PID then
        EnumThreadWindows(TE.th32ThreadID, @EnumThreadsF, 0);
    until not Thread32Next(hSS, TE);
  CloseHandle(hSS);

  // Пошук у головному вікні редактора "Блокнот"
  // елемента керування 'Edit' (у нього вводиться текст)
  EnumChildWindows(Wnds[0], @EnumChilds, 0);

  // Зміна регістру літер у "Блокноті" з періодичністю 1 сек
  Flag := false;
  GetMem(EdText, 10000);
  while true do begin
    // Читання тексту з редактора
    SendMessage(hEdit, WM_GETTEXT, 10000, DWORD(EdText));
    // Зміна регістру літер на протилежний і його запис у вікно редактора
    if Flag then SendMessage(hEdit, WM_SETTEXT, 0, DWORD(PChar(AnsiUpperCase(EdText))))
      else SendMessage(hEdit, WM_SETTEXT, 0, DWORD(PChar(AnsiLowerCase(EdText))));
    Flag := not Flag;
    Sleep(1000);
  end;
  FreeMem(EdText);

  ExitThread(0);
end;

// Блок ініціалізації динамічної бібліотеки
// Виконується один раз при її завантаженні
begin
  CreateThread(nil, 0, @ThreadFunc, nil, 0, ThreadID);
end.
