|
I need to send and receive unmanaged strings to a Unix box using sockets and because of our buffer protocols changing from time to time the best way to manage this is by using structs. Currently if I have 30 fields defined in my buffer with fixed lengths and I change the field length for field number 15 I now I have to go into all the properties for fields 16 to 30 and change their substring starting points which is a hassle. I find that using structs eliminates all that hassle since it will automatically adjust itself in that scenario. My character set will have to be unicode but I am struglling with the idea of Marshaling and I can't seem to find a good code example of this for c sharp. I have seen examples of copying structs to structs and arrays to structs but not strings to struct casting.
Diego
|
|
|
|
|
Again, this is still a simple parsing problem. Do read about the UnmanagedType.ByValTStr , though. Using that in your MarshalAsAttribute for fields and setting the SizeConst field means you don't even have to change the offsets - another reason to use LayoutKind.Sequential .
This still doesn't make a whole lot of sense, though. How is it easier to pass a string as a struct? Just encode the string and pass the byte[] array, since a byte[] is always the same on any platform (not taking into account endianess). Just make sure you use the same encoding on both ends. The HTTP protocol, for example, specifies the encoding in the HTTP headers.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Right now our code is in vb6 and I have a type defined as:
' This is the buffer passed in from my winsock control.
buffer = "abcdefgh1234567"
type mytype
fname as string * 4
lname as string * 4
phone as string * 7
end type
dim mt as mytype
up = VarPtr(mt)
' Copy buffer to struct
CopyMemory ByVal up, ByVal StrPtr(buffer), LenB(buffer)
debug.print mt.fname
If I needed to modify lname to make it 5 bytes all I have to do is change it to 5 in only one place - the struct.
If I substring the buffer I would have to change the starting position for phone to have one byte more and then the same for every field after phone. This is why substring is a hassle here - especially for a proprietary protocol that has dozens and dozens of fields. I basically want to mimic the vb example above in C sharp.
Diego
|
|
|
|
|
Again, you don't want to use FieldOffsetAttribute , because that would cause you to have to change the offset for each field. If you read the documentation, it is the offset from the beginning of the structure - not the last field.
AS I said, though, this can still be done using the Marshal class. See the Marshal.PtrToStructure method, for example. To get the IntPtr for the string, use GCHandle.Alloc .
There's one problem you're also overlooking: in VB6 and below, strings are not null terminated. In most Windows APIs - including the .NET Framework - strings are null terminated.
So, lets say you use UnmanagedType.ByValTStr that I mentioned before. While Marshal.PtrToStructure would honor the StructLayoutAttribute , the problem is that the character sequences in your string will not be delimited with null characters. You need to write a work-around for this, or implement an ICustomMarshaler and implement the work-around.
Stil, though, nothing says that simply parsing the string has to be difficult. When you read in a substring, use the index and get the next substring starting from that index. This still allows you to change one line without changing others.
Consider the following example:
public struct Phone
{
public int CountryCode;
public int AreaCode;
public string Number;
public static Phone Parse(string value)
{
Phone p = new Phone();
int index = 0;
p.CountryCode = int.Parse(value.Substring(0, 1); index += 1;
p.AreaCode = int.Parse(value.Substring(index, 3); index += 3;
p.Number = value.Substring(index, 7);
}
} See? All relative. You just need to change the length of the string to grab with String.Substring plus the index addition/assignment right operand.
To recap, though, the reason what you had worked in VB6 is because strings are null-terminated, allow for a sequence of characters to be packed in a struct. While conceptually the same is possible, it's the null termination that will cause you a problem.
With some fanagling, you could get it to work. See the .NET Framework SDK documentation for the Marshal class for lots of helpful methods.
And remember, the FieldOffsetAttribute won't work for what you want because it'll force you to go through and chance all the preceeding offsets if you change one offset since they are the offset from the beginning of the struct (offset 0, of course).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Heath,
Thanks for all your help. I finally figured out how to cast a string into a struct thanks to your help. Here is the code I finsally came up with.
class Class1
{
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct MyStruct
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=4)] public string fname;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=4)] public string lname;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=7)] public string phone;
}
public static void Main()
{
string buffer = "abcdefgh2223333";
IntPtr pBuf = Marshal.StringToBSTR(buffer);
MyStruct ms = (MyStruct)Marshal.PtrToStructure(pBuf,typeof(MyStruct));
Console.WriteLine("fname is: {0}",ms.fname);
Console.WriteLine("lname is: {0}",ms.lname);
Console.WriteLine("phone is: {0}",ms.phone);
}
}
I am going to post this bit of code on the site.
Diego
|
|
|
|
|
I wanted a multiline textbox control with possibility of giving different background colors to the lines. for eg:- if the first line has a white background the second line should have a yellow background etc. Please help
|
|
|
|
|
hi,
The code below demonstrates one possible way of doing what you have requested...
Label l1 = new Label();
l1.Text = "Hi there";
l1.Width = richTextBox1.Width;
l1.Location = new Point(0,0);
l1.BackColor = Color.AliceBlue;
Label l2 = new Label();
l2.Width = richTextBox1.Width;
l2.Location = new Point(0,l1.Bottom);
l2.Text = "Howz life";
l2.BackColor = Color.Beige ;
richTextBox1.Controls.Add(l1);
richTextBox1.Controls.Add(l2);
hope this helps you or atleast gives you an idea... this has what occured to me...
regards,
Aryadip.
Cheers !! and have a Funky day !!
|
|
|
|
|
Hi,
Thanks for that very good idea.
What I want is also that this textbox should have editing capabilities also
like a notepad.
By doing the way you mentioned in the sample code, we might be able to edit/select only one line at a time.
Thanks & Regards
Mahesh
|
|
|
|
|
The best way to accomplish that, would be a RichtextBox. LokiSD wrote an article[^] on how to do Richtextbox background highlighting in Vb.Net. It would be worth looking into.
What you would need to do, is find out the length of the line, and where the line starts. Set the selectionstart to the linestart, and selectionlength to the linelength. Then, call the function to highlight the selection color.
Hope this gives you some idea's.
Aaron Eldreth
TheCollective4.com
My Articles
While much is too strange to be believed,
Nothing is too strange to have happened.
- T. Hardy
|
|
|
|
|
Thanks a lot.
That does the work for me.
|
|
|
|
|
Hi!
I am downloading a file from the web (mostly HTML file). Now I want to load the whole file into a string. How can I do this? I need a method that handles all encodings correctly, i.e. at least ANSI, Unicode and UTF-8...
Best regards,
Dominik
_outp(0x64, 0xAD);
and
__asm mov al, 0xAD __asm out 0x64, al
do the same... but what do they do??
(doesn't work on NT)
|
|
|
|
|
If you use TextReader it should detect the encoding.
If you're downloading it from the net you can wrap the input stream in StreamReader and then use ReadToEnd method. It has overloaded constructor so that you can specify encoding of your choice.
|
|
|
|
|
Hi!
First thanks for your reply. I tried this:
public static string TextFileToString(string strFilename)<br />
{<br />
string str;<br />
<br />
StreamReader re = File.OpenText(strFilename);<br />
str = re.ReadToEnd();<br />
re.Close();<br />
<br />
return str;<br />
}
This seems to load UTF-8 files very well, but it fails to load Unicode-encoded files (just the first character of the file is loaded)... Using Win98. Any idea?
Best regards and thanks,
Dominik
_outp(0x64, 0xAD);
and
__asm mov al, 0xAD __asm out 0x64, al
do the same... but what do they do??
(doesn't work on NT)
|
|
|
|
|
If you're using the HttpWebRequest to request the files, then the HttpWebResponse will contain the encoding.
You can get the encoding by passing HttpWebResponse.ContentEncoding to Encoding.GetEncoding and create a StreamReader using that Encoding and HttpWebResponse.GetResponseStream .
If you read the documentation for the HttpWebResponse.GetResponseStream in the .NET Framework SDK, it even has an example (although they get the Encoding for "utf-8" - just replace that string with myHttpWebResponse.ContentEncoding in regard to the sample code).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Currently I'm using the WebRequest class instead of HttpWebRequest, and WebResponse instead of HttpWebResponse. Is there maybe any way to look if my WebRequest is a HttpWebRequest and if so, somehow convert it? So I can use the header encoding information?
Thanks for your reply and best regards,
Dominik
_outp(0x64, 0xAD);
and
__asm mov al, 0xAD __asm out 0x64, al
do the same... but what do they do??
(doesn't work on NT)
|
|
|
|
|
If you're making HTTP requests, cast to a HttpWebRequest . The call to WebRequest.Create with an HTTP or HTTPS scheme actually creates an instance of the HttpWebRequest . This use a provider pattern, however, which can only return the base class (bases don't know about their derivatives, only vice-versa).
Look at the example I mentioned and you'll see what to do. You just cast to the necessary class, assuming that the instance created was an instance of that class (like making a request on a file:// scheme and casting to an HttpWebRequest won't work).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I suppose it's because of IntPtr.Zero in line 1
....logically you can't assign IntPtr.Zero as Window - handle parameter.......rather use something like this:
Form frm = new Form();
Graphics g = frm.CreateGraphics();
//...
|
|
|
|
|
You didn't say waht error message you got or what line it was on. But, Graphics.FromHwnd(IntPtr.Zero) will not return a valid Graphics container. You MUST give it a valid hWnd to work on.
[EDIT]
I take it you want to draw these images on the Desktop and not in your form? You might want to get the hWnd of the Desktop by P/Invoking GetDesktopWindow.
[DllImport("user32.dll")]
static extern IntPtr GetDesktopWindow();
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
Hi!
I'm having some problems in my code. I want to get values from a datareader to a double[]. I have read the values to an array list, this is my code:
int counter = 0;
ArrayList al = new ArrayList();
while(dtr.Read())
{
object[] values = new object[dtr.FieldCount];
dtr.GetValues(values);
al.Add(values);
counter = counter++;
}
If I write al it returns the correct values, but I can't get theese values in to a double. How can I do this? Is it maybe easier to put the values directly from the datareader to the byte array?
Thanks!
|
|
|
|
|
hi,
your question is not clear. I don't understand what exactly do you want...
Well here are the 2 possibilities that I can think of...
1st Possiblity :
If you require a specific Array of type object from the arraylist then you may use a similar code as below
string[] s = new string[10];
s[0] = "Aryadip";
ArrayList al = new ArrayList();
al.Add(s);
string[] ss = (string[])al[0];
MessageBox.Show( ss[0] );
2nd Possibility :
You require the full arraylist content in an array...in other words the array representation of the arraylist.
Now the complexity is the arraylist elements are arrays
Then the resulting array will be double dimentional...
The code to retrieve the same is :
string[] s = new string[10];
s[0] = "Aryadip";
ArrayList al = new ArrayList();
al.Add(s);
string[][] ss = (string[][])al.ToArray(s.GetType());
MessageBox.Show( ss[0][0] );
Now tips for your code :
DataReader is returning you an object array. After adding that object array to arraylist(like you did) you can get them back by using one of the methods mentioned above(replace string with object).
In the Individual object arrays that you add to the arraylist... if all the values are of type double then you can safely typecast with double array.
In case you are not sure or the object array contains values from different datatype then first obtain the object array by using one of the above methods and then use "Convert.ToDouble()" method to convert the specific array element to double value.Please refer to code below to get a better understanding...
object[] s = new object[10];
s[0] = "Aryadip";
ArrayList al = new ArrayList();
al.Add(s);
string[][] ss = (string[][])al.ToArray(new string[10].GetType());
MessageBox.Show( ss[0][0] );
Hope this helps you... if I have gone into wrong track... then sorry for that...
regards,
Aryadip.
Cheers !! and have a Funky day !!
|
|
|
|
|
Hi
I don't think that you understood me correctly, I'll try to explain it better this time. I want to get values from my db (that I have done). There are at the most 100 values, but there can also be less, but they are all in the same formate (numbers). I want to put theese number in to at double array so I can write them out in a graph.
Thanks again!
|
|
|
|
|
If you want to read doubles from a DataReader like a SqlDataReader , then use SqlDataReader.GetDouble (these types of methods are declared on DataReader derivatives). If each field is a double, then continously read through your DataReader like you're doing, but then iterate over the field count and read those doubles into an array. You can either use an ArrayList or use a multi-dimensional or jagged array.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Hi wizzards and all!
In the MS-Help is allways a blue banner with title.
I'd like to have the same in my html-helpfiles. Is there an example how to do it?
Ariadne
|
|
|
|
|
Right-click and click "View Source". There's your example.
If you want to generate MS-Help like code documentation, then use NDoc[^]. We went to a lot of work to provide help files that work like MSDN (both old an new) and provide other documenters as well.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
>Right-click and click "View Source". There's your example.
No, there is a link to some 'occult' files.
I look for a snipped, which makes the blue banner.
Thanks
Ariadne
|
|
|
|