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

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

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 08.01.2016, 22:08   #1
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
Печаль Ошибка при работе с хуками (WH_CALLWNDPROCRET)

Периодически (несколько раз (раза 3 пока)) при работе с хуками вылазила фатальная ошибка. При этом 'вылетают' работающее приложение, сама делфя, и перезапускается Explorer. И вот, только сейчас заметил, антивирусник тоже 'вылетел' и не запустился (как Opera и Winamp).

Вот сообщения, которые при этом вылезли:
Цитата:
Сообщение от explorer.exe - Ошибка приложения
Инструкция по адресу "0x03877642" обратилась к памяти по адресу "0x043b8508". Память не может быть "read".
"ОК" -- завершение приложения
"Отмена" -- отладка приложения
Цитата:
Сообщение от Error
Runtime error 216 at 03877642
Цитата:
Сообщение от explorer.exe - Ошибка приложения
Исключение неисвестное программное исключение (0xc0000409) в приложении по адресу 0x7e37e374
В отладчик я не полез, ибо понятия не имею чего там искать.

------------------------------------------------

Антивирус запустил. Убрал из проекта всё лишнее. Запуслил
Цитата:
Сообщение от explorer.exe - Ошибка приложения
Инструкция по адресу "0x00000000" обратилась к памяти по адресу "0x00000000". Память не может быть "read"."ОК" -- завершение приложения
"Отмена" -- отладка приложения
Опять всё повылетало.
Теперь это стало уже постоянно. Вспомнить с какого момента началось так и не смог.

------------------------------------------------

Перезагрузился. Запустил через EXE
Цитата:
Сообщение от explorer.exe - Ошибка приложения
Инструкция по адресу "0x00000000" обратилась к памяти по адресу "0x00000000". Память не может быть "read"."ОК" -- завершение приложения
"Отмена" -- отладка приложения
Опять всё повылетало. Explorer не перезапустился.

------------------------------------------------

Вышел из системы, зашел снова (без перезагрузки). "HookLibrary.dll" (моя библиотека) не удаляется.
Цитата:
Сообщение от Ошибка при удалении файла или папки
Не удается удалить HookLibrary. Нет доступа.

Диск может быть переполнен или защищен от записи,
либо файл занят другим приложением.
Через ProcessExplorer узнал, что "HookLibrary.dll" занят антивирусником :O

------------------------------------------------

Перезагрузился. Отключил антивирус. Запустил через EXE. Опять ... бла-бла-бла

------------------------------------------------

Включил антивирус. Залез в исходники. Добавил в библиотеку и приложение System.ShareMem. Опять ... бла-бла-бла.
Отключил антивирус. ... бла-бла-бла.
И главное ОНО с exe-шника работает. Ошибка есть. Всё вылетает, а ОНО работает.

------------------------------------------------

Короче, сами всё видите. Я багажник открыл, колёса попинал, фары протёр. Чё дальше делать?

------------------------------------------------

Delphi XE5
Windows XP SP3
ESET Smart Security 8
Исходник во вложении
Вложения
Тип файла: zip (2016.01) Hook.zip (62.2 Кб, 7 просмотров)
Sibedir вне форума Ответить с цитированием
Старый 08.01.2016, 22:08   #2
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

Общий модуль для DLL и EXE
Код:
unit HookUnit;

interface

uses
  Winapi.Windows;

type
  PCallWndRetProc_Proc = ^TCallWndRetProc_Proc;
  TCallWndRetProc_Proc = procedure (Msg: PCWPRetStruct; var Handled: Boolean);

implementation

end.
DLL
Код:
library HookLibrary;

uses
  System.ShareMem,
  System.SysUtils,
  Winapi.Windows,
  HookUnit in 'HookUnit.pas';

var
  CallWndRetProc_Hook: HHook = 0;
  CallWndRetProc_Proc: TCallWndRetProc_Proc = nil;

{$R *.res}

function FilterFunc_CallWndRetProc (code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT; stdcall;
var
  msg: PCWPRetStruct;
  Handled: Boolean;
begin
  if Code <> HC_ACTION then begin
    Result := CallNextHookEx (CallWndRetProc_Hook, Code, wParam, lparam);
  end
  else begin
    Result := 0;
    msg := PCWPRetStruct(lParam);
    Handled := False;
    try
      CallWndRetProc_Proc (msg, Handled);
    finally
      if not Handled then
        Result := CallNextHookEx (CallWndRetProc_Hook, Code, wParam, lparam);
    end;
  end;
end;

function SetHook_CallWndRetProc (AHandler: TCallWndRetProc_Proc): DWORD;
begin
  if Assigned(AHandler) then begin
    CallWndRetProc_Proc := AHandler;
    if CallWndRetProc_Hook = 0 then begin
      CallWndRetProc_Hook := SetWindowsHookEx (WH_CALLWNDPROCRET, @FilterFunc_CallWndRetProc, HInstance, 0);
      if CallWndRetProc_Hook <> 0 then
        Exit(GetLastError);
    end;
  end
  else begin
    if CallWndRetProc_Hook <> 0 then begin
      if not UnhookWindowsHookEx (CallWndRetProc_Hook) then
        Exit(GetLastError);
      CallWndRetProc_Hook := 0;
      CallWndRetProc_Proc := nil;
    end;
  end;
  Result := 0;
end;

function UnHook_CallWndRetProc: DWORD;
begin
  Result := SetHook_CallWndRetProc(nil);
end;

exports SetHook_CallWndRetProc;
exports  UnHook_CallWndRetProc;

begin

end.
Главное окно
Код:
unit MainForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls,
  HookUnit;

type
  TfrmMain = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

function SetHook_CallWndRetProc (AHandler: TCallWndRetProc_Proc): DWORD; external 'HookLibrary.dll' name 'SetHook_CallWndRetProc';
function UnHook_CallWndRetProc: DWORD; external 'HookLibrary.dll' name 'UnHook_CallWndRetProc';

procedure CallWndRetProc_Proc (Msg: PCWPRetStruct; var Handled: Boolean);

var
  frmMain: TfrmMain;

implementation

uses
  Unit1;

procedure CallWndRetProc_Proc (Msg: PCWPRetStruct; var Handled: Boolean);
//var
//  WC: TWinControl;
begin
//  WC := FindControl (Msg.hwnd);
//  if WC is TForm then
//    with (WC as TForm) do begin
//      if Msg.message = WM_CREATE then begin
//        Color := clRed;
//      end;
//    end;
end;

{$R *.dfm}

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  SetHook_CallWndRetProc (CallWndRetProc_Proc);
end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  UnHook_CallWndRetProc;
end;

procedure TfrmMain.Button1Click(Sender: TObject);
begin
  Application.CreateForm(TForm1, Form1);
  Form1.ShowModal;
  FreeAndNil (Form1);
end;

end.
Ну, а остальное во вложении #1.
Sibedir вне форума Ответить с цитированием
Старый 10.01.2016, 18:24   #3
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

Ну вот теперь я точно в полном ступоре.
Windows 7
Delphi XE8

DLL
Код:
library HookLibrary;

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

var
  CallWndRetProc_Hook: HHook = 0;

{$R *.res}

function FilterFunc_CallWndRetProc (code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT; stdcall;
begin
  Result := CallNextHookEx (CallWndRetProc_Hook, Code, wParam, lparam);
end;

function SetHook_CallWndRetProc: DWORD;
begin
  if CallWndRetProc_Hook = 0 then begin
    CallWndRetProc_Hook := SetWindowsHookEx (WH_CALLWNDPROCRET, @FilterFunc_CallWndRetProc, HInstance, 0);
    if CallWndRetProc_Hook <> 0 then
      Exit(GetLastError);
  end;
  Result := 0;
end;

function UnHook_CallWndRetProc: DWORD;
begin
  if CallWndRetProc_Hook <> 0 then begin
    if not UnhookWindowsHookEx (CallWndRetProc_Hook) then
      Exit(GetLastError);
    CallWndRetProc_Hook := 0;
  end;
  Result := 0;
end;

exports SetHook_CallWndRetProc;
exports  UnHook_CallWndRetProc;

begin

end.
Главное окно
(остальное вырезал)
Код:
unit MainForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls;

type
  TfrmMain = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

function SetHook_CallWndRetProc: DWORD; external 'HookLibrary.dll' name 'SetHook_CallWndRetProc';
function UnHook_CallWndRetProc: DWORD; external 'HookLibrary.dll' name 'UnHook_CallWndRetProc';

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  SetHook_CallWndRetProc;
end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  UnHook_CallWndRetProc;
end;

end.
При закрытии формы
Безымянный.jpg
Хвала небесам, еще делфя и антивирусником (Eset SS 9) не вылетают. Тока explorer перезапускается. Но этож не дело.
Sibedir вне форума Ответить с цитированием
Старый 10.01.2016, 19:36   #4
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

В фильтре вы не обрабатываете должным образом то, что вам приходит.
Читайте про return value на MSDN.
Код:
Result:=0;
if code = HC_ACTION then
begin
 //Обработываем то, что поймали....
 Resylt := 0;
end else
 result := CallNextHook ...
И это, менеджер памяти то за каким лешим в dll включен? Это только delphi-специфичная вещь для строковых типов. В остальнвх дров наломает. А вы тут хуков напихали...
Человек_Борща вне форума Ответить с цитированием
Старый 11.01.2016, 06:35   #5
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

Цитата:
Сообщение от Человек_Борща Посмотреть сообщение
В фильтре вы не обрабатываете должным образом то, что вам приходит.
Читайте про return value на MSDN.
Я это читал. И очень внимательно:
Цитата:
Если nCode больше или равен нулю, то настоятельно рекомендуется вызвать CallNextHookEx и вернуть его значение; в противном случае, другие приложения, которые установили хук WH_CALLWNDPROCRET, не будете получать уведомления и в результате могут работать неправильно.
Вот
Код:
  if Code <> HC_ACTION then begin
    Result := CallNextHookEx (CallWndRetProc_Hook, Code, wParam, lparam);
  end
  else begin
    Result := 0;
    msg := PCWPRetStruct(lParam);
    Handled := False;
    try
      //Тут я как раз и хотел обработать то, что поймали,
      CallWndRetProc_Proc (msg, Handled);
    finally
      if not Handled then // и если Handled=False,
        Result := CallNextHookEx (CallWndRetProc_Hook, Code, wParam, lparam); // вернуть CallNextHookEx. Иначе Result останется равен 0.
    end;
  end;
-------------------------------------------------------------------------------
Цитата:
И это, менеджер памяти то за каким лешим в dll включен? Это только delphi-специфичная вещь для строковых типов. В остальнвх дров наломает. А вы тут хуков напихали...
ShareMem я уже после добавил. Без него тоже ошибки вылазили. Я и сам думал, что это лишнее, и, как настоящая блондинка, решил попробовать. Но теперь, когда ты сказал, я его убираю.
-------------------------------------------------------------------------------
Пробую дальше. Еще лобовуху протереть нужно, запаску подкачать и аптечку проверить...
Sibedir вне форума Ответить с цитированием
Старый 11.01.2016, 06:50   #6
Filka
Форумчанин
 
Регистрация: 29.10.2015
Сообщений: 273
По умолчанию

Код:
begin
  if Code < 0 then
  begin
    Result := CallNextHookEx(CallWndRetProc_Hook, Code, wParam, lparam);
    Exit;
  end;
 
  if Code = HC_ACTION then
  begin
    //...
  end;

  Result := CallNextHookEx(CallWndRetProc_Hook, Code, wParam, lparam);
end;
https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx
?

Последний раз редактировалось Filka; 11.01.2016 в 06:58.
Filka вне форума Ответить с цитированием
Старый 19.01.2016, 17:48   #7
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

Всё никак руки не доходили отписаться. Короче:

Основная ошибка была в том, что я устанавливал глобальный хук,
Код:
SetWindowsHookEx (WH_CALLWNDPROCRET, @FilterFunc_CallWndRetProc, HInstance, 0);
а при обработке обращался к локальным данным
Код:
library HookLibrary;
uses
...
  HookUnit in 'HookUnit.pas';
...
var
  CallWndRetProc_Hook: HHook = 0;
  CallWndRetProc_Proc: TCallWndRetProc_Proc = nil;
...
function FilterFunc_CallWndRetProc (code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT; stdcall;
...
begin
...
      CallWndRetProc_Proc (msg, Handled);
...
        ...CallNextHookEx (CallWndRetProc_Hook, Code, wParam, lparam);
...
end;
Нужно или локальный хук использовать или усложнять обработку через проецируемые в память файлы/данные.
Sibedir вне форума Ответить с цитированием
Старый 19.01.2016, 19:13   #8
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

Что значит "локальным данным"? Просто много экемпляров этой либы и каждый пишет в свои локальные переменные. Локальный хук ровным счетом ничего не изменит.

Пишите некое observer-приложение, которое будет слушать все ваши хуки.
Человек_Борща вне форума Ответить с цитированием
Старый 19.01.2016, 20:42   #9
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

Цитата:
Сообщение от Человек_Борща Посмотреть сообщение
Что значит "локальным данным"? Просто много экемпляров этой либы и каждый пишет в свои локальные переменные.
Ну да, я терминологией не очень владею. Имел в виду обращение к не инициализированным данным из глобального обработчика хука.
Опять, наверное, какую-то фигню сморозил
Цитата:
Пишите некое observer-приложение, которое будет слушать все ваши хуки.
Но мне нужен локальный хук. Конкретно, нужно отследить создание окна типа TForm потоком моего приложения.
Цитата:
Локальный хук ровным счетом ничего не изменит
Не пойму, разве локальный хук
Код:
CT := GetCurrentThreadId;
SetWindowsHookEx (WH, @FilterFunc, 0, CT);
не локальный. Мне то нужно, чтобы он цеплялся к окнам, созданным моим CT потоком.

Последний раз редактировалось Sibedir; 20.01.2016 в 05:56.
Sibedir вне форума Ответить с цитированием
Старый 19.01.2016, 23:40   #10
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

Цитата:
Но мне нужен локальный хук. Конкретно, нужно отследить создание окна типа TForm потоком моего приложения.
Грандиозное решение однако придумали. Т.е. вы сами создаете окно и вы же никак н можете узнает что оно создалось?

Если так, то посылайте от него своё сообщение через Broadcast, и ловите его же где надо (самое простое на мой взгляд).
Человек_Борща вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Ошибка при работе с БД Antohka Помощь студентам 1 10.07.2015 08:38
Ошибка при работе автофильтра ruavia3 Microsoft Office Excel 5 21.09.2009 15:05
ошибка при работе с указателем Vladss Общие вопросы C/C++ 22 29.07.2009 03:58
ошибка при работе с файлом Juffin Общие вопросы Delphi 3 11.04.2009 21:37
Ошибка при работе с БД malevich БД в Delphi 8 25.11.2007 15:10