Computername über DLL ermitteln

  • Hallo Autoitter,

    Ich würde gerne meine Fähigkeiten beim Umgang mit DLLs in Autoit verbessern.
    Zu diesem Zweck habe ich einige DLL-Aufrufe in eigene Funktionen eingebaut.
    Auch mit Unterstützung von Bug-fix DLL-Tutorial hab ich einiges ausprobiert.
    Allerdings habe ich nun das Problem mit der Funktion "GetComputerName":
    C++

    Code
    BOOL WINAPI GetComputerName(
      __out    LPTSTR lpBuffer,
      __inout  LPDWORD lpnSize
    );


    Wie müsste dieser Code in Autoit aussehen?
    Ich bin mir im Klaren darüber, dass es das Makro @ComputerName gibt, mir geht es um die richtige Verwendung der DLL!

    Bisher habe ich folgendes:

    [autoit]

    Func _GetComputerName()
    $fkernel32 = @SystemDir & "\" & "kernel32.dll"
    $function = "GetComputerName"
    $MaxLength = 15
    $lpBuffer = DllStructCreate("char[" & $MaxLength + 2 & "]")
    $nSize = DllStructCreate("int nSize")
    $dll = DllOpen($fkernel32)
    $return = DllCall($dll, "int", $function, "ptr", DllStructGetPtr($lpBuffer), "int_ptr", DllStructGetPtr($nSize))
    DllClose($dll)
    Return DllStructGetData($lpBuffer,1)
    EndFunc

    [/autoit]

    Hierbei bekomme ich keine Ergebnisse! (Aber auch keine Fehlermeldungen)

    Gruß
    Der Strahleman 8)

    Wenn denn alles so einfach wäre wie

    [autoit]

    "Autoit"

    [/autoit]

    meine UDFs
    Math2

    Wichtige Threads
    Math2

    Einmal editiert, zuletzt von Strahleman (14. August 2012 um 13:53)

  • Spoiler anzeigen
    [autoit]

    #include <WinAPI.au3>

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

    Global $s_ComputerName = _GetComputerName()
    If @error Then
    MsgBox(48, "Fehler", "Es ist ein Fehler aufgetreten!" & @CRLF & @CRLF & "@Error: " & @error & @CRLF & "@Extended: " & @extended)
    Else
    MsgBox(0, "Computername", "Computername: " & $s_ComputerName)
    EndIf

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

    Func _GetComputerName()
    Local Const $MaxLength = 255
    Local $lpBuffer = DllStructCreate("char[" & $MaxLength & "]")
    Local $lpnSize = DllStructCreate("DWORD nSize")

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

    DllStructSetData($lpnSize, 1, DllStructGetSize($lpBuffer))
    Local $a_Ret = DllCall("kernel32.dll", "BOOL", "GetComputerName", "ptr", DllStructGetPtr($lpBuffer), "ptr", DllStructGetPtr($lpnSize))
    If @error Then
    Return SetError(1, @error, -1)
    ElseIf $a_Ret[0] = 0 Then
    Return SetError(2, _WinAPI_GetLastError(), -1)
    Else
    Return DllStructGetData($lpBuffer, 1)
    EndIf
    EndFunc

    [/autoit]

    Ich bin mir allerdings nicht ganz sicher ob in $lpnSize die Anzahl der Characters ($MaxLength) eingetragen wird oder die Größe des Buffers (DllStructGetSize). In dem Fall ist es aber wurst da ein char eh nur 1 byte verbraucht und somit die Zahl die gleiche ist.
    Wenn du eine Dll nur einmal aufrufst brauchst du kein DllOpen welches du dann direkt nach DllCall wieder mit DllClose beendest. In dem Fall wird im Hintergrund genau das selbe gemacht wenn du einfach nur den Dll-Namen einträgst.

    Einmal editiert, zuletzt von AspirinJunkie (14. August 2012 um 12:38)

  • Hallo AspirinJunkie,

    dein Code hat leider keinen Erfolg gebracht.
    Danke für den Hinweis mit dem DllOpen und DllClose, ich habe nur auf Nummer Sicher gehen wollen, da ich ja keine Ergebnisse bekommen habe.
    Gibt's noch eine andere Idee, warum ich den Computer-Namen nicht auslesen kann?

    Wenn denn alles so einfach wäre wie

    [autoit]

    "Autoit"

    [/autoit]

    meine UDFs
    Math2

    Wichtige Threads
    Math2

  • So wie der Code dasteht funktioniert er bei mir problemlos.
    Was erhälst du denn als Ergebnis?
    Eine Fehlermeldung oder einfach nur einen leeren Computernamen?

    Zwar sollte die Windows-API auch die x64-Dlls bereitstellen aber hast du mal versucht den Code nur als x86 zu kompilieren?

  • Das geht auch viel einfacher:

    [autoit]

    $sCN = _GetComputerName()
    ConsoleWrite($sCN & @CRLF)

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

    Func _GetComputerName()
    Local $iLen = 100
    $aRet = DllCall("kernel32.dll", "int", "GetComputerName", "str", "", "int*", $iLen)
    Return $aRet[1]
    EndFunc

    [/autoit][autoit][/autoit][autoit][/autoit]
  • Sehr schönes Beispiel dass man die übergebenen Parameter auch über den Return-Wert auslesen kann.
    Aber etwas möchte ich noch kurz zur Diskussion stellen: ""int*", $iLen"
    Das bedeutet doch, dass er in deinem Fall im Arbeitsspeicher an die Adresse 100 springt, diesen Speicherbereich als DWORD auswertet und diese Zahl als Buffersize verwendet - oder nicht?
    Weil der übergebene Pointer den Wert 100 hat.

  • Danke funkey, so funktioniert es.

    Allerdings weiß ich noch nicht wieso? Die Parameter sind doch Pointer und müssten über einen Struct definiert werden.

    [autoit]

    DllCall("kernel32.dll", "int", "GetComputerName", "str", "", "int*", $iLen)

    [/autoit]


    Der Aufruf erfolgt also direkt mit String-Parameter und einem Integer-Pointer, mmh ?(

    Wenn denn alles so einfach wäre wie

    [autoit]

    "Autoit"

    [/autoit]

    meine UDFs
    Math2

    Wichtige Threads
    Math2

  • Ein String ist (zumindestens in C-Syntax) ein Array von Chars.
    Die Variable eines Array enthält hierbei als Wert den Pointer auf den Anfang des Char-Arrays.
    Übergibt man nun einen leeren String wird der Pointer darauf übergeben.
    Beim Auslesen über den Returnwert wird wieder auf den Speicherbereich gesprungen und der Inhalt als String interpretiert.

    Bei dem int*-Pointer hingegen ist mir das ganze aber nicht mehr so logisch da als Pointer-Adresse (nicht als Wert!) ja wie gesagt $iLen eingetragen wird was aber dennoch funktioniert.
    Wäre schön wenn das einer erklären könnte.

  • So hätte es auch funktioniert, war mir aber viel zu kompliziert:

    Spoiler anzeigen
    [autoit]

    Func _GetComputerName()
    $fkernel32 = @SystemDir & "\" & "kernel32.dll"
    $function = "GetComputerName"
    $MaxLength = 15
    $lpBuffer = DllStructCreate("char[" & $MaxLength + 2 & "]")
    $nSize = DllStructCreate("int nSize")
    DllStructSetData($nSize, 1, $MaxLength)
    $dll = DllOpen($fkernel32)
    $return = DllCall($dll, "int", $function, "ptr", DllStructGetPtr($lpBuffer), "int_ptr", DllStructGetPtr($nSize))
    DllClose($dll)
    Return DllStructGetData($lpBuffer,1)
    EndFunc

    [/autoit]

    Außerdem:
    'int*, 100' heißt nicht, dass ein Pointer eines Integers mit der Adresse 100 übergeben wird, sondern, dass die Variable ByRef übergeben wird und so von der Funktion verändert werden kann. AutoIt macht alles automatisch, damit der Funktion ein Pointer übergeben wird.

  • Na gut,

    dann probiere ich mal noch ein wenig weiter - auch mit anderen Aufrufen.
    Ich hoffe mal, dass es jetzt besser funktioniert.

    Ansonsten, weiß ich ja wen ich fragen kann ;)

    Gruß
    der Strahleman 8)

    Wenn denn alles so einfach wäre wie

    [autoit]

    "Autoit"

    [/autoit]

    meine UDFs
    Math2

    Wichtige Threads
    Math2


  • Hallo funkey,
    das hat wieder nicht mehr funktioniert! ?(?(?(

    Wenn denn alles so einfach wäre wie

    [autoit]

    "Autoit"

    [/autoit]

    meine UDFs
    Math2

    Wichtige Threads
    Math2

  • Das geht auch viel einfacher:

    [autoit]

    Func _GetComputerName()
    Local $iLen = 100
    $aRet = DllCall("kernel32.dll", "int", "GetComputerName", "str", "", "int*", $iLen)
    Return $aRet[1]
    EndFunc

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

    Nein. AutoIt weiß nicht, wie groß der erzeugte Buffer beim ersten Parameter sein soll. Handelt es sich um einen zu langen Namen, wird über den Puffer hinausgeschrieben.