Gendarme.Rules.Interoperability

Gendarme's interoperability rules are located in the Gendarme.Rules.Interoperability.dll assembly. Latest sources are available from anonymous SVN (http://anonsvn.mono-project.com/viewcvs/trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/).

Rules

DoNotAssumeIntPtrSizeRule

This rule checks for any cast of IntPtr or UIntPtr into a 32bits (or smaller) value. It will also check if memory read with Marshal.ReadInt32and Marshal.ReadInt64 methods are being casted into an IntPtr or UIntPtr. IntPtr are generally used to reference a memory location and downcasting them to 32bits will make the code fail on 64bits CPU.

Bad example (cast):

int ptr = dest.ToInt32 ();
for (int i = 0; i < 16; i++) {
    Marshal.StructureToPtr (this, (IntPtr)ptr, false);
    ptr += 4;
}

Bad example (Marshal.Read*):

// that won't work on 64 bits platforms
IntPtr p = (IntPtr) Marshal.ReadInt32 (p);

Good example (cast):

long ptr = dest.ToInt64 ();
for (int i = 0; i < 16; i++) {
    Marshal.StructureToPtr (this, (IntPtr) ptr, false);
    ptr += IntPtr.Size;
}

Good example (Marshal.Read*):

IntPtr p = (IntPtr) Marshal.ReadIntPtr (p);

Notes

  • This rule is available since Gendarme 2.0 but was named DoNotCastIntPtrToInt32Rule before 2.2

GetLastErrorMustBeCalledRightAfterPInvokeRule

Marshal.GetLastWin32Error()should be called directly after a P/Invoke call. Intermediate method calls, even managed, could overwrite the error code.

Bad example:

public void DestroyError ()
{
    MessageBeep (2);
    Console.WriteLine ("Beep");
    int error = Marshal.GetLastWin32Error ();
}

Good example:

public void GetError ()
{
    MessageBeep (2);
    int error = Marshal.GetLastWin32Error ();
    Console.WriteLine ("Beep");
}
 
public void DontUseGetLastError ()
{
    MessageBeep (2);
    Console.WriteLine ("Beep");
}

MarshalBooleansInPInvokeDeclarationsRule

This rule warns the developer if a [MarshalAs] attribute has not been specified for boolean parameters of a P/Invoke method. The size of boolean types vary across language (e.g. 4 bytes for language treating it as an integer, 1 byte in C++ bool). By default the CLR will marshal System.Booleanas a 32 bits value (UnmanagedType.Bool) like the Win32 API BOOLuse. But, for clarity, you should always specify the correct value.

Bad example:

// bad assuming the last parameter is a single byte being mapped to a bool
private static extern bool Bad (bool b1, ref bool b2);

Good example:

[DllImport ("liberty.so")]
[return: MarshalAs (UnmanagedType.Bool)]
private static extern bool Good ([MarshalAs (UnmanagedType.Bool)] bool b1, [MarshalAs (UnmanagedType.U1)] ref bool b2);

MarshalStringsInPInvokeDeclarationsRule

This rule warns the developer if the CharSet has not been specified for string parameters of P/Invoke method, unless if they are individually decorated with [MarshalAs] attribute. This applies to any System.Stringand System.Text.StringBuilder parameters.

Bad example:

[DllImport("coredll.dll")]
static extern int SHCreateShortcut (StringBuilder szShortcut, StringBuilder szTarget);

Good examples:

[DllImport("coredll.dll", CharSet = CharSet.Auto)]
static extern int SHCreateShortcut (StringBuilder szShortcut, StringBuilder szTarget);
 
[DllImport("coredll.dll")]
static extern int SHCreateShortcut ([MarshalAs(UnmanagedType.LPTStr)] StringBuilder szShortcut,
[MarshalAs(UnmanagedType.LPTStr)] StringBuilder szTarget);

PInvokeShouldNotBeVisibleRule

This rule checks for PInvoke declaration methods that are visible outside their assembly.

Bad example:

[DllImport ("user32.dll")]
public static extern bool MessageBeep (UInt32 beepType);

Good example:

[DllImport ("user32.dll")]
internal static extern bool MessageBeep (UInt32 beepType);

UseManagedAlternativesToPInvokeRule

This rule warns the developer if certain external (P/Invoke) methods are being called in case they have managed alternatives provided by the .NET framework

Bad example:

[DllImport ("kernel32.dll")]
static extern void Sleep (uint dwMilliseconds);
 
public void WaitTwoSeconds ()
{
    Sleep (2000);
}

Good example:

public void WaitTwoSeconds ()
{
    System.Threading.Thread.Sleep (2000);
}

Feedback

Please report any documentation errors, typos or suggestions to the Gendarme Google Group (http://groups.google.com/group/gendarme). Thanks!