Seite 1 von 2

Wie Stringrückgabe aus PB-DLL in VB.NET?

Verfasst: 13.12.2006 09:12
von Kukulkan
Hallo,

Ich habe eine DLL in PB geschrieben. Da das mit der Rückgabe von Strings nicht so Einfach ist, habe ich unter VB6 eine kleine Function für "String From Pointer" benötigt (siehe unten). Die Klappt super.

Jetzt die Frage:
Kann man in VB.NET das vereinfachen? Gibt es die Möglichkeit die Strings leichter zurückzubekommen? Ich möchte die DLL nicht verändern. Ich muss einen String aus dem von PB gelieferten Pointer erhalten. Meine PB-DLL liefert den String mit 1 Byte je Zeichen. VB.NET verwendet wohl auch wie VB 2 Byte je Zeichen, oder?

VB6-Code:

Code: Alles auswählen

Private Function P2S(lngPtr As Long) As String
    ' Pointer to string. Returns a string of a pointer in VB6.
    ' Example call:
    ' Debug.Print "Version: " & P2S(FunctionName(Parameter))
    Dim strTemp As String
    Dim lngLen As Long
    If lngPtr Then
        lngLen = lstrlenW(lngPtr) * 2
        If lngLen Then
            strTemp = Space(lngLen)
            CopyMemory ByVal strTemp, ByVal lngPtr, lngLen
            P2S = Left(strTemp, InStr(1, strTemp, Chr(0)) - 1)
        End If
    End If
End Function
Kann mir jemand kurz helfen?

Volker

Verfasst: 13.12.2006 11:51
von Kaeru Gaman
evtl. hilft es schon, wenn du deine PB-DLL mit Unicode Aktiv kompilierst,
dann sollte sie schon 2bpc-strings zurückgeben...

Verfasst: 13.12.2006 12:07
von Kukulkan
Hallo Kaeru,

Vielen Dank für den Tipp, aber wie im Posting schon erwähnt möchte ich die DLL nicht verändern. Ansonsten müssen alle Kunden mit der aktuellen Version Ihre Aufrufe verändern. Da ich sicherlich keine Unicode Daten zurückgeben werde, ist das auch unnütz.

Noch einen anderen Tipp von jemandem der mit .NET arbeitet?

Volker

Verfasst: 13.12.2006 12:14
von Kaeru Gaman
hi Volker,

sorry, hatte ich nicht richtig verstanden...

ich kenn mich zwar mit .NET nicht aus, aber auch dort müsste es eine möglichkeit geben,
dem interface zu sagen, dass das input ein ANSI-String ist.

um irgendwelche Copy-Memory-Geschichten wirst du kaum herumkommen,
da PB dir ja nur den pointer zurückgibt.

Verfasst: 13.12.2006 13:00
von Rings
es kann auch ohne copymemory gehen :)

der code iss nurbissl größer, da es sich um ein kleines
projekt handelt.
Eigentlich brauchst du nur alles im module 'DLL_Zugriff'

Code: Alles auswählen

Imports System.Runtime.InteropServices
Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Vom Windows Form Designer generierter Code "

    Public Sub New()
        MyBase.New()

        ' Dieser Aufruf ist für den Windows Form-Designer erforderlich.
        InitializeComponent()

        ' Initialisierungen nach dem Aufruf InitializeComponent() hinzufügen

    End Sub

    ' Die Form überschreibt den Löschvorgang der Basisklasse, um Komponenten zu bereinigen.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    ' Für Windows Form-Designer erforderlich
    Private components As System.ComponentModel.IContainer

    'HINWEIS: Die folgende Prozedur ist für den Windows Form-Designer erforderlich
    'Sie kann mit dem Windows Form-Designer modifiziert werden.
    'Verwenden Sie nicht den Code-Editor zur Bearbeitung.
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.TextBox1 = New System.Windows.Forms.TextBox
        Me.SuspendLayout()
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(16, 16)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(128, 64)
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Go"
        '
        'TextBox1
        '
        Me.TextBox1.Location = New System.Drawing.Point(16, 88)
        Me.TextBox1.Name = "TextBox1"
        Me.TextBox1.Size = New System.Drawing.Size(128, 20)
        Me.TextBox1.TabIndex = 1
        Me.TextBox1.Text = "TextBox1"
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 273)
        Me.Controls.Add(Me.TextBox1)
        Me.Controls.Add(Me.Button1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MsgBox(VBGetHeiligeKuh())
    End Sub
End Class
Module DLL_Zugriff
    <DllImport("pbtest.dll", EntryPoint:="HeiligeKuh")> _
        Public Function GetHeiligeKuh() As IntPtr
    End Function
    Public Function VBGetHeiligeKuh() As String
        Dim sDummy As String = "Nix"
        Dim Handle As IntPtr

        Try
            Handle = GetHeiligeKuh()
            sDummy = Marshal.PtrToStringAnsi(Handle) 'ansi
            'sDummy = Marshal.PtrToStringUni(Handle)  'unicode

        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
        Return sDummy
    End Function
End Module

Verfasst: 14.12.2006 15:55
von Kukulkan
Hi Rings,
Marshal.PtrToStringAnsi(Handle) 'ansi
Das war das was ich gesucht habe! Vielen Dank!

Volker

Verfasst: 14.12.2006 21:46
von Spirit
Ist der Umweg über den IntPtr wirklich nötig? Man könnte doch gleich den
Rückgabewert der Funktion marshallen, oder irre ich mich da?

Also in etwa so (ist C#, mit VB.NET Syntax bin ich leider nicht vertraut):

Code: Alles auswählen

[DllImport("pbtest.dll")]
public extern static [MarshalAs(UnmanagedType.LPStr)]string PbFunction();

Verfasst: 15.12.2006 00:27
von Kaeru Gaman
ich kenn mich weder mit NET noch mit C# aus...

aber in deinem codeschnippsel sehe ich keinen hinweis darauf,
wie man einer Unicode-Funktion mitteilt,
dass der ankommende string in ANSI codiert ist...

Verfasst: 15.12.2006 17:13
von Spirit
Kaeru Gaman hat geschrieben:ich kenn mich weder mit NET noch mit C# aus...

aber in deinem codeschnippsel sehe ich keinen hinweis darauf,
wie man einer Unicode-Funktion mitteilt,
dass der ankommende string in ANSI codiert ist...
MSDN hat geschrieben:UnmanagedType.LPStr: Eine aus ANSI-Zeichen bestehende, mit NULL beendete Einzelbyte-Zeichenfolge. Sie können diesen Member für den System.String-Datentyp oder den System.Text.StringBuilder-Datentyp verwenden.

Verfasst: 15.12.2006 17:29
von Kaeru Gaman
ahja... interessant...

ist auch alles andere als selbsterklärend, der begriff "UnmanagedType.LPStr"... :mrgreen: