Форум: "Основная";
Текущий архив: 2004.03.14;
Скачать: [xml.tar.bz2];
ВнизПередача данных в dll Найти похожие ветки
← →
Vilux (2004-02-25 15:38) [0]Как мне передать в dll данные? Допустим есть глобальная переменная, как мне сделать, чтобы dll могла ей воспользоваться? Передать адрес этой переменной, но как?
← →
PVOzerski (2004-02-25 15:47) [1]Что значит как? В dll пишем функцию с параметром-указателем или параметром по ссылке (что различается только синтаксисом), вызываем эту ф-цию из приложения.
← →
Skier (2004-02-25 15:50) [2]>Vilux © (25.02.04 15:38)
Расскажи о задаче подробнее...
← →
Digitman (2004-02-25 15:58) [3]в Dll :
var
SomeGlobVarPtr: Pointer;
..
procedure SetGlobVarPtr(const Value: Pointer);
begin
SomeGlobVarPtr := Value;
end;
в хост-приложении:
var
SomeGlobVar: Integer;
...
SetGlobVarPtr(@SomeGlobVar);
← →
Vilux (2004-02-25 23:25) [4]Вот кусок ниже. Т.к. код выполняется каждый раз в разном пространстве, то мне нужно, чтобы в функции был доступ к переменной, которая задается где-нибудь в головной программе
Например, мне нужно, чтобы из функции Key_Hook из DLL можно было прочитать значение переменной MyValue
Кусок основной программы
------------------
MyValue:=0;
hookhandle:=0;
hinstDLL := LoadLibrary(pchar(dir+"sendkey.dll"));
hkprcKeyboard := GetProcAddress(hinstDLL, "Key_Hook");
hookhandle:=SetWindowsHookEx(WH_KEYBOARD, hkprcKeyboard, hinstDLL, 0);
------------------
А это сама dll...
library sendket;
uses
SysUtils, Windows,dialogs,registry;
function Key_Hook(Code: integer; wParam: word; lParam: Longint): Longint;stdcall; export;
begin
...
end;
exports Key_Hook;
var
s:string;
{инициализация DLL при загрузке ее в память}
begin
...
end.
← →
Гаврила (2004-02-25 23:37) [5]>>Vilux © (25.02.04 23:25) [4]
Тебе же все написали, см ответ 3
в DLL заведи глобальную переменную
MyValuePtr : PInteger;
перед первым вызовом Key_Hook передай в DLL отдельной процедурой
@MyValue из основной программы
SetGlobVarPtr(@MyValue);
Реализация в DLL
procedure SetGlobVarPtr(Ptr: PInteger);
begin
MyValuePtr :=Ptr;
end;
после этого значение MyValuePtr^ в DLL всегда равно значению MyValue в exe, потому что она указывает на ту же область памяти.
← →
Vilux (2004-02-29 11:17) [6]Подскажите, где ошибка... мало с указателями работал
Основная программа...
var
capt,dir:string[250];
Foo: procedure(PtrCapt,PtrDir: PString);
begin
capt:="a";
dir:="b";
hookhandle:=0;
hinstDLL := LoadLibrary(pchar("sendkey.dll"));
Foo := GetProcAddress(hinstDLL, "SetGlobVarPtr");
Foo(@capt,@dd);
...
end;
Сама dll:
...
var
ss:string[250];
dirr,Capt : PString;
procedure SetGlobVarPtr(PtrCapt,PtrDir: PString);
begin
Capt :=PtrCapt;
dirr:=PtrDir;
ss:=PtrCapt^;<----здесь вылетает ошибка при запуске.
end;
...
exports SetGlobVarPtr;
...
← →
Vilux (2004-03-01 08:55) [7]Разобрался в проблеме, те советы, что мне давали оказались неправильными, или я что-то не так понял, вот пример правильного решения моей проблемы, тем, кто с этим столкнется. Пример взят со статьи с Корлевства Дельфи
// Example2, Process2 //
// @Aleksey Pavlov //
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
{для динамической загрузки функций из DLL}
type
MyProcType = procedure (flag : Boolean); stdcall;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Hdll : HWND; { дескриптор загружаемой DLL (для динамической загрукзки)}
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
hook: MyProcType;
begin
@hook:= nil; // инициализируем переменную hook
{ ********* динамическая загрузка **************}
Hdll:= LoadLibrary(PChar("hook_dll2.dll")); { загрузка DLL }
if Hdll > HINSTANCE_ERROR then { если всё без ошибок, то }
begin
@hook:=GetProcAddress(Hdll, "hook"); { получаем указатель на необходимую процедуру}
Button2.Enabled:=True;
Button1.Enabled:=False;
hook(true);
end
else
ShowMessage("Ошибка при загрузке DLL !");
{ **********************************************}
end;
procedure TForm1.Button2Click(Sender: TObject);
var
hook: MyProcType;
begin
@hook:= nil; // инициализируем переменную hook
if Hdll > HINSTANCE_ERROR then
begin { если всё без ошибок, то }
@hook:=GetProcAddress(Hdll, "hook"); { получаем указатель на необходимую процедуру}
Button1.Enabled:=True;
Button2.Enabled:=False;
hook(false); {вызываем нужную процедуру из DLL}
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeLibrary(Hdll); { при закрытии формы - освобождаем DLL }
end;
end.
--------------DLL-----------------------
// Example2; Second DLL //
// @Aleksey Pavlov //
// Demo of correct hook - DLL module //
library hook_dll2;
uses
Windows,
Messages,
Forms;
const
MMFName: PChar = "MyMMF2"; // имя объекта файлового отображения
{структура, поля которой будут отображены в файл подкачки}
type
PGlobalDLLData = ^TGlobalDLLData;
TGlobalDLLData = packed record
SysHook: HWND; // дескриптор установленной ловушки
end;
var
GlobalData: PGlobalDLLData;
MMFHandle: THandle;
{Данная ф-ия вызывается системой каждый раз, когда возникает какое-то событие в
dialog box-е, message box-е, menu, или scroll bar-е}
function SysMsgProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;
begin
if code = HC_ACTION then
begin
{Проверяю, нажата ли правая кнопка мыши}
if TMsg(Pointer(lParam)^).message = WM_RBUTTONDOWN then
{Вывожу сообщение при удачной работе.}
MessageBox(0, "HOOK2 working !", "Message from Exampel2/Process2", 0);
end;
{Пытаемся передать сообщение дальше по цепочке hook-ов. }
Result:= CallNextHookEx(GlobalData^.SysHook, Code, wParam, lParam);
end;
{Процедура установки HOOK-а}
procedure hook(switch : Boolean) export; stdcall;
begin
if switch=true then
begin
{Устанавливаю HOOK, если он не установлен (switch=true). }
GlobalData^.SysHook := SetWindowsHookEx(WH_GETMESSAGE, @SysMsgProc, HInstance, 0);
if GlobalData^.SysHook <> 0 then
MessageBox(0, "HOOK2 установлен !", "Message from Exampel2/Process2", 0)
else
MessageBox(0, "HOOK2 установить не удалось !", "Message from Exampel2/Process2", 0);
end
else
begin
{Удаляю функцию-фильтр, если она установлена (т.е. switch=false). }
if UnhookWindowsHookEx(GlobalData^.SysHook) then
MessageBox(0, "HOOK2 снят !", "Message from Exampel2/Process2", 0)
else
MessageBox(0, "HOOK2 снять не удалось !", "Message from Exampel2/Process2", 0);
end;
end;
procedure OpenGlobalData();
begin
{получаем объект файлового отображения}
// MMFHandle:= CreateFileMapping(DWord(-1), nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), MMFName); // можно так, но лучше: см. след. строку
MMFHandle:= CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), MMFName);
if MMFHandle = 0 then
MessageBox(0, "Can""t create FileMapping", "Message from Exampel2/Process2", 0);
{отображаем глобальные данные на АП вызывающего процесса и получаем указатель
на начало выделенного пространства}
GlobalData:= MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TGlobalDLLData));
if GlobalData = nil then
begin
CloseHandle(MMFHandle);
MessageBox(0, "Can""t make MapViewOfFile", "Message from Exampel2/Process2", 0);
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;
exports hook;
begin
//MessageBox(0, PChar(Application.ExeName), "Message from Exampel1/Process1", 0);
{назначим поцедуру переменной DLLProc}
DLLProc:= @DLLEntryPoint;
{вызываем назначенную процедуру для отражения факта присоединения данной
библиотеки к процессу}
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
← →
Юрий Зотов (2004-03-01 13:01) [8]> Vilux © (01.03.04 08:55) [7]
> те советы, что мне давали оказались неправильными,
> или я что-то не так понял,
Второе.
← →
Vilux (2004-03-01 18:45) [9]2Юрий Зотов
Тогда просьба, объяснить, почему не работал кусок кода, через одно сообщение назад от этого...
← →
Юрий Зотов (2004-03-02 01:21) [10]> Vilux © (01.03.04 18:45) [9]
Хорошо.
Во-первых, главная ошибка - в вопросе было произнесено слово "глобальный", но ни слова не было сказано ни о глобальных хуках, ни о том, что глобальность требуется на уровне всей системы. Поэтому, естественно, вопрос все поняли так, что нужна глобальность на уровне лишь одной DLL - так и отвечали. Поэтому, если говорить об изначально поставленном вопросе, то ответы [1] и [3] уже были абсолютно верными.
Далее, в [4] Вы уточнили вопрос, упомянув о глобальном хуке (а это уже СОВСЕМ другая задача). Но снова сделали ошибку, причем очень характерную. Состоит она в том, Вы спросили не о том, как решить проблему ИСТИННУЮ, а о том, как решить ту проблему, которую Вы себе представили. Вот смотрите сами:
"Т.к. код выполняется каждый раз в разном пространстве, то мне нужно, чтобы в функции был доступ к переменной, которая задается где-нибудь в головной программе"
Как же так? Вы же сами говорите, что код выполняется каждый раз в разном пространстве - а получить доступ хотите к переменной из пространства Вашей программы. Вот и получилась подмена понятий. Раз в разные пространства внедряется DLL - значит, и переменная должна быть именно в DLL, а не в программе, ведь верно? (о том, как и зачем нужно ее проецировать в страничную память системы - разговор отдельный, а сейчас только скажу, что это нужно всего лишь для ее правильной инициализации во всех копиях данных DLL).
Это и была вторая ошибка - навязывание отвечающим ошибочного видения проблемы и ошибочного подхода к ее решению. Но была еще и ошибка третья.
До сих пор Вы ни разу не упоминали о строках и указателях на них. И лишь в [6] всплыл тип PString (кстати, Вы все же не расшифровали, что такое PString, поэтому я буду предполагать наиболее вероятный, с моей точки зрения, вариант - что это объявленный в SysUtils указатель на длинную строку: PString = ^string). Вот теперь мы и подошли к вопросу - почему не работал вариант [6]. Ниже я убрал из кода все, не относящееся к сути.
var
Capt: string[250];
Foo: procedure(PtrCapt: PString);
begin
Сapt := "a";
Foo(@Capt);
В последней строке уже две ошибки. Во первых, Вы передаете адрес короткой строки вместо адреса длинной - то есть, получаете прямую адресацию вместо заказанной Вами же косвенной (вспомним, что длинная строка - это УЖЕ указатель, поэтому PString - это указатель на указатель). Во-вторых, здесь передается ссылка на служебный нулевой символ короткой строки. Идем дальше и смотрим, к чему же это приводит.
var
SS: string[250];
procedure SetGlobVarPtr(PtrCapt: PString);
begin
SS := PtrCapt^; <----здесь вылетает ошибка
Вспомним, что перед вызовом Foo Вы написали Capt := "a" (то есть, Capt[0] стало равно #1), а при вызове Foo передали именно адрес Capt[0].
Далее программа честно пытается делает ей то, что Вы ей велели - она разыменовывает PtrCapt и хочет скопировать в строку SS 250 символов ASCIIZ-строки, которая находится по адресу, который сам записан по адресу $00000001. А эта область ей запрещена (нижние 4K под Win9x и нижние 64K под NT). Понятно, что система говорит "стой, не лезь куда не положено" - и генерит ошибку доступа к памяти. Приплыли.
Но даже если бы этот адрес был бы программе доступен, то, как видите, он все равно неверен - и поэтому все равно возникла бы ошибка. Точнее, программа работала бы, но работала неверно. И отловить причину вот ТАКОЙ ошибки было бы гораздо труднее - так что Вам еще повезло, что ошибка выскочила сама и так быстро.
← →
Alex Konshin (2004-03-02 01:27) [11]Насколько я вижу, все еще проще - переменная Foo не инициализирована.
← →
Юрий Зотов (2004-03-02 01:44) [12]Хм... мне казалось, что этого достаточно:
Foo := GetProcAddress(hinstDLL, "SetGlobVarPtr");
:о)
← →
Alex Konshin (2004-03-02 08:25) [13]А, точно, в оригинале это есть, а вот в твоем фрагменте этого нет.
Sorry.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2004.03.14;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.014 c