Конференция "WinAPI" » Альтернатива SendMessage [D7, WinXP]
 
  • Игорь404 (07.04.09 09:40) [0]
    Уважаемые, существует ли альтернатива использованию конструкции SendMessage() для передачи сообщения объекту тестируемого приложения.

    Дело в том, что данная конструкция не работает на практике, применительно к объектам следующих классов: TreeView и DateTimePicker (В тестируемом приложении используются модификации этих классов. SysTreeView32, SysDateTimePick32). Всевозможные варианты использования SendMessage() уже перебрал и не добился результатов. Неделя потраченного времени и нервов. Возможно существует другой способ отправки сообщений?
    Существует ли возможность изменения значения (к примеру даты в DateTimePicker) через адреса памяти текущего процесса?
    Заранее благодарен.
  • Медвежонок Пятачок © (07.04.09 10:04) [1]
    СендМессджу глубоко фиолетово, что там было модифицировано. Он как посылал сообщение окну, так и посылает.
  • Игорь Шевченко © (07.04.09 10:54) [2]

    > Дело в том, что данная конструкция не работает на практике


    работает. применительно к объектам любых классов, лишь бы HWND был
  • Игорь404 (07.04.09 11:40) [3]
    Игорь, я пробовал следующие конструкции:
    SendMessage(Win_Handle ,DTM_SETSYSTEMTIME, GDT_VALID, Longint(@stF) );

    где
    stF: SYSTEMTIME;

     stF.wYear:= 2009;
     stF.wMonth:= 1;
     stF.wDay:= 11;
     stF.wHour:= 12;
     stF.wMinute:= 30;
     stF.wSecond:= 12;
     stF.wMilliseconds:= 0;

    Применительно к приложению, они не работают.

    Но вот, что интересно: конструкция
    SendMessage(a,DTM_SETFORMAT,0, Longint(PChar(Edit1.Text)));

    отрабатывает и возвращает (1), но формат устанавливается "неправильный".
  • Игорь Шевченко © (07.04.09 11:47) [4]
    Э...тебе в другое приложение надо указатель передать через SendMessage ?

    Так точно не получится, надо в другое приложение DLL внедрять
  • Игорь404 (07.04.09 11:56) [5]
    Да, именно, к внешнему процессу.
    И sendMessage() работает в большенстве случаев. (Применительно к объектам ComboBox и EditText например).
    И если это единственное решение, не мог бы поподробне рассказать (в контексте решаймой задачи)? А теорию я уже сам нарою.
  • Игорь Шевченко © (07.04.09 12:46) [6]
    Игорь404   (07.04.09 11:56) [5]


    > Да, именно, к внешнему процессу.
    > И sendMessage() работает в большенстве случаев. (Применительно
    > к объектам ComboBox и EditText например).


    Строки Windows умеет передавать между приложениями, а вот структуры - не умеет.


    > И если это единственное решение, не мог бы поподробне рассказать
    > (в контексте решаймой задачи)?


    Подробнее в книге Рихтера "Windows для профессионалов", четвертое издание, глава 22.
  • Игорь404 (07.04.09 12:50) [7]
    Игорь, спасибо за столь точную ссылку. :) Иду читать...
  • DVM © (07.04.09 16:03) [8]

    > Игорь Шевченко ©   (07.04.09 12:46) [6]


    > Строки Windows умеет передавать между приложениями, а вот
    > структуры - не умеет.

    WM_COPYDATA умеет
  • Игорь Шевченко © (07.04.09 16:08) [9]
    DVM ©   (07.04.09 16:03) [8]

    К сожалению оконные классы, указанные в первом посте ветки на WM_COPYDATA не реагируют так, как хотелось бы автору.
  • аноним (07.04.09 21:26) [10]
    Вот люди а, передают в чужой процесс указатель и ждут, что там появится его структура.
  • аноним (07.04.09 21:28) [11]
    Что delphi делает с человеком ?!!!
  • guav © (08.04.09 00:02) [12]

    > Вот люди а, передают в чужой процесс указатель и ждут, что
    > там появится его структура.

    И вам читать Рихтера :-)
  • guav © (08.04.09 00:07) [13]
    Кстати, к сожалению из издания "Windows via C/C++" 2008 года убрана глава про сообщения.
  • Игорь Шевченко © (08.04.09 00:26) [14]
    guav ©   (08.04.09 00:07) [13]

    У меня есть третье издание Windows для профессионалов (95-го года), так в четвертое тоже не все вошло и тоже выброшена часть по User (правда, сейчас не вспомню, какая), и выброшен хороший пример по синхронизации (Supermarket). Это к тому, что в очередном издании появится что-нибудь про особенности 128-разрядной Windows как там борятся с DLL Hell, но будет убрана например глава про Memory-mapped files...
  • guav © (08.04.09 00:58) [15]
    Кстати, ещё момент. В Висте ж появилось Address space layout randomization. В издании 2008 года оно упоминается. Но пример внедрения с CreateRemoteThread тоже имеется, и описание rebase тоже. Тема влияния ASLR на CreateRemoteThread не раскрыта.
  • аноним (08.04.09 08:23) [16]
    >guav ©   (08.04.09 00:02) [12]
    >И вам читать Рихтера :-)
    Что именно ?
  • Человек (08.04.09 08:56) [17]

    > guav ©   (08.04.09 00:58) [15]
    > Кстати, ещё момент. В Висте ж появилось Address space layout
    > randomization. В издании 2008 года оно упоминается. Но пример
    > внедрения
    > с CreateRemoteThread тоже имеется, и описание rebase тоже.
    >
    > Тема влияния ASLR на CreateRemoteThread не раскрыта.
    >

    А должно быть влияние ?
  • аноним (08.04.09 12:09) [18]

    > И вам читать Рихтера :-)

    Мало читать плохо, и много читать тоже вредно, начинает мерещиться всякое, всякое страшное и не возможное
  • guav © (08.04.09 15:53) [19]
    аноним   (08.04.09 08:23) [16]

    > Что именно ?


    Про маршаллинг сообщений.
    Некоторые структуры таки оказываются "чудом" в чужом процессе. Все структуры сообщений, что меньше WM_USER.

    Человек   (08.04.09 08:56) [17]

    > А должно быть влияние ?

    Нет, но это ж неочевидно ;-)
  • Rouse_ © (08.04.09 15:57) [20]

    > Так точно не получится, надо в другое приложение DLL внедрять

    Библиотеку то зачем?
  • аноним (08.04.09 19:00) [21]

    > Про маршаллинг сообщений.Некоторые структуры таки оказываются
    > "чудом" в чужом процессе. Все структуры сообщений, что меньше
    > WM_USER

    Тут как раз таки никакого волшебства, система про эти сообщения знает, знает размер структуры или строки и копирует в адресное пространство все это.
    В данном случае надо это делать самому, без магии все ручками
    ИМХО тут WM_COPYDATA лучший вариант
  • Rouse_ © (08.04.09 22:31) [22]
    Никак не могу понять, чем WM_COPYDATA (будучи упомянутой уже дважды в данной ветке) может помочь при отправке того-же DTM_SETSYSTEMTIME?
  • Игорь Шевченко © (08.04.09 22:51) [23]
    Rouse_ ©   (08.04.09 22:31) [22]


    > Никак не могу понять, чем WM_COPYDATA (будучи упомянутой
    > уже дважды в данной ветке) может помочь при отправке того-
    > же DTM_SETSYSTEMTIME?


    ну если DTM_SETSYSTEMTIME не получается, может DateTimePicker на WM_COPYDATA согласится...
  • Игорь404 (09.04.09 07:24) [24]
    С WM_COPYDATA у меня таки ничего не получилось. Да даже еслиб и получилось, то как в этом случае быть с TreeView?
  • clickmaker © (09.04.09 10:00) [25]
    > даже еслиб и получилось, то как в этом случае быть с TreeView?

    а почему тривью должно вдруг обрабатывать wm_copydata?
  • Rouse_ © (09.04.09 10:10) [26]

    > как в этом случае быть с TreeView?

    Вот тебе старый пример работы с CommCtrl окнами в удаленном процессе, делай по аналогии:

    ////////////////////////////////////////////////////////////////////////////////
    //
    //  ****************************************************************************
    //  * Unit Name : RemoteSysListView32
    //  * Purpose   : Демо работы с удаленным SysListView32
    //  * Author    : Александр (Rouse_) Багель
    //  * Copyright : © Fangorn Wizards Lab 1998 - 2007
    //  * Version   : 1.01
    //  * Home Page : http://rouse.drkb.ru
    //  ****************************************************************************
    //

    program RemoteSysListView32;

    {$APPTYPE CONSOLE}

    uses
     Windows,
     SysUtils,
     CommCtrl;

    var
     hwndRemoteSysListView: HWND = 0;
     hProcess: THandle = 0;
     dwProcessID: DWORD = 0;
     dwBytesWriten: DWORD;
     nItemCount: Integer = 0;
     I, nTextLength: Integer;
     cchTextMax: Integer = 255;
     plviRemoteLVItem: PLVItem = nil;
     lviRemoteLVItem: LV_ITEM;
     pszText: PChar = nil;
     svText: ShortString;
     ARect: TRect;
     pRemoteRect: Pointer = nil;

     function GetFirstChild(hwndValue: HWND): HWND;
     begin
       Result := GetWindow(hwndValue, GW_CHILD);
     end;

     function Translate(Value: String): String;
     begin
       SetLength(Result, Length(Value));
       AnsiToOem(@Value[1], @Result[1]);
     end;

    begin
     // Ищем SysListView32 рабочего стола
     hwndRemoteSysListView := GetFirstChild(GetFirstChild(FindWindow('ProgMan', nil)));
     if hwndRemoteSysListView = 0 then ExitProcess(GetLastError);

     // Получаем количество элементов (ярлыков на рабочем столе)
     nItemCount := ListView_GetItemCount(hwndRemoteSysListView);

     // Получаем ID процесса, которому принадлежит найденное окно
     GetWindowThreadProcessId(hwndRemoteSysListView, @dwProcessID);
     if dwProcessID = 0 then ExitProcess(GetLastError);

     // Открываем процесс
     hProcess := OpenProcess(PROCESS_ALL_ACCESS, TRUE, dwProcessID);
     if hProcess = 0 then ExitProcess(GetLastError);

     // Выделяем в нем память под текстовый буффер
     pszText := VirtualAllocEx(hProcess, nil, cchTextMax,
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
     if GetLastError <> 0 then ExitProcess(GetLastError);

     // Выделяем в нем память под структуру LVITEM
     plviRemoteLVItem := VirtualAllocEx(hProcess, nil, SizeOf(LV_ITEM),
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
     if GetLastError <> 0 then ExitProcess(GetLastError);

     // Заполняем структуру
     ZeroMemory(@lviRemoteLVItem, SizeOf(LV_ITEM));
     lviRemoteLVItem.mask := LVIF_TEXT;
     lviRemoteLVItem.pszText := pszText;
     lviRemoteLVItem.cchTextMax := cchTextMax;

     // Пишем ее в память удаленного процесса
     if not WriteProcessMemory(hProcess, plviRemoteLVItem, @lviRemoteLVItem,
       SizeOf(LV_ITEM), dwBytesWriten) then ExitProcess(GetLastError);

     // Выделяем в нем память под структуру TRect
     pRemoteRect := VirtualAllocEx(hProcess, nil, SizeOf(TRect),
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
     if GetLastError <> 0 then ExitProcess(GetLastError);

     // Получаем текст со всех элементов
     for I := 0 to nItemCount - 1 do
     begin
       // Отправляем сообщение с указателем на выделенный буффер под LVITEM
       nTextLength := SendMessage(hwndRemoteSysListView, LVM_GETITEMTEXT,
         I, Integer(plviRemoteLVItem));

       // Читаем результат
       ZeroMemory(@svText, cchTextMax);
       ReadProcessMemory(hProcess, lviRemoteLVItem.pszText,
         @svText[1], nTextLength, dwBytesWriten);

       // Чтобы получить координаты каждого элемента нужно подготовить структуру
       ZeroMemory(@ARect, SizeOf(TRect));
       ARect.Left := LVIR_ICON;
       if not WriteProcessMemory(hProcess, pRemoteRect, @ARect,
         SizeOf(TRect), dwBytesWriten) then ExitProcess(GetLastError);

       // Посылаем сообщение для получения координат каждого элемента
       SendMessage(hwndRemoteSysListView, LVM_GETITEMRECT,
         I, Integer(pRemoteRect));

       // Читаем результат
       ReadProcessMemory(hProcess, pRemoteRect,
         @ARect, SizeOf(TRect), dwBytesWriten);

       Writeln(Translate(PChar(@svText[1])));
       Writeln(Translate(
         Format('- координаты: Left = %d, Top = %d, Right = %d, Bottom = %d',
           [ARect.Left, ARect.Top, ARect.Right, ARect.Bottom])));

     end;

     // Освобождаем ранее выделенную память
     VirtualFreeEx(hProcess, pszText, 0, MEM_RELEASE);
     VirtualFreeEx(hProcess, plviRemoteLVItem, 0, MEM_RELEASE);

     // Закрываем описатель процесса
     CloseHandle(hProcess);

     Readln;
    end.

  • Игорь404 (09.04.09 13:26) [27]
    Дело в том, что элементов управления очень много и придется адаптировать код к каждому отдельно (или адаптировать ко всем сразу).

    Но вот на что я наткнулся
    "Внедрение библиотеки через CreateRemoteThread"
    http://delphisite.ru/faq/vnedrenie-biblioteki-cherez-createremotethread
    Выполнение собственного кода в чужом процессе.

    Осталось только взвесить эти два варианта на предмет трудоемкости и выбрать наиболее гибкое и легкореализуемое...
  • Rouse_ © (09.04.09 13:32) [28]
    Из пушки по воробьям :) Хотя... хозяин барин.

    ЗЫ: Если что - то этот пример (по ссылке) нормально выгружается только из своего собственного процесса, более полный вариант этой демки можешь взять тут: http://forum.sources.ru/index.php?showtopic=248156&st=0&#entry2057057
  • Игорь404 (09.04.09 14:19) [29]
    Наверное много времени бы потратил на отладку :)

    К счастью человек эволюционирует и на смену рогаткам, с чрезвычайно узким спектром применения, приходят мелкокалиберные винтовки, с ненамного большим, но однако же большим. И все это я к тому, что не факт что только по "воробьям", если ты меня понимаешь. :) В мое случае приложение должно быть достаточно гибким, чтобы в перспективе была возможноть оперативно изменять его согласно новым требованиям. Мне кажется в случае с DLL injection приложение будет обладать достаточной гибкостью и масштабируюмостью.
  • аноним (09.04.09 15:29) [30]

    > Никак не могу понять, чем WM_COPYDATA (будучи упомянутой
    > уже дважды в данной ветке) может помочь при отправке того-
    > же DTM_SETSYSTEMTIME?

    Привилегий хватит писать в память чужого процесса ? Как Виста на такое отреагирует и Вин7 (я точно не знаю)?
    Лучше переписать прогу чтобы она принимала WM_COPYDATA и не волноваться за будующее
  • Игорь Шевченко © (09.04.09 20:30) [31]

    > Лучше переписать прогу чтобы она принимала WM_COPYDATA и
    > не волноваться за будующее


    DateTimePicker переписать или TreeView ?
  • аноним (10.04.09 04:15) [32]

    > DateTimePicker переписать или TreeView ?

    Такие откровенные глупости писать не надо. Хорошо ?
    Я понимаю делфи и все такое, но есть же предел в конце концов.
  • Rouse_ © (10.04.09 09:11) [33]

    > Такие откровенные глупости писать не надо. Хорошо ?

    Хорошо, не будем - только и ты плз глупости не пиши о переписывании программы и читай внимательней, желательно с самого начала. Приложение чужое, поэтому у тебя и спрашивают, что именно в чужом приложении стоит переписать?
  • Игорь404 (10.04.09 11:41) [34]
    Возможно я ввел кого-то в заблуждение, но к коду тестируемого приложения доступа нет.
  • аноним (10.04.09 13:36) [35]

    > Хорошо, не будем - только и ты плз глупости не пиши о переписывании
    > программы и читай внимательней, желательно с самого начала.
    >  Приложение чужое, поэтому у тебя и спрашивают, что именно
    > в чужом приложении стоит переписать?

    Где там сказано, что код чужой ? Там сказано, что процесс другой.
  • Игорь404 (10.04.09 15:11) [36]
    Задача решена. Я внедрил DLL в процесс тестируемого приложения и передал ему
    SendMessage(handle, DTM_SETSYSTEMTIME, GDT_VALID, Longint(@dateTime));
    теперь все работает, не тестировал еще с TreView, но думаю и здесь проблем не будет.
    Осталось решить проблему с адаптированием DLLки к разным элементам управления, но это уже другая история.

    p.s. Ради таких минут мы и живем друзья, спасибо! :)
  • имя (13.07.09 13:10) [37]
    Удалено модератором
 
Конференция "WinAPI" » Альтернатива SendMessage [D7, WinXP]
Есть новые Нет новых   [134433   +24][b:0][p:0.003]