Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

вызов DLL [D7, WinXP]


Страницы:   1 2

Цукор 5 ©   (2005-09-11 13:08:00) 

Есть библиотека :

library Project1;
uses
 SysUtils,
 Classes;

type MyRetVal=record
 Line1:PChar;
 Line2:PChar;
 Dept :Byte;
 Group:Byte;
end;

type  TVal=array of MyRetVal;

function ReadSales(Num1,Num2:Word; var Value:TVal):Boolean;stdcall;
 var I:Integer;
begin
 SetLength(Value,5);
 for I:=0 to Length(Value)-1 do
 begin
   Value[I].Line1:=PChar('Test1');
   Value[I].Line2:=PChar('Test2');
   Value[I].Dept :=$01;
   Value[I].Group:=$0a;
 end;
 Result:=True;
end;

Exports
 ReadSales;
{$R *.res}
begin
end.


Вызываю так :

procedure TForm1.Button1Click(Sender: TObject);
var hDLL:HWND;
    Val:TVal;
    I:Integer;
    ReadSales:function(Num1,Num2:Word;var Value:TVal):boolean;stdcall;
begin
hDLL := LoadLibrary ('Project1');
if hDLL<>0 then
begin
  @ReadSales:=GetProcAddress(hDLL,'ReadSales');
  if Assigned(@ReadSales) then
  ReadSales(1,5,Val);
  for I:=0 to Length(Val)-1 do
  begin
    Memo1.Lines.Add('L'+IntToStr(I)+'_'+Val[I].Line1);
    Memo1.Lines.Add('L'+IntToStr(I)+'_'+Val[I].Line2);
  end;
  // до это момента все прекрасно !
  FreeLibrary (hDLL);// а вот тут AV
end
else MessageDlg('Error!!!',mtError,[MbOk],0);
end;


