This test code works for me to marshal the FILE_ID_BOTH_DIR_INFO structure. It is very similar to the structure you are attempting to marshal.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
class Program
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CreateFileW(
string filename,
uint access,
uint share,
IntPtr securityAttributes,
uint creationDisposition,
uint flagsAndAttributes,
IntPtr templateFile);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
[StructLayout(LayoutKind.Explicit)]
public struct LargeInteger
{
[FieldOffset(0)]
public int Low;
[FieldOffset(4)]
public int High;
[FieldOffset(0)]
public long QuadPart;
// use only when QuadPart canot be passed
public long ToInt64()
{
return ((long)this.High << 32) | (uint)this.Low;
}
// just for demonstration
public static LargeInteger FromInt64(long value)
{
return new LargeInteger
{
Low = (int)(value),
High = (int)((value >> 32))
};
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct FILE_ID_BOTH_DIR_INFO
{
public int NextEntryOffset;
public int FileIndex;
public LargeInteger CreationTime;
public LargeInteger LastAccessTime;
public LargeInteger LastWriteTime;
public LargeInteger ChangeTime;
public LargeInteger EndOfFile;
public LargeInteger AllocationSize;
public int FileAttributes;
public int FileNameLength;
public int EaSize;
public char ShortNameLength;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 12)]
public string ShortName;
public LargeInteger FileId;
public char FileName;
};
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetFileInformationByHandleEx(IntPtr hFile, int infoClass, IntPtr dirInfo, uint dwBufferSize);
const uint GENERIC_READ = 0x80000000;
const uint FILE_SHARE_READ = 0x00000001;
const uint FILE_SHARE_WRITE = 0x00000002;
const uint OPEN_EXISTING = 3;
const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
const int FileIdBothDirectoryInfo = 10;
static void Main(string[] args)
{
IntPtr hFile = CreateFileW("C:\\Users\\RLWA32\\Documents", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero);
if (hFile != (IntPtr)(-1))
{
IntPtr buffer = Marshal.AllocHGlobal(16384); // Arbitrary value
if(GetFileInformationByHandleEx(hFile, FileIdBothDirectoryInfo, buffer, 16384))
{
bool bcontinue = true;
IntPtr ptr = buffer;
IntPtr fnameOffset = Marshal.OffsetOf<FILE_ID_BOTH_DIR_INFO>("FileName");
do
{
FILE_ID_BOTH_DIR_INFO info = new FILE_ID_BOTH_DIR_INFO();
info = Marshal.PtrToStructure<FILE_ID_BOTH_DIR_INFO>(ptr);
IntPtr pfilename = ptr + (int)fnameOffset;
string filename = Marshal.PtrToStringUni(pfilename, info.FileNameLength / 2); // FileNameLength in bytes, not chars
Console.WriteLine(filename);
if (info.NextEntryOffset != 0)
ptr += info.NextEntryOffset;
else
bcontinue = false;
} while (bcontinue);
}
Marshal.FreeHGlobal(buffer);
CloseHandle(hFile);
}
}
}
}