DLL dynamiczne wywołanie procedury w Delphi

0

Witam
Proszę o pomoc z dll, wiem ze na forum temat był już poruszany wiele razy niemniej żaden z postów nie rozwiązał problemu. Chce dodać do programu dll-ke kontrolującą kartę 8 przekaźników podpiętych pod usb z wbudowanym konwerterem do rs232 (kontrola przez RSPin tez się nie udała)
jeśli chodzi o załadowanie dll do pamięci stosuje ładowanie dynamiczne wg .opisu z:

Biblioteki DLL

Problem pojawia się w chwili wywołania procedury. Przy wywołaniach sugerowałem się opisem ze strony:

http://www.ucprojects.eu/relay-board/9-instrukcja-obugi-bilioteki-relayboardlib

Próbowałem kilkoma programami odczytać dll, jednak nic sensownego to nie dało.
Proszę o sugestie jak najlepiej to rozgryź, i czy jest to wykonalne.

0

może byś tak dla odmiany chociaż kawałek kodu dał a nie tylko opisujesz jaki to biedny jesteś

0

Uwielbiam to :)
Wczytywanie procedur oparłem na opisie ładowania dynamicznego z pierwszego linku tzn.

var
  DLL : THandle;
  ShowForm : procedure;
begin
  DLL := LoadLibrary('RelayBoard.dll'); 
  try
    @ShowForm := GetProcAddress(DLL, 'relayBoard.Off(5'); 
    if @ShowForm=nil then Log('Bład - nie mogę znaleźć proceudry w bibliotece!');
    ShowForm; 
  finally
    FreeLibrary(DLL);
  end;

GetProcAddress- próbowałem pobrać zarówno z parametrem jak i bez,

0

chłopie pojęcia podstawowego nie masz o tym co próbujesz zrobić. To jest dll dla .net i nie da się jej zaimportować jak normalną bibliotekę. Tu masz opisany sposób, który może zadziała http://forums.devshed.com/delphi-programming-90/c-dll-need-to-be-used-in-delphi-231122.html

BTW nic nie stoi na przeszkodzie aby zobaczyć sobie co w tej dllce siedzi i przepisać to na delphi

0

Tu masz opisany sposób, który może zadziała

Jest też inny sposób — napisanie wrappera w C++/CLI, który będzie eksportować zwykłe nieobiektowe funkcje, i załadowanie go z Delphi jak normalnej DLL-ki.

1
Azarien napisał(a)

Jest też inny sposób — napisanie wrappera w C++/CLI, który będzie eksportować zwykłe nieobiektowe funkcje, i załadowanie go z Delphi jak normalnej DLL-ki.
prościej chyba potraktować tą dllkę reflektorem i po prostu napisać to choćby w delphi. Nie ma tego tam wcale tak dużo - może by było ze 100 linii kodu :p

0

O_o
Panowie ja tylko tak nieskromnie przypomnę ze to moje pierwsze podejście do dll. A biorąc pod uwagę moje doświadczenie w programowaniu do przepisywania dll do Delphi zabiorę się.. w następnej dekadzie :)

0

Pomijając fakt, że sam sposób importowania procedury z biblioteki jest nietrafiony dodam tylko, że ten kod:

if @ShowForm = nil then Log('Bład - nie mogę znaleźć proceudry w bibliotece!');
ShowForm;

nie ma sensu, bo bez względu na to co będzie zawierał wskaźnik @ShowForm, procedura ShowForm i tak zostanie wykonana... Właściwa konstrukcja warunku powinna wyglądać co najmniej tak:

if @ShowForm = nil then
  Log('Bład - nie mogę znaleźć proceudry w bibliotece!')
else
  ShowForm;

Miej się na baczności jak będziesz pisał za niedługo nową wersję;

0

Furious Programming powyższy kod już wywaliłem faktycznie był poroniony.
Udało mi się odczytać dll. faktycznie nie ma tam cudów, interesujące mnie funkcje bazuja na dwóch klasach, z czego jedna odwołuje się do przerwań, wiec myślę ze ogarnę temat.

ps. Misiekd dzięki za namiar na Reflektor- genialne narzędzie.

0

Chyba jednak przeceniłem swoje umiejętności. Przy probie dodania funkcji do programu wypluwa mi wszystkie możliwe błędy. Czy mogę prosić o pomoc i wytłumaczenie. Poniżej podaje kod obu klas.

 
public RelayBoard = class
    // Methods
    constructor RelayBoard.Create(portName: string);
    begin

    end;
    constructor RelayBoard.Create(portName: string; boundRate: Integer);
    begin
        self.DefaultAdress := 1;
        self._serialPort := SerialPort.Create(portName, boundRate);
        self._serialPort.Open
    end;
    procedure RelayBoard.Finalize;
    begin
        try
            if ((self._serialPort <> nil) and self._serialPort.IsOpen) then
                self._serialPort.Close
        finally
            inherited Finalize
        end
    end;
    function RelayBoard.Get: Byte;
    begin
        Result := self.Get(self.DefaultAdress)
    end;

    function RelayBoard.Get(adress: Byte): Byte;
    begin
        i := 0;
        while ((i < 5)) do
        begin
            self.SendPacket(adress, $47, 0);
            num2 := 0;
            goto Label_0087;

        Label_0015:
            if (self._serialPort.ReadChar = $55) then
            begin
                buffer := New(array[4] of Byte);
                self._serialPort.Read(buffer, 0, 4);
                if (Crc8.Count(buffer, 0, 3) <> buffer[3]) then
                    raise InvalidDataException.Create('CRC error.');
                if (adress = buffer[0]) then
                begin
                    if (buffer[1] <> $52) then
                        raise InvalidDataException.Create('Got echo (what have been sent have come back) from the port. Probably you have chosen wrong COM port.');
                    begin
                        Result := buffer[2];
                        exit
                    end
                end
            end;
        Label_006E:
            if (self._serialPort.BytesToRead > 4) then
                goto Label_0015;
            Thread.Sleep(10);
            inc(num2);
        Label_0087:
            if (num2 < 100) then
                goto Label_006E;
            inc(i)
        end;
        raise TimeoutException.Create('Timeout exception. No data recived from the device.')
    end;
    function RelayBoard.GetPortNames: string[];
    begin
        Result := SerialPort.GetPortNames
    end;
    function RelayBoard.IsOn(relayNumber: Byte): boolean;
    begin
        Result := self.IsOn(self.DefaultAdress, relayNumber)
    end;
    function RelayBoard.IsOn(adress: Byte; relayNumber: Byte): boolean;
    begin
        if ((relayNumber > 8) or (relayNumber < 1)) then
            raise ArgumentOutOfRangeException.Create('relayNumber', 'The value should be  betwen 1 and 8.');
        begin
            Result := ((self.Get(adress) and ((1 as Integer) shl (relayNumber - 1))) = ((1 as Integer) shl (relayNumber - 1)));
            exit
        end
    end;
    procedure RelayBoard.Off(relayNumber: Byte);
    begin
        self.Off(self.DefaultAdress, relayNumber)
    end;
    procedure RelayBoard.Off(adress: Byte; relayNumber: Byte);
    begin
        if ((relayNumber < 1) or (relayNumber > 8)) then
            raise ArgumentOutOfRangeException.Create('relayNumber', 'The value should be  betwen 1 and 8.');
        self.SendPacket(adress, 70, ((relayNumber - 1) as Byte))
    end;
    procedure RelayBoard.On(relayNumber: Byte);
    begin
        self.On(self.DefaultAdress, relayNumber)
    end;
    procedure RelayBoard.On(adress: Byte; relayNumber: Byte);
    begin
        if ((relayNumber < 1) or (relayNumber > 8)) then
            raise ArgumentOutOfRangeException.Create('relayNumber', 'The value should be  betwen 1 and 8.');
        self.SendPacket(adress, $4f, ((relayNumber - 1) as Byte))
    end;

    procedure RelayBoard.SendPacket(adress: Byte; cmd: Byte; arg: Byte);
    var
        buffer: Byte[];
    begin
        buffer := New(array[5] of Byte, ( ( $55, adress, cmd, arg, Crc8.Count(buffer, 1, 3) ) ));
        self._serialPort.Write(buffer, 0, 5)
    end;

    procedure RelayBoard.Set(mask: Byte);
    begin
        self.Set(self.DefaultAdress, mask)
    end;

    procedure RelayBoard.Set(adress: Byte; mask: Byte);
    begin
        self.SendPacket(adress, $53, mask)
    end;


    // Properties
    public property DefaultAdress: Byte read get_DefaultAdress write set_DefaultAdress;

    // Fields
    strict private const _retransmit: Integer = 5;
    strict private {readonly} _serialPort: SerialPort;
    strict private const _timeOut: Integer = 100;
    strict private const Preamble: Byte = $55;

i 2 klasa

 
strict private Crc8 = class
    // Methods
    function Crc8.Count(data: Byte[]): Byte;
    begin
        Result := Crc8.Count(0, data)
    end;

    function Crc8.Count(initValue: Byte; data: Byte[]): Byte;
    begin
        Result := Crc8.Count(initValue, data, 0, data.Length)
    end;

    function Crc8.Count(data: Byte[]; start: Integer; length: Integer): Byte;
    begin
        Result := Crc8.Count(0, data, start, length)
    end;

    function Crc8.Count(initValue: Byte; data: Byte[]; start: Integer; length: Integer): Byte;
    begin
        num2 := initValue;
        i := start;
        while ((i < (start + length))) do
        begin
            num2 := Crc8._lookupTable[(data[i] xor num2)];
            inc(i)
        end;
        begin
            Result := num2;
            exit
        end
    end;


    // Fields
    strict private class var {readonly} _lookupTable: Byte[] = New(array[$100] of Byte, ( ( 
        0, $5e, $bc, $e2, $61, $3f, $dd, $83, $c2, $9c, $7e, $20, $a3, $fd, $1f, $41, 
        $9d, $c3, $21, $7f, $fc, $a2, $40, 30, $5f, 1, $e3, $bd, $3e, $60, 130, 220, 
        $23, $7d, $9f, $c1, $42, $1c, $fe, 160, $e1, $bf, $5d, 3, $80, $de, 60, $62, 
        190, $e0, 2, $5c, $df, $81, $63, $3d, $7c, $22, $c0, $9e, $1d, $43, $a1, $ff, 
        70, $18, 250, $a4, $27, $79, $9b, $c5, $84, $da, $38, $66, $e5, $bb, $59, 7, 
        $db, $85, $67, $39, $ba, $e4, 6, $58, $19, $47, $a5, $fb, 120, $26, $c4, $9a, 
        $65, $3b, $d9, $87, 4, 90, $b8, 230, $a7, $f9, $1b, $45, $c6, $98, $7a, $24, 
        $f8, $a6, $44, $1a, $99, $c7, $25, $7b, $3a, 100, $86, $d8, $5b, 5, $e7, $b9, 
        140, 210, $30, 110, $ed, $b3, $51, 15, $4e, $10, $f2, $ac, $2f, $71, $93, $cd, 
        $11, $4f, $ad, $f3, $70, $2e, $cc, $92, $d3, $8d, $6f, $31, $b2, $ec, 14, 80, 
        $af, $f1, $13, $4d, $ce, $90, $72, $2c, $6d, $33, $d1, $8f, 12, $52, $b0, $ee, 
        50, $6c, $8e, $d0, $53, 13, $ef, $b1, 240, $ae, $4c, $12, $91, $cf, $2d, $73, 
        $ca, $94, $76, 40, $ab, $f5, $17, $49, 8, $56, 180, $ea, $69, $37, $d5, $8b, 
        $57, 9, $eb, $b5, $36, $68, $8a, $d4, $95, $cb, $29, $77, $f4, 170, $48, $16, 
        $e9, $b7, $55, 11, $88, $d6, $34, $6a, $2b, $75, $97, $c9, $4a, 20, $f6, $a8, 
        $74, $2a, 200, 150, $15, $4b, $a9, $f7, $b6, $e8, 10, $54, $d7, $89, $6b, $35
     ) ));

end;

to jest kod który odczytałem z reflektora.
Jak to czytać, jak przenosić do normalnego unita, na co zwrócić uwagę.

0

Pierwsze co się rzuca w oczy to private przed class, a poza tym w Delphi nie ma strict private class jest typ packed record i nie może być tak "z d**y" wzięty na końcu kodu jeżeli masz się do tego typu odwoływać. Po prostu kod trzeba mozolnie przerobić. Więcej to Ci pewnie ktoś jeszcze podpowie. Ja doświadczenie w tłumaczeniu z C/C++ mam małe, ale jeżeli to Ci wygenerował zewnętrzny program to od razu na pierwszy rzut ok widac, ten że kod nie do końca przypomina Pascala. Zresztą komunikaty o błędach od kompilatora mówią wszystko.

0

To jest prawdopodobnie Delphi for .Net (niewspierany już).

0

Witam
Szukam pomocy w przepisaniu opisanych wyżej klas bezpośrednio w kod Delphego. Wiem ze temat powinien być dodany z "paca" ale nie chciałbym niepotrzebnie spamować forum.

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