Hi, I'm just getting started with Interop, and I would appreciate any help
you might give me on this question (and others upcoming, I'm sure).
I have been assigned a project which requires me to interact with a regular
non-COM DLL. I don't have any definitions for the library functions, but I
have detailed VB examples of how to work with the DLL.
The Visual Basic examples show the following:
Type BVLogonRecord
Directory As String * 256
UserID As String * 12
Password As String * 8
LogonDate As String * 8
End Type
Declare Function BVLogonWithDir Lib "bvapi.dll" (LogonRecord As
BVLogonRecord) As Integer
VB function:
Dim LogonRecord As BVLogonRecord
LogonRecord.Directory = "C:\DBDIR"
LogonRecord.UserID = "USER"
LogonRecord.Password = "PASSWORD"
LogonRecord.LogonDate = "20041117"
result = BVLogonWithDir(LogonRecord)
So, I tried this in C#:
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
public struct BVLogonRecord
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String Directory;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)]
public String UserID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)]
public String Password;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)]
public String LogonDate;
}
[DllImport(@"C:\BV\bvapi.dll", CharSet=CharSet.Ansi)]
public static extern int BVLogonWithDir
([MarshalAs(UnmanagedType.Struct)]BVLogonRecord LogonRecord);
public void Logon()
{
String dir = @"C:\DBDIR".PadRight(256,' ');
String usr = "USER".PadRight(12,' ');
String pwd = "PASSWORD".PadRight(8,' ');
String dt = "20041117".PadRight(8,' ');
BVLogonRecord lr = new BVLogonRecord(dir,usr,pwd,dt);
int result = BVTest.BVLogonWithDir(lr);
}
So I have been able to come up with three results:
1) if I append all the strings together and store them in Directory, then
the function works. (regardless of what's stored in the other variables)
2) when I use UnmanagedType.ByValTStr I get "Object reference not set to
an instance of an object." on the call to the BVTest.BVLogonWithDir(lr). As
soon as I comment out the [MarshalAs...] on the struct properties, i don't
get the error any more, but the function still doesn't work.
3) everything else I do gives me bad parameter errors, missing paramters,
etc.
Sorry for the long post, but I'm hoping that if someone can help me figure
out where I'm going wrong. Plus any website references to help me convert
VB examples to working C# functions/call woud be invaluable.
Thanks very, very, very much in advance for any help.
Sincerely,
Trevor Braun
Lau Lei Cheong - 25 Nov 2004 08:35 GMT
try this to see if it works:
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
public class BVLogonRecord
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String Directory;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)]
public String UserID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)]
public String Password;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)]
public String LogonDate;
public BVLogonRecord()
{
}
}
[DllImport(@"C:\BV\bvapi.dll", CharSet=CharSet.Ansi)]
public static extern int BVLogonWithDir
(ref BVLogonRecord LogonRecord);
public void Logon()
{
BVLogonRecord lr = new BVLogonRecord();
lr.dir = @"C:\DBDIR".PadRight(256,' ');
lr.usr = "USER".PadRight(12,' ');
lr.pwd = "PASSWORD".PadRight(8,' ');
lr.dt = "20041117".PadRight(8,' ');
int result = BVTest.BVLogonWithDir(ref lr);
}
Btw, as a win32 application, use Unicode whenever possible.
> Hi, I'm just getting started with Interop, and I would appreciate any help
> you might give me on this question (and others upcoming, I'm sure).
[quoted text clipped - 71 lines]
> Sincerely,
> Trevor Braun
Trevor Braun - 26 Nov 2004 01:16 GMT
Thanks for the response.
It is the ref that fixed the problem. Question though, if I use unicode,
won't that cause "old" DLL to have problems? I've used ANSI and gotten it
working to some degree. Won't it cause problems if I send a Unicode string?
Trevor
> try this to see if it works:
>
[quoted text clipped - 116 lines]
>> Sincerely,
>> Trevor Braun
Lau Lei Cheong - 26 Nov 2004 02:04 GMT
Actually I prefer to set CharSet to CharSet.Auto and let Windows decide
which method to use(A or W).
If it's Win9X/ME, A method will be chosen and if it's WinXp/2k/2003 it'll
use Unicode. This will be most flexible.
Don't worry about conversion as ANSI to Unicode of Low ASCII (value >=
127)involves inserting \0 bytes between characters only and I think the
Marshal class will handle it automatically.
> Thanks for the response.
>
[quoted text clipped - 124 lines]
> >> Sincerely,
> >> Trevor Braun
Trevor Braun - 26 Nov 2004 03:08 GMT
This really hasn't fixed the problem for me.
It got rid of the "object ... reference" error, but still getting invalid
parameter errors.
Thanks,
Trevor
> try this to see if it works:
>
[quoted text clipped - 116 lines]
>> Sincerely,
>> Trevor Braun
Lau Lei Cheong - 26 Nov 2004 03:45 GMT
Perhaps you should use Text.StringBuilder instead of String.PadRight()
> This really hasn't fixed the problem for me.
>
[quoted text clipped - 124 lines]
> >> Sincerely,
> >> Trevor Braun
Trevor Braun - 26 Nov 2004 04:01 GMT
Tried StringBuilder to solve the problem. Here's where I am:
If I append the four parameters into a single string (using stringbuilder or
padright), and stick the whole string into the Directory field and then send
the struct to the function, it works using ANSI.
If I use StringBuilder, i have to .ToString() to put it into the struct
anyway, so I end up with the same thing as .PadRight. But I tried
StringBuilder as you suggested. It didn't help.
I have gotten to the point where the function is only telling me that the
last parameter is invalid, leading me to believe there is something wrong
with the way the struct is being sent to the function.
Thanks for all your help so far, Lau Lei.
Trevor
> Perhaps you should use Text.StringBuilder instead of String.PadRight()
>
[quoted text clipped - 130 lines]
>> >> Sincerely,
>> >> Trevor Braun
Lau Lei Cheong - 26 Nov 2004 04:29 GMT
Since I do not have your library, and I cannot see other possible errors in
your code, I think I cannot help you further.
However, I'll suggest you to use:
int lrsize = System.Runtime.InteropServices.Marshal.SizeOf(lr);
To see if your assumption on struct is correct. You may also found
System.Runtime.InteropServices.Marshal.StructureToPtr() useful.
> Tried StringBuilder to solve the problem. Here's where I am:
> If I append the four parameters into a single string (using stringbuilder or
[quoted text clipped - 146 lines]
> >> >> Sincerely,
> >> >> Trevor Braun
Lau Lei Cheong - 25 Nov 2004 09:12 GMT
One more note:
usually specify the size if string in struct is not necessary. You can
employ System.Text.StringBuilder to do that.
e.g.: lr.dir = new StringBuilder("C:\DBDIR", 256);
> Hi, I'm just getting started with Interop, and I would appreciate any help
> you might give me on this question (and others upcoming, I'm sure).
[quoted text clipped - 71 lines]
> Sincerely,
> Trevor Braun