views:

466

answers:

4

Hi,

I have some code in VB6 which imports a function from a dll, it uses the byVal and byRef keywords, I want to convert that code into C# 3.5.

  1. Is there going to be a problem with unicode encoding of the strings?

  2. Do I declare the varibles that are "byRef" in vb6 into "ref" varibles in the C# code?

  3. It seams that return value is entered into a string send by the VB6 code as a "byVal" parameter, how does that work, aren't you supposed to send stuff "byRef", if you want to allow the function to edit the string? Is this concept still going to work with my C# code?

I tryed coping the function declaration from VB6, the parameter types are just int's, long's and string. Where there was a "byVal" keyword I just left it empty and replaced "byRef" keywords with the "ref" keyword in C# and the code dosn't work.

The VB6 Code:

Private Declare Function Foo Lib "Foo_Functions.dll" (ByVal a as String, ByVal b
as Long, ByVal c as String, ByVal d as String, ByVal e as String, ByVal f
as String, ByVal g as Long, ByVal h as String, ByVal i as String, ByRef j
as Long, ByRef k as Long) As
Integer

My C# 3.5 Translation:

[Dllimkport("foo_functions.dll")] public static extern int foo(String a, long b,
string c, string d, string e, string f, long g, string h, stringbuilder i,
ref long j, ref long k);

Please help, I'v already spent a whole day on this :p....

In the end I converted the function call to a VB.NET lib, using the automatic project converter (from VB6 to VB.NET 2008), and called it using C# reference.

Thanks.

A: 

Could you please paste your VB6 code for us to see?

Computer Linguist
I'd love to but unfortunately I can't, sorry..., I'm not eligible to show the source.
Haim Bender
You can replace function and parameter names with some random identifiers to show the parameter/return types at least.
Pent Ploompuu
just typed it in.
Haim Bender
A: 

Modifiable byVal strings should work if you replace them with StringBuilder in C#. Another possible solution is to use [MarshalAs(UnmanagedType.VBByRefStr)] ref string i.

I used the "Upgrade Visual Basic 6 code..." tool in Visual Studio and this resulted in the following VB.NET code:

Private Declare Function Foo Lib "Foo_Functions.dll" (ByVal a As String, _
  ByVal b As Integer, ByVal c As String, ByVal d As String, ByVal e As _
  String, ByVal f As String, ByVal g As Integer, ByVal h As String, ByVal i _
  As String, ByRef j As Integer, ByRef k As Integer) As Short

Note that VB6 Long was converted to Integer and VB6 Integer was converted to Short. I then used reflector to see how it should look like in C#:

[DllImport("Foo_Functions.dll", CharSet=CharSet.Ansi, SetLastError=true, ExactSpelling=true)]
private static extern short Foo([MarshalAs(UnmanagedType.VBByRefStr)] ref
  string a, int b, [MarshalAs(UnmanagedType.VBByRefStr)] ref string c,
  [MarshalAs(UnmanagedType.VBByRefStr)] ref string d,
  [MarshalAs(UnmanagedType.VBByRefStr)] ref string e,
  [MarshalAs(UnmanagedType.VBByRefStr)] ref string f, int g,
  [MarshalAs(UnmanagedType.VBByRefStr)] ref string h,
  [MarshalAs(UnmanagedType.VBByRefStr)] ref string i, ref int j, ref int k);

This is the exact translation of the VB6 declaration and should have the same behaviour. If this still doesn't work then perhaps you could describe how exactly it doesn't work (does the unmanaged function ever get called, are the arguments garbage, are the returned values garbage, something else?).

Pent Ploompuu
doesn't help :/
Haim Bender
Try the VBByRefStr variant and also add CharSet=CharSet.Unicode to the DllImport attribute if needed.
Pent Ploompuu
@Pent Ploompuu: been there done that, doesn't help
Haim Bender
I converted the original code VB6 -> VB.NET -> C# and got this declaration, maybe this works?
Pent Ploompuu
+2  A: 

have a look at www.pinvoke.net It shows C# and VB.net examples.

Mark Redman
As I understand, this tool is only for calling dll's connected to the windows operating systems, and not custom ones.
Haim Bender
Yes you are correct. It has various examples of dllImport calls for windows API's etc. The examples may help you convert VB to C#.
Mark Redman
A: 

If a VB6 Declare statement which includes ByVal s As String, that parameter will be marshalled as a pointer to an ANSI string. I would try changing the DLLImport to [DllImport("Foo_Functions.dll", CharSet=CharSet.Ansi)]

For output parameters, you will need to use StringBuilder s and also preinitialise the StringBuilder large enough to hold the output. For input parameters, you can use String s

Do you have a C declaration for the DLL? Mabe in the original vendor's documentation, or the DLL source code? If so, there is a free tool CLRInsideOut that will convert that C declaration to C# or VB.Net PInvoke code. Read more on MSDN here.

Disclaimer: JaredPar should really get any rep points for this answer since he wrote some of the tool.

MarkJ