Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / October 2005

Tip: Looking for answers? Try searching our database.

C# passing managed byte array to C++ function in unmanaged code

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
tsnyder@digital-ego.com - 18 Oct 2005 17:02 GMT
Hello All,

I've recently come accross a problem when trying to work with a
unmanaged dll compiled in C++ (Visual Studio 6.0). When calling the dll
from my C# application primitive data works okay for converting PLONG,
INT, BOOL to the right function signature. For example:

C++ Function:
LOGGER_API BOOL APIENTRY ConnectToDevice(void);
LOGGER_API LONG APIENTRY GetDeviceVersion(int iTargetMicro);
LOGGER_API LONG APIENTRY GetDeviceDataSize(void);

C#:
[DllImport("Logger.dll")]
private static extern bool ConnectToDevice();
[DllImport("Logger.dll")]
private static extern int GetDeviceVersion(int TargetMicro);
[DllImport("Logger.dll")]
private static extern int GetDeviceDataSize();

All calls invoke the dll perfectly and I get back the right response.
However, there is one particular method that has a method signature:

C++
BOOL GetDeviceData(LPBYTE HrmInputData, PLONG HrmDataSize, LPBYTE
GPSData, PLONG GPSDataSize);

The api docs for this method/function read: 'on successful upload the
API will copy the uploaded device data into the memory space indicated
by the two addresses being passes to this API as parameters. The size
of the uploaded data will also be placed into the variables whose
addresses have been passed.'

So I went ahead and made this method signature in C# to call the
unmanaged code:

[DllImport ("Logger.dll", SetLastError=true)]
public static extern bool GetDeviceData( [In,Out] byte[] array, ref
System.IntPtr hrmDataSize, [In,Out] byte[] gpsData, ref System.IntPtr
gpsDataSize);

C# Calls To UnManaged:
byte[] hrmData = new byte[deviceDataSize];
byte[] gpsData = new byte[deviceDataSize];
System.IntPtr hrmDataSize = new System.IntPtr(0);
System.IntPtr gpsDataSize = new System.IntPtr(0);
TimexHRMGPS.GetDeviceData(hrmData, ref hrmDataSize,  gpsData, ref
gpsDataSize);

The problem resides here, but its rather confusing. The call works
because I see the dll get executed and a progress bar from the dll
showing the status of the upload displays. On return however, I have
the right data for HRM data Size, and GPS data Size BUT NOT any data in
my byte[] array, its just an empty array. I tried using 'ref byte[]' to
simulate what I suspect it wants (a pointer to memory) and even
'Marshal.AllocCoTaskMem(hrmDataSize)' and locking it.

I am probably missing something retarded as I haven't used Interop
before today, but given my success with other functions I am not quite
sure what the method signature should read?

Sorry for the long winded explanation, I do hope you are able to help
as I have hit a wall.

Terrance A. Snyder
tsnyder@digital-ego.com - 18 Oct 2005 17:54 GMT
Well I seem to have something now:

Changed Declaration To:
//
----------------------------------------------------------------------------
[DllImport ("Logger.dll", SetLastError=true)]
public static extern bool GetDeviceData( ref IntPtr array, ref
System.IntPtr hrmDataSize, ref System.IntPtr gpsData, ref System.IntPtr
gpsDataSize);
//
----------------------------------------------------------------------------

IntPtrs instead of byte[] or ref byte[]. And changed the calls to:
//
----------------------------------------------------------------------------
IntPtr unmanagedArray = Marshal.AllocCoTaskMem(deviceDataSize);
byte[] hrmData = new byte[deviceDataSize];

byte[] gpsData = new byte[deviceDataSize];
IntPtr gpsArray = Marshal.AllocCoTaskMem(deviceDataSize);

System.IntPtr hrmDataSize = new System.IntPtr(0);
System.IntPtr gpsDataSize = new System.IntPtr(0);

TimeGPSHRM.GetDeviceData(ref unmanagedArray, ref hrmDataSize,  ref
gpsArray, ref gpsDataSize);

