Structures with embedded string fields

Tuesday’s quiz used character arrays to represent string fields of the DEVMODE structure.  Why not define them as strings, which would be more convenient to manipulate in managed code? If you define a structure field as a string, it is marshaled as a pointer to an unmanaged string by default (LPSTR/LPWSTR).  But with MarshalAsAttribute and UnmanagedType.ByValTStr,…

2

Quiz: What’s wrong with the following code?

The following C# code has the goal of enabling managed code to call CreateDC, but it’s incorrect.  Calling all Interop aficionados… Can you see what’s wrong? using System; using System.Runtime.InteropServices; internal class DeviceContext {   [DllImport(“gdi32.dll”, CharSet=CharSet.Auto)]   internal static extern IntPtr CreateDC(     string lpszDriver, string lpszDevice,     string lpszOutput, ref DEVMODE lpInitData); }…

36

size_is in managed code?

IDL has a size_is attribute (as well as length_is, first_is, last_is, max_is, …) that decorates a C-style array with enough information for it to be marshaled.  Without such an attribute, the array would not be distinguishable from a pointer to a single element.  Here’s an example of size_is being used on the IDL definition of…

2

PreserveSig

For managed signatures that represent unmanaged functions, the PreserveSig pseudo custom attribute controls an important aspect of run-time behavior.  In COM Interop scenarios, a C# method defined as follows:   string GetName(); is treated like the following unmanaged method (in IDL syntax):   HRESULT GetName([out, retval] BSTR* pRetVal); When managed code calls a COM object…

6

Pseudo custom attributes

Tomorrow I’d like to talk about the PreserveSig pseudo custom attribute, but first I thought I’d briefly point out the difference between pseudo custom attributes and “real” custom attributes. The CLR/.NET Framework has a handful of pseudo custom attributes that are used just like real custom attributes in high-level source code, but are not stored in metadata the…

5

GetLastError and managed code

In the Win32 world, calling the GetLastError API is often the mechanism to get additional error information when an API call fails.  When calling these same Win32 APIs in managed code via PInvoke or via “It Just Works (IJW)” in managed C++, the rules are slightly different.  That’s because the CLR itself could be making…

3

UnmanagedType.Struct and VARIANT marshaling

Continuing yesterday’s theme of marshaling directives, today I’ll talk about UnmanagedType.Struct, another poorly-named (and therefore confusing) enumeration value.  If you pretend that it’s called “UnmanagedType.Variant,” it should make more sense.   This marshaling directive is only valid for parameters/fields/return types defined as System.Object (not types derived from System.Object), and it instructs the marshaler to marshal the…

1

The confusing UnmanagedType.LPStruct marshaling directive

MarshalAsAttribute controls marshaling behavior for managed data types that can have multiple unmanaged representations.  Often, the challenge of using MarshalAsAttribute is choosing the right value from the UnmanagedType enumeration to pass to the attribute’s constructor.  Probably the UnmanagedType value that I’ve seen misused the most is LPStruct.  And I don’t blame people who misuse it! …

10