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 / July 2007

Tip: Looking for answers? Try searching our database.

C# 2 fixed sized buffers and interop

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
skeet@pobox.com - 10 Jul 2007 12:47 GMT
I've just started looking into fixed sized buffers in C# 2, and I
think I must be missing something. I have no problems when not dealing
with interop, but as soon as I start using interop things go wrong.

I thought I'd try GetTimeZoneInformation as a starting point, partly
as I know I can get at the character data using
UnmanagedType.ByValTStr for a consistency check. Unfortunately, I'm
only getting the first character of the daylight name and the standard
name. A complete program follows - could someone point out the stupid
mistake I've doubtless made? Uncommenting the version using
"Marshal.As UnmanagedType.ByValTStr" gives the correct values (GMT
etc) but as posted it just prints out "G" twice.

Jon

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=1)]
struct SystemTime
{
 public ushort Year;
 public ushort Month;
 public ushort DayOfWeek;
 public ushort Day;
 public ushort Hour;
 public ushort Minute;
 public ushort Second;
 public ushort Milliseconds;
}

[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Unicode)]
unsafe struct TimeZoneInformation
{
 public int Bias;
 //[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
 //public string StandardName;
 public fixed char StandardName[32];
 public SystemTime StandardDate;
 public int StandardBias;
 //[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
 //public string DaylightName;
 public fixed char DaylightName[32];
 public SystemTime DaylightDate;
 public int DaylightBias;
}

public class Test
{
 [DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
 static extern uint GetTimeZoneInformation
   (out TimeZoneInformation timeZoneInformation);

 static void Main()
 {
     unsafe
     {
       TimeZoneInformation info;
       uint result = GetTimeZoneInformation (out info);
       //Console.WriteLine (info.StandardName);
       //Console.WriteLine (info.DaylightName);
       Console.WriteLine (new string(info.DaylightName));
       Console.WriteLine (new string(info.StandardName));
     }
 }
}
Willy Denoyette [MVP] - 11 Jul 2007 01:31 GMT
> I've just started looking into fixed sized buffers in C# 2, and I
> think I must be missing something. I have no problems when not dealing
[quoted text clipped - 62 lines]
>  }
> }

I have encountered the same issue some time ago, I guess the marshaler
ignores the CharSet attribute for fixed char buffers and considers the
unmanaged char buffer to be Ansi encoded.
Here is how I would fix it.

 public fixed byte StandardName[64]; // declare a byte type to prevent the
marshaler to mess with the buffer (length in bytes now!)
...
 public fixed byte DaylightName[64];
...
}

public class Test
{

...
       Console.WriteLine (new string((char*)info.DaylightName)); // cast
the byte* to char*
...

Willy.
Jon Skeet [C# MVP] - 11 Jul 2007 19:50 GMT
<snip>

> I have encountered the same issue some time ago, I guess the marshaler
> ignores the CharSet attribute for fixed char buffers and considers the
> unmanaged char buffer to be Ansi encoded.

How bizarre. In this case, I really just want the marshaller to get out
of the way - all it needs to do is pass in a pointer, without doing any
extra copying. Is there any way of doing this?

> Here is how I would fix it.
>
[quoted text clipped - 12 lines]
> the byte* to char*
> ...

Yup, that appears to fix it. (I thought I'd tried something like that
before, but apparently not.)

Out of interest, have you used the new-to-C#2 fixed buffers? Have you
found them handy? I can't say I've ever used them before, as I very
rarely touch unsafe code in the first place. Have you encountered them
outside interop?

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

Willy Denoyette [MVP] - 12 Jul 2007 10:32 GMT
> <snip>
>
[quoted text clipped - 5 lines]
> of the way - all it needs to do is pass in a pointer, without doing any
> extra copying. Is there any way of doing this?

The callee (kernel32 function) stores the value of a TimeZoneInformation
structure into the location pointed to by the caller (here to "info" on the
callers stack) .
The marshaller stays out of the picture as long as the structure contains
only blittable types, however, a *char* is non-blittable , so the marshaller
must convert the source (Unicode or MBCS) buffer to the dest *char* buffer.
This conversion occurs after the actual store of the value type, this
requires some *extra copying* of the fixed char array's (which is what you
meant I guess).
This is the point where the marshaller goes wrong (a bug!), he treats the
return buffer as a MBCS, irrespective the CharSet attribute, that means that
the conversion stops after the first character in case of a Unicode buffer.
One way to prevent this *extra copying* is to make the structure blittable
(as I illustrated).

>> Here is how I would fix it.
>>
[quoted text clipped - 18 lines]
>
> Out of interest, have you used the new-to-C#2 fixed buffers?

We maintain company wide "Programming Guidelines" that define the usage
context of API's an features of a product (MS and others). For C# and the
FCL, we have three categories of API guidelines (the red, orange and green
books), the green book lists all API's that can safely be used in production
code, the orange book lists (annotated) all API's that need special care,
they may be used for prototyping and in "trusted"  libraries, while the red
book lists the "prohibited" API's and features.
"unsafe" constructs and "fixed" are in the orange book for V2 they need some
care as they may cause unexpected behavior when used (as illustrated).

>Have you
> found them handy? I can't say I've ever used them before, as I very
> rarely touch unsafe code in the first place. Have you encountered them
> outside interop?

Honestly, I don't write that much code these days, but IMO they have not
much value outside interop.

Willy.
Jon Skeet [C# MVP] - 12 Jul 2007 19:14 GMT
> >> I have encountered the same issue some time ago, I guess the marshaler
> >> ignores the CharSet attribute for fixed char buffers and considers the
[quoted text clipped - 13 lines]
> requires some *extra copying* of the fixed char array's (which is what you
> meant I guess).

Right - in this case I want to basically tell the marshaller that it
really *is* blittable, just get on with it.

> This is the point where the marshaller goes wrong (a bug!), he treats the
> return buffer as a MBCS, irrespective the CharSet attribute, that means that
> the conversion stops after the first character in case of a Unicode buffer.
> One way to prevent this *extra copying* is to make the structure blittable
> (as I illustrated).

Right - and there's no way of doing that while still using a char
buffer?

> > Yup, that appears to fix it. (I thought I'd tried something like that
> > before, but apparently not.)
[quoted text clipped - 10 lines]
> "unsafe" constructs and "fixed" are in the orange book for V2 they need some
> care as they may cause unexpected behavior when used (as illustrated).

Indeed!

> >Have you
> > found them handy? I can't say I've ever used them before, as I very
[quoted text clipped - 3 lines]
> Honestly, I don't write that much code these days, but IMO they have not
> much value outside interop.

Okay - thanks for that.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

Willy Denoyette [MVP] - 12 Jul 2007 20:10 GMT
>> >> I have encountered the same issue some time ago, I guess the marshaler
>> >> ignores the CharSet attribute for fixed char buffers and considers the
[quoted text clipped - 32 lines]
> Right - and there's no way of doing that while still using a char
> buffer?

It should have done it in your case (a Unicode encode struct), but it can't
do it when the native structure holds Ansi character buffers. The Ansi
buffer need to be *marshaled* to a fixed char buffer (Unicode only) .

Consider this sample:
a "native" Ansi encoded structure:
stuct MyNativeStruct {
   fixed char buff[16];
   int val;
}

and it's C# counterpart:
stuct MyManagedStruct {
   fixed char buff[16];
   int val;
}

here MyNativeStruct.buff is 16 bytes, while the MyManagedStruct.buff is 32
bytes. You can't treat the structure as blittable and just pass the
structure as is, both the char encoding and the lay-out don't match, so you
need to marshal.

Willy.
Jon Skeet [C# MVP] - 12 Jul 2007 21:33 GMT
> > Right - and there's no way of doing that while still using a char
> > buffer?
>
> It should have done it in your case (a Unicode encode struct), but it can't
> do it when the native structure holds Ansi character buffers. The Ansi
> buffer need to be *marshaled* to a fixed char buffer (Unicode only) .

Yup - that makes perfect sense. I was only considering the cases where
the structure really was going to be filled with Unicode characters in
the first place.

Hmm. I'm still looking for a really good example of using this...

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too


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.