1

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.

tedski
  • 2,271
  • 3
  • 27
  • 48
  • look here at some precious `SO` posting http://stackoverflow.com/questions/4550207/what-are-the-causes-and-solutions-of-exception-code-c0000005-in-mscorwks-dll also do a google search on this `error code 0xc0000005 (Access Denied)` – MethodMan Apr 05 '13 at 19:35
  • I've seen stuff like this, you can bet I googled it. The first so posts suggest the solution I'm trying to get away from, running an executable. I'm trying to use Windows Apis to better manage the code, and not have to open a command prompt and hope everything goes alright. The second post makes no sense to me. – tedski Apr 05 '13 at 19:45
  • I think I know what you are wanting I have seen an earlier post let me find it again and see if it's related – MethodMan Apr 05 '13 at 19:47
  • TargetPriority is wrong. It is a struct, not a pointer. – Hans Passant Apr 05 '13 at 21:33
  • Wow, can't believe I overlooked that. Thanks @HansPassant. Could you list that as an answer? Here's the link to the structure definition that confirms it: http://msdn.microsoft.com/en-us/library/windows/desktop/bb524797(v=vs.85).aspx – tedski Apr 08 '13 at 14:11
  • Go ahead and post the answer. I can't explain why this bombs with a FEEE. – Hans Passant Apr 08 '13 at 14:14
  • You can rectify the issue of multiple shares per storage struct with a nested loop. There is an example of this in C++ on the MSDN page [here](http://msdn.microsoft.com/en-us/library/bb524809(v=vs.85).aspx) I'm still working on a C# version but can't seem to get it to work yet. – sean_m Sep 24 '14 at 07:02
  • Got it working. [Here's a gist](https://gist.github.com/sean-m/88e74171cd2d07a4c608) with a method that implements this. This scratches my own itch and returns a list of structs, ignoring some values returned by NetDfsEnum so please modify as you see fit. – sean_m Sep 24 '14 at 08:38

1 Answers1

1

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.

tedski
  • 2,271
  • 3
  • 27
  • 48