interop c dll import function returns a structure containing strings

K

kagorami

Q: How do you return a LPSTR from unmanaged code?
A: Use a StringBuilder.

What about this:
public struct CSTRUCT {
string return_value;
}

How do you get a LPSTR from unmanaged code when it is in a STRUCT?

Read on for more detail.....

Hello,

I have been getting up to speed on C# Interop the last few days.

I have a program that works fairly well in C++ but I want to port it to
C# because I am more comfortable with C#.

Here is a sample of the struct I am working with: (the actual structure
is much larger).

<code>
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=2 )]
public struct CSTRUCT
{
public uint prev; /* PREVIOUS */
public uint curr; /* CURRENT record pointers */
public uint next; /* NEXT */
public short list_type;
[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=34 )]
public string input_data;
[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=34 )]
public string return_data;
}
</code>

I pass this to a function defined like so (assume that some fields in
CSTRUCT are for internal use by the API. In this example, input_data is
a string that I need to assign a value to for the work to be done
properly):

<code>
[ DllImport( "oldc.dll", CharSet=CharSet.Ansi )]
public static extern int doWork(int a_number, ref CSTRUCT a_record);
</code>

Then I wait for the dll to raise an event. I need to call another
function to determine if doWork succeeded and what the contents of
a_record.return_data is.

<code>
[ DllImport( "oldc.dll", CharSet=CharSet.Ansi )]
public static extern int workDone(ref EVENT an_event, out CSTRUCT
updated_record);
</code>

Note that the API in oldc.dll maintains an internal copy of a_record.
When workDone is called, you pass in an initialised CSTRUCT variable
and workDone fills in the return_data member. (an_event is a structure
which tells the api which record to return).

My problem is this:
The code compiles (not yet, keep reading)
CLR does not raise an exception (whew! should be okay, right?)
Oops, a_record is not updated by the function call (does anybody sense
trouble?)

If I do a debug trace on the C++ code in my other project, I can see
that the structure contains unintialised data before the function call,
then afterward, return_data is correctly populated.

When I do a similar debug trace in C#, the struct is initialised to
null values (0 for integral types, "" for string types) before the
function call, and is the same after the function call.
If I do not destroy a_record after the call to doWork, and pass that to
workDone, in this case the data also is not changed, eg, input_data is
still populated, but return_value has not changed. Is this the standard
behaviour for .Net? Is there another way to accomplish this?

Things tried: changing updated_record from "out" to "ref" - no change.
Changing "ref CSTRUCT" to "CSTRUCT" (and making CSTRUCT a class instead
of a struct) - no change.
Examining the int return value from workDone - the return value
indicates that the function succeeded.
Changing "out CSTRUCT" to "byte[]" where the byte array is initialised
to the same size as CSTRUCT - after the function call, the byte array
is unchanged, eg all items are 0. (I tried this on the doWork function
and the data was passed in correctly.)

Ideas:
1) Go back to c++ and create a separate application
2) Go back to c++, create a wrapper of some kind (dll) that I call from
C#. C++ gets the returned struct, then passes back the string values
individually to C#.

Thanks,

kagorami
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top