Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.013 c
1-43430
SaYbr
2004-03-01 08:38
2004.03.14
Вопрос по поводу TreeView


9-43242
Savenych
2003-07-21 06:42
2004.03.14
Где найти спрайты?


1-43535
Mentov
2004-02-29 17:50
2004.03.14
RichEdit


1-43580
tararasyk
2004-02-27 14:32
2004.03.14
Как нарисовать перпендикуляр ?


4-43933
bar
2004-01-05 14:03
2004.03.14
Как изменить чужую иконку в tray?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский