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 / Languages / C# / May 2007

Tip: Looking for answers? Try searching our database.

Casting of bytes allocated by stackalloc to struct ptr -- It is possible but immediately

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
valentin tihomirov - 20 May 2007 19:13 GMT
Typically, you need the stackalloc when using win32 platform fucntions,
which tell you the amount of memory required for the output structure in the
first call, like GetJob does. The weired thing is that this works:
     byte* p = stackalloc byte[size];
     JOB_INFO_2* ji2 = (JOB_INFO_2*) p;

But the immediate casting does not:
     JOB_INFO_2* ji2 = (JOB_INFO_2*) stackalloc byte[size];

It throws a lot of compilation messages. Peahaps, it is a compiler bug.
Willy Denoyette [MVP] - 20 May 2007 22:26 GMT
> Typically, you need the stackalloc when using win32 platform fucntions,
> which tell you the amount of memory required for the output structure in
[quoted text clipped - 6 lines]
>
> It throws a lot of compilation messages. Peahaps, it is a compiler bug.

Why not simply use?

   JOB_INFO_2* ps = stackalloc JOB_INFO_2[1];

Willy.
valentin tihomirov - 21 May 2007 07:54 GMT
Because the structure is extended by private fields. Why do you think the
win api designers provide the functions to return output structure size for
the user to allocate the buffer?
Willy Denoyette [MVP] - 21 May 2007 11:50 GMT
> Because the structure is extended by private fields. Why do you think the
> win api designers provide the functions to return output structure size
> for the user to allocate the buffer?

True, I didn't look at this particular struct in detail. Anyway in this case
I would not use stackallock, stack alloc is great when you have to deal with
small structs of blittable types.
I would rather use Marshal.AllocHGlobal to allocate the buffer and use
Marshal.PtrToStruct() to marshal the buffer to a managed representation of
the struct. This way I don't need to resort to unsafe code constructs, and I
don't have to marshal the individual fields of the unmanaged buffer to their
managed representation.
If you really want your unmanaged buffer to be stack allocated, you can
always declare it like this:

..  int jobs;
   int bNeeded;
   // Get buffer size needed
   ret = EnumJobs(hPrinter, 0, 1, 2, IntPtr.Zero, bNeeded, out bNeeded, out
jobs);
   if(ret )
   {
       void* buffer = stackalloc byte[bNeeded];
       EnumJobs(hPrinter, 0, 1, 2, ptr, bNeeded, out bNeeded, out jobs);
       IntPtr ptr = new(buffer);
       Marshal.PtrToStruct(ptr, ...);
   ..

Willy.
valentin tihomirov - 21 May 2007 13:47 GMT
Ok, I will tell you why marshalling is bad for p/invoking. Let me
demonstrate on the GetJob/SetJob example.

[1]

At first, DEVMODE is referred by pointer in JOB_INFO_2. But in .net, we
cannot use UnmanagedType.LPStruct:
   [MarshalAs(UnmanagedType.LPStruct)] public DEVMODE pDevMode;

All the pointers to structures must be declared as opaque IntPtr. Thus, when
I unmarshal result of GetJob, the IntPtr devMode field will have some value
to be unmarshalled separately. After getting the print job settings, I
update the fields of interest and use SetJob to apply the updated settings
to the system. The SetJob invokation must be preceded by unmanaged space
allocation and marshalling. It will be done twice again (for job_info and
devmode). Furthermore, the IntPtr devMode field must be updated explicitly
accordingly.

As a conclustion, I have to do 22 lines of code, multiple heap memory
allocations and copy, where normally 2 lines of code with stack alloc and no
data copying suffices.

In addition to the code bloating, marshalling is not just possible in many
cases, since it requires exact structure descriptions. Take the
GetJob/SetJob example. I got the job settings into a structure, updated some
fields of it and wrote it back leaving other printing settings untouched.
The first two fields of DEVMODE are structure size and extra size. I do not
have the declarations of the extra fields. So Marshal.SizeOf(myDevMode) will
return a size smaller than specified in the size fields of the structure.
The spooler will fail on SetJob accessing the not described and thus not
allocated/marshaled fields.

Marshaling makes your code cumbersome and fragile.
Willy Denoyette [MVP] - 21 May 2007 15:48 GMT
> Ok, I will tell you why marshalling is bad for p/invoking. Let me
> demonstrate on the GetJob/SetJob example.
[quoted text clipped - 29 lines]
>
> Marshaling makes your code cumbersome and fragile.

All depends on the usage scenario, on what structure you have to deal with,
what fields you need to use in your code in managed form, for instance if
you need to get at the items declared as LPTSTR you'll have to marshal these
to a System.String anyway.
I agree that in your scenario, where you only need the raw structure to
modify some fields and pass this back to another API, you can go without
marshaling, however, I don't like unsafe constructs.
I agree, that some Win32 structs are hard to marshal, this is where C style
data types meets OO style (and this is also a reason why some Win32 API's
are not wrapped in the FCL), dealing with API's designed for "C " from other
languages is by itself cumbersome and fragile.
That's why I wouldn't use C# to access the spooler API's, I would use
C++/CLI. This is also what MS is doing, some of the new FCL classes are now
written using managed C++, it's easier to get it right, especially when you
have to deal with a lot of (OS version dependent) API's and structures, much
is taken care of in the header files. I wonder how much of the FCL would
have been written using C# if C++/CLI had been available since day one?

Willy.

Willy.
Christof Nordiek - 22 May 2007 10:38 GMT
> Typically, you need the stackalloc when using win32 platform fucntions,
> which tell you the amount of memory required for the output structure in
[quoted text clipped - 6 lines]
>
> It throws a lot of compilation messages. Peahaps, it is a compiler bug.

Following the specification of C# the stackalloc construct can only be used
as variable initializer. Maybe its only meant for declaring 'unsafe
variables'.

Christof
Willy Denoyette [MVP] - 22 May 2007 18:11 GMT
>> Typically, you need the stackalloc when using win32 platform fucntions,
>> which tell you the amount of memory required for the output structure in
[quoted text clipped - 12 lines]
>
> Christof

This is not the point, JOB_INFO_2* is an unsafe variable (it's a pointer
variable).
JOB_INFO_2* ptr = stackalloc JOB_INFO_2[2]
compiles just fine, the point is that the compiler doesn't like the cast in:
JOB_INFO_2* ptr = (JOB_INFO_2*)stackalloc  byte[sizeofjob_info_2];
I don't know if it's a bug, looks more like a missing feature. Anyway not
quite a big issue, the bypass is illustrated by the OP.

Willy.

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.