struct record {
char id[32];
char name[64];
char number[16];
char dept[64];
... you get the idea ...
};My searches have brought me to the conclusion that I'm working with something called "unmanaged code", which I gather means the CLR won't be touching my API. I converted the struct to something that I think is equivalent:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct pager_record
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string id;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string number;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string dept;
... you get the idea ...
};
When I try to pass the structure into my API call, I get an "Object Reference not set to an instance of an object" error. This is the code I use to initialize and populate the struct:
private void btnAdd_Click(object sender, System.EventArgs e)
{
StringBuilder error = new StringBuilder(Export.ERROR_BUFFER_SIZE);
Admin.record pr = new Admin.record();pr.id = "123456789";
pr.name = "George Bush";
pr.number = "5555555555";
pr.dept = "Executive";
... you get the picture ...
This is the line that fails:
int Stat = Admin.pagemate_add(pr, error);
And this is the API method itself:
[DllImport(API.dll)]
public static extern int add(record Record, StringBuilder error_buffer);
I know that I'm populating the struct fine; if I change the struct to a managed equivalent (without the [MarshalAs(��) ] code, data makes it into program. It's just that the data that gets in is gibberish. I'm guessing this has something to do with references, since .NET passes data ByVal by default.
So the questions:
1.Is this how I want to rewrite the Struct?
a.Why?
2.What do I need to do to pass the structure into the API call?
a.Why?
Thanks��
-ChrisChris,
Unmanaged simply means that the CLR won't do type-checking and garbage collection for your non .Net library.
What level of indirection does your unmanged method require? This may affect how you can pass the struct into the API. If you need one level of indirection you can pass the struct in using the ref keyword. No indierction, you can use standard byval. Two levels, you are out of luck. See this MSDN article for more information on supported indirection levels.
Also, I think the attribute you need on your struct members is [FieldOffset] vs [MarshallAs].
What you are really dealing with here is called Platform Invoke, or P-Invoke.
Hope this helps.
-kristopher
Kristopher,
Thanks. I'm not sure but I think I require one level of indirection. Here's the original method definition:
extern long int add(struct record *, char *);
Changing to [FieldOffset] and passing the struct byref allows the code to execute again. Interesting results. I call the API through a button.click event. The first time I press the button (or call the API) it tells me the record ID is empty or null, and the insert fails. If I click a second time it will addsomething, but not what I put in the fields. A third call fails the same way the first does, a fourth tries to add (but fails because the record already exists), etc.
-Chris
Interesting. Have you verified that what is being passed to the API is the same as what you entered (i.e. by using the debugger)? Also, check to make sure that your offsets are correct, otherwise its possible you're stepping on other struct members (aka a C union).
-k
0 comments:
Post a Comment