Re: Structure Marshalling Question

Tech-Archive recommends: Speed Up your PC by fixing your registry

From: SB (stormfire1_at_yahoo.com)
Date: 02/27/05


Date: Sat, 26 Feb 2005 22:02:51 -0500

Have you looked into Marshal::PtrToStringAnsi? I tested the code below and
it worked fine for me. I didn't see a need to create a managed
structure...so I just used the unmanaged one you posted:
    typedef struct tag_KVFilterOutput
    {
        BYTE *pcText;
        int cbText;
    }KVFilterOutput;
Here is the code in the managed C++ app:
    private: System::Void button1_Click(System::Object^ sender,
System::EventArgs^ e)
    {
        KVFilterOutput kvf;
        ZeroMemory(&kvf, sizeof(KVFilterOutput)); // just a habit of mine
        kvf.cbText = 256;
        kvf.pcText = (BYTE *) calloc(kvf.cbText, 1);
        if (kvf.pcText != NULL )
        {
            TestFunc(&kvf); // call the dll function
            IntPtr^ p = gcnew IntPtr(kvf.pcText);
            System::String^ s =
System::Runtime::InteropServices::Marshal::PtrToStringAnsi(*p, kvf.cbText);
            free(kvf.pcText);
        }
    }

Note that the above is .NET 2.0b code...so the syntax for you will be
slightly different.

Oh...and the DLL code I used to simulate your unmanaged code was something
like:
extern "C" __declspec(dllexport) void TestFunc(KVFilterOutput *data)
{
    BYTE buffer[] = {65, 66, 67}; // "ABC" in ANSI
    memcpy(data->pcText, buffer, 4);
}

Note that I also set the calling convention in the dll and the application
to _stdcall.

Of course, someone else might point out a better way to do this since I'm
by no means an expert in this area (or in managed C++...since I normally use
C#).

Also, I wondered why you are writing a managed C++ wrapper and using it from
C#...when you can just do it all in C#?

HTH,
-sb

"Thomas Delany" <eshuttle@community.nospam> wrote in message
news:pan.2005.02.26.17.02.04.125000@community.nospam...
> On Fri, 25 Feb 2005 17:34:12 -0500, SB wrote:
>
>> I've been learning about Marshalling structs and handling callbacks all
>> week...so maybe I can help. What do exactly you plan on doing with
>> pcText
>> array? Can you elaborate on what the function does and how you would
>> like
>> to use the results?
>>
>> -sb
>>
>> "Thomas Delany" <eshuttle@community.nospam> wrote in message
>> news:pan.2005.02.25.20.07.55.625000@community.nospam...
>>> Hi,
>>>
>>> I am trying to write a C++ wrapper class using MC++ that wraps calls to
>>> a
>>> dll that exposes a C API.
>>>
>>> I have found several examples of marshalling struct data between managed
>>> and unmanaged code where you have to pass a struct full of data to an
>>> unmanaged code function. I have a slightly different situation that I
>>> am
>>> dealing with, however. I have a C function that requires a pointer to
>>> an
>>> empty struct, which it subsequently fills up with data upon completion.
>>>
>>> Here is the unmanaged struct declaration:
>>>
>>> typedef struct tag_KVFilterOutput
>>> {
>>> BYTE *pcText;
>>> int cbText;
>>> }
>>> KVFilterOutput;
>>>
>>> The unmanaged code sets pcText to the address of a BYTE array containing
>>> the results from the call, and cbText contains the size of the array.
>>> The
>>> caller is responsible for freeing the array.
>>>
>>> I am assuming I will need to create a managed equivalent similar to:
>>>
>>> [StructLayout(LayoutKind::Sequential)]
>>> typedef __value public struct TAG_FilterOutput
>>> {
>>> IntPtr pText;
>>> System::Int32 cbSize;
>>> } FILTER_OUTPUT;
>>>
>>> I believe I know how to code things to pass the empty struct to the
>>> unmanaged function. My question is: how do I marshal the results
>>> pointed
>>> to by pText to something useful in the managed code?
>>>
>>> Thanks in advance.
>>>
>>> Tom Delany
>>>
>
> The API is one we licensed that supports multiple platforms (Windows,
> Linux, Unix, etc.) which is the reason for their implementing the bare
> bones C API (it was the lowest common denominator).
>
> The BYTE array returned by this API function is actually text. I believe
> they declared it as a pointer to a BYTE array because it could potentially
> be in any of several languages, including multi-byte character sets, and
> they felt that BYTE was the best choice due to their LCD approach.
>
> I would be perfectly happy to get this as a String, StringBuilder,
> whatever. I just need to get the results contained in the array into
> something usable from .NET (I intend to call the C++ wrapper from the main
> application, which we are writing in C#).
>
> Thanks,
>
> Tom Delany
>


Quantcast