Marshal.Copy(unmanagedArray, hrmData, 0, deviceDataSize);
Marshal.Copy(gpsArray, gpsData, 0, deviceDataSize);
//
----------------------------------------------------------------------------

While now it looks like I have data, it doesn't seem to be complete, it
looks truncated. One step at a time I supposed. Any help would be
appreciated.
tsnyder@digital-ego.com - 20 Oct 2005 16:37 GMT
Well seeing as there is very little activity on this, I'll help those
who might come across a similar problem. The final working code I have
for consuming LPBYTE from managed C# is the following:

public static void Main(string[] args) {
...
IntPtr hrmArray = Marshal.AllocCoTaskMem(deviceDataSize);
IntPtr gpsArray = Marshal.AllocCoTaskMem(deviceDataSize);

IntPtr hrmDataSize = new IntPtr(0);
IntPtr gpsDataSize = new IntPtr(0);

timexHRM.GetDeviceData(hrmArray, ref hrmDataSize,  gpsArray, ref
gpsDataSize);

byte[] hrmBytes = new byte[hrmDataSize.ToInt32()];
byte[] gpsBytes = new byte[gpsDataSize.ToInt32()];

Marshal.Copy(hrmArray, hrmBytes, 0, hrmDataSize.ToInt32());
Marshal.Copy(gpsArray, gpsBytes, 0, gpsDataSize.ToInt32());
....
}

class timexHRM {
...
[DllImport ("Logger.dll", SetLastError=true)]
public static extern unsafe bool GetDeviceData( [In,Out] System.IntPtr
hrmArray, ref System.IntPtr hrmDataSize, [In,Out] System.IntPtr
gpsData, ref System.IntPtr gpsDataSize);
...
}
Dragon - 20 Oct 2005 17:23 GMT
Hi Terrance,

Just an idea:
If a parameter is of type LPBYTE why not declare it as ~ ref Byte
HrfInputData ~ (Sorry for any syntax errors - I virtually don't know C#)
and pass first element of an array to function?

If this still doesn't work, then correct your second attempt, i.e.
remove ref in ~ ref IntPtr array ~. IntPtr is already a pointer so it
doesn't make much sense to pass it ByRef.

BTW,

- Why do you use IntPtr for hrmDataSize & gpsDataSize params? PLONG is
long* so wouldn't it be more correct (and convenient) to use Int32 for
this?
- Why do you use Marshal.AllocCoTaskMem()? Your routine seems to do
nothing with COM, so you should probably use Marshal.AllocHGlobal().

Hope this helps,
Roman

> Well I seem to have something now:
>
[quoted text clipped - 31 lines]
> looks truncated. One step at a time I supposed. Any help would be
> appreciated.
tsnyder@digital-ego.com - 21 Oct 2005 14:24 GMT
Like I said before, I've never used Interop before but I will try your
suggestions and give you the results. Thank you very much for your
insight.
tsnyder@digital-ego.com - 25 Oct 2005 16:39 GMT
doesn't work, the returned values are now 0 for everything. kind of
made it worse :)
tsnyder@digital-ego.com - 26 Oct 2005 16:13 GMT
figured out the solution for those that want access:

IntPtr dataSize = Marshal.AllocHGlobal(4); // PLONG
IntPtr dataBytes = Marshal.AllocHGlobal([deviceSize]);  // LPBYTE
device.GetEEPROMData(dataBytes, dataSize);  // call the unmanaged
function

// -- total size reported from the function
int rDataSize = Marshal.ReadInt32(dataSize); // read from pointer
Marshal.FreeHGlobal(dataSize); // free pointer

// -- get data downloaded from device
byte[] dataDump = new byte[rDataSize];
// read through entire pointer byte by byte and put into managed array
for (int pos=0; pos < rDataSize ; pos++) {
    dataDump[pos] = Marshal.ReadByte(dataBytes, pos);
}
Marshal.FreeHGlobal(dataBytes);  // free pointer
....
[DllImport("Logger.dll")]
public static extern bool GetEEPROMData(IntPtr data, IntPtr dataSize);
....

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.