Search code examples
c#dllimportunmanagedaccess-violationmanaged

DllImport causing access violation exception


The C dll header is this:

HRESULT App_Process(char *FileName, char *Output, const bool& LogInformation);

My C# DllImport looks like this:

[DllImport("App.dll")]
public static extern Int32 App_Process(
    [MarshalAs(UnmanagedType.LPStr)]string FileName,
    [MarshalAs(UnmanagedType.LPStr)]string Output,
    [MarshalAs(UnmanagedType.Bool)]bool LogInformation);

The exception is:

var result = App_Process("MyFile.txt", "Output.txt", true);

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Now the strange this is that the method is successfully doing everything its supposed to do.

Any ideas?


Solution

  • Original answer

    The last parameter of the extern method should be a ref bool rather than bool, given that the DLL header has a parameter of type const bool&:

    // Parameter names changed to be idiomatic for C#
    [DllImport("App.dll")]
    public static extern Int32 App_Process(
        [MarshalAs(UnmanagedType.LPStr)] string fileName,
        [MarshalAs(UnmanagedType.LPStr)] string output,
        [MarshalAs(UnmanagedType.Bool)] ref bool logInformation);
    

    With C# 7.2 I suspect you could use in instead of ref, which would make the method simpler to call:

    // Parameter names changed to be idiomatic for C#
    [DllImport("App.dll")]
    public static extern Int32 App_Process(
        [MarshalAs(UnmanagedType.LPStr)] string fileName,
        [MarshalAs(UnmanagedType.LPStr)] string output,
        [MarshalAs(UnmanagedType.Bool)] in bool logInformation);
    

    Update

    (From the comment from Hans Passant)

    This is not C code, as bool& is only valid in C++. That makes it very likely that the argument needs to be marshalled as [MarshalAs(UnmanagedType.U1)]. Double-check with sizeof(bool) in the native code. But you should talk to the author of the DLL, as const bool& makes no sense at all. There's no point in passing a bool by reference but then not allowing the code to update it.