marshal binary data file, written with C++, with my C# code

V

Vertilka

I need to read binary data file written by C++ program, using my C#
application.
How do i marshal the bytes i read with my C# code to .NET types.

The data is numbers (integers float doubles etc..) and strings.

I looked at the Marshal class but did not know how to use it with file.
Please add few code lines.

Thanks alot
 
B

bb

here is something i use for reading a string stored by C++ as an IntPtr


public class MarshalUtil
{
IntPtr m_objData = IntPtr.Zero;
int m_nPosition = 0;

public MarshalUtil(IntPtr objData)
{
m_objData = objData;
}

public string ReadString()
{
ArrayList objBytes = new ArrayList();
byte byt;
string strData = "";

while((byt = Marshal.ReadByte(m_objData, m_nPosition)) != 0)
{
strData += (char) byt;
m_nPosition += 2;
}

m_nPosition += 2;

return strData;
}

public bool MoreData
{
get
{
return (Marshal.ReadByte(m_objData, m_nPosition) != 0);
}
}
}
 
J

Jon Skeet [C# MVP]

bb said:
here is something i use for reading a string stored by C++ as an IntPtr

public class MarshalUtil
{
IntPtr m_objData = IntPtr.Zero;
int m_nPosition = 0;

public MarshalUtil(IntPtr objData)
{
m_objData = objData;
}

public string ReadString()
{
ArrayList objBytes = new ArrayList();
byte byt;
string strData = "";

while((byt = Marshal.ReadByte(m_objData, m_nPosition)) != 0)
{
strData += (char) byt;
m_nPosition += 2;
}

m_nPosition += 2;

return strData;
}

That will be hideously inefficient with large strings - you should at
the very least be using a StringBuilder. You also seem to be ignoring
every other byte - I don't believe the above will work with strings
containing Unicode characters above U+00FF. Instead, you should read
*two* bytes, and shift one left by 8 bits.

Jon
 
J

Jon Skeet [C# MVP]

Vertilka said:
And what about integers float and doubles, how to marshal them ?

Have a look at Marshal.ReadInt32 (etc) for integers. For doubles you
should use Marshal.ReadInt64 and then call
BitConverter.Int64BitsToDouble. I'm not guaranteeing it will work, but
it's certainly worth a try.

Unfortunately there's no direct equivalent for that process for floats
(at least not in 1.1 - I haven't checked 2.0) - instead you'd probably
want to use BitConverter.ToSingle(byte[]) having read 4 bytes into a
byte array first.

Jon
 
N

Nicholas Paldino [.NET/C# MVP]

You can always use the overload of the static Copy method which takes an
IntPtr and populates an array of doubles (or floats, there is an overload
for that as well). If you want one double/float, you can just declare an
array of one element (a little overkill, I know, but less code, right?).

Also, if the OP is willing to use unsafe code, then it could be much
easier (just cast to the appropriate pointer type and dereference).


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Jon Skeet said:
Vertilka said:
And what about integers float and doubles, how to marshal them ?

Have a look at Marshal.ReadInt32 (etc) for integers. For doubles you
should use Marshal.ReadInt64 and then call
BitConverter.Int64BitsToDouble. I'm not guaranteeing it will work, but
it's certainly worth a try.

Unfortunately there's no direct equivalent for that process for floats
(at least not in 1.1 - I haven't checked 2.0) - instead you'd probably
want to use BitConverter.ToSingle(byte[]) having read 4 bytes into a
byte array first.

Jon
 
V

Vertilka

Jon, Nicholas,
Thanks for your answers.

Can you both post code snippets.
Lets say that i have 8 bytes that i want to get a bouble from them.

Thanks.
 
B

bb

yes its just used to get a known small length string from my device
driver

although im not sure thats an excuse for hideous code ;-)
 
V

Vertilka

Jon,

I tried you advise.
How do i convert array of bytes to IntPtr, to use with
Marshal.ReadInt32 ?

=== Code snippet ===

FileStream fs = new FileStream(@"C:\myfile.bin", FileMode.Open);

byte[] buffer = new byte[1024];
fs.Read(buffer, 0, 8);

Marshal.ReadInt64( ???? );

??? BitConverter.Int64BitsToDouble();

=== Code snippet ===
 
W

Willy Denoyette [MVP]

| Jon,
|
| I tried you advise.
| How do i convert array of bytes to IntPtr, to use with
| Marshal.ReadInt32 ?
|
| === Code snippet ===
|
| FileStream fs = new FileStream(@"C:\myfile.bin", FileMode.Open);
|
| byte[] buffer = new byte[1024];
| fs.Read(buffer, 0, 8);
|
| Marshal.ReadInt64( ???? );
|
| ??? BitConverter.Int64BitsToDouble();
|
| === Code snippet ===
|

Use the BinaryReader and wrap your FileStream, there is no need to call
Marshal methods, you simply need to call the right read method. Just beware
of the char encoding when reading cjar array's and strings.


string s1;
byte b1;
int i1;
float f1;
double d1;
char[] ca;

....
using(BinaryReader binReader =
new BinaryReader(File.Open(@".\myfile.bin", FileMode.Open)))
{
try {
while (true)
{
s1 = binReader.ReadString();
b1 = binReader.ReadByte();
i1 = binReader.ReadInt32();
f1 = binReader.ReadSingle();
d1 = binReader.ReadDouble();
ca = binReader.ReadChars(5);
Console.WriteLine(f1);
}
}
catch(EndOfStreamException ex)
{
// end of file reached
}
}

Willy.
 
V

Vertilka

Willy,

I don't know if you notice but the binary data file was written by C++.
I am not sure that type bits written into the binary file, using C++,
is the same as type bits writen using .NET.

Vertilka
 
W

Willy Denoyette [MVP]

| Willy,
|
| I don't know if you notice but the binary data file was written by C++.
| I am not sure that type bits written into the binary file, using C++,
| is the same as type bits writen using .NET.
|
| Vertilka
|

This is the first thing you should try to find out, right? You can't read a
file if you don't know the data types used in the file.
You said it's a binary data file, where is the data file written? On what
system (Windows, Unix, mainframe). Things to look for are endianess, char
encoding and eventual padding. If the file is written on Windows system,
then you are almost certain that the binary and floating point types are
exactly the same, more problematic are the char arrays and strings (which
are basically the same as arrays of chars once serialized), here you have to
know the encoding used so that you know how to read and to decode them.

Willy.
 
J

Jon Skeet [C# MVP]

Vertilka said:
Jon, Nicholas,
Thanks for your answers.

Can you both post code snippets.
Lets say that i have 8 bytes that i want to get a bouble from them.

double d = BitConverter.Int64BitsToDouble(Marshall.ReadInt64(...));

Of course, that assumes it's in the right format. Worth trying to see.
 
V

Vertilka

again, friends...

i have a byte array with data.
i know for example that the first 8 bytes are double.

now.
with this line:
double d = BitConverter.Int64BitsToDouble(Marshall.ReadInt64(...));
i need to give intptr to ReadInt64.
how to convert byte array to intptr

thanks.
 
J

Jon Skeet [C# MVP]

Vertilka said:
again, friends...

i have a byte array with data.
i know for example that the first 8 bytes are double.

In that case I'm not sure where the Marshal class comes in at all.
That's what's been confusing us, I suspect.
now.
with this line:
double d = BitConverter.Int64BitsToDouble(Marshall.ReadInt64(...));
i need to give intptr to ReadInt64.
how to convert byte array to intptr

Use BitConverter.ToDouble then.
 

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