Не могу понять в чем причина. Я уже и SetLength(Val,0) и Val=nil делал...не то :(
P.S. Да простят меня модераторы... я не знаю как назвать тему вопроса.


Slym   (2005-09-13 09:36:00) [1]

type
 PEntry=^TEntry;
 TEntry=packed record
   Line1:PChar;
   Line2:PChar;
   Dept :Byte;
   Group:Byte;
 end;

 PEntries=^TEntries;
 TEntries=array[0..MaxListSize - 1] of PEntry;

 PEntryArray=^TEntryArray;
 TEntryArray=packed record
   Size:integer;
   Entries:PEntries;
 end;

function OpenDevice:PEntryArray;stdcall;
begin
 New(result);
 result.Size:=0;
 result.Entries:=nil;
end;

function ClearEntryArray(Dev:PEntryArray):LongBool;stdcall;
var i:integer;
 Entry:PEntry;
begin
 for i:=0 to Dev.Size-1 do
 begin
   Entry:=Dev.Entries[i];
   if Entry.Line1<>nil then
     FreeMem(Entry.Line1);
   if Entry.Line2<>nil then
     FreeMem(Entry.Line2);
   Dispose(Entry);
 end;
 FreeMem(Dev.Entries);
 Dev.Size:=0;
end;

function CloseDevice(Dev:PEntryArray):LongBool;stdcall;
begin
 ClearEntryArray(Dev);
 Dispose(Dev);
end;

const Line='Test,Test';

function ReadDevice(Dev:PEntryArray):LongBool;stdcall;
var
 i:integer;
 Entry:PEntry;
begin
 if Dev.Size>0 then
   ClearEntryArray(Dev);
 Dev.Size:=10;
 GetMem(Dev.Entries,SizeOf(PEntry)*Dev.Size);
 for i:=0 to Dev.Size-1 do
 begin
   New(Dev.Entries[i]);
   Entry:=Dev.Entries[i];
   GetMem(Entry.Line1,Length(Line)+1);
   StrLCopy(Entry.Line1,PChar(Line),Length(Line));
   GetMem(Entry.Line2,Length(Line)+1);
   StrLCopy(Entry.Line2,PChar(Line),Length(Line));
   Entry.Dept:=i;
   Entry.Group:=Dev.Size-i;
 end;
end;

procedure Usage;
var EntryArray:PEntryArray;
 i:integer;
begin
 EntryArray:=OpenDevice;
 ReadDevice(EntryArray);
 for i:=0 to EntryArray.Size-1 do
 begin
   MessageBox(0,EntryArray.Entries[i].Line1,EntryArray.Entries[i].Line2,0);
 end;
 CloseDevice(EntryArray);
end;


Defunct   (2005-09-13 02:23:00) [2]

> Цукор 5

В [33] я отвечал на [30].
чтобы развеять сомнения относительно достоверности, привожу аналог структуры

TMyRetVal=record
 Line1:String[31];
 Line2:String[31];
 Dept : Byte;
end;

на Cи:

typedef SmallString<31>   MyStr;
struct TMyRetVal
{
 MyStr Line1;
 MyStr Line2;
 char  Dept;
};


Defunct   (2005-09-13 02:06:00) [3]

> в Delphi будет легче работать со String

читать так:
в Delphi будет легче работать со String[] чем с array[] of char.


Defunct   (2005-09-13 02:00:00) [4]

Цукор 5   (13.09.05 01:49) [35]

Герман имел в виду, помоему то же самое.
String[..] это уже и так array[..] of char.

> Меняю все на  array[] of char.
не стоит, в Delphi будет легче работать со String, в других языках объявят за вас.


Цукор 5   (2005-09-13 01:49:00) [5]

Блин. [33]<>[32]. Так где же истина???


Цукор 5   (2005-09-13 01:47:00) [6]

2 Германн ©   (13.09.05 01:42) [32]
Понял. Меняю все на  array[] of char.Надежней будет(наверное:О )
Спасибо!


Defunct   (2005-09-13 01:46:00) [7]

обязательно поставьте packedrecord

> А во всех ли языках есть String[25]?

String[25] это просто массив Char (array[0..25] of char), у которого первый символ содержит количество используемых символов массива. Объявить такой массив можно imho во всех языках.

ps: может быть лучше String[ 31]? (по 32 байта на строку, как-то более цивильно будет, заодно все поля будут выровняны на границу dword)


Германн   (2005-09-13 01:42:00) [8]

2 Цукор 5   (13.09.05 01:29) [30]
Имхо, String[] - есть Pascal'ева конструкция. И её НЕТ в других языках!
Но array[] of char - найдется везде, имхо.
А PChar - найдется во всех, наиболее известных языках и компиляторах, которые работают в среде Win32. Имхо!


Цукор 5   (2005-09-13 01:40:00) [9]

Понятно,что для решения [27] структура ДОЛЖНА быть такой:

type
TMyRetVal=record
Line1:PChar;
Line2:PChar;
Dept : Byte;
end;

я вот думаю про http://www.delphimaster.ru/cgi-bin/forum.pl?id=1126539754&n=0.Там то нельзя указать Pchar ибо тогда я никогда не узнаю размер "массива"

З.Ы. Да простят меня модераторы за 2 вопроса в одной ветке.


Цукор 5   (2005-09-13 01:29:00) [10]

2 Defunct ©   (13.09.05 01:17) [29]
Кстати,а еще вопросик. Вопрос навеян тем,что библиотека будет передана не Delphi-программистам.
Вот я обьявил такую структуру :

type
TMyRetVal=record
Line1:String[25];
Line2:String[25];
Dept : Byte;
end;

А во всех ли языках есть String[25]? Или что-нибудь другое выдумывать??? Как Вы считаете?


Defunct   (2005-09-13 01:17:00) [11]

Цукор 5   (13.09.05 01:11) [28]

вот и гут ;>

ps: я не настаиваю именно на таком решении, возможно есть решение и лучше. Тем не менее очень рад, что вы поняли о чем речь ;>


Цукор 5   (2005-09-13 01:11:00) [12]

2 Defunct
Спасибо. Буду знать.Теперь вроде понятно.


Defunct   (2005-09-13 01:07:00) [13]

Цукор 5   (13.09.05 01:01) [25]
> Хм... а откуда взялось implementation в DLL?

Что значит откуда?
Кто мешает в теле DLL подключить модуль?

library MyLibrary;

uses MyUnit;

exports
OpenDevice,
ReadDevice,
CloseDevice,
GetItem,
Count;

begin
end.


> так я считаю,что это глобальная переменная.
неправильно считаете.

unit MyUnit;

interface

 procedure OpenDevice;
 procedure ReadDevice;
 procedure CloseDevice;
 function Count:integer;
 function GetItem(idx:integer):TMyType;
 
implementation

var
 DataToExport : Array of TMyType;

...
end.


DataToExport - не более чем локальная переменная модуля MyUnit.


Германн   (2005-09-13 01:06:00) [14]

2 Цукор 5  
А что ты так сфокусировался на "глобальности" переменных в DLL?


Цукор 5   (2005-09-13 01:01:00) [15]

2 Defunct ©   (13.09.05 00:52) [23]
Хм... а откуда взялось implementation в DLL?


var
DataToExport : Array of SomeType;

> этот массив локален для модуля в котором он описан
Как по мне...так я считаю,что это глобальная переменная.Хорошо,а что ж тогда глобальная переменная???


Цукор 5   (2005-09-13 00:57:00) [16]

2 Defunct ©   (13.09.05 00:49) [22]
Вероятно я не понял Вас,а Вы меня. С телом DLL я как-нибудь сам разберусь. Мне непонятно следующее.
Итак :
>ReadDevice(..); // считает весь блок данных с устройства в массив
> GetItem  // передаст  некую часть массива  в хост-приложение

Две ф-ции.Одна создает массив,вторая выберает и передает. Где и как это все хранить? Вот я о чем.


Defunct   (2005-09-13 00:52:00) [17]

> Но я никак не могу понять,как это реализовать без глобальной переменной в DLL.

Очень просто, например так:

implementation

var
 DataToExport : Array of SomeType; <--- этот массив локален для модуля в котором он описан.


Defunct   (2005-09-13 00:49:00) [18]

> Цукор 5  
экспортируем сл. функции:

OpenDevice;
ReadDevice;
CloseDevice;

и также для работы с массивом (буфером внутри dll)

GetItem;
SetItem;
Count;

далее используем их так

OpenDevice(..);
ReadDevice(..);
for i:=0 to Count-1 do
 begin
    zzz := GetItem;
 end;
CloseDevice(..);

OpenDevice/ReadDevice/CloseDevice не обязательно экспортировать, их можно просто вызвать внутри функции Count.


Цукор 5   (2005-09-13 00:43:00) [19]

2 Defunct ©   (12.09.05 03:04) [13]
Хотя стоп...
>Например, при вызове GetCount пусть DLL и прочитает из устройства все значения себе в массив.

Этот вариант мне приемлим.Но я никак не могу понять,как это реализовать без глобальной переменной в DLL. Ведь одна ф-ция должна создать "массив",а вторая выбирать из него данные.


Defunct   (2005-09-13 00:41:00) [20]

> Цукор 5   (13.09.05 00:37) [19]

Интересно, в каком месте?


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо