.netwinformsnetapi32

fatalExecutionEngineError when using Windows API


I am trying to use a Windows API .dll called netapi32.dll to manipulate DFS shares. We are using DFS on Windows Server 2008 R2, and I am using .NET 4.0. I've never used something like this before in .NET, but I am having trouble understanding what is failing.

I am using DllImport to call NetDfsGetInfo to test getting information about a DFS share. I had to create structures for the level of information I wanted to receive from the function.

public struct DFS_INFO_3
{
    [MarshalAs(UnmanagedType.LPWStr)]
    public string EntryPath;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string Comment;
    public UInt32 State;
    public UInt32 NumberOfStorages;
    public IntPtr Storage;
}

public struct DFS_STORAGE_INFO
{
    public ulong State;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ServerName;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ShareName;
}

I used the following code to get and read the result:

[DllImport("netapi32", CallingConvention = CallingConvention.Winapi)]
public static extern int NetDfsGetInfo(
                    [MarshalAs(UnmanagedType.LPWStr)] string DfsEntryPath,
                    [MarshalAs(UnmanagedType.LPWStr)]string ServerName, 
                    [MarshalAs(UnmanagedType.LPWStr)]string ShareName, 
                    int Level, 
                    out IntPtr Buffer);

public void GetInfo() {
    IntPtr buffer;
    string dfsPath = "\\\\server\\share";

    int result = NetDfsGetInfo(EntryPath, null, null, 3, out buffer);

    if (result == 0) { //0 is Success
        DFS_INFO_3 info = (DFS_INFO_3)Marshal.PtrToStructure(buffer, typeof(DFS_INFO_3));
        DFS_STORAGE_INFO storage = (DFS_STORAGE_INFO)Marshal.PtrToStructure(info.Storage, typeof(DFS_STORAGE_INFO)); //Error
        Console.WriteLine("{0}, {1}, {2} ", storage.ServerName, storage.ShareName, storage.State);
    }
}

Everything goes fine until it goes to read the storage line.

I sometimes get an error that says:

The runtime has encountered a fatal error. The address of the error was at 0x626ac91c, on thread 0x1d44. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.

The error type is fatalExecutionEngineError, which isn't a .NET Exception, so I can't catch it. It doesn't happen every time, but I'd say about 50% of the time I get this error. Looking up Windows error codes, I'm seeing that 5 is "Access Denied". Being only intro-level Comp Sci proficient, I understand a bit about pointers (which is what the IntPtr object is), and that the pointer may have spilled over into a piece of the result that it wasn't supposed to? I still don't understand why this error would occur only some of the time.

How do I understand/avoid this error?


Solution

  • Your definition of DFS_STORAGE_INFO is incorrect. In .NET a long/ulong is 64 bits while in unmanaged Win32 it's only 32 bits (the same as an int/uint)

    public struct DFS_STORAGE_INFO
    {
        public UInt32 State;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string ServerName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string ShareName;
    }
    

    When you marshal the DFS_STORAGE_INFO you would be reading 4 bytes past the end of the structure - which may or may not work depending on what is after the structure.