Question

I'm having a problem building an array of structs from an IntPtr in another struct.

This structure is returned by a Windows API I'm using:

public struct DFS_INFO_9 {
    [MarshalAs(UnmanagedType.LPWStr)]
    public string EntryPath;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string Comment;
    public DFS_VOLUME_STATE State;
    public UInt32 Timeout;
    public Guid Guid;
    public UInt32 PropertyFlags;
    public UInt32 MetadataSize;
    public UInt32 SdLengthReserved;
    public IntPtr pSecurityDescriptor;
    public UInt32 NumberOfStorages;
    public IntPtr Storage;
}

[DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int NetDfsEnum([MarshalAs(UnmanagedType.LPWStr)]string DfsName, int Level, int PrefMaxLen, out IntPtr Buffer, [MarshalAs(UnmanagedType.I4)]out int EntriesRead, [MarshalAs(UnmanagedType.I4)]ref int ResumeHandle);

I'm trying to get the array of DFS_STORAGE_INFO_1s referenced by IntPtr Storage.

Here's that structure (if it matters):

public struct DFS_STORAGE_INFO_1 {
    public DFS_STORAGE_STATE State;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ServerName;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ShareName;
    public IntPtr TargetPriority;
}

So far this code has been working to get the DFS_INFO_9s with only one storage, but fails when trying to marshal the second item in the array.

DFS_INFO_9 info = GetInfoFromWinApi();
List<DFS_STORAGE_INFO_1> Storages = new List<DFS_STORAGE_INFO_1>();
for (int i = 0; i < info.NumberOfStorages; i++) {
    IntPtr pStorage = new IntPtr(info.Storage.ToInt64() + i * Marshal.SizeOf(typeof(DFS_STORAGE_INFO_1)));
    DFS_STORAGE_INFO_1 storage = (DFS_STORAGE_INFO_1)Marshal.PtrToStructure(pStorage, typeof(DFS_STORAGE_INFO_1));
    Storages.Add(storage);
}

I'm getting a FatalExecutionEngineError that spits out error code 0x0000005 (Access Denied). I'm assuming the size of the DFS_STORAGE_INFO_1 is being miscalculated causing the marshal to attempt to access memory outside that allocated for the array. But this is happening on i = 1, when there might be 7 storages to get through. Maybe my thinking is flawed, but I have no idea how to rectify this.

Was it helpful?

Solution

The actual definition of DFS_STORAGE_INFO_1 is this:

public struct DFS_STORAGE_INFO_1 {
    public DFS_STORAGE_STATE State;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ServerName;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ShareName;
    DFS_TARGET_PRIORITY TargetPriority;
}

TargetPriority is a structure, defined here:

public struct DFS_TARGET_PRIORITY {
    public DFS_TARGET_PRIORITY_CLASS TargetPriorityClass;
    public UInt16 TargetPriorityRank;
    public UInt16 Reserved;
}

public enum DFS_TARGET_PRIORITY_CLASS {
    DfsInvalidPriorityClass = -1,
    DfsSiteCostNormalPriorityClass = 0,
    DfsGlobalHighPriorityClass = 1,
    DfsSiteCostHighPriorityClass = 2,
    DfsSiteCostLowPriorityClass = 3,
    DfsGlobalLowPriorityClass = 4
}

As for the FatalExecutionEngineError, I believe that the size of the structure DFS_STORAGE_INFO_1 was being miscalculated since it was defined incorrectly. When trying to convert the pointers to the structures they referenced, the next index was wrong because the size was off. When converting the block of memory, it presumably referenced a block that shouldn't have been accessible, throwing the "Access Denied (0x0000005)" error.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top