Wczytywanie funkcji z plików *.dll

0

Potrzebuję wczytać kilka funkcji zawartych w pliku *.dll. Plik ten został stworzony w Visual C++.
Plik nagłówkowy dla Delphi tworzę na podstawie plik nagłowkowego dla Visual C++, który już istnieje.
Sprawa wydaje się dosyć prosta, bo:
w VC++ mamy:

int __stdcall tltmSetReadSessionDuration(HANDLE hHandle, unsigned int uiTag, int iDuration);

a w delphi:

Function tltmSetReadSessionDuration(hHandle:Cardinal; uiTag:Integer; iDuration:Integer):Integer; stdcall; external  'LibTSMap.dll' name 'tltmSetReadSessionDuration';

Wszytuję w delphi tą samą funkcję z pliku DLL.

Ale nie mam zielonego pojęcia, jak przekonwerterować następującą funkcję na pascal'a:

int __stdcall tltmStartReadingRawItems(HANDLE hHandle, unsigned int uiFieldsMask, BOOL boSetEAS, void (__stdcall *lpfnRawCallBack)(HANDLE hHandle, int iReasonForCall, struct tltmRawItem *myRawItem, void *pParam), void *pParam);

w tej funkcji "zaszyta jest procedura(funkcja, nie wiem). W dokumentacji znalazłem tylko informację, że ta zagnieżdżona procedura jest jakby Event'em wywoływaną w odpowiednim momencie.
Nie chodzi o to co ona robi ale jak "przetworzyć" taki zapis na język pascala.
Za słabo znam VC++, dlatego liczę na waszą pomoc.

pozdrawiam
Billy

0
// jakaś struktura - ale uwaga: „alignment” elementów może się różnić między kompilatorami
type PmyRawItem = ^TmyRawItem;
     TmyRawItem = record
        // tutaj coś ...
     end;

// Delphi wymaga, aby typ proceduralny był zdefiniowany osobno - a nie zagnieżdżony w nagłówku funkcji jak w C++
type TRawCallback = procedure(hHandle:THandle;
                              iReasonForCall:longint;
                              tltmRawItem:PmyRawItem;
                              pParam:pointer); stdcall;

function tltmStartReadingRawItems(hHandle:THandle;
                                  uiFieldsMask:longword;
                                  boSetEAS:longbool;
                                  lpfnRawCallBack:TRawCallback;
                                  pParam:pointer):longint; stdcall; external 'foobar.dll';

Function tltmSetReadSessionDuration(hHandle:Cardinal; uiTag:Integer; iDuration:Integer):Integer; stdcall; external 'LibTSMap.dll' name 'tltmSetReadSessionDuration';

źle. uiTag jest "unsigned", czyli longword a nie integer. oprócz tego lepiej dać THandle a nie Cardinal.

0
Azarien napisał(a)
// jakaś struktura - ale uwaga: „alignment” elementów może się różnić między kompilatorami
type PmyRawItem = ^TmyRawItem;
     TmyRawItem = record
        // tutaj coś ...
     end;

// Delphi wymaga, aby typ proceduralny był zdefiniowany osobno - a nie zagnieżdżony w nagłówku funkcji jak w C++
type TRawCallback = procedure(hHandle:THandle;
                              iReasonForCall:longint;
                              tltmRawItem:PmyRawItem;
                              pParam:pointer); stdcall;

function tltmStartReadingRawItems(hHandle:THandle;
                                  uiFieldsMask:longword;
                                  boSetEAS:longbool;
                                  lpfnRawCallBack:TRawCallback;
                                  pParam:pointer):longint; stdcall; external 'foobar.dll';

Function tltmSetReadSessionDuration(hHandle:Cardinal; uiTag:Integer; iDuration:Integer):Integer; stdcall; external 'LibTSMap.dll' name 'tltmSetReadSessionDuration';

źle. uiTag jest "unsigned", czyli longword a nie integer. oprócz tego lepiej dać THandle a nie Cardinal.

Dziękuje... za logiczne wyjaśnienia...
Informacje wprowadziłem w pliku nagłówkowym.
Jednak nie potrafię wywołać prawidłowo tej funkcji tltmStartReadingRawItems za każdym razem przy próbie wywołania wyrzuca błąd (access violation...)
przypuszcza, że robię coś nie tak z wartością pParam.
Przepraszam za moją niewiedzę, ale nigdy z taką dziwną konstrukcją nie miałem do czynienia i przyznam szczerze, że jej nie rozumiem.

Czy ktoś mógłby mi przedstawić wzór prawidłowego wywołania tej funkcji?
Będę bardzo wdzięczny.

pozdrawiam
Billy

0

Sądzę że problem w strukturze:
TmyRawItem = record
// tutaj coś ...
end;
Masz ją odpowiednio uzupełnić.

0
_13th_Dragon napisał(a)

Sądzę że problem w strukturze:
TmyRawItem = record
// tutaj coś ...
end;
Masz ją odpowiednio uzupełnić.

Nie... to jest ok..
bo ten sam tym miałem wcześniej zadeklarowany i wykorzystuje go inna funkcja pojedynczego odczytu.
Mam funkcje, która dokonuje pojedynczego odczytu danych i ona działa poprawnie (tltmReadSingleRawItem) i wykorzystuje właśnie TmyRawItem.
Natomiast funkcja którą przedstawiłem na forum dotyczy odczytu ciągłego... i dlatego zadeklarowana jest ta wewnętrzna procedura, która wywoływana jest np. gdy odebrano nowe dane. Tak przynajmniej jest napisane (tak zrozumiałem) w dokumentacji.
Ja natomiast w prozaiczny sposób nie potrafię jej poprawnie wywołać.
Dołączam fragment dokumentacji:

7.5.1.1 Starting a read process
int __stdcall tltmStartReadingRawItems(HANDLE hHandle, unsigned int uiFieldsMask, BOOL
boSetEAS, void (__stdcall *lpfnRawCallBack)(HANDLE hHandle, int iReasonForCall, tltmRawItem
*myRawItem, void *pParam), void *pParam);
Description :
Call this function to start a reading process using the “Raw Memory Mapping”.
Parameters :
hHandle : Handle to the connection obtained from tltmOpenXxx() functions.
UiFieldsMask : The “Raw Mapping” fields that the DLL must try to read. This is any “ored”
combination of TLTM_RAWITEM_EAS, TLTM_RAWITEM_LOCKING,
TLTM_RAWITEM_BLOCK(n).
boSetEAS : For C320 only, TRUE to activate the EAS bit while reading.
lpfnRawCallback: Pointer to a callback function that the DLL will call each time an event
occurs (ie reading started,reading stopped, item read, etc..)
pParam : A user defined parameter that will be passed to the callback function each time it
is called. 
7.5.1.2 Stopping a read process
int __stdcall tltmStopReadingRawItems(HANDLE hHandle);
Description :
Call this function to stop a “Raw” reading process.
Parameters :
hHandle : Handle to the connection obtained from tltmOpenXxx() functions.
7.5.1.3 Reading callback
void __stdcall fnRawCallBack(HANDLE hHandle, int iReasonForCall, struct tltmRawItem
*myRawItem, void *pParam);
This is the way the callback function passed to tltmStartReadingRawItems(…) must be declared. It
is called each time an event occurs (see iReasonForCall) and receives the following parameters:
hHandle : The handle to the connection that triggered the event.
iReasonForCall : The reason for this call. It is either TLTM_READING_STARTED (the
reading has just begun), TLTM_READING_STOPPED (the reading was interrupted) or
TLTM_READING_NEW_DATA ( a new chip was read. Its contents is pointed by myRawItem).
myRawItem : Pointer to a tltmRawItem structure representing the item that was read. This
pointer is meaningful only when iReasonForCall is TLTM_READING_NEW_DATA. This pointer is
temporary and should never be used outside the callback function. 
7.5.2 Reading of One Single Chip
Int__stdcall tltmReadSingleRawItem(HANDLE hHandle, unsigned int uiReadTime, unsigned int
uiFieldsMask, BOOLboSetEAS, tltmRawItem*myRawItem)
Description :
Call this function to read one single chip using the “Raw Memory Mapping”. This function will verify
that only one chip is present in the field.
Parameters :
hHandle: Handle to the connection obtained fromtltmOpenXxx() functions.
uiReadTime: The time in milliseconds the function will spend reading the chips.
uiFieldsMask: The “Raw Mapping” fields that the DLL must try to read. This is any “ored”
combination of TLTM_RAWITEM_EAS, TLTM_RAWITEM_LOCKING,
TLTM_RAWITEM_BLOCK(n).
boSetEAS: For C320 only, TRUE to activate the EAS bit while reading.
myRawItem: Pointer to a tltmRawItem structure that will receive chip data. 
1

A jak tą funkcje wywołujesz?
I co podstawiasz zamiast CallBack'a?

0
_13th_Dragon napisał(a)

A jak tą funkcje wywołujesz?
I co podstawiasz zamiast CallBack'a?

wywołuje tak:

procedure TForm1.Button2Click(Sender: TObject);
var
UchwytCOM:Cardinal;
MyRawItem:PltmRawItem;
Mylpf:TlpfnRawCallBack;
x:Pointer;
.....
begin
.....
Pobieram UchwytCom (na pewno dobrze, bo inne funkcje wymagające tego parametru działają prawidłowo 
.....
tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0, mylpf,x);
//(po wywołaniu tej funkcji pojawiają się błąd Access Violation)
/ /próbowałem jeszcze tak:
tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,mylpf(UchwytCom,0,MyRawItem,x),x);

// ale kompilator zgłaszał, że w taki sposób nie można wywoływać funkcji
end;
a dokładnie podaje takie błąd:
[Error] Unit1.pas(73): Incompatible types: 'TlpfnRawCallBack' and 'procedure, untyped pointer or untyped parameter'
 
1

A jak inicjalizujesz mylpf ?

0
_13th_Dragon napisał(a)

A jak inicjalizujesz mylpf ?

Nie robię inicjalizacji.
Tylko deklaruję tak jak zmienną.
A strukturę w pliku nagłówkowym zrobiłem dokładnie tak jak wcześniej podałeś.

Nic więcej poza tym przykładem co podałem wcześniej nie robię.

Wykasowałem w przykładzie tylko elementy, które nie mają żadnego znaczenia.

1

echh... mylpf ma być PROCEDURĄ, która będzie wywoływana z wewnątrz biblioteki.

procedure mylpf(hHandle:THandle; iReasonForCall:longint; tltmRawItem:PmyRawItem; pParam:pointer); stdcall;
begin
  // co tam tutaj chcesz
end;
0
Azarien napisał(a)

echh... mylpf ma być PROCEDURĄ, która będzie wywoływana z wewnątrz biblioteki.

procedure mylpf(hHandle:THandle; iReasonForCall:longint; tltmRawItem:PmyRawItem; pParam:pointer); stdcall;
begin
  // co tam tutaj chcesz
end;

Zadeklarowałem procedure mylpf powyżej, i wywołuje:

tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,Mylpf(UchwytCom,0,MyRawItem,x),x);

ale kompilator w dalszym ciągu zwraca mi identyczny błąd, jak wcześniej:

type TlpfnRawCallBack=procedure(hHandle:Cardinal;iReasonForCall:Integer;var myRawItem:PltmRawItem;var pParam:Pointer);stdcall;
procedure mylpf(hHandle:THandle; iReasonForCall:longint; tltmRawItem:PltmRawItem; pParam:pointer);
PltmRawItem=^TltmRawItem;
 
implementation

procedure mylpf(hHandle:THandle; iReasonForCall:longint; tltmRawItem:PltmRawItem; pParam:pointer);
begin
  // co tam tutaj chcesz
end;
procedure TForm1.Button2Click(Sender: TObject);
var
x:Pointer;
MyRawItem:PltmRawItem;
begin
...
tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,Mylpf1(UchwytCom,0,MyRawItem,x),x);
// tutaj kompilator zgłasza identyczny błąd jak wcześniej, czyli:
// [Error] Unit1.pas(80): Incompatible types: 'TlpfnRawCallBack' and 'procedure, untyped pointer or untyped parameter'
end;

Co robię jeszcze nie tak?

pozdrawiam
Billy

0

wywołuj poprawnie:
tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,Mylpf1,x);

0

A jak "przetworzyć" na pascala taki zapis:

#define TLTM_RAWITEM_BLOCK(n)						(TLTM_RAWITEM_BLOCK_0 << (n))
0

Na 99% się mylę, ale spróbuję:

Function TLTM_RAWITEM_BLOCK(n: Integer): Integer;
Begin
 Result := TLTM_RAWITEM_BLOCK_0 Shl N;
End;
0

Nie da się tego przetłumaczyć.

Można zrobić tak:
function TLTM_RAWITEM_BLOCK(TLTM_RAWITEM_BLOCK_0,n:Integer):Integer;
begin
Result:=TLTM_RAWITEM_BLOCK_0 shl N;
end;
a każde wywołanie:
TLTM_RAWITEM_BLOCK()
zamienić na:
TLTM_RAWITEM_BLOCK(TLTM_RAWITEM_BLOCK_0,
)

lub bez funkcji zamienić każde wywołanie:
TLTM_RAWITEM_BLOCK()
na:
(TLTM_RAWITEM_BLOCK_0 shl (
))

0
_13th_Dragon napisał(a)

Nie da się tego przetłumaczyć.

Można zrobić tak:
function TLTM_RAWITEM_BLOCK(TLTM_RAWITEM_BLOCK_0,n:Integer):Integer;
begin
Result:=TLTM_RAWITEM_BLOCK_0 shl N;
end;
a każde wywołanie:
TLTM_RAWITEM_BLOCK()
zamienić na:
TLTM_RAWITEM_BLOCK(TLTM_RAWITEM_BLOCK_0,
)

lub bez funkcji zamienić każde wywołanie:
TLTM_RAWITEM_BLOCK()
na:
(TLTM_RAWITEM_BLOCK_0 shl (
))

Dziękuję.

Wracając jedna do wczorajszego problemu, który w dalszym ciągu nie mogę sobie poradzić, czyli typu proceduralnego.
Wiem już "jak to się je" natomiast nie wiem jak to zastosować w połączeniu z biblioteką DLL.

Mam tak:

//===============Plik Nagłówkowy==============
PltmRawItem=^TltmRawItem;
type TlpfnRawCallBack=procedure(hHandle:Cardinal;iReasonForCall:Integer;var myRawItem:PltmRawItem;var pParam:Pointer);stdcall;
Function tltmStartReadingRawItems(hHandle:Cardinal;uiFieldsMask:Cardinal;boSetEAS:Word; var lpfnRawCallBack:TlpfnRawCallBack;var pParam:Pointer):Integer;stdcall; external  'LibTSMap.dll' name 'tltmStartReadingRawItems';
procedure mylpf(hHandle:Cardinal; iReasonForCall:Integer; tltmRawItem:PltmRawItem; pParam:pointer); stdcall;
begin
 ; // co tam tutaj chcesz
end;
//=====================End Plik Nagłówkowy===============

//====================Główny Plik======================
procedure TForm1.btn_StartClick(Sender: TObject);
var
UchwytCom:Cardinal;
x:Pointer;
lpfnRawCallBack:TlpfnRawCallBack;
MyRaw:PltmRawItem;
begin

//wywołuje funkcję

tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,lpfnRawCallBack(mylpf(UchwytCom,0,MyRaw,x)),x);

// wg tak powinno wyglądać wywołanie, jednak tak nie jest, bo kompilator zgłasz błąd:
//  [Error] Unit1.pas(208): Incompatible types: 'Cardinal' and 'procedure, untyped pointer or untyped parameter';
// i ustawia kursor w tym miejscu: tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,lpfnRawCallBack(mylpf(UchwytCom,0,MyRaw,x))[kursor],x);

end;
//=====================End Główny Plik==================

Moje pytanie więc brzmi...
Jak poprawnie wywołać funkcję:
tltmStartReadingRawItems i powiązać ją z procedurą mylpf ??
Docelowo muszę "wydobyć" dane z rekordru MyRaw, które dzięki uruchomieniu funkcji tltmStartReadingRawItems
powinienem móc odczytać Myraw dzięki procedurze mylpf (tak mniemam);

0

Może czytaj odpowiedzi, już ci na to odpowiedziałem:
tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,mylpf,x);

0
_13th_Dragon napisał(a)

Może czytaj odpowiedzi, już ci na to odpowiedziałem:
tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,mylpf,x);

Tak czytałem i zapomniałem dodać, że przy tym wywołaniu kompilator również zgłasza błąd:
[Error] Unit1.pas(208): Types of actual and formal var parameters must be identical

również wywołanie:

tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,mylpf(UchwytCom,0,MyRaw,x),x);

zgłasza identyczny błąd;

Może chodzi o jakąś niezgodność bo te funkcje zwracają wartości również prze parametr?
Oryginalna deklaracja funkcji w C++ wygląda tak:

int __stdcall tltmStartReadingRawItems(HANDLE hHandle, unsigned int uiFieldsMask, BOOL boSetEAS, void (__stdcall *lpfnRawCallBack)(HANDLE hHandle, int iReasonForCall, struct tltmRawItem *myRawItem, void *pParam), void *pParam);

Parametry ze znaczkiem (*) są to parametry wyjściowe funkcji/procedury wywoływanej dodatkowo autor oznaczył je jeszcze przydomkiem"my".
Za słabo znam C++, żebym mógł powiedzieć gdzie popełniam błąd.

0
Billy1 napisał(a)
_13th_Dragon napisał(a)

Może czytaj odpowiedzi, już ci na to odpowiedziałem:
tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,mylpf,x);

Tak czytałem i zapomniałem dodać, że przy tym wywołaniu kompilator również zgłasza błąd:
[Error] Unit1.pas(208): Types of actual and formal var parameters must be identical

również wywołanie:

tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,mylpf(UchwytCom,0,MyRaw,x),x);

zgłasza identyczny błąd;

Może chodzi o jakąś niezgodność bo te funkcje zwracają wartości również prze parametr?
Oryginalna deklaracja funkcji w C++ wygląda tak:

int __stdcall tltmStartReadingRawItems(HANDLE hHandle, unsigned int uiFieldsMask, BOOL boSetEAS, void (__stdcall *lpfnRawCallBack)(HANDLE hHandle, int iReasonForCall, struct tltmRawItem *myRawItem, void *pParam), void *pParam);

Parametry ze znaczkiem (*) są to parametry wyjściowe funkcji/procedury wywoływanej dodatkowo autor oznaczył je jeszcze przydomkiem"my".
Za słabo znam C++, żebym mógł powiedzieć gdzie popełniam błąd.

chyba znalazłem rozwiązanie....
tltmStartReadingRawItems(UchwytCom,TLTM_RAWITEM_EAS,0,@mylpf,x);

kompiluje się prawidłowo...
wywołanie również przebiega bez błędów...
pozostało tylko wydobyć jakość dane z MyRaw. Jak?
Jakieś sugestie?

0

A jak zamienić zapis C++:

unsigned char ucChips[][P0XX_ANTICOLL_ARRAY]

gdzie:
P0XX_ANTICOLL_ARRAY=128

na zapis Pascal'a ?

pozdrawiam
Billy

1

A jak zamienić zapis C++:

[azarien@freebsd-vm ~]$ cdecl
Type `help' or `?' for help
explain unsigned char ucChips[][128]
declare ucChips as array of array 128 of unsigned char

więc formalnie będzie tak

type Tarray128 = array[0..P0XX_ANTICOLL_ARRAY] of byte;
     Parray128 = ^Tarray128;
var ucChips:Parray128;

ale mogą być lepsze sposoby, zależnie od tego jak to jest wykorzystywane (np. przekazanie parametru jako var Tarray128 albo const Tarray128 zamiast Parray128 — ze strony C++ to wygląda tak samo).

Procedura wywołuje się bez zarzutów, odczytuje dane i jest ok. Problem gdy procedura zostanie wywołana drugi raz i następne razy. Pomimo, że dane zmieniły się, ja nadal odczytuje dane które odczytałem za pierwszą razą.

Coś Źle Robisz.

0
Azarien napisał(a)

A jak zamienić zapis C++:

[azarien@freebsd-vm ~]$ cdecl
Type `help' or `?' for help
explain unsigned char ucChips[][128]
declare ucChips as array of array 128 of unsigned char

więc formalnie będzie tak

type Tarray128 = array[0..P0XX_ANTICOLL_ARRAY] of byte;
     Parray128 = ^Tarray128;
var ucChips:Parray128;

ale mogą być lepsze sposoby, zależnie od tego jak to jest wykorzystywane (np. przekazanie parametru jako var Tarray128 albo const Tarray128 zamiast Parray128 — ze strony C++ to wygląda tak samo).

Procedura wywołuje się bez zarzutów, odczytuje dane i jest ok. Problem gdy procedura zostanie wywołana drugi raz i następne razy. Pomimo, że dane zmieniły się, ja nadal odczytuje dane które odczytałem za pierwszą razą.

Coś Źle Robisz.

a tak dla formalności....
Jak powinno wyglądać samo:

unsigned char ucReply[]

w delphi?

1 użytkowników online, w tym zalogowanych: 0, gości: 1