4
votes

Simple: How can I explicitly marshal the result of a WinAPi function ?


I know how to marshal parameters of WinApi functions in C# but how can I also marshal the return values ? Or do I actually have to marshal them ? I understand WinAPi returns only BOOL or all types of INT (handles are int as well in unmanaged code).
// common signature
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
static extern int GetFileAttributes([MarshalAs(UnmanagedType.LPStr)] string filename);

// my prefered signature because easy to handle the result
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
static extern FileAttributes GetFileAttributes([MarshalAs(UnmanagedType.LPStr)] string filename);

Since FileAttributes is enum and each value can easily be cast to int I'm sure I'm safe with this notation. But can I marshal the result in this one signature like I do with the parameters ? I actually only know Marshal class and MarshalAs attribute.

1
Why in the world are you explicitly calling the ANSI version of the function? The year 1998 called, they want their code back.Cody Gray
@CodyGray Because Google and the rest of the internet is full of Ansi versions of this function. I have already worked out all 3 versions but this is just an example.Bitterblue
I don't really believe that, but even if it is true, that doesn't make it right. At a minimum, you want CharSet.Auto, but anymore, there's really no reason not to use CharSet.Unicode unless you're targeting .NET 2.0 and Windows 98.Cody Gray
This doesn't belong here but I worked with Ansi until today when I finally found out how to make Auto work. Because it didn't. pinvoke didn't supply my knowledge with enough information about that. Now I have for all my WinApi file-functions all 3 signatures implemented so I can switch between them. If you say Unicode is the way to go. I will remember that and take it into account next time. Ok ?Bitterblue
You have to use the appropriate string type, too, or it won't work. That would be UnmanagedType.LPWStr for Unicode, and UnmanagedType.LPTStr for Auto. Or better yet, omit the MarshalAs attribute altogether and just use the default marshalling. The CLR knows what it's doing for string types.Cody Gray

1 Answers

5
votes

Yes you can. You just need to use the [return:] attribute syntax, for example:

[return: MarshalAs(UnmanagedType.LPStruct)]

But in your case, there is no marshalling to do. Marshalling is not needed to convert integral types like that, so just use the second form in your example.

If you really want, you could write a public method that called GetFileAttributes() which checked the return value for validity.