Probleme mit DllCall

  • So, nun läuft es ! Es fehlte ':cdecl' ...

    Also, die Struktur des Puffers als ubyte(unsigned char = 0 bis 255), den Funktionsparameter als ubyte*, so ist es korrekt. :)

    Bei mir läuft das Skript aber nur bis zum ersten Aufruf und gibt DHE_ERROR_COMMAND zurück, bei dir müsste es aber schon anders sein ...

    Spoiler anzeigen
    [autoit]


    ; Konstanten

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $DHC_SIUDI0 = 0 ; COMMAND
    Global Const $DHC_SIUDI1 = 100 ; COMMAND
    Global Const $DHC_SIUDI2 = 200 ; COMMAND
    Global Const $DHC_SIUDI3 = 300 ; COMMAND
    Global Const $DHC_SIUDI4 = 400 ; COMMAND
    Global Const $DHC_SIUDI5 = 500 ; COMMAND
    Global Const $DHC_SIUDI6 = 600 ; COMMAND
    Global Const $DHC_SIUDI7 = 700 ; COMMAND
    Global Const $DHC_SIUDI8 = 800 ; COMMAND
    Global Const $DHC_SIUDI9 = 900 ; COMMAND

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $DHC_OPEN = 1 ; COMMAND
    Global Const $DHC_CLOSE = 2 ; COMMAND
    Global Const $DHC_DMXOUTOFF = 3 ; COMMAND
    Global Const $DHC_DMXOUT = 4 ; COMMAND
    Global Const $DHC_PORTREAD = 5 ; COMMAND
    Global Const $DHC_PORTCONFIG = 6 ; COMMAND
    Global Const $DHC_VERSION = 7 ; COMMAND
    Global Const $DHC_DMXIN = 8 ; COMMAND

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $DHC_RESET = 11 ; COMMAND
    Global Const $DHC_DEBUG_OPEN = 12 ; COMMAND
    Global Const $DHC_DEBUG_CLOSE = 13 ; COMMAND

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $DHC_WRITEMEMORY = 21 ; COMMAND
    Global Const $DHC_READMEMORY = 22 ; COMMAND
    Global Const $DHC_SIZEMEMORY = 23 ; COMMAND

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $DHC_3DWRITE = 25 ; COMMAND
    Global Const $DHC_3DREAD = 26 ; COMMAND
    Global Const $DHC_MMWRITE = 27 ; COMMAND
    Global Const $DHC_MMREAD = 28 ; COMMAND

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $DHC_TRANSPORT = 30 ; COMMAND
    Global Const $DHP_TRANSPORT_MODEALW = 1 ; PARAM
    Global Const $DHP_TRANSPORT_MODEALW32 = 2 ; PARAM
    Global Const $DHP_TRANSPORT_MODEOPT = 3 ; PARAM DEFAULT
    Global Const $DHP_TRANSPORT_MODEOPT32 = 4 ; PARAM

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $DHC_SERIALNREAD = 47 ; COMMAND
    Global Const $DHC_SERIALNWRITE = 48 ; COMMAND

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $DHE_OK = 1 ; RETURN NO ERROR
    Global Const $DHE_NOTHINGTODO = 2 ; RETURN NO ERROR

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $DHE_ERROR_COMMAND = -1 ; RETURN ERROR
    Global Const $DHE_ERROR_NOTOPEN = -2 ; RETURN ERROR
    Global Const $DHE_DMXOUT_PACKWRITE = -1000 ; RETURN ERROR -1005 = ERROR_ACCESS_DENIED -1023 = ERROR_CRC
    Global Const $DHE_DMXOUT_PACKREAD = -1100 ; RETURN ERROR

    [/autoit] [autoit][/autoit] [autoit]

    ; Dll öffnen
    Global Const $dhcDll = DllOpen ('DasHard.dll')

    [/autoit] [autoit][/autoit] [autoit]

    Opt ('OnExitFunc', 'Terminate')

    [/autoit] [autoit][/autoit] [autoit]

    ; Dll schließen
    Func Terminate ( )

    DllClose ($dhcDll)

    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; *** Dll Funktion ***
    Func HardDllCommand ($iCommand, $iParam, $pBloc)

    $aRes = DllCall ($dhcDll, 'int:cdecl', 'DasHardCommand', _
    'int', $iCommand, _
    'int', $iParam, _
    'ubyte*', $pBloc)
    Return $aRes[0]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; *** Open the interface when your application start :

    [/autoit] [autoit][/autoit] [autoit]

    Dim $v, $interface_open; // global
    ; Struktur für den Daten-Block erzeugen
    $dmxblock = DllStructCreate ('ubyte dmxblock[512]'); // global

    [/autoit] [autoit][/autoit] [autoit]

    $interface_open = HardDllCommand ($DHC_OPEN,0,0);
    switch $interface_open
    case $DHE_ERROR_NOTOPEN
    MsgBox (266256, 'DasHardCommand - Error', 'DHE_ERROR_NOTOPEN')
    case $DHE_ERROR_COMMAND
    MsgBox (266256, 'DasHardCommand - Error', 'DHE_ERROR_COMMAND')
    case $DHE_NOTHINGTODO
    MsgBox (266304, 'DasHardCommand - Info', 'DHE_NOTHINGTODO')
    case $DHE_OK
    MsgBox (266304, 'DasHardCommand - Info', 'DHE_OK')
    endswitch
    if ($interface_open > 0) then
    for $i = 1 to 512
    ; eigentlich unnötig, wie ProgAndy schon andeutete,
    ; aber ist ja nur ein Schreibtest ... ;)
    ConsoleWrite (DllStructSetData ($dmxblock, 'dmxblock', 0, $i) & @crlf);
    next
    $v = HardDllCommand ($DHC_DMXOUTOFF,0,0);
    endif
    ; Note :
    ; - When you open the interface, you don't know the state of the DMX output levels into the interface.
    ; It's why it's better to clean all DMX levels to be sure.

    [/autoit] [autoit][/autoit] [autoit]

    ; *** Send the DMX and read the PORT everytime :

    [/autoit] [autoit][/autoit] [autoit]

    Dim $v, $ports;
    if ($interface_open > 0) then
    $ports = HardDllCommand ($DHC_PORTREAD,0,0);
    $v = HardDllCommand ($DHC_DMXOUT, 512, DllStructGetPtr ($dmxblock, 'dmxblock')); evtl. 'dmxblock[0]' ...
    if ($v < 0) then
    $v = HardDllCommand ($DHC_CLOSE,0,0);
    $v = HardDllCommand ($DHC_OPEN,0,0);
    endif
    endif

    [/autoit] [autoit][/autoit] [autoit]

    ; Note :
    ; - When you use the DHC_DMXOUT command, the DLL analyses your DMX block.
    ; If there is no changes on the DMX levels, the function returns DHE_NOTHINGTODO and
    ; the DLL don't make a USB communication to save the CPU time of your computer.
    ; - After 6 seconds without USB communication, the USBDMX1 and interfaces go in stand alone mode
    ; (it's a nice feature, if the computer fails). It's why we propose to read the state of the
    ; port everytime to force a USB communication, with this, the interface do not go in stand alone mode.
    ; - If the DHC_DMXOUT command fails (for example, if the user unplug the USB interface !), you need
    ; to close and try to open again the interface.

    [/autoit] [autoit][/autoit] [autoit]

    ; *** Close the interface when your application finish :

    [/autoit] [autoit][/autoit] [autoit]

    Dim $v;
    if ($interface_open>0) then _
    $v = HardDllCommand ($DHC_CLOSE,0,0);

    [/autoit] [autoit][/autoit] [autoit][/autoit]

    EDIT: Das Exit musste natürlich noch raus ...


    LG
    Greenhorn


    2 Mal editiert, zuletzt von Greenhorn (10. November 2008 um 19:43)

  • Hm, das cdecl scheint ja ganz gut zu funktionieren :) , aber was macht das denn?
    Hm leider muss ich festellen dass ich den selben Errorcode erhalte...
    greetz DJ

  • Die Treiber sind installiert ?
    SIUDI.SYS
    SIUDI-EC.SYS
    SIUDI-IN.SYS

    Die DLL registriert ?


    Japp die Treiber sind alle installiert und das Interface funktioniert auch soweit ganz gut, das Standardprogramm ist installiert und es ist in der Lage das Interface anzusteuern. Da es mir aber funktionell nicht ausreicht möchte ich halt mit AutoIt was scripten.
    PS: Die dll lässt sich übrigens nicht registrieren da sie über keinen DllRegisterServer-Eingangspunkt verfügt.
    greetz DJ

  • nein leider nicht -.-
    Ich will das jetzt mit C++ versuchen, muss mir noch das PDSK installieren.
    greetz DJ

  • Also, die HardDllCommand ist immer noch nicht richtig, denke ich. der dritte Parameter, pBlock muss vom Typ PTR sein. diesem wird der Pointer zu der DllStruct übergeben.
    ubyte* bedeutet: Pointer zu einem UByte. Das Ubyte wird in DllCall als Wert angegeben und dann der Pointer dazu an die DLL gesendet.
    ptr bedeutet: Pointer zu der übergebenen DLLStruktur, hier ein array von ubytes :)

    Spoiler anzeigen
    [autoit]

    ; *** Dll Funktion ***
    Func HardDllCommand ($iCommand, $iParam, $pBloc)

    $aRes = DllCall ($dhcDll, 'int:cdecl', 'DasHardCommand', _
    'int', $iCommand, _
    'int', $iParam, _
    'ptr', $pBloc)
    Return $aRes[0]

    EndFunc

    [/autoit]
  • Also, die HardDllCommand ist immer noch nicht richtig, denke ich. der dritte Parameter, pBlock muss vom Typ PTR sein. diesem wird der Pointer zu der DllStruct übergeben.
    ubyte* bedeutet: Pointer zu einem UByte. Das Ubyte wird in DllCall als Wert angegeben und dann der Pointer dazu an die DLL gesendet.
    ptr bedeutet: Pointer zu der übergebenen DLLStruktur, hier ein array von ubytes :)

    ptr ist ein VOID* ! Also ein Zeiger vom Typ void.
    ubyte* ist ein Zeiger auf eine ubyte Variable.
    Also stimmt es schon so, die Funktion funzt ja in der letzten Version.

    In C/C++ müssen die Datentypen übereinstimmen, d.h. explizit deklariert werden.
    Ein long* kann nur auf einen long zeigen und nicht auf einen char ...
    Ob ein Zeiger auf ein Array verweist oder eine einfache Variable spielt keine Rolle.
    http://www.highscore.de/cpp/einfuehrung/variablen.html

    AutoIt wandelt die Typen manchmal automatisch um, aber verlassen würde ich mich nicht immer drauf ...


    LG
    Greenhorn


  • Also, AutoIt interessiert es NICHT, was das für ein Pointer ist. ein pointer ist ein pointer, die Integrität der Daten wird nur beim kompilieren von c(++) geprüft.
    ubyte* steht in AutoIt für einen Pointer auf ein ubyte, ja. Aner es wird nicht der Pointer an DLLCall übergeben, sondern der Wert des Bytes selbst. Wenn der Wert geändert wurde, steht er danach in returnarray[ParameterIndex]. Den Pointer bekommst du in AutoIt nirgends.

    Zitat

    * | Add * to the end of another type to pass it by reference. For example "int*" passes a pointer to an "int" type.

  • Moin Andy, mein Bester,

    natürlich hast Du Recht, daß 'ptr'(void*) genauso gut funktioniert wie 'ubyte*', solange ich den richtigen Datentyp an DllCall() übergebe. ;)
    Denn AutoIt überprüft wirklich nicht um welchen Datentyp es sich genau handelt.

    Zitat

    * | Add * to the end of another type to pass it by reference. For example "int*" passes a pointer to an "int" type.


    Hier wird nicht das Objekt selbst übergeben sondern ein Zeiger auf ein Objekt.
    Das ist ähnlich wie ByRef, der Unterschied ist aber, das der Funktionsparameter ein Zeiger ist und nicht das Objekt selbst ...

    Beispiele:

    Spoiler anzeigen


    Wenn ich ein Objekt per Referenz an eine Funktion übergeben muss, sieht die Funktionsdeklaration wie folgt aus:

    Spoiler anzeigen


    Letzteres wäre in AutoIt wie folgt definiert ...

    Spoiler anzeigen
    [autoit]


    Func DoSomething ( ByRef $argument )
    $argument += 1
    Return 0
    EndFunc

    [/autoit]

    Wie meinst Du das "Den Pointer bekommst du in AutoIt nirgends." ? ?(

    LG
    Greenhorn


    3 Mal editiert, zuletzt von Greenhorn (14. November 2008 um 13:16)

  • Wenn man in AutoIt beim DLLCall den Stern verwendet, musst du trotzdem den Wert übergeben und nicht den Pointer.
    Der * sagt AutoIt:
    -nimm den Wert, speichere ihn und verwende den Pointer zum Speicher für den DLLCall
    -führe DLLCall mit dem Pointer aus
    -ließ danach den neuen Wert vom Pointer und speichere ihn im Reutrn-Array
    -gib das Return Array zurück