Unmanaged DLLs
-
Hi, I have a mostly C++ background and have a small VB.NET problem and was hoping for some advice from you guru's out there in VB land. I am using VS.NET 2002, incase anyone know of a problem with that version. I am trying to access functions in a unmanaged DLL from a managed VB application. I can get this to work fine until I use a DLL function that has a string as a parameter. When I call a function with a string as a parameter, although the DLL receives the string correcly, the return value of all future DLL calls is garbage. I have created a small sample application (DLL and VB) to demonstrate the problem. I have posted the code in this post (sorry about that but figured it would be nessecary). Any help would be awesome? Thanks in Advance, Charles Example follows, in the VB application the first two calls to fnTestNumber are handled fine, but the return value from fnTestString and the last fnTestNumber are random. VB Application:
Imports System.Runtime.InteropServices Module Module1 <DllImport("TestDLL.DLL", _ CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _ Function fnTestNumber(ByVal iTest As Long) As Long End Function <DllImport("TestDLL.DLL", _ CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _ Function fnTestString(<MarshalAs(UnmanagedType.LPStr)> ByVal szTest As String) As Long End Function Sub Main() Dim retcode As Long retcode = fnTestNumber(9876) retcode = fnTestNumber(7654) retcode = fnTestString("DATAFILE1.DAT") retcode = fnTestNumber(1234) End Sub End Module
C++ DLL:__declspec(dllexport) int fnTestNumber(int iTest) { return iTest; } __declspec(dllexport) int fnTestString(const char* szTest) { return 42; }
-
Hi, I have a mostly C++ background and have a small VB.NET problem and was hoping for some advice from you guru's out there in VB land. I am using VS.NET 2002, incase anyone know of a problem with that version. I am trying to access functions in a unmanaged DLL from a managed VB application. I can get this to work fine until I use a DLL function that has a string as a parameter. When I call a function with a string as a parameter, although the DLL receives the string correcly, the return value of all future DLL calls is garbage. I have created a small sample application (DLL and VB) to demonstrate the problem. I have posted the code in this post (sorry about that but figured it would be nessecary). Any help would be awesome? Thanks in Advance, Charles Example follows, in the VB application the first two calls to fnTestNumber are handled fine, but the return value from fnTestString and the last fnTestNumber are random. VB Application:
Imports System.Runtime.InteropServices Module Module1 <DllImport("TestDLL.DLL", _ CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _ Function fnTestNumber(ByVal iTest As Long) As Long End Function <DllImport("TestDLL.DLL", _ CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _ Function fnTestString(<MarshalAs(UnmanagedType.LPStr)> ByVal szTest As String) As Long End Function Sub Main() Dim retcode As Long retcode = fnTestNumber(9876) retcode = fnTestNumber(7654) retcode = fnTestString("DATAFILE1.DAT") retcode = fnTestNumber(1234) End Sub End Module
C++ DLL:__declspec(dllexport) int fnTestNumber(int iTest) { return iTest; } __declspec(dllexport) int fnTestString(const char* szTest) { return 42; }
Hi, I am used to use P/Invoke between managed C# and native C, here are some suggestions: - passing a read-only string from managed to unmanaged works fine, it does not even need MarshalAs(UnmanagedType.LPStr - by default managed strings are Unicode and get marshaled as 16-bit char collections; adding CharSet:=CharSet.Ansi should fix that were appropriate. - I avoid returning a string, since that would mean the unmanaged world needs to create an object that can continue to exist in the managed world; instead: - when needing a string result, I tend to pass a StringBuilder object, with its initial capacity appropriately set, and also pass that capacity; then the unmanaged world can treat it as a char buffer of specified length. - always: your calling conventions must match; since I fail to remember the default, I always make it explicit on both sides. - most things you do wrong in P/Invoke result in an exception, quite often corresponding to an access violation. Hope this helps.
Luc Pattyn [Forum Guidelines] [My Articles]
This month's tips: - before you ask a question here, search CodeProject, then Google; - the quality and detail of your question reflects on the effectiveness of the help you are likely to get; - use PRE tags to preserve formatting when showing multi-line code snippets.
-
Hi, I have a mostly C++ background and have a small VB.NET problem and was hoping for some advice from you guru's out there in VB land. I am using VS.NET 2002, incase anyone know of a problem with that version. I am trying to access functions in a unmanaged DLL from a managed VB application. I can get this to work fine until I use a DLL function that has a string as a parameter. When I call a function with a string as a parameter, although the DLL receives the string correcly, the return value of all future DLL calls is garbage. I have created a small sample application (DLL and VB) to demonstrate the problem. I have posted the code in this post (sorry about that but figured it would be nessecary). Any help would be awesome? Thanks in Advance, Charles Example follows, in the VB application the first two calls to fnTestNumber are handled fine, but the return value from fnTestString and the last fnTestNumber are random. VB Application:
Imports System.Runtime.InteropServices Module Module1 <DllImport("TestDLL.DLL", _ CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _ Function fnTestNumber(ByVal iTest As Long) As Long End Function <DllImport("TestDLL.DLL", _ CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _ Function fnTestString(<MarshalAs(UnmanagedType.LPStr)> ByVal szTest As String) As Long End Function Sub Main() Dim retcode As Long retcode = fnTestNumber(9876) retcode = fnTestNumber(7654) retcode = fnTestString("DATAFILE1.DAT") retcode = fnTestNumber(1234) End Sub End Module
C++ DLL:__declspec(dllexport) int fnTestNumber(int iTest) { return iTest; } __declspec(dllexport) int fnTestString(const char* szTest) { return 42; }
In addition to what Luc said, you're using and returning 32-bit numbers in/from your C++ functions, but your VB.NET declarations are
Long
s. The Long type in VB.NET is a 64-bit signed integer. I think you're actually looking for theInteger
type, which is 32-bit signed.<DllImport("TestDLL.DLL", _
CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _
Function fnTestNumber(ByVal iTest As Integer) As Integer
End Function
<DllImport("TestDLL.DLL", _
CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _
Function fnTestString(ByVal szTest As String) As Integer
End FunctionA guide to posting questions on CodeProject[^]
Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
2006, 2007 -
In addition to what Luc said, you're using and returning 32-bit numbers in/from your C++ functions, but your VB.NET declarations are
Long
s. The Long type in VB.NET is a 64-bit signed integer. I think you're actually looking for theInteger
type, which is 32-bit signed.<DllImport("TestDLL.DLL", _
CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _
Function fnTestNumber(ByVal iTest As Integer) As Integer
End Function
<DllImport("TestDLL.DLL", _
CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _
Function fnTestString(ByVal szTest As String) As Integer
End FunctionA guide to posting questions on CodeProject[^]
Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
2006, 2007Right. I missed that one, although I have made similar mistakes myself. :)
Luc Pattyn [Forum Guidelines] [My Articles]
This month's tips: - before you ask a question here, search CodeProject, then Google; - the quality and detail of your question reflects on the effectiveness of the help you are likely to get; - use PRE tags to preserve formatting when showing multi-line code snippets.
modified on Tuesday, January 15, 2008 1:41:17 PM
-
In addition to what Luc said, you're using and returning 32-bit numbers in/from your C++ functions, but your VB.NET declarations are
Long
s. The Long type in VB.NET is a 64-bit signed integer. I think you're actually looking for theInteger
type, which is 32-bit signed.<DllImport("TestDLL.DLL", _
CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _
Function fnTestNumber(ByVal iTest As Integer) As Integer
End Function
<DllImport("TestDLL.DLL", _
CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _
Function fnTestString(ByVal szTest As String) As Integer
End FunctionA guide to posting questions on CodeProject[^]
Dave Kreskowiak Microsoft MVP Visual Developer - Visual Basic
2006, 2007Ah...... I knew it would be something really annoyingly simple. Thank you both very much for the help. You have no idea the hours of frustration that saved me. Thanks again, Charles