Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 02.06.2008, 01:39   #11
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Тогда покажите, как выглядит Ваш хук. А то мы всё вокруг да около.
B_N вне форума Ответить с цитированием
Старый 02.06.2008, 02:21   #12
MyasNick
Пользователь
 
Аватар для MyasNick
 
Регистрация: 30.05.2008
Сообщений: 22
Сообщение

Цитата:
Сообщение от B_N Посмотреть сообщение
Тогда покажите, как выглядит Ваш хук. А то мы всё вокруг да около.


Да, собственно, вполне стандартно и безобидно

вот библиотека:

Код:
library hooklib;

uses
  Windows,
  Messages;  

const
  CM_TKHOOK = WM_USER + $1000;
  HotKey = 'Right Ctrl';

var
  TKHOOK      : HHook;
  MyHandle    : THandle;
  PReceptor   : ^Integer;
  isActivate  : boolean;

function HookFunc    ( Code    : Integer;
                       wParam  : WPARAM;
                       lParam  : LPARAM
                     )         : LRESULT; stdcall;

var MyKey : array[0..32] of char;
begin
  Result := 0;
  MyHandle := OpenFileMapping (FILE_MAP_READ, False, 'Receptor');
  if (MyHandle <> 0) then
    begin
      GetKeyNameText(LParam, @MyKey, 32);
      if string(MyKey) = HotKey
        then if ((lParam shr 31) and 1) = 1 
                then isActivate := false
                else isActivate := true;
      if (Code in [HC_ACTION, HC_NOREMOVE]) and isActivate
        then begin
          PReceptor := MapViewOfFile (MyHandle, FILE_MAP_READ, 0, 0, 0);
          SendMessage (PReceptor^, CM_TKHOOK, wParam, lParam);
          UnmapViewOfFile (PReceptor);
          CloseHandle (MyHandle);
          Result := 1;
        end;
    end;
  CallNextHookEx (TKHOOK, Code, wParam, lParam);
end;

procedure HookOn; stdcall;
begin
  TKHOOK := SetWindowsHookEx (WH_KEYBOARD, HookFunc, HInstance, 0);
end;

procedure HookOff;  stdcall;
begin
  UnhookWindowsHookEx (TKHOOK);
end;

exports
  HookOn,
  HookOff;

begin
end.
вот обработчик:

Код:
procedure TfrmMain.Hooking (var Message: TMessage);
var MyKey : array[0..32] of char;
begin
  GetKeyNameText (Message.LParam, @MyKey, 32);
  if (length(string(MyKey)) = 1) and not (((Message.lParam shr 31) and 1) = 1)
    then TypeSymbol(MyKey[0]);
end;

function TypeSymbol(Key: char): boolean;
var Symbol: word;
    A,B: DWORD;
begin
  A := GetCurrentThreadId;
  B := GetWindowThreadProcessId(GetForegroundWindow, nil);
  if A<>B then AttachThreadInput(A, B, True);
  Symbol := constEqual; // тут код символа
  SendMessage(GetFocus, WM_CHAR, Symbol, 1); // Строка убивает IE7
  if A<>B then AttachThreadInput(A, B, false);      
  Result := Symbol <> 0;
end;
в .Create главной формы вот этот код идентификации приложения, инициализации dll-ки и запуска hook-а:

Код:
  HandleDLL := LoadLibrary (PChar(ApplicationPath + DLLName));
   if HandleDLL = 0 then raise Exception.Create('DLL not found');
  @HookOn  := GetProcAddress(HandleDLL, 'HookOn');
  @HookOff := GetProcAddress(HandleDLL, 'HookOff');
  if not assigned(HookOn) or not assigned(HookOff)  then
    raise Exception.Create('Can''t find the required DLL functions');
  MyHandle := CreateFileMapping( $FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(Integer), 'Receptor');
  if MyHandle = 0 then
     raise Exception.Create('Error while creating file');
  PReceptor := MapViewOfFile(MyHandle,FILE_MAP_WRITE,0,0,0);
  PReceptor^ := Handle;
  HookOn;
MyasNick вне форума Ответить с цитированием
Старый 02.06.2008, 03:14   #13
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Значит, первое, что бросилось в глаза.
1. Нужна ли Вам AttachThreadInput? Если вся её задача состоит в получении фокуса, то это можно сделать так: http://programmersforum.ru/showpost....75&postcount=9
2. Есть ли вообще смысл в пересылке сообщений "хозяину" хука? (насколько я понял TfrmMain.Hooking - это обработчик CM_TKHOOK в "главном" процессе). Отправить WM_CHAR можно меньшими усилиями уже находясь в "нужном" потоке (или по крайней мере, процессе) внутри хука.
3. В строке 38 Вы закрываете хэндл не в том месте (внутри еще одного условия). Да и зачем, вообще, Вы каждый раз открываете/закрываете мэппинг, если это достаточно сделать при инициализации/выгрузке Ваше Dll? Это, кстати, не самая быстрая операция.
4. Не изменится ли картина если после строки 39 не передавать сообщение следующему хуку?
B_N вне форума Ответить с цитированием
Старый 03.06.2008, 20:56   #14
MyasNick
Пользователь
 
Аватар для MyasNick
 
Регистрация: 30.05.2008
Сообщений: 22
Восклицание

Цитата:
Сообщение от B_N Посмотреть сообщение
Значит, первое, что бросилось в глаза.
1. Нужна ли Вам AttachThreadInput? Если вся её задача состоит в получении фокуса, то это можно сделать так: http://programmersforum.ru/showpost....75&postcount=9
Да, только для получения фокуса. Сделал как Вы предлагаете. Работает. Единственно, не уловил смысла в этом. Или использование AttachThreadInput не оптимально или чем-то чревато? Просто ее использование рекомендует MSDN.

Цитата:
Сообщение от B_N Посмотреть сообщение
2. Есть ли вообще смысл в пересылке сообщений "хозяину" хука? (насколько я понял TfrmMain.Hooking - это обработчик CM_TKHOOK в "главном" процессе). Отправить WM_CHAR можно меньшими усилиями уже находясь в "нужном" потоке (или по крайней мере, процессе) внутри хука.
Согласен с Вами, но такого поведения требует архитектура проекта.

Цитата:
Сообщение от B_N Посмотреть сообщение
3. В строке 38 Вы закрываете хэндл не в том месте (внутри еще одного условия). Да и зачем, вообще, Вы каждый раз открываете/закрываете мэппинг, если это достаточно сделать при инициализации/выгрузке Ваше Dll? Это, кстати, не самая быстрая операция.
Да, Вы совершенно правы. Спасибо! Мой недосмотр. Воспользовался готовым кодом хука, подточив его под себя. Видимо, недоточил

Цитата:
Сообщение от B_N Посмотреть сообщение
4. Не изменится ли картина если после строки 39 не передавать сообщение следующему хуку?
Нет, IE7 как падал, так и падает. Да и нельзя этого делать - умирают клавиатурные хуки других приложений.
MyasNick вне форума Ответить с цитированием
Старый 06.06.2008, 03:44   #15
MyasNick
Пользователь
 
Аватар для MyasNick
 
Регистрация: 30.05.2008
Сообщений: 22
По умолчанию

Все оказалось достаточно элементарно. Вместо WM_CHAR нужно использовать WM_IME_CHAR. IE перестает падать, все прекрасно работает в FireFox, Word и т.д.

B_N, большое спасибо за помощь!
MyasNick вне форума Ответить с цитированием
Старый 06.06.2008, 11:30   #16
JTG
я получил эту роль
Старожил
 
Аватар для JTG
 
Регистрация: 25.05.2007
Сообщений: 3,694
По умолчанию

* HINT: Не используйте в хуковых процедурах (и callback-процедурах вообще) SendMessage, иначе зависнувший хук может потащить за собой приложение.
Лучше PostMessage
пыщь
JTG вне форума Ответить с цитированием
Старый 06.06.2008, 17:15   #17
MyasNick
Пользователь
 
Аватар для MyasNick
 
Регистрация: 30.05.2008
Сообщений: 22
Восклицание

Цитата:
Сообщение от JTG Посмотреть сообщение
* HINT: Не используйте в хуковых процедурах (и callback-процедурах вообще) SendMessage, иначе зависнувший хук может потащить за собой приложение. Лучше PostMessage
Только что в этом сам убедился! Спасибо за предупреждение.

В общем так: IE глючил именно из-за SendMessage. Правда в сочетании с WM_IME_CHAR он как-то её переваривал. С PostMessage дружат все (и Word и Photoshop, и FireFox, и д.р.). Для отправки символов с кодом >=255 нужно просто использовать PostMessageW.

Но тут начинается другое шаманство: большая часть программ прекрасно работает с PostMessage/PostMessageW + WM_CHAR. Но есть софт (FireFox, редактор Delphi) которые переваривают только WM_IME_CHAR. Интересно, есть умный способ это обойти?
MyasNick вне форума Ответить с цитированием
Старый 06.06.2008, 17:26   #18
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Цитата:
Сообщение от MyasNick Посмотреть сообщение
Интересно, есть умный способ это обойти?
В качестве варианта - проверяйте нужное окно через IsWindowUnicode, а по результату PostMessageA или PostMessageW (функции PostMessage не существует). А ещё лучше - всю цепочку, включая GetKeyNameText. JTG правильно написал, я уже и сам только потом заметил, что там SendMessage, но падало всё по-моему не от этого, какой-то глюк Вы обнаружили, по всей видимости, просто WM_CHAR - это по идее уже оттранслированное через TranslateMessage сообщение, а Вы его отправляете в юникод-окно в качестве такового, но в ANSI-виде.
B_N вне форума Ответить с цитированием
Старый 06.06.2008, 21:24   #19
MyasNick
Пользователь
 
Аватар для MyasNick
 
Регистрация: 30.05.2008
Сообщений: 22
Сообщение

IsWindowUnicode, к сожалению, не показатель. Дело в том, что некоторые Юникодные окна нормально работают с WM_CHAR и не работают с WM_IME_CHAR и наоборот. Сейчас у меня следующий код

Код:
    
if Symbol < 255
      then PostMessageA (hFocusedControl , WM_CHAR, Symbol, 1)
      else PostMessageW (hFocusedControl , WM_CHAR, Symbol, 1);
нормально работает везде, кроме FireFox, который упорно отзывается только на WM_IME_CHAR, а Word с ним так и не подружился. Уже начинаю грешить на корявую работу с LPARAM.
MyasNick вне форума Ответить с цитированием
Старый 08.04.2012, 10:46   #20
tral
Новичок
Джуниор
 
Регистрация: 08.04.2012
Сообщений: 4
Радость

Прошло почти 4 года с последнего UP'а топика
Но, все же, если автору несложно - можете скинуть работающий код?
У меня в Mozilla Firefox при длительных танцах с бубном не вставляет unicode символы. В остальные места, которые тестил - все ок.

Версия Мозиллы 11.0. Вставляю по горячей клавише в активный контрол активного окна.

Код:
procedure TForm1.WMHotkey( var msg: TWMHotkey );
var Symbol: word;
    A,B: DWORD;
begin
  if msg.hotkey = 1 then
  begin
    A := GetCurrentThreadId;
    B := GetWindowThreadProcessId(GetForegroundWindow, nil);
    if A<>B then AttachThreadInput(A, B, True);
    Symbol := Ord(#0224); // òóò êîä ñèìâîëà

    PostMessageW (GetFocus , WM_IME_CHAR, Symbol, 1);

    if A<>B then AttachThreadInput(A, B, false);

  end;
end;
tral вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Вставка текста в RichEdit NoName_emaNoN Компоненты Delphi 4 03.05.2008 12:12
чужое приложение Electrod Win Api 12 27.01.2008 17:04
Вставка текста Pedro Общие вопросы Delphi 4 27.01.2008 10:27
! Вставка текста ! ♠STO♠ Общие вопросы Delphi 2 30.08.2007 17:05
Как активировать чужое приложение Hintman Win Api 3 30.04.2007 16:24