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

Вниз

Типы в Dll   Найти похожие ветки 

 
!_SM_!   (2006-07-19 20:15) [0]

Есть DLL (моя) в ней описан тип
TInfo = record
Name, Author: String;
end;

есть процедура

procedure GetInfo(var Inf: TInfo); stdcall; export;
begin
 Inf.Name:="Name";
 Inf.Author:="Author";
end;

в ехе описан тот-же тип
TInfo = record
Name, Author: String;
end;

описана переменная

var GetInfo: procedure (var Inf: TInfo); stdcall;

из ехе динамически гружу dll"ку получаю указатель на процедуру, вызываю ее

 HDll:=LoadLibrary(PChar(<путь и имя dll>));
 if HDll<>0 then begin
  @GetInfo:=GetProcAddress(HDll, "GetInfo");
   if @GetInfo=nil then FreeLibrary(HDll) else
   begin
    SetLength(Inf.Name, 50);
    SetLength(Inf.Author, 50);
    GetInfo(Inf);
    ShowMessage(Inf.Name);
   end;
 end;

получаю AV. Как это обойти и желательно без использования ShareMem?


 
!_SM_!   (2006-07-19 20:19) [1]

AV на строке GetInfo(Inf);


 
StriderMan ©   (2006-07-19 21:11) [2]

вместо

> var GetInfo: procedure (var Inf: TInfo); stdcall;

надо

type
 TGetInfoProc = procedure (var Inf: TInfo); stdcall;
var
 GetInfo: TGetInfoProc ;

далее
...
GetInfo:=GetProcAddress(HDll, "GetInfo");
if Assigned(GetInfo) then

....


 
Zeqfreed ©   (2006-07-19 21:15) [3]

ShareMem ещё не забыть.


 
Rial ©   (2006-07-19 21:18) [4]

Если тебе не нравится ShareMem, то не используй стринги.

Сделай хотябы
TInfo = record
Name, Author: PChar;
end;

С указателями проблем не будет.

Или вообще

TInfo = record
Name, Author: Pointer;
end;

Размещай даные строк в память по указателю, запоминай размер и передавай.


 
StriderMan ©   (2006-07-19 21:20) [5]

а может вообще сделать

PInfo = ^TInfo;

и его использовать


 
sniknik ©   (2006-07-19 21:23) [6]

> Как это обойти и желательно без использования ShareMem?
TInfo = record
Name, Author: String[50];
end;

ну и естественно убрать
SetLength(Inf.Name, 50);
SetLength(Inf.Author, 50);


 
!_SM_!   (2006-07-19 21:55) [7]


> StriderMan ©   (19.07.06 21:11) [2]


> type  TGetInfoProc = procedure (var Inf: TInfo); stdcall;
> var   GetInfo: TGetInfoProc ;

А это разве не одно и тоже
var GetInfo: procedure (var Inf: TInfo); stdcall;
??????

> sniknik ©   (19.07.06 21:23) [6]


Не работает.
Вот как делаю:
переделал

type
 TInfo = record
  Name, Author: String[50];
 end;
 TGetInfo = procedure (var Inf: TInfo); stdcall;

var GetInfo: TGetInfo;
........
procedure TForm1.FormCreate(Sender: TObject);
var SR: TSearchRec;
N, HDLL: Integer;
Inf: TInfo
procedure AddInf(const FDll: String);
begin
  HDll:=LoadLibrary(PChar(FDll));
  if HDll<>0 then begin
   @GetInfo:=GetProcAddress(HDll, "GetInfo");
   if @GetInfo=nil then FreeLibrary(HDll)
   else begin
    GetInfo(Inf);
    ShowMessage(Inf.Name);
   end;
  end else FreeLibrary(HDll);
end;
begin
 N:=FindFirst("*.dll", faAnyFile, SR);
 while N=0 do begin
  AddInf(SR.Name);
  N:=FindNext(SR);
 end;
 FindClose(SR);
end;


При условии что есть более 1 DLL (подходящих)
показывает 1 раз ShowMessage(Inf.Name);
и AV.
Если закомментировать
//GetInfo(Inf);
//ShowMessage(Inf.Name);

и вставить
ShowMessage(FDll);
то ошибки нет показываются все имена Dll"ек.


 
!_SM_!   (2006-07-19 21:58) [8]

В библиотеке тоже переделал
TInfo = record
 Name, Author: String[50];
end;


 
sniknik ©   (2006-07-19 22:55) [9]

> показывает 1 раз ShowMessage(Inf.Name);
> и AV.
одну dll исправил, и она первая находится, остальные нет...


 
!_SM_!   (2006-07-19 23:04) [10]

Блин, ведь остальные просто копии были.... правильно.... сейчас попробую
сделал еще так
type TAvtInfo = record
     Name, CopyR: PChar;
    end;

сейчас попробую, отпишусь


 
!_SM_!   (2006-07-19 23:05) [11]

Блин, ведь остальные dll просто копии были (неправильные).... правильно.... сейчас попробую
сделал еще так
type TAvtInfo = record
     Name, CopyR: PChar;
    end;

сейчас попробую, отпишусь


 
!_SM_!   (2006-07-19 23:07) [12]

Все нормально с PChar"ом


 
!_SM_!   (2006-07-19 23:08) [13]

Все нормально с PChar"ом без ShareMem"a.
Спасибо всем.


 
GL00m   (2006-07-20 00:50) [14]

Если не возражаете, я присоединюсь к дискуссии - у меня проблема со схожими исходными данными:
имеется
type MyMessage = record
   myID : PChar;
end;
PMyMessage = ^MyMessage;

которые также описаны и в DLL-ке и в проекте. В длл-ке есть функция MyMsgUnpack(s : PChar) : PMyMessage.
Я делаю все то же, что и выше описано:
var rez : MyMessage;
...
h := LoadLibrary(PChar("file.dll"));
@f := GetProcAddress(h,"MyMsgUnpack");
p := PChar(data);
pmsg := f(p);
rez := pmsg^;
FreeLibrary(h);

До этого момента все ОК. Но! Как только я делаю что-то вроде Label1.Caption := rez.MyID;, то получаю AV и чё за фигня - не пойму. =( Не подскажете, куда копать?


 
Юрий Зотов ©   (2006-07-20 02:37) [15]

> GL00m   (20.07.06 00:50) [14]

Где и как выделяется память под запись, адрес которой возвращает DLL и под строку в этой записи?


 
GL00m   (2006-07-20 11:13) [16]

В общем-то нигде, это все. Т.е. просто
var rez : MyMessage; pmsg : PMyMessage;
Дальше тело, которое я написал: h := LoadLibrary(PChar("file.dll")); итд. В DLL-е в функции MyMsgUnpack сначала
var msg : MyMessage;
Потом
msg.myID := PChar("smthn");
а затем
Result := @msg
Причем, если в запись MyMessage добавить, например, i : Integer, то с ним все работает нормально, а вот с PChar-ом - AV.


 
StriderMan ©   (2006-07-20 12:39) [17]


> !_SM_!   (19.07.06 21:55) [7]
> > StriderMan ©   (19.07.06 21:11) [2]
> > type  TGetInfoProc = procedure (var Inf: TInfo); stdcall;
> > var   GetInfo: TGetInfoProc ;
> А это разве не одно и тоже
> var GetInfo: procedure (var Inf: TInfo); stdcall;
> ??????

по сути да. но это более правильный подход. (не ИМХО). Не зря ведь в делфи процедурные типы сделали?

благодаря такому подохду не нужны вот эти пляски с бубном:

>  @GetInfo:=GetProcAddress(HDll, "GetInfo");
>    if @GetInfo=nil then FreeLibrary(HDll) else


 
sniknik ©   (2006-07-20 13:21) [18]

> благодаря такому подохду не нужны вот эти пляски с бубном:

>>  @GetInfo:=GetProcAddress(HDll, "GetInfo");
>>    if @GetInfo=nil then FreeLibrary(HDll) else

как это не нужны? нужны, это же получение и проверка на существование экспортной функции (вполне можно "зацепить" и не свою dll где ее не будет), и эта проверка совсем не зависит от того как именно задана процедурная переменная. (через предварительно описанный тип, или непосредственно у переменной)

а вот переписать в более понятном виде не  помешает... типа
(писал тут, возможны ошибки, поправте если что)

procedure TForm1.FormCreate(Sender: TObject);
var SR: TSearchRec;

 procedure AddInf(const FDll: String);
 var
   HDLL: Integer;
   Inf: TInfo
 begin
   HDll:=  LoadLibrary(PChar(FDll));
   if HDll <= 32  then RaiseLastOSError;

   try
     @GetInfo:= GetProcAddress(HDll, "GetInfo");
     if @GetInfo <> nil then begin
       GetInfo(Inf);
       ShowMessage(Inf.Name);
     end;
    finally
      FreeLibrary(HDll)
    end;
 end;

begin
 if FindFirst("*.dll", faAnyFile, SR) = 0 then begin
   repeat
     AddInf(SR.Name);
   until FindNext(SR) <> 0;
   FindClose(SR);
 end;  
end;


 
StriderMan ©   (2006-07-20 13:28) [19]


> как это не нужны? нужны, это же получение и проверка на
> существование экспортной функции (вполне можно "зацепить"
> и не свою dll где ее не будет), и эта проверка совсем не
> зависит от того как именно задана процедурная переменная.
>  (через предварительно описанный тип, или непосредственно
> у переменной)


а проверка
> @GetInfo <> nil

всегда даст true. Ведь переменная GetInfo уже объявлена, адрес ее известен. чтобы в этом убедиться предлагаю маленький тест:

procedure TForm1.Button1Click(Sender: TObject);
var
 P: Pointer;
begin
 ShowMessage(IntToStr(integer(@P)));
end;


Вот более простой, прозрачный и правильный код

> GetInfo:=GetProcAddress(HDll, "GetInfo");
> if Assigned(GetInfo) then


 
GL00m   (2006-07-20 13:53) [20]

Я опять встряну со своей проблемой, если не возражаете. =)
Переделал я немного свои функции, сделал выделение памяти:

type
 TMyMsgUnpack=procedure(m:PChar;var pm:PMyMessage);
 MyMessage = record
   myID : PChar;
   myCount : Integer;
 end;
...
var
 m : MyMessage;
 pm : PMyMessage;
 h : Integer;
 f : TMyMsgUnpack
begin
 pm := AllocMem(SizeOf(m));
 h := LoadLibrary("file.dll");
 @f := GetProcAddress(h,"MyMsgUnpack");
 p := PChar("somedata");
 f(p,pm);
 FreeLibrary(h);
 FreeMem(pm,SizeOf(m));
end;

Процедура MyMsgUnpack лежит в DLL-ке, в ней делается что-то типа:
pm^.myID := PChar("Hello");
pm^.myCount := 5;

Так вот в моей функции после строчки f(p,pm); получается:
pm^.myID = "Hello"
pm^.myCount = 5

, но сразу после FreeLibrary(h); myID становится равным "", а myCount остается 5. Что я не так делаю?


 
sniknik ©   (2006-07-20 14:30) [21]

> а проверка
>> @GetInfo <> nil

> всегда даст true. Ведь переменная GetInfo уже объявлена, адрес ее известен. чтобы в этом убедиться предлагаю маленький
> тест:
в свою очередь предлагаю немного изменить этот маленький тест... ;)

type
 TInfo = record
   Name, Author: String[50];
 end;

 TGetInfoProc = procedure (var Inf: TInfo); stdcall;

 ....

var
 Form1: TForm1;

 GetInfo1: procedure (var Inf: TInfo); stdcall; //это то что у него было
 GetInfo2: TGetInfoProc;                             //это  посоветовано тобой
 //(правильно в принципе посоветовано, но причина зачем это делать немного "не та" должна быть)

procedure TForm1.Button1Click(Sender: TObject);
var
 P: Pointer;
begin
 ShowMessage(IntToStr(Integer(@P))+" : "+IntToStr(Integer(@GetInfo1))+" : "+IntToStr(Integer(@GetInfo2)));
end;


смотри разницу. (вернее ее отсутствие ;)

> Я опять встряну со своей проблемой, если не возражаете. =)
не парься, сделай на коротких строках, если не умееш с PChar работать. ([6])

> Что я не так делаю?
память под myID не выделил, и данные в нее не записал, вместо этого присвоил указатель переменной из модуля.


 
StriderMan ©   (2006-07-20 14:41) [22]


> смотри разницу. (вернее ее отсутствие ;)

да, слушай, ты прав! Я и забыл что переменная процедурного типа ведет себя не как pointer.

Но все же меня смущает присвоение ей адреса процедуры через оператор взятия адреса (@).
Я обычно делаю как описал и никаких "собачек" не нужно. и проверка Assigned() вроде специально для этого придумана.


 
GL00m   (2006-07-20 14:50) [23]

to sniknik:
Черт! Видимо спать надо больше: я был уверен, что с ShortString я уже пробовал и было то же самое. Сейчас сделал и все получилось. Спасибо!


> память под myID не выделил, и данные в нее не записал, вместо
> этого присвоил указатель переменной из модуля

Память выделить - это через StrAlloc? А то, что я присвоил указатель, вместо записи данных - надо было делать StrPCopy(pm^.myID,"Hello") ?
(это я для самообразования на будущее =))



Страницы: 1 вся ветка

Текущий архив: 2006.08.06;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.046 c
2-1152875372
crazy_corpse
2006-07-14 15:09
2006.08.06
ВОПРОСЫ АЛГОРИТМОВ!


15-1152619036
Gorlum
2006-07-11 15:57
2006.08.06
Интересует как можно больше информации


2-1153147531
asail
2006-07-17 18:45
2006.08.06
Запрос SQL


3-1149245155
Still Swamp
2006-06-02 14:45
2006.08.06
Как через TADOConnection подцепиться к FB Embeded.


2-1153325727
!_SM_!
2006-07-19 20:15
2006.08.06
Типы в Dll