Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.08.06;
Скачать: [xml.tar.bz2];

Вниз

Типы в 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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.51 MB
Время: 0.011 c
2-1153134172
STX
2006-07-17 15:02
2006.08.06
Блокирование строки таблицы на время редактирования


2-1153308761
Роман88
2006-07-19 15:32
2006.08.06
Internet Explorer 6 (Добавить в избранное)


15-1152095029
igrek23
2006-07-05 14:23
2006.08.06
компоненты для работы с топографическими картами


2-1152725374
Антибайт
2006-07-12 21:29
2006.08.06
Нарисовать кнопку внутри Edit, как у The Bat!.


2-1153054681
UMU
2006-07-16 16:58
2006.08.06
При изменении разрешения экрана...





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский