I've run into a problem marshaling data from managed code to unmanaged code
and I can't seem to figure out what's going on. I have a theory, but even
if it's correct, I don't knwo what the solution is.
Here's my situation. I have a stream interface driver in C that takes a
struct passed into the xxx_Write and xxx_Read functions. This struct looks
like this:
struct MyData
{
DWORD a;
DWORD b;
BYTE *pData;
DWORD len;
};
So in C# I created a class that exposes a byte[] operator and internally it
holds a 16-byte array that holds this data. The pData member is where the
problem lies.
In the C# class, when I want to set the data, I use AllocHGlobal (calls
LocalAlloc) to reserve memory and get back an IntPtr, which I stuff into the
internal byte array. The P/Invoke passes the byte array to WriteFile
(through the OpenNETCF StreamInterfaceDriver class).
When I view the object in C#, using the memory viewer in Studio, all is
well. All data in the struct is correct, and if I view the memory at the
address held in pData, it's the right data I wish to pass.
On the driver side, the struct is also just fine, a, b, len and pData are
all identical to what was passed from the managed side. However if I
dereference pData and look at what is at that memory location, it's all
zeros. So it seems the struct marshalled fine, but the memory pointer has
become invalid in some way. Reading the dereferenced data does not cause a
data about though.
My initial theory was that since the driver is running in a separate process
slot (device.exe) it may have a different copy of the local data, and
therefore the LocalAlloced data is not valid in the device.exe context.
There are 2 problems with that theory, however.
1. It works just fine from a C application - only the managed app pukes
2. I modified the driver to use MapPtrToProcess on the pData member passed
in and while that results in non-zero data, it's *not* the data I passed in,
and doing so breaks the C application
So, anyone got any ideas on A) Why do I see this behavior and B) what I can
do to get past it?
I realize that rewriting the driver to not use this ugliness is a good
solution, and I'm in the process of doing that. However customers that
already have devices with the old driver will have to make modifications to
their applications if I make a change. Also, I want to understand what's
going on, not just end-run around it.
I've got code I can share, as well as screen shots showing the memory views,
etc. if anyone is interested.
--
Chris Tacke
Co-founder
OpenNETCF.org
Has OpenNETCF helped you? Consider donating to support us!
http://www.opennetcf.org/donate