Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.03.14;
Скачать: CL | DM;

Вниз

Передача данных в 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;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.019 c
1-43456
Помогите
2004-03-01 00:39
2004.03.14
Перерисовка


3-43263
Sirgfine
2004-02-06 04:42
2004.03.14
Индексация в qBase


1-43452
Marina_S
2004-02-28 15:20
2004.03.14
как определить в каком модуле и в каком месте циклит программа


1-43609
kirill_bezrukov
2004-03-01 22:04
2004.03.14
Передача в BPL(DLL) DataSet или IBDataBase


3-43339
OlegM
2004-02-17 07:46
2004.03.14
Синхронизация баз