I have a chunk of binary data which contains structures with offsets and then strings;
in C++ it is easy:
struct foo
{
int offset;
char * s;
}
void * data;
... data is read and set
foo * header = (foo*) data;
header->s = (int)header-> + (int)data;
int len = strlen(header->s);
char* ns = new char[len+1];
strcpy(ns,header->s);
simple enough...
in C# how would you do this?
The biggest problem is that I don't know the length of the string. It is null terminated.
I have the data in a byte[] and an IntPtr to the memory but I need a POINTER to that data a a string (char *) something that I can get the length of the string.
C# is a high level language, and working with pointers is simply unnatural for this language.
To convert the data from byte array to a string, you can use the BitConverter class:
BitConverter.ToInt32(byte_array, start index);
To convert it to a string, you can use the StringBuilder class:
StringBuilder str = new StringBuilder();
// i=starting index of text
for (int i = 3; i<byte_array.Length; i++)
str.Append(byte_array[i];
return str.ToString();
If there is more data after the string, you can put the stopping condition for the loop byte_array[i]!=0, and when it stops, byte_array[i] will be the string terminator. Save the value of i, and you can get the data after it.
Another method of doing this is to use the ASCIIEncoding.ASCII.GetString() method:
ASCIIEncoding.ASCII.GetString(byte_array, start_index, bytes_count);
Related
When I receive data from unmanaged code written in C (WinAPI) it asks to reserve a number of bytes and pass the handle (pointer) to the string.
Using Marshal.AllocHGlobal(150) didit.
In return, I received the number of chars, terminated by '/0' - C style.
When I build string from this char array using new string(charBuff) it doesn't cut the string at the '/0' point.
Well, I could use Substring + IndexOf, but is there any elegant way to cut it using some special existing method?
Ok, I found it after wakening up.
It's
Marshal.PtrToStringUni(IntPtr)
string MyStringFromWinAPI()
{
string result;
IntPtr strPtr = Marshal.AllocHGlobal(500);
// here would be any API that gets reserved buffer to rerturn string value
SendMessage(camHwnd, WM_CAP_DRIVER_GET_NAME_UNICODE, 500, strPtr);
// now you could follow 2 ways
// 1-st one is long and boring
char[] charBuff = new char[500];
Marshal.Copy(strPtr, charBuff, 0, 500);
Marshal.FreeHGlobal((IntPtr)strPtr);
result = new string(charBuff);
result = result.Substring(0, result.IndexOf('\0'));
return result;
// or more elegant way
result = Marshal.PtrToStringUni(strPtr);
Marshal.FreeHGlobal((IntPtr)strPtr);
return result;
}
I have a structure which I want to send to a TCP client throught TCP protocol so I want to assign or copy this struct data to byte array:
struct StartReadXML
{
public int CmdID;//3
public char[] CmdName;//ReadXML
public char[] Description;//Other data
};
here am assigning data to struct data members as below :
StartReadXML startXML=new StartReadXML();
startXML.CmdID = 3;
startXML.CmdName = "sreedhar".ToCharArray();
startXML.Description = "Kumar".ToCharArray();
Now, I want it to be assigned to a byte array. Which am doing using marshalling as below:
int sizestartXML = Marshal.SizeOf(startXML);//Get size of struct data
byte[] startXML_buf = new byte[sizestartXML];//byte array & its size
IntPtr ptr = Marshal.AllocHGlobal(sizestartXML);//pointer to byte array
Marshal.StructureToPtr(startXML, ptr, true);
Marshal.Copy(ptr, startXML_buf, 0, sizestartXML);
Marshal.FreeHGlobal(ptr);
//Sending struct data packet
stm.Write(startXML_buf, 0, startXML_buf.Length);//Modified
But, it fails at Structuretoptr conversion method. Please help in transferring the struct data as bytes for which am using above steps.
Thanks in advance Smile | :) !!
You cannot call StructureToPtr on arrays of variable size.
What this boils down to is that unless you know the size of CmdName and declare it - if it would be for example, 20 chars in size, like so:
public fixed char[] CmdName[20];
You will be greeted with an exception from the Marshal saying that your structure is either non-blittable or no meaningful size can be obtained.
This is a requirement the CLR imposes, and you can not work around.
An alternative method would be to use the Convert class or a serializer to convert the members of your struct manually, but unless you know the size of those arrays up front, you won't be able to use StructureToPtr - the same goes for the string type, as I'm assuming that's what your char array will contain.
Consider using a MemoryStream and writing values to the stream, and sending the contents of the stream using stream.ToArray() instead.
Considering that you can't simply convert to binary a struct, use for example:
class StartReadXML
{
public int CmdID;//3
public string CmdName;//ReadXML
public string Description;//Other data
}
Then:
var srx = new StartReadXML();
srx.CmdID = 3;
srx.CmdName = "sreedhar";
srx.Description = "Kumar";
// Example of how to Write to byte[] buffer
byte[] buffer;
using (var ms = new MemoryStream())
{
using (var bw = new BinaryWriter(ms, Encoding.UTF8))
{
bw.Write(srx.CmdID);
bw.Write(srx.CmdName);
bw.Write(srx.Description);
}
buffer = ms.ToArray();
}
// Example of how to Read from byte[] buffer
var srx2 = new StartReadXML();
using (var ms = new MemoryStream(buffer))
{
using (var br = new BinaryReader(ms, Encoding.UTF8))
{
srx2.CmdID = br.ReadInt32();
srx2.CmdName = br.ReadString();
srx2.Description = br.ReadString();
}
}
Note that here I'm working with a "variable length" packet: the length of CmdName and Description aren't fixed (and BinaryWriter/BinaryReader handle this by prepending the length of the string).
The opposite is when you have a packet of fixed length, with fixed-length strings. That requires a totally different handling.
i want to convert string to Byte[] in C# and with the help of previous topics i use this code :
string s = "0a";
System.Text.ASCIIEncoding encode = new System.Text.ASCIIEncoding();
byte[] b = encode.GetBytes(s);
Console.WriteLine(b);
but when i run this code it only prints : " System.byte[]"
I think I may have finally deciphered your question. Are you trying to get the hex digits of your string into an array?
I'm assuming that you want to take 2-digit hex values from a string and convert each lot into bytes. If not, I'm as lost as everyone else. Please note that I have not included any error checking!
byte[] data = new byte[s.Length/2];
for(int i = 0; i < s.Length/2; ++i)
{
byte val = byte.Parse(s.Substring(i*2,2), System.Globalization.NumberStyles.HexNumber);
data[i] = val;
}
foreach(byte bv in data)
{
Console.WriteLine(bv.ToString("X"));
}
If you want do this Console.WriteLine(b) it will prints the type of b which is System.Byte[].
In order to print the string stored in byte[] b, just make use of System.Text.ASCIIEncoding.GetString(byte[] b);
so in your case, encode.GetString(b); will get your string.
You can use BitConverter class Check: http://msdn.microsoft.com/en-us/library/3a733s97(v=vs.100).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
System.Text.ASCIIEncoding encode = new System.Text.ASCIIEncoding();
byte[] b = encode.GetBytes(s);
Console.WriteLine(BitConverter.ToString(b));
Your code already does the trick of converting string to byte, if your query is to print individual byte value, why not use a loop to print the value in byte array:
foreach (byte bb in b)
{
Console.Write(Convert.ToInt32(bb));
}
That's because it's returning the type of the object that you are typing. If you want to print the content of the array, try this:
Arrays.toString(byteArray)
I need some help with the following. I've got a c++ API (no access to source) and I'm struggling with the methods returning char* attributes, or returned structures containing char* attributes. According to the API's documentation the return value is as follows:
Return Values
If the function succeeds, the return value is a pointer to a series of null-terminated strings, one for each project on the host system, ending with a second null character. The following example shows the buffer contents with <null> representing the terminating null character:
project1<null>project2<null>project3<null><null>
If the function fails, the return value is NULL
The problem I'm having is that the returned pointer in C# only contains the first value... project1 in this case. How can I get the full list to be able to loop through them on the managed side?
Here's the c# code:
[DllImport("vmdsapi.dll", EntryPoint = "DSGetProjectList", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr DSGetProjectList();
Calling method:
IntPtr ptrProjectList = DSAPI.DSGetProjectList();
string strProjectList = Marshal.PtrToStringAnsi(ptrProjectList).ToString();
strProjectList only contains the first item.
Here's the info from the API's header file...
DllImport char *DSGetProjectList dsproto((void));
Here's some sample code from a c++ console app which I've used for testing purposes...
char *a;
a = DSGetProjectList( );
while( *a ) {
printf("a=%s\n", a);
a += 1 + strlen(a);
}
Each iteration correctly displays every project in the list.
The problem is that when converting the C++ char* to a C# string using Marshal.PtrToStringAnsi, it stops at the first null character.
You shouldn't convert directly the char* to a string.
You could copy the char* represented by an IntPtr to a byte[] using Marshal.Copy and then extract as many string as necessary (see Matthew Watson's answer for extracting strings from a managed array), but you'll need to get the multi-string size first.
As leppie suggest you can also extract the first string using Marshal.PtrToStringAnsi then increment the pointer by this string size and extract the next string and so on. You stops when is extracts an empty string (from the last NULL character).
Something like :
IntPtr ptrProjectList = DSAPI.DSGetProjectList();
List<string> data;
string buffer;
do {
buffer = Marshal.PtrToStringAnsi(ptrProjectList);
ptrProjectList += buffer.size() + 1;
data.Add(buffer);
}while(buffer.size() > 0)
This kind of string is called a Multi-String, and it's quite common in the Windows API.
Marshaling them is fiddly. What you have to do is marshal it as a char[] array, rather than a string, and then convert the char[] array to a set of strings.
See here for an example solution. I've copied the relevant code into this answer, but it is copied from the link I gave:
static List<string> MultiStringToList(char[] multistring)
{
var stringList = new List<string>();
int i = 0;
while (i < multistring.Length)
{
int j = i;
if (multistring[j++] == '\0')
break;
while (j < multistring.Length)
{
if (multistring[j++] == '\0')
{
stringList.Add(new string(multistring, i, j - i - 1));
i = j;
break;
}
}
}
return stringList;
}
My variable holds some text but is currently being stored as an int (the class used reads the bytes at a memory address and converts to int. Variable.ToString just displays the decimal representation, but doesn't encode it to readable text, or in other words, I would now like to convert the data from int to string with ascii encoding or something.
Here is a demo (based on our Q+A above).
Note: Settings a string with the null terminator as a test, then encoding it into ASCII bytes, then using unsafe (you will need to allow that in Build Option in project properties), itearte through each byte and convert it until 0x0 is reached.
private void button1_Click(object sender, EventArgs e)
{
var ok = "OK" + (char)0;
var ascii = Encoding.ASCII;
var bin = ascii.GetBytes( ok );
var sb = new StringBuilder();
unsafe
{
fixed (byte* p = bin)
{
byte b = 1;
var i = 0;
while (b != 0)
{
b = p[i];
if (b != 0) sb.Append( ascii.GetString( new[] {b} ) );
i++;
}
}
}
Console.WriteLine(sb);
}
Note the FIXED statement, this is required managed strings/arrayts etc are not guaranteed to be statically placed in memory - this ensures it during that section.
assuming an int variable
int x=10;
you can convert this into string as
string strX = x.ToString();
Try this
string s = "9quali52ty3";
byte[] ASCIIValues = Encoding.ASCII.GetBytes(s);
foreach(byte b in ASCIIValues) {
Console.WriteLine(b);
}
Int32.ToString() has an overload that takes a format string. Take a look at the available format strings and use one of those.
Judging by your previous question, the int you have is (probably) a pointer to the string. Depending on whether the data at the pointer is chars or bytes, do one of these to get your string:
var s = new string((char*)myInt);
var s = new string((sbyte*)myInt);
OK. If you variable is a pointer, then Tim is pointing you in the right direction (assuming it is an address and not an offset from an address - in which case you will need the start address to offset from).
If, on the other hand, your variable contains four encoded ascii characters (of a byte each), then you need to split to bytes and convert each byte to a character. Something like this Console.WriteLine(TypeDescriptor.GetConverter(myUint).ConvertTo(myUint, typeof(string))); from Here - MSDN ByteConverter