[TRIXI] Implementation Perl

Als Freund „anderer“ Programmiersprachen habe ich es mal mit Perl versucht, komme aber auch nicht über den Connect hinaus:

#!/usr/bin/perl -w
use strict;
use WIN32::API;
my $ips_connect=new Win32::API(‚trixi‘,‚Connect‘, ‚PI‘,‚B‘,’__stdcall’);
unless ($ips_connect) {
print "DLL Load Failed or Function not found
";
exit 1;
}
my $server=‚127.0.0.1‘.chr(0);
my $port=3773;
my $status=$ips_connect->Call($server,$port);
unless ($status) {
print "Connect Failed
";
exit 1;
}

Die DLL wird geladen, aber was ich auch als Server eingebe, der Status ist immer ‚0‘.
Gibt es evtl. ein Debug-Flag in der DLL, wodurch man ein Log o.ä. aktivieren könnte?

Tommi

ich muss gestehen ich hab zu wenig Plan von Perl… Aber kennt Perl die Aufrufkonvention LPCSTR aus der WinAPI? Versuchs mal damit. Einfach ein nullterminirter String scheint mir zu einfach. Aber vielleicht ist das aber ja auch „Perl-Magic“ :wink:

Gibt es evtl. ein Debug-Flag in der DLL, wodurch man ein Log o.ä. aktivieren könnte?

Du würdest dich wundern wie wenig momentan in der DLL steckt… Der Quellcode hat ca 4kb. Den Rest macht das (leicht modifizierte) IPS SDK aus :eek:. Muss mal schauen. Son Flag mit Output in eine Datei ließe sich sicherlich einbauen…

Toni

Vielleicht fragst du mal in nem Perl-Forum ob man das so machen kann denn irgendwie sehe ich immer noch nicht, dass du da irgendetwas mit Pointern tust. Macht Perl das automatisch? Gibts den @ Operator in Perl?

hilft dir diese Tutorial? (Klick)

Toni

Hallo Toni,
So, neuer Versuch mit V013Beta
Die einfachen Sachen klappen, aber Readstring, Readfloat, aber auch Disconnect nicht. Bei ersten beiden fliege ich komplett aus dem Programm, Disconnect rödelt ewig rum und gibt dann auch nichts zurück. Irgendwie klappt das mit den Pointern bzw. Speichern nicht. Evtl. ist es eine möglich bei Readstring, einen Bufferpointer und die Grösse als Parameter zu übergeben und als Rückgabewert die echte Länge,wie das sonst mit DLL Aufrufen gemacht wird. Bei Float gibt es bestimmt unterschiedliche Vorstellungen von der Größe eines Floats. Könntest Du mal die C Prototypen mitschicken? Die Booleans musste ich als int in Empfang nehmen.

Tommi

BTW: Wenn Du schon mit Lazarus experimentiert hast: Hast Du evtl auch schon die DLL unter Linux kompiliert bekommen? Ich weiss, dazu muss man auch am SDK was tun…

Testscript

#!/usr/bin/perl -w
use strict;
use WIN32::API;

#prototype
my $ips_connect=new Win32::API('trixi','Connect', 'PI','I');
my $ips_disconnect=new Win32::API('trixi','int Disconnect()');
my $ips_isonline=new Win32::API('trixi','int IsOnline()');
my $ips_readinteger=new Win32::API('trixi','ReadInteger', 'N','N');
my $ips_readfloat=new Win32::API('trixi','ReadFloat', 'N','F');
my $ips_readstring=new Win32::API('trixi','ReadString', 'N','P');
my $ips_readboolean=new Win32::API('trixi','ReadBoolean', 'N','I');

#DLL geladen?
unless ($ips_connect) {
    print "DLL Load Failed or Function not found
";
    exit 1;
}
print "DLL Loaded
";

#Connect (ret 0/1)
my $server='localhost';
my $port=3773;
my $r=$ips_connect->Call($server,$port);
unless ($r) {
    print "Connect failed
";
    exit 1;
}
print "Connect OK
";

#isOnline (ret 0/1)
$r=$ips_isonline->Call();
unless ($r) {
    print "IPS not Online
";
    exit 1;
}
print "IPS ist Online
";

#read Boolean (ret 0/1)
$r=$ips_readboolean->Call(46304);
print "Return Bool: $r 
";

#read integer
$r=$ips_readinteger->Call(47681);
print "Return Int: $r 
";

#read float
$r=$ips_readfloat->Call(20241);
print "Return Float: $r 
";

#read string 
$r=$ips_readstring->Call(30145);
print "Return String: $r 
" if $r;

$r=$ips_disconnect->Call();
unless ($r) {
    print "Disconnect failed
";
    exit 1;
}
print "Disconnect OK
";

Das Problem mit ReadString habe ich hinbekommen, da hat eine andere Aufrufmethode geholfen.
Das readFloat-Problem dagegen wird sich sich nicht so leicht lösen lassen, da es offenbar die unterschiedlichsten und nicht transparenten Methoden gibt, wie die 8Byte von double verteilt werden. Wenn ich die Funktion als long definiere, bekomme ich was zurück, habe aber keine Ahnung, was das ist. Da wäre evtl die Rückgabe als String(evtl. in einer weiteren Methode) hilfreich.

Tommi

#prototype
my $ips_connect=new Win32::API('trixi','long Connect (LPSTR * s,int b)');
my $ips_disconnect=new Win32::API('trixi','long Disconnect()');
my $ips_isonline=new Win32::API('trixi','long IsOnline()');
my $ips_readinteger=new Win32::API('trixi','long ReadInteger (long v)');
my $ips_readfloat=new Win32::API('trixi','double ReadFloat(long v)');
my $ips_readstring=new Win32::API('trixi','LPSTR ReadString(long v)');
my $ips_readboolean=new Win32::API('trixi','long ReadBoolean (long v)');

Und das wird auch das Problem sein. Denn Wenn es in allen anderen Sprachen klappt, denke ich, hab ich den Standard schon recht gut getroffen. Und eine komplizierte, wenn auch übliche, Aufrufkonvention zu verwenden wiederspricht eigentlich dem Gedanken eines „SDK für Dummies“…

Disconnect machte übrigens unter VBA auch Probleme. Muss noch testen was das ist oder ob das so muss. Habs auf meiner public Todo. im Hauptthread (1 Beitrag).


// c++

typedef Double (* ReadFloat)(long);
int _tmain(int argc, _TCHAR* argv[])
{
  [..] 
  ReadFloat ips_readfloat;
  [..]
  // DLL Datei laden
  HINSTANCE hTRIXI = LoadLibrary("TRIXI.dll");

  if (hTRIXI)
  {
        if (ips_connect)
	  result = ips_connect(pIP, 3773);
        if (result)
        {
          ips_readfloat = (ReadFloat) (int) GetProcAddress(hTRIXI,"ReadFloat");
	  [..]
          printf("Variable lesen: %4.5f 
", ips_readfloat(12657));
        }
  }

Hilft dir das weiter? Funktioniert so unter C++ Builder 2009. Hab von c++ leider überhaupt keinen Plan mehr. Von den paar Zeilen hab ich mir echt Hirnzerrrung geholt. :rolleyes:

Gruß,

Toni

Wenn Du schon mit Lazarus experimentiert hast: Hast Du evtl auch schon die DLL unter Linux kompiliert bekommen? Ich weiss, dazu muss man auch am SDK was tun…

Hab mir da grade noch mal Gedanken drüber gemacht. Paresy weist ja darauf hin, dass die neueren Indy (Tiburon) Komponenten benötigt werden. Indy gibts ja für FPC ja noch nicht so richtig. Wenn man nun hingehen würde und die SOAP Schnittstelle manuell bedient, müsste das aber wohl klappen. Aber ich hab keine Linux Maschine, keine Lust mich in irgend einen Emulator einzuarbeiten und eigentlich auch keinen Schimmer von SOAP… :rolleyes:

Aber der bissel Bock hätt ich schon drauf. :smiley:

Toni

Ich habe jetzt mal etwas weiter mit Perl und der offiziellen Version 0.13 gespielt. Das sieht schon mal ganz gut aus, der Disconnect geht jetzt auch bei mir, auch wenn er länger als die anderen Befehle dauert.
Folgende Probleme habe ich noch:
-Manchmal bleibt das Script beim 2. Aufruf irgendwo in der Mitte stehen.
-GetVariableIDByName geht genau einmal im Script, dann nicht mehr. Die Funktion wird genausowenig geloggt wie GetScriptIDByName.
-WriteFloat gibt mir false zurück, obwohl es im Log und in der Variable richtig steht.
-ReadFloat taucht manchmal gar nicht erst im Log auf, da schmiert das Programm auch immer ab. Anbei mein (fast vollständiges) Testscript und das erzeugte Log, das erste mal ohne ReadFloat, beim 2.mal mit.

Callbacks habe ich nur definiert, aber nicht probiert.

BTW:Verwendest Du zum Kompilieren TurboDelphi?
Dort muss man FastMM4 ganz am Anfang laden, das war jedenfalls das Problem bei meinen Modulen.

Tommi

Perl.zip (1.57 KB)

Disconnect dauert. Das ist normal und liegt an der Message Sink, die muss runtergefahren werden. Macht Paresys demo auch.

TRIXI entwickle ich unter D2k9. Einen separaten Speichermanager verwende ich nicht. Sonst wär TRIXI womöglich davon abhängig und das wollte ich nicht. Alles Handarbeit. :wink:

GetVariableIDByName und GetScriptIDByName sind aus dem SDK geforewarded. Sind jeweils nur eine Zeile. Kann da zwar noch ne Zeile Log rein machen aber iwi nicht sonderlich sinnvoll…

Die anderen Punkte schau ich mir morgen mal an.

Edit:

Ich könnt an der entsprechenden Stelle mal nen try except block drüber legen. Mal ne doofe Frage: Was brauch ich denn um ein pearl script durch laufen zu lassen?!?

Was brauch ich denn um ein pearl script durch laufen zu lassen

Das hat nix mit „Perlen“ im herkömlichen Sinne zu tun, ist aber (für mich) eine Perle, die mir auch beim Geldverdienen hilft :-)))
Du brauchst natürlich den Perl-Interpreter und ggfls ein paar Module. Unter Windows ist es am einfachsten, sich das passende Activestate-Packet von ActivePerl Downloads - Perl Binaries for Windows, Linux and Mac | ActiveState runterzu laden. Ich empfehle die 32bit-Version perl 5.10 unter Windows zu nehmen.
Dazu den Editor Deines Vertrauens (oder die IDE Komodo vom gleichen Hersteller).
Gestartet wird das aus der IDE oder auf der Kommandozeile mit „perl <scriptname>“.

Tommi