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"...
