begin
{назначим процедуру переменной DLLProc}
DLLProc:= @DLLEntryPoint;
{вызываем назначенную процедуру для отражения факта присоединения данной
библиотеки к процессу}
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
FileMapping
В библиотеке при загрузке оной :
Код:
Ну объявлены ест-но глобально там же:
Код:
const
MMFName: PChar = 'HandleMMF';
type
PGlobalDLLData = ^TGlobalDLLData;
TGlobalDLLData = packed record
MyAppWnd: HWND; // дескриптор нашего приложения
end;
var
….
GlobalData: PGlobalDLLData;
MMFHandle: THandle;
MMFName: PChar = 'HandleMMF';
type
PGlobalDLLData = ^TGlobalDLLData;
TGlobalDLLData = packed record
MyAppWnd: HWND; // дескриптор нашего приложения
end;
var
….
GlobalData: PGlobalDLLData;
MMFHandle: THandle;
Идём дальше по ходу выполнения :
Код:
procedure OpenGlobalData();
begin
{получаем объект файлового отображения}
MMFHandle:= CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), MMFName); //для 64-ричных систем
if MMFHandle = 0 then
begin
MessageBox(0, 'Can''t create FileMapping', 'Message from keyhook.dll', 0);
Exit;
end;
{отображаем глобальные данные на АП вызывающего процесса и получаем указатель
на начало выделенного пространства}
GlobalData:= MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TGlobalDLLData)); // FILE_MAP_WRITE как вариант…тоже не катит
if GlobalData = nil then
begin
CloseHandle(MMFHandle);
MessageBox(0, 'Can''t make MapViewOfFile', 'Message from keyhook.dll', 0);
Exit;
end;
end;
procedure CloseGlobalData();
begin
UnmapViewOfFile(GlobalData);
CloseHandle(MMFHandle);
end;
procedure DLLEntryPoint(dwReason: DWord); stdcall;
begin
case dwReason of
DLL_PROCESS_ATTACH: OpenGlobalData;
DLL_PROCESS_DETACH: CloseGlobalData;
end;
end;
begin
{получаем объект файлового отображения}
MMFHandle:= CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), MMFName); //для 64-ричных систем
if MMFHandle = 0 then
begin
MessageBox(0, 'Can''t create FileMapping', 'Message from keyhook.dll', 0);
Exit;
end;
{отображаем глобальные данные на АП вызывающего процесса и получаем указатель
на начало выделенного пространства}
GlobalData:= MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TGlobalDLLData)); // FILE_MAP_WRITE как вариант…тоже не катит
if GlobalData = nil then
begin
CloseHandle(MMFHandle);
MessageBox(0, 'Can''t make MapViewOfFile', 'Message from keyhook.dll', 0);
Exit;
end;
end;
procedure CloseGlobalData();
begin
UnmapViewOfFile(GlobalData);
CloseHandle(MMFHandle);
end;
procedure DLLEntryPoint(dwReason: DWord); stdcall;
begin
case dwReason of
DLL_PROCESS_ATTACH: OpenGlobalData;
DLL_PROCESS_DETACH: CloseGlobalData;
end;
end;
Так…с этим вроде разобрались…передаю из главной формы хэндл окна, принимаю в библиотеке :
Код:
Procedure Appl(FH:HWND); stdcall; //это точно работает
begin
GlobalData^.MyAppWnd:= FH;
end;
begin
GlobalData^.MyAppWnd:= FH;
end;
По идее потом как-нить жму клавишу и показывается окно :
Код:
procedure ShowForm; stdcall;
begin
PostMessage(GlobalData^.MyAppWnd, MY_MESSAGE, 0,0);
end;
begin
PostMessage(GlobalData^.MyAppWnd, MY_MESSAGE, 0,0);
end;
Но это уже не играет роли.
Итак, ПРОБЛЕМА ! Прога пускается…висит в рабочем режиме ,вроде всё ок, НО как только я пытаюсь запустить игру или мне приходит сообщение в аську, агента или ещё куда-нибудь, вылетают две ошибки…обе связаны с памятью. В одной прямо говорится, что в моей dll-ке произошёл Fatall Error.
Проблема именно в том, как реализован FileMapping. Т.к. если его убрать, то программа висит и на приходящие сообщения никак не реагирует.
Вообще не понимаю, как это взаимосвязано ?? Глобальный хук описан на сигналы с клавиатуры, но никак не на перехват сообщений. ….
У кого какие идеи ??
ещё раз расскажи для чего нужен хук
Код:
function Key_Hook(Code: integer; wParam: word; lParam: DWord): Longint;stdcall; export;
Программно изменяет громкость в системе при нажатии на опр-е клавиши.
Сам хук работает корректно.
Просто у меня была проблема с посланием сообщения через PostMessage главной формt из библиотеки, и для того, чтобы каждый процесс (куда подгружается моя библиотека при загрузке) знал Handle главной формы, я использовал FileMapping, храня в страничном файле Handle главной формы
Код:
Procedure Appl(FH:HWND); stdcall;
begin
GlobalData^.MyAppWnd:= FH; //при создании главная форма передаёт сюда свой Handle
end;
begin
GlobalData^.MyAppWnd:= FH; //при создании главная форма передаёт сюда свой Handle
end;
Теперь я знаю Handle формы и могу послать ему сообщение
Код:
PostMessage(GlobalData^.MyAppWnd, MY_MESSAGE, 0,0);
Хотя сейчас проверил - даже без отправки сообщения в главное меню вылазят ошибки. Т.е. ошибка где-то в создании страничного файла и хранении там хэндла главной формы.
Работает....дык всё же есть проблема, описанная выше
Одна из ошибок содержит текст :
"Exception EAccessViolation in module dll_change.dll ......."
вот описаные этого исключения :
"Приложение осуществило доступ к неверному адресу в памяти. Обычно это означает, что программа обратилась за данными по неинициализированному указателю."
Вот и ищу....где ж оно и куда неверно могло обратиться
это наверное потому что аськин клиент думает что твоя дллка в которой находится обработчик и которая загружена в её адресное пространство это какой нибудь троян который следит за клавой и выгружает это дллку, а хук то остаётся и при ображению к обработчику на его месте пустота потому что он выгружен и отсуда ошибка
а игра выгружает дллку потому что игра для экономия памяти выгружает из себя всё что можно
но это только моё мнение.........
Без FileMapping игра не выгружала мою dll-ку, и она вполне корректно работала в процессе игры...тут что-то другое.
Предполагаю (на основе "метода проб и ошибок"), что при приходе сообщения в аську в первый раз (т.е. я пустил прогу..и жду ,пока придёт мессага), длл-ка, загруженная в АП аськи, пытается выполнить код procedure OpenGlobalData(), где при попытке вызова
MMFHandle:= OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,MMFName) ;
//это я уже через Open работаю в длл-ке, а Create делаю в основной форме....но это всё равно не помогло.
вылазит ошибка. К сожалению, пошагово всё это отследить не могу, и соотв-но, не утверждаю на верность всего этого.....сижу, уже 3-й день, ломаю голову над этой проблемой...
а SysUtils используешь?
вот...нашёл, чтобы понять, в чём же, собственно, проблема:
http://www.gamedev.ru/download/?id=4663 (сорри, чо-то файл сюда незагрузился сам..привожу ссылку на него).
Чтобы понять мою проблему. Там две АБСОЛЮТНО одинаковые программы, работающие с хуком WH_GETMESSAGE и используют FileMapping. Кому не лень, пробегитесь глазами по коду программ (он короткий). Если пустить обе программы, то они работают...до N-го времени...а потом вылетает та же ошибка, что и у меня.
из-за SysUtils может глючить. его лучше не использовать при написании длл, которые предназначены для внедрения в другой процесс.
Убрал SysUtils....не помогло
"Инструкция по адресу ... обратилась к памяти по адресу ... . Память не может быть written".
Длл выгружается, а qip продолжает работать. У тебя такая ошибка?
с аськой и игрой - да, они продолжает работать... НО если это вылетает в Delphi7 или в MailAgent (или ещё где-нибудь, наверное ), то они ваще выгружаются (закрываются аварийно).
тема была по поводу такой ошибки мы там с Borland_prog'ом разбирались в чем дело. я просто стал писать без SysUtils, а он дальше вроде ковырял, но результатов не знаю.
у тебя модуль Forms или какой-нибудь другой, использующий SysUtils используется? если используется, вот ошибку и выдает. на форуме
Windows,
MMSystem,
Messages;
Они не содержат SysUtils, насколько я знаю (ну и смотрел сам их код).
В главной форме в uses я не объявляю SysUtils, но через другие модули он подключается...без этого там никак уж.
Я уж и OllyDbg достал...правда мало пока с ним разобрался ..
Как я понял из разговора, проблема находится в Forms и следовательно в самой VCL.
Полагаю, если использовать KOL или вообще писать код на win32 API, можно обойти ошибку.
Код:
CreateWindowEx(
WS_EX_TOPMOST,
STATIC,
WinName, // const WinName = 'MainWClass'; //да не суть важно
SS_Center,
// стандартные горизонтальное, вертикальное положение, ширина и высота
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
0,//нет родительского окна
0,//нет меню
hInstance, // handle to application instance
nil); // no window-creation data
WS_EX_TOPMOST,
STATIC,
WinName, // const WinName = 'MainWClass'; //да не суть важно
SS_Center,
// стандартные горизонтальное, вертикальное положение, ширина и высота
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
0,//нет родительского окна
0,//нет меню
hInstance, // handle to application instance
nil); // no window-creation data
Ошибка с STATIC....разбираюсь, как же создать.
Но если кто-то поможет, буду очень благодарен.
в архиве примерчик как из длл создать диалог со Static только там использовано создание диалога из ресурса с помощью DialogBoxParam. там же готовая длл a.dll вызови из неё процедуру ShowDialog и увидишь диалог. есстественно без SysUtils.
спасибо, посмотрел. Но мне желательно сделать без использования ресурсов. Тем более, что я не знаю, как из создавать и как с ними работать :(. Создаю новую ветку по новой теме, дабы не оффтопить