I'm trying to initialize a disk and create a NTFS partition via DeviceIOControl, without using either DiskPart or WMI.
Using the below code I'm able to initialize the disk and create a RAW partition, but I'm unable to tweak the parameters so that the new partition is NTFS.
Any ideas?
//Returns true if drive Index is successfully created
//Returns false if not created successfully
public static bool CreatePartition(int driveIndex, string physicalName)
{
IntPtr handle = GetHandle(driveIndex, physicalName);
if (handle == INVALID_HANDLE_VALUE)
{
return false;
}
//Step 2: IOCTL_DISK_GET_DRIVE_GEOMETRY_EX to get the physical disk's geometry ( we need some information in it to fill partition data)
//The number of surfaces (or heads, which is the same thing), cylinders, and sectors vary a lot; the specification of the number of each is called the geometry of a hard disk.
//The geometry is usually stored in a special, battery-powered memory location called the CMOS RAM , from where the operating system can fetch it during bootup or driver initialization.
int size = 0;
DISK_GEOMETRY_EX geometry = new DISK_GEOMETRY_EX();
IntPtr lpOutBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DISK_GEOMETRY_EX)));
Marshal.StructureToPtr(geometry, lpOutBuffer, false);
int result = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, IntPtr.Zero, 0, lpOutBuffer, Marshal.SizeOf(typeof(DISK_GEOMETRY_EX)), ref size, IntPtr.Zero);
geometry = (DISK_GEOMETRY_EX)Marshal.PtrToStructure(lpOutBuffer, typeof(DISK_GEOMETRY_EX));
//Step 3: IOCTL_DISK_CREATE_DISK is used to initialize a disk with an empty partition table.
CREATE_DISK createDisk = new CREATE_DISK();
createDisk.PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR;
createDisk.Mbr.Signature = 1;
IntPtr createDiskBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CREATE_DISK)));
Marshal.StructureToPtr(createDisk, createDiskBuffer, false);
byte[] arr1 = new byte[Marshal.SizeOf(typeof(CREATE_DISK))];
Marshal.Copy(createDiskBuffer, arr1, 0, Marshal.SizeOf(typeof(CREATE_DISK)));
result = DeviceIoControl(handle, IOCTL_DISK_CREATE_DISK, createDiskBuffer, Marshal.SizeOf(typeof(CREATE_DISK)),
IntPtr.Zero, 0, ref size, IntPtr.Zero);
result = DeviceIoControl(handle, IOCTL_DISK_UPDATE_PROPERTIES, IntPtr.Zero, 0, IntPtr.Zero, 0, ref size, IntPtr.Zero);
//Step 4: IOCTL_DISK_SET_DRIVE_LAYOUT_EX to repartition a disk as specified.
//Note: use IOCTL_DISK_UPDATE_PROPERTIES to synchronize system view after IOCTL_DISK_CREATE_DISK and IOCTL_DISK_SET_DRIVE_LAYOUT_EX
/* DWORD driveLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX) * 4 * 25;
DRIVE_LAYOUT_INFORMATION_EX *DriveLayoutEx = (DRIVE_LAYOUT_INFORMATION_EX *) new BYTE[driveLayoutSize];*/
IntPtr driveLayoutbuffer = Marshal.AllocHGlobal(192);
FillMemory(driveLayoutbuffer, 192, 0);
DRIVE_LAYOUT_INFORMATION_EX driveLayoutEx = new DRIVE_LAYOUT_INFORMATION_EX();
driveLayoutEx.PartitionEntry = new PARTITION_INFORMATION_EX[1];
mediaType = (int)geometry.Geometry.MediaType;
Int64 bytes_per_track = (geometry.Geometry.SectorsPerTrack) * (geometry.Geometry.BytesPerSector);
driveLayoutEx.PartitionEntry[0].StartingOffset = 0x0;
Int64 main_part_size_in_sectors, extra_part_size_in_sectors = 0;
main_part_size_in_sectors = (geometry.DiskSize - driveLayoutEx.PartitionEntry[0].StartingOffset) / geometry.Geometry.BytesPerSector;
if (main_part_size_in_sectors <= 0)
{
return false;
}
extra_part_size_in_sectors = (MIN_EXTRA_PART_SIZE + bytes_per_track - 1) / bytes_per_track;
main_part_size_in_sectors = ((main_part_size_in_sectors / geometry.Geometry.SectorsPerTrack) -
extra_part_size_in_sectors) * geometry.Geometry.SectorsPerTrack;
if (main_part_size_in_sectors <= 0)
{
return false;
}
driveLayoutEx.PartitionEntry[0].PartitionLength = 1024 * 1024 * 1024 * (long)20;
driveLayoutEx.PartitionEntry[0].PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR;
driveLayoutEx.PartitionEntry[0].Mbr.PartitionType = 0x80;
driveLayoutEx.PartitionEntry[0].Mbr.BootIndicator = true;
driveLayoutEx.PartitionEntry[0].PartitionNumber = 1;
driveLayoutEx.PartitionEntry[0].RewritePartition = true;
driveLayoutEx.PartitionEntry[0].Mbr.RecognizedPartition = true;
driveLayoutEx.PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR;
driveLayoutEx.PartitionCount = 1; //It should be a multiple of 4
driveLayoutEx.Mbr.Mbr.Signature = createDisk.Mbr.Signature;
Marshal.StructureToPtr(driveLayoutEx, driveLayoutbuffer, false);
result = DeviceIoControl(handle, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, driveLayoutbuffer, 192, IntPtr.Zero, 0, ref size, IntPtr.Zero);
result = DeviceIoControl(handle, IOCTL_DISK_UPDATE_PROPERTIES, IntPtr.Zero, 0, IntPtr.Zero, 0, ref size, IntPtr.Zero);
Marshal.FreeHGlobal(driveLayoutbuffer);
Marshal.FreeHGlobal(createDiskBuffer);
Marshal.FreeHGlobal(lpOutBuffer);
return true;
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32")]
static extern int CloseHandle(IntPtr handle);
[DllImport("kernel32")]
private static extern int DeviceIoControl
(IntPtr deviceHandle, uint ioControlCode,
IntPtr inBuffer, int inBufferSize,
IntPtr outBuffer, int outBufferSize,
ref int bytesReturned, IntPtr overlapped);
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const uint FILE_SHARE_READ = 0x00000001;
public const uint FILE_SHARE_WRITE = 0x00000002;
public const uint OPEN_EXISTING = 0x00000003;
public const uint FILE_ATTRIBUTE_NORMAL = 0x80;
public const uint FSCTL_ALLOW_EXTENDED_DASD_IO = 0x90083;
public const int DRIVE_ACCESS_RETRIES = 10;
public const int DRIVE_ACCESS_TIMEOUT = 15000;
public const uint FSCTL_LOCK_VOLUME = 0x00090018;
static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
public const uint IOCTL_DISK_GET_DRIVE_LAYOUT_EX = 0x00070050;
public const uint IOCTL_DISK_GET_DRIVE_GEOMETRY_EX = 0x000700A0;
public const uint IOCTL_DISK_CREATE_DISK = 0x0007C058;
public const uint IOCTL_DISK_UPDATE_PROPERTIES = 0x00070140;
public const uint IOCTL_DISK_SET_DRIVE_LAYOUT_EX = 0x0007C054;
public const int MIN_EXTRA_PART_SIZE = 1024 * 1024;
public static int mediaType = 0;
[DllImport("kernel32.dll", EntryPoint = "RtlFillMemory", SetLastError = false)]
public static extern void FillMemory(IntPtr destination, uint length, byte fill);
/// <summary>
/// Describes the geometry of disk devices and media.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct DISK_GEOMETRY
{
/// <summary>
/// The number of cylinders.
/// </summary>
[FieldOffset(0)]
public Int64 Cylinders;
/// <summary>
/// The type of media. For a list of values, see MEDIA_TYPE.
/// </summary>
[FieldOffset(8)]
public MEDIA_TYPE MediaType;
/// <summary>
/// The number of tracks per cylinder.
/// </summary>
[FieldOffset(12)]
public uint TracksPerCylinder;
/// <summary>
/// The number of sectors per track.
/// </summary>
[FieldOffset(16)]
public uint SectorsPerTrack;
/// <summary>
/// The number of bytes per sector.
/// </summary>
[FieldOffset(20)]
public uint BytesPerSector;
}
public enum MEDIA_TYPE
{
Unknown, // Format is unknown
F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector
F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector
F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector
F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector
F3_720_512, // 3.5", 720KB, 512 bytes/sector
F5_360_512, // 5.25", 360KB, 512 bytes/sector
F5_320_512, // 5.25", 320KB, 512 bytes/sector
F5_320_1024, // 5.25", 320KB, 1024 bytes/sector
F5_180_512, // 5.25", 180KB, 512 bytes/sector
F5_160_512, // 5.25", 160KB, 512 bytes/sector
RemovableMedia, // Removable media other than floppy
FixedMedia, // Fixed hard disk media
F3_120M_512, // 3.5", 120M Floppy
F3_640_512, // 3.5" , 640KB, 512 bytes/sector
F5_640_512, // 5.25", 640KB, 512 bytes/sector
F5_720_512, // 5.25", 720KB, 512 bytes/sector
F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector
F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector
F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector
F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector
F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector
F8_256_128, // 8", 256KB, 128 bytes/sector
F3_200Mb_512, // 3.5", 200M Floppy (HiFD)
F3_240M_512, // 3.5", 240Mb Floppy (HiFD)
F3_32M_512 // 3.5", 32Mb Floppy
}
/// <summary>
/// Describes the extended geometry of disk devices and media.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
private struct DISK_GEOMETRY_EX
{
/// <summary>
/// A DISK_GEOMETRY structure.
/// </summary>
[FieldOffset(0)]
public DISK_GEOMETRY Geometry;
/// <summary>
/// The disk size, in bytes.
/// </summary>
[FieldOffset(24)]
public Int64 DiskSize;
/// <summary>
/// Any additional data.
/// </summary>
[FieldOffset(32)]
public Byte Data;
}
/// <summary>
/// Represents the format of a partition.
/// </summary>
public enum PARTITION_STYLE : uint
{
/// <summary>
/// Master boot record (MBR) format.
/// </summary>
PARTITION_STYLE_MBR = 0,
/// <summary>
/// GUID Partition Table (GPT) format.
/// </summary>
PARTITION_STYLE_GPT = 1,
/// <summary>
/// Partition not formatted in either of the recognized formats—MBR or GPT.
/// </summary>
PARTITION_STYLE_RAW = 2
}
/// <summary>
/// Contains partition information specific to master boot record (MBR) disks.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct PARTITION_INFORMATION_MBR
{
#region Constants
/// <summary>
/// An unused entry partition.
/// </summary>
public const byte PARTITION_ENTRY_UNUSED = 0x00;
/// <summary>
/// A FAT12 file system partition.
/// </summary>
public const byte PARTITION_FAT_12 = 0x01;
/// <summary>
/// A FAT16 file system partition.
/// </summary>
public const byte PARTITION_FAT_16 = 0x04;
/// <summary>
/// An extended partition.
/// </summary>
public const byte PARTITION_EXTENDED = 0x05;
/// <summary>
/// An IFS partition.
/// </summary>
public const byte PARTITION_IFS = 0x07;
/// <summary>
/// A FAT32 file system partition.
/// </summary>
public const byte PARTITION_FAT32 = 0x0B;
/// <summary>
/// A logical disk manager (LDM) partition.
/// </summary>
public const byte PARTITION_LDM = 0x42;
/// <summary>
/// An NTFT partition.
/// </summary>
public const byte PARTITION_NTFT = 0x80;
/// <summary>
/// A valid NTFT partition.
///
/// The high bit of a partition type code indicates that a partition is part of an NTFT mirror or striped array.
/// </summary>
public const byte PARTITION_VALID_NTFT = 0xC0;
#endregion
/// <summary>
/// The type of partition. For a list of values, see Disk Partition Types.
/// </summary>
[FieldOffset(0)]
[MarshalAs(UnmanagedType.U1)]
public byte PartitionType;
/// <summary>
/// If this member is TRUE, the partition is bootable.
/// </summary>
[FieldOffset(1)]
[MarshalAs(UnmanagedType.I1)]
public bool BootIndicator;
/// <summary>
/// If this member is TRUE, the partition is of a recognized type.
/// </summary>
[FieldOffset(2)]
[MarshalAs(UnmanagedType.I1)]
public bool RecognizedPartition;
/// <summary>
/// The number of hidden sectors in the partition.
/// </summary>
[FieldOffset(4)]
public uint HiddenSectors;
}
/// <summary>
/// Contains GUID partition table (GPT) partition information.
/// </summary>
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct PARTITION_INFORMATION_GPT
{
/// <summary>
/// A GUID that identifies the partition type.
///
/// Each partition type that the EFI specification supports is identified by its own GUID, which is
/// published by the developer of the partition.
/// </summary>
[FieldOffset(0)]
public Guid PartitionType;
/// <summary>
/// The GUID of the partition.
/// </summary>
[FieldOffset(16)]
public Guid PartitionId;
/// <summary>
/// The Extensible Firmware Interface (EFI) attributes of the partition.
///
/// </summary>
[FieldOffset(32)]
public UInt64 Attributes;
/// <summary>
/// A wide-character string that describes the partition.
/// </summary>
[FieldOffset(40)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 36)]
public string Name;
}
/// <summary>
/// Provides information about a drive's master boot record (MBR) partitions.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
private struct DRIVE_LAYOUT_INFORMATION_MBR
{
/// <summary>
/// The signature of the drive.
/// </summary>
[FieldOffset(0)]
public uint Signature;
}
/// <summary>
/// Contains information about a drive's GUID partition table (GPT) partitions.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
private struct DRIVE_LAYOUT_INFORMATION_GPT
{
/// <summary>
/// The GUID of the disk.
/// </summary>
[FieldOffset(0)]
public Guid DiskId;
/// <summary>
/// The starting byte offset of the first usable block.
/// </summary>
[FieldOffset(16)]
public Int64 StartingUsableOffset;
/// <summary>
/// The size of the usable blocks on the disk, in bytes.
/// </summary>
[FieldOffset(24)]
public Int64 UsableLength;
/// <summary>
/// The maximum number of partitions that can be defined in the usable block.
/// </summary>
[FieldOffset(32)]
public uint MaxPartitionCount;
}
/// <summary>
/// Contains information about a disk partition.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct PARTITION_INFORMATION_EX
{
/// <summary>
/// The format of the partition. For a list of values, see PARTITION_STYLE.
/// </summary>
[FieldOffset(0)]
public PARTITION_STYLE PartitionStyle;
/// <summary>
/// The starting offset of the partition.
/// </summary>
[FieldOffset(8)]
public Int64 StartingOffset;
/// <summary>
/// The length of the partition, in bytes.
/// </summary>
[FieldOffset(16)]
public Int64 PartitionLength;
/// <summary>
/// The number of the partition (1-based).
/// </summary>
[FieldOffset(24)]
public uint PartitionNumber;
/// <summary>
/// If this member is TRUE, the partition information has changed. When you change a partition (with
/// IOCTL_DISK_SET_DRIVE_LAYOUT), the system uses this member to determine which partitions have changed
/// and need their information rewritten.
/// </summary>
[FieldOffset(28)]
[MarshalAs(UnmanagedType.I1)]
public bool RewritePartition;
/// <summary>
/// A PARTITION_INFORMATION_MBR structure that specifies partition information specific to master boot
/// record (MBR) disks. The MBR partition format is the standard AT-style format.
/// </summary>
[FieldOffset(32)]
public PARTITION_INFORMATION_MBR Mbr;
/// <summary>
/// A PARTITION_INFORMATION_GPT structure that specifies partition information specific to GUID partition
/// table (GPT) disks. The GPT format corresponds to the EFI partition format.
/// </summary>
[FieldOffset(32)]
public PARTITION_INFORMATION_GPT Gpt;
}
[StructLayout(LayoutKind.Explicit)]
private struct DRIVE_LAYOUT_INFORMATION_UNION
{
[FieldOffset(0)]
public DRIVE_LAYOUT_INFORMATION_MBR Mbr;
[FieldOffset(0)]
public DRIVE_LAYOUT_INFORMATION_GPT Gpt;
}
/// <summary>
/// Contains extended information about a drive's partitions.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
private struct DRIVE_LAYOUT_INFORMATION_EX
{
/// <summary>
/// The style of the partitions on the drive enumerated by the PARTITION_STYLE enumeration.
/// </summary>
[FieldOffset(0)]
public PARTITION_STYLE PartitionStyle;
/// <summary>
/// The number of partitions on a drive.
///
/// On disks with the MBR layout, this value is always a multiple of 4. Any partitions that are unused have
/// a partition type of PARTITION_ENTRY_UNUSED.
/// </summary>
[FieldOffset(4)]
public uint PartitionCount;
/// <summary>
/// A DRIVE_LAYOUT_INFORMATION_MBR structure containing information about the master boot record type
/// partitioning on the drive.
/// </summary>
[FieldOffset(8)]
public DRIVE_LAYOUT_INFORMATION_UNION Mbr;
/// <summary>
/// A DRIVE_LAYOUT_INFORMATION_GPT structure containing information about the GUID disk partition type
/// partitioning on the drive.
/// </summary>
// [FieldOffset(8)]
//public DRIVE_LAYOUT_INFORMATION_GPT Gpt;
/// <summary>
/// A variable-sized array of PARTITION_INFORMATION_EX structures, one structure for each partition on the
/// drive.
/// </summary>
[FieldOffset(48)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1)]
public PARTITION_INFORMATION_EX[] PartitionEntry;
}
[StructLayout(LayoutKind.Explicit)]
private struct CREATE_DISK_MBR
{
[FieldOffset(0)]
public uint Signature;
}
[StructLayout(LayoutKind.Explicit)]
private struct CREATE_DISK_GPT
{
[FieldOffset(0)]
public Guid DiskId;
[FieldOffset(16)]
public uint MaxPartitionCount;
}
[StructLayout(LayoutKind.Explicit)]
private struct CREATE_DISK
{
[FieldOffset(0)]
public PARTITION_STYLE PartitionStyle;
[FieldOffset(4)]
public CREATE_DISK_MBR Mbr;
[FieldOffset(4)]
public CREATE_DISK_GPT Gpt;
}
static IntPtr GetHandle(int driveIndex, string physicalName)
{
IntPtr handle;
//bool locked = false;
Console.WriteLine(physicalName);
handle = CreateFile(physicalName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
if (handle == INVALID_HANDLE_VALUE)
{
Console.WriteLine(Marshal.GetLastWin32Error());
return IntPtr.Zero;
}
return handle;
}
partition can be formatted by any FS. for do this you can use fmifs.dll - he export function
VOID WINAPI FormatEx( PWSTR DriveRoot,
FMIFS_MEDIA_TYPE MediaType,
PWSTR FileSystemName, // L"NTFS"
PWSTR VolumeLabel, // OPTIONAL
BOOL QuickFormat,
DWORD ClusterSize, // 0 - default cluster size
PFMIFSCALLBACK Callback );
you can use it for format. code example on c++:
//
// Callback command types
//
enum CALLBACKCOMMAND {
PROGRESS,
DONEWITHSTRUCTURE,
UNKNOWN2,
UNKNOWN3,
UNKNOWN4,
UNKNOWN5,
INSUFFICIENTRIGHTS,
UNKNOWN7,
UNKNOWN8,
UNKNOWN9,
UNKNOWNA,
DONE, // format OK!
UNKNOWNC,
UNKNOWND,
OUTPUT,
STRUCTUREPROGRESS
};
//
// FMIFS callback definition
//
typedef BOOLEAN (WINAPI *PFMIFSCALLBACK)( CALLBACKCOMMAND Command, DWORD SubAction, PVOID ActionInfo );
enum FMIFS_MEDIA_TYPE {
Unknown = MEDIA_TYPE::Unknown, // Format is unknown
RemovableMedia = MEDIA_TYPE::RemovableMedia, // Removable media other than floppy
FixedMedia = MEDIA_TYPE::FixedMedia, // Fixed hard disk media
};
ULONG g_dwTlsIndex;
struct FORMAT_DATA
{
BOOLEAN fOk;
};
BOOLEAN FormatCb( CALLBACKCOMMAND Command, DWORD SubAction, PVOID ActionInfo )
{
DbgPrint("FormatCb(%u, %x, %p)\n", Command, SubAction, ActionInfo);
FORMAT_DATA* fd = (FORMAT_DATA*)TlsGetValue(g_dwTlsIndex);
if (Command == DONE)
{
fd->fOk = TRUE;
}
return TRUE;
}
BOOL TryFormat()
{
FORMAT_DATA fd;
fd.fOk = FALSE;
if ((g_dwTlsIndex = TlsAlloc()) != TLS_OUT_OF_INDEXES)
{
if (HMODULE hmod = LoadLibrary(L"fmifs"))
{
VOID (WINAPI * FormatEx)( PWSTR DriveRoot,
FMIFS_MEDIA_TYPE MediaType,
PWSTR FileSystemName,
PWSTR VolumeLabel,
BOOL QuickFormat,
DWORD ClusterSize,
PFMIFSCALLBACK Callback );
*(void**)&FormatEx = GetProcAddress(hmod, "FormatEx");
if (FormatEx)
{
TlsSetValue(g_dwTlsIndex, &fd);
FormatEx(L"e:", RemovableMedia, L"NTFS", L"SomeLabel", TRUE, 512, FormatCb);
}
FreeLibrary(hmod);
}
TlsFree(g_dwTlsIndex);
}
return fd.fOk;
}
Assuming that you want to use a supported API, I believe that you need either the Virtual Disk Service or the Windows Storage Management Provider depending on the version of Windows.
To the best of my knowledge, there is no I/O control code for formatting partitions. Presumably this is because doing so would require the formatting code to be part of the file system driver, which means it would always be in (virtual) memory, which would be inefficient for functionality that is used so very infrequently.
Related
Iam trying to use DeviceIOControl to create multiple partiions in USB. It is always creating only one partition.
Here is my source code
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32")]
static extern int CloseHandle(IntPtr handle);
[DllImport("kernel32")]
private static extern int DeviceIoControl
(IntPtr deviceHandle, uint ioControlCode,
IntPtr inBuffer, int inBufferSize,
IntPtr outBuffer, int outBufferSize,
ref int bytesReturned, IntPtr overlapped);
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const uint FILE_SHARE_READ = 0x00000001;
public const uint FILE_SHARE_WRITE = 0x00000002;
public const uint OPEN_EXISTING = 0x00000003;
public const uint FILE_ATTRIBUTE_NORMAL = 0x80;
public const uint FSCTL_ALLOW_EXTENDED_DASD_IO = 0x90083;
public const int DRIVE_ACCESS_RETRIES = 10;
public const int DRIVE_ACCESS_TIMEOUT = 15000;
public const uint FSCTL_LOCK_VOLUME = 0x00090018;
static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
public const uint IOCTL_DISK_GET_DRIVE_LAYOUT_EX = 0x00070050;
public const uint IOCTL_DISK_GET_DRIVE_GEOMETRY_EX = 0x000700A0;
public const uint IOCTL_DISK_CREATE_DISK = 0x0007C058;
public const uint IOCTL_DISK_UPDATE_PROPERTIES = 0x00070140;
public const uint IOCTL_DISK_SET_DRIVE_LAYOUT_EX = 0x0007C054;
public const int MIN_EXTRA_PART_SIZE = 1024 * 1024;
public static int mediaType = 0;
/// <summary>
/// Describes the geometry of disk devices and media.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct DISK_GEOMETRY
{
/// <summary>
/// The number of cylinders.
/// </summary>
[FieldOffset(0)]
public Int64 Cylinders;
/// <summary>
/// The type of media. For a list of values, see MEDIA_TYPE.
/// </summary>
[FieldOffset(8)]
public MEDIA_TYPE MediaType;
/// <summary>
/// The number of tracks per cylinder.
/// </summary>
[FieldOffset(12)]
public uint TracksPerCylinder;
/// <summary>
/// The number of sectors per track.
/// </summary>
[FieldOffset(16)]
public uint SectorsPerTrack;
/// <summary>
/// The number of bytes per sector.
/// </summary>
[FieldOffset(20)]
public uint BytesPerSector;
}
/// <summary>
/// Describes the extended geometry of disk devices and media.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
private struct DISK_GEOMETRY_EX
{
/// <summary>
/// A DISK_GEOMETRY structure.
/// </summary>
[FieldOffset(0)]
public DISK_GEOMETRY Geometry;
/// <summary>
/// The disk size, in bytes.
/// </summary>
[FieldOffset(24)]
public Int64 DiskSize;
/// <summary>
/// Any additional data.
/// </summary>
[FieldOffset(32)]
public Byte Data;
}
/// <summary>
/// Represents the format of a partition.
/// </summary>
public enum PARTITION_STYLE : uint
{
/// <summary>
/// Master boot record (MBR) format.
/// </summary>
PARTITION_STYLE_MBR = 0,
/// <summary>
/// GUID Partition Table (GPT) format.
/// </summary>
PARTITION_STYLE_GPT = 1,
/// <summary>
/// Partition not formatted in either of the recognized formats—MBR or GPT.
/// </summary>
PARTITION_STYLE_RAW = 2
}
/// <summary>
/// Contains partition information specific to master boot record (MBR) disks.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct PARTITION_INFORMATION_MBR
{
#region Constants
/// <summary>
/// An unused entry partition.
/// </summary>
public const byte PARTITION_ENTRY_UNUSED = 0x00;
/// <summary>
/// A FAT12 file system partition.
/// </summary>
public const byte PARTITION_FAT_12 = 0x01;
/// <summary>
/// A FAT16 file system partition.
/// </summary>
public const byte PARTITION_FAT_16 = 0x04;
/// <summary>
/// An extended partition.
/// </summary>
public const byte PARTITION_EXTENDED = 0x05;
/// <summary>
/// An IFS partition.
/// </summary>
public const byte PARTITION_IFS = 0x07;
/// <summary>
/// A FAT32 file system partition.
/// </summary>
public const byte PARTITION_FAT32 = 0x0B;
/// <summary>
/// A logical disk manager (LDM) partition.
/// </summary>
public const byte PARTITION_LDM = 0x42;
/// <summary>
/// An NTFT partition.
/// </summary>
public const byte PARTITION_NTFT = 0x80;
/// <summary>
/// A valid NTFT partition.
///
/// The high bit of a partition type code indicates that a partition is part of an NTFT mirror or striped array.
/// </summary>
public const byte PARTITION_VALID_NTFT = 0xC0;
#endregion
/// <summary>
/// The type of partition. For a list of values, see Disk Partition Types.
/// </summary>
[FieldOffset(0)]
[MarshalAs(UnmanagedType.U1)]
public byte PartitionType;
/// <summary>
/// If this member is TRUE, the partition is bootable.
/// </summary>
[FieldOffset(1)]
[MarshalAs(UnmanagedType.I1)]
public bool BootIndicator;
/// <summary>
/// If this member is TRUE, the partition is of a recognized type.
/// </summary>
[FieldOffset(2)]
[MarshalAs(UnmanagedType.I1)]
public bool RecognizedPartition;
/// <summary>
/// The number of hidden sectors in the partition.
/// </summary>
[FieldOffset(4)]
public uint HiddenSectors;
}
/// <summary>
/// Contains GUID partition table (GPT) partition information.
/// </summary>
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct PARTITION_INFORMATION_GPT
{
/// <summary>
/// A GUID that identifies the partition type.
///
/// Each partition type that the EFI specification supports is identified by its own GUID, which is
/// published by the developer of the partition.
/// </summary>
[FieldOffset(0)]
public Guid PartitionType;
/// <summary>
/// The GUID of the partition.
/// </summary>
[FieldOffset(16)]
public Guid PartitionId;
/// <summary>
/// The Extensible Firmware Interface (EFI) attributes of the partition.
///
/// </summary>
[FieldOffset(32)]
public UInt64 Attributes;
/// <summary>
/// A wide-character string that describes the partition.
/// </summary>
[FieldOffset(40)]
public string Name;
}
/// <summary>
/// Provides information about a drive's master boot record (MBR) partitions.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
private struct DRIVE_LAYOUT_INFORMATION_MBR
{
/// <summary>
/// The signature of the drive.
/// </summary>
[FieldOffset(0)]
public uint Signature;
}
/// <summary>
/// Contains information about a drive's GUID partition table (GPT) partitions.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
private struct DRIVE_LAYOUT_INFORMATION_GPT
{
/// <summary>
/// The GUID of the disk.
/// </summary>
[FieldOffset(0)]
public Guid DiskId;
/// <summary>
/// The starting byte offset of the first usable block.
/// </summary>
[FieldOffset(16)]
public Int64 StartingUsableOffset;
/// <summary>
/// The size of the usable blocks on the disk, in bytes.
/// </summary>
[FieldOffset(24)]
public Int64 UsableLength;
/// <summary>
/// The maximum number of partitions that can be defined in the usable block.
/// </summary>
[FieldOffset(32)]
public uint MaxPartitionCount;
}
/// <summary>
/// Contains information about a disk partition.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct PARTITION_INFORMATION_EX
{
/// <summary>
/// The format of the partition. For a list of values, see PARTITION_STYLE.
/// </summary>
[FieldOffset(0)]
public PARTITION_STYLE PartitionStyle;
/// <summary>
/// The starting offset of the partition.
/// </summary>
[FieldOffset(8)]
public Int64 StartingOffset;
/// <summary>
/// The length of the partition, in bytes.
/// </summary>
[FieldOffset(16)]
public Int64 PartitionLength;
/// <summary>
/// The number of the partition (1-based).
/// </summary>
[FieldOffset(24)]
public uint PartitionNumber;
/// <summary>
/// If this member is TRUE, the partition information has changed. When you change a partition (with
/// IOCTL_DISK_SET_DRIVE_LAYOUT), the system uses this member to determine which partitions have changed
/// and need their information rewritten.
/// </summary>
[FieldOffset(28)]
[MarshalAs(UnmanagedType.I1)]
public bool RewritePartition;
/// <summary>
/// A PARTITION_INFORMATION_MBR structure that specifies partition information specific to master boot
/// record (MBR) disks. The MBR partition format is the standard AT-style format.
/// </summary>
[FieldOffset(32)]
public PARTITION_INFORMATION_MBR Mbr;
/// <summary>
/// A PARTITION_INFORMATION_GPT structure that specifies partition information specific to GUID partition
/// table (GPT) disks. The GPT format corresponds to the EFI partition format.
/// </summary>
[FieldOffset(32)]
public PARTITION_INFORMATION_GPT Gpt;
}
[StructLayout(LayoutKind.Explicit)]
private struct DRIVE_LAYOUT_INFORMATION_UNION
{
[FieldOffset(0)]
public DRIVE_LAYOUT_INFORMATION_MBR Mbr;
[FieldOffset(0)]
public DRIVE_LAYOUT_INFORMATION_GPT Gpt;
}
/// <summary>
/// Contains extended information about a drive's partitions.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
private struct DRIVE_LAYOUT_INFORMATION_EX
{
/// <summary>
/// The style of the partitions on the drive enumerated by the PARTITION_STYLE enumeration.
/// </summary>
[FieldOffset(0)]
public PARTITION_STYLE PartitionStyle;
/// <summary>
/// The number of partitions on a drive.
///
/// On disks with the MBR layout, this value is always a multiple of 4. Any partitions that are unused have
/// a partition type of PARTITION_ENTRY_UNUSED.
/// </summary>
[FieldOffset(4)]
public uint PartitionCount;
/// <summary>
/// A DRIVE_LAYOUT_INFORMATION_MBR structure containing information about the master boot record type
/// partitioning on the drive.
/// </summary>
[FieldOffset(8)]
public DRIVE_LAYOUT_INFORMATION_UNION Mbr;
/// <summary>
/// A DRIVE_LAYOUT_INFORMATION_GPT structure containing information about the GUID disk partition type
/// partitioning on the drive.
/// </summary>
// [FieldOffset(8)]
//public DRIVE_LAYOUT_INFORMATION_GPT Gpt;
/// <summary>
/// A variable-sized array of PARTITION_INFORMATION_EX structures, one structure for each partition on the
/// drive.
/// </summary>
[FieldOffset(48)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 4)]
public PARTITION_INFORMATION_EX[] PartitionEntry;
}
[StructLayout(LayoutKind.Explicit)]
private struct CREATE_DISK_MBR
{
[FieldOffset(0)]
public uint Signature;
}
[StructLayout(LayoutKind.Explicit)]
private struct CREATE_DISK_GPT
{
[FieldOffset(0)]
public Guid DiskId;
[FieldOffset(16)]
public uint MaxPartitionCount;
}
[StructLayout(LayoutKind.Explicit)]
private struct CREATE_DISK
{
[FieldOffset(0)]
public PARTITION_STYLE PartitionStyle;
[FieldOffset(4)]
public CREATE_DISK_MBR Mbr;
[FieldOffset(4)]
public CREATE_DISK_GPT Gpt;
}
static IntPtr GetHandle(int driveIndex)
{
IntPtr handle;
//bool locked = false;
Program p = new Program();
string physicalName = p.GetPhysicalName(driveIndex);
Debug.WriteLine(physicalName);
handle = CreateFile(physicalName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
if (handle == INVALID_HANDLE_VALUE)
{
Debug.WriteLine(Marshal.GetLastWin32Error());
return IntPtr.Zero;
}
return handle;
}
//Returns true if drive Index is successfully created
//Returns false if not created successfully
static bool CreatePartition(int driveIndex)
{
IntPtr handle = GetHandle(driveIndex);
if (handle == INVALID_HANDLE_VALUE)
{
return false;
}
//Step 2: IOCTL_DISK_GET_DRIVE_GEOMETRY_EX to get the physical disk's geometry ( we need some information in it to fill partition data)
//The number of surfaces (or heads, which is the same thing), cylinders, and sectors vary a lot; the specification of the number of each is called the geometry of a hard disk.
//The geometry is usually stored in a special, battery-powered memory location called the CMOS RAM , from where the operating system can fetch it during bootup or driver initialization.
int size = 0;
DISK_GEOMETRY_EX geometry = new DISK_GEOMETRY_EX();
IntPtr lpOutBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DISK_GEOMETRY_EX)));
Marshal.StructureToPtr(geometry, lpOutBuffer, false);
int result = DeviceIoControl( handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, IntPtr.Zero, 0, lpOutBuffer,
Marshal.SizeOf(typeof(DISK_GEOMETRY_EX)),
ref size, IntPtr.Zero);
geometry = (DISK_GEOMETRY_EX)Marshal.PtrToStructure(lpOutBuffer, typeof(DISK_GEOMETRY_EX));
//Step 3: IOCTL_DISK_CREATE_DISK is used to initialize a disk with an empty partition table.
CREATE_DISK createDisk = new CREATE_DISK();
createDisk.PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR;
createDisk.Mbr.Signature = 1;
IntPtr createDiskBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CREATE_DISK)));
Marshal.StructureToPtr(createDisk, createDiskBuffer, false);
byte[] arr1 = new byte[Marshal.SizeOf(typeof(CREATE_DISK))];
Marshal.Copy(createDiskBuffer, arr1, 0, Marshal.SizeOf(typeof(CREATE_DISK)));
result = DeviceIoControl(handle, IOCTL_DISK_CREATE_DISK, createDiskBuffer, Marshal.SizeOf(typeof(CREATE_DISK)),
IntPtr.Zero, 0, ref size, IntPtr.Zero);
result = DeviceIoControl(handle, IOCTL_DISK_UPDATE_PROPERTIES, IntPtr.Zero, 0, IntPtr.Zero, 0, ref size, IntPtr.Zero);
//Step 4: IOCTL_DISK_SET_DRIVE_LAYOUT_EX to repartition a disk as specified.
//Note: use IOCTL_DISK_UPDATE_PROPERTIES to synchronize system view after IOCTL_DISK_CREATE_DISK and IOCTL_DISK_SET_DRIVE_LAYOUT_EX
/* DWORD driveLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX) * 4 * 25;
DRIVE_LAYOUT_INFORMATION_EX *DriveLayoutEx = (DRIVE_LAYOUT_INFORMATION_EX *) new BYTE[driveLayoutSize];*/
IntPtr driveLayoutbuffer = Marshal.AllocHGlobal(624);
DRIVE_LAYOUT_INFORMATION_EX driveLayoutEx = new DRIVE_LAYOUT_INFORMATION_EX();
int pn = 0;
driveLayoutEx.PartitionEntry = new PARTITION_INFORMATION_EX[4];
mediaType = (int)geometry.Geometry.MediaType;
Int64 bytes_per_track = (geometry.Geometry.SectorsPerTrack) * (geometry.Geometry.BytesPerSector);
driveLayoutEx.PartitionEntry[pn].StartingOffset = 0x123;
Int64 main_part_size_in_sectors, extra_part_size_in_sectors = 0;
main_part_size_in_sectors = (geometry.DiskSize - driveLayoutEx.PartitionEntry[pn].StartingOffset) / geometry.Geometry.BytesPerSector;
if (main_part_size_in_sectors <= 0)
{
return false;
}
extra_part_size_in_sectors = (MIN_EXTRA_PART_SIZE + bytes_per_track - 1) / bytes_per_track;
main_part_size_in_sectors = ((main_part_size_in_sectors / geometry.Geometry.SectorsPerTrack) -
extra_part_size_in_sectors) * geometry.Geometry.SectorsPerTrack;
if (main_part_size_in_sectors <= 0)
{
return false;
}
driveLayoutEx.PartitionEntry[pn].PartitionLength = 50000;
driveLayoutEx.PartitionEntry[pn].PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR;
driveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x07;
driveLayoutEx.PartitionEntry[pn].Mbr.BootIndicator = true;
pn++;
// Set the optional extra partition
// Should end on a track boundary
driveLayoutEx.PartitionEntry[pn].StartingOffset = 0x400;
driveLayoutEx.PartitionEntry[pn].PartitionLength = 26244; //TODO: Has to change
driveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0xef;
pn++;
for (uint i = 0; i < pn; i++)
{
driveLayoutEx.PartitionEntry[i].PartitionNumber = i + 1;
driveLayoutEx.PartitionEntry[i].PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR;
driveLayoutEx.PartitionEntry[i].RewritePartition = true;
}
driveLayoutEx.PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR;
driveLayoutEx.PartitionCount = 4; //It should be a multiple of 4
driveLayoutEx.Mbr.Mbr.Signature = createDisk.Mbr.Signature;
Marshal.StructureToPtr(driveLayoutEx, driveLayoutbuffer, false);
result = DeviceIoControl(handle, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, driveLayoutbuffer, 624, IntPtr.Zero, 0, ref size, IntPtr.Zero);
result = DeviceIoControl(handle, IOCTL_DISK_UPDATE_PROPERTIES, IntPtr.Zero, 0, IntPtr.Zero, 0, ref size, IntPtr.Zero);
Marshal.FreeHGlobal(driveLayoutbuffer);
Marshal.FreeHGlobal(createDiskBuffer);
Marshal.FreeHGlobal(lpOutBuffer);
return true;
}
It only creates one partition with offset to zero and partition length to full size of USB.
Iam trying this from past two days but still no solution.
I got the Solution.
It was because:
Marshal.AllocHGlobal allocated memory is not zero filled.
PARTITION_INFORMATION_GPT structure name member filled is only has 8
bytes of memory allocated instead it requires 72 bytes.
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct PARTITION_INFORMATION_GPT
{
/// <summary>
/// A GUID that identifies the partition type.
///
/// Each partition type that the EFI specification supports is identified by its own GUID, which is
/// published by the developer of the partition.
/// </summary>
[FieldOffset(0)]
public Guid PartitionType;
/// <summary>
/// The GUID of the partition.
/// </summary>
[FieldOffset(16)]
public Guid PartitionId;
/// <summary>
/// The Extensible Firmware Interface (EFI) attributes of the partition.
///
/// </summary>
[FieldOffset(32)]
public UInt64 Attributes;
/// <summary>
/// A wide-character string that describes the partition.
/// </summary>
[FieldOffset(40)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 36)]
public string Name;
}
I know i can extract a file's icon using
using (System.Drawing.Icon sysicon = System.Drawing.Icon.ExtractAssociatedIcon(filePath))
{
icon = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(
sysicon.Handle,
System.Windows.Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
}
But how can I, with no file, get the icon for a given extension?
Use the GetFileIcon method from this CodeProject article from Paul Ingles and pass .ext as the name parameter.
The GetFileIcon method is a wrapper around the native SHGetFileInfo and copied here for illustration:
public static System.Drawing.Icon GetFileIcon(string name, IconSize size,
bool linkOverlay)
{
Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();
uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES;
if (true == linkOverlay) flags += Shell32.SHGFI_LINKOVERLAY;
/* Check the size specified for return. */
if (IconSize.Small == size)
{
flags += Shell32.SHGFI_SMALLICON ; // include the small icon flag
}
else
{
flags += Shell32.SHGFI_LARGEICON ; // include the large icon flag
}
Shell32.SHGetFileInfo( name,
Shell32.FILE_ATTRIBUTE_NORMAL,
ref shfi,
(uint) System.Runtime.InteropServices.Marshal.SizeOf(shfi),
flags );
// Copy (clone) the returned icon to a new object, thus allowing us
// to call DestroyIcon immediately
System.Drawing.Icon icon = (System.Drawing.Icon)
System.Drawing.Icon.FromHandle(shfi.hIcon).Clone();
User32.DestroyIcon( shfi.hIcon ); // Cleanup
return icon;
}
Below code is also based on Paul Ingles solution, but:
Usable with WPF (ImageSource instead of Icon)
Has simple caching
Removed all stuff related to directories (I have only files in my
case)
Refactored using R# tips and wrapped with a single-class simple API
I've tested it on Windows 7 and Windows XP SP3, it works as expected with any string as a fileName.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
/// <summary>
/// Internals are mostly from here: http://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using
/// Caches all results.
/// </summary>
public static class IconManager
{
private static readonly Dictionary<string, ImageSource> _smallIconCache = new Dictionary<string, ImageSource>();
private static readonly Dictionary<string, ImageSource> _largeIconCache = new Dictionary<string, ImageSource>();
/// <summary>
/// Get an icon for a given filename
/// </summary>
/// <param name="fileName">any filename</param>
/// <param name="large">16x16 or 32x32 icon</param>
/// <returns>null if path is null, otherwise - an icon</returns>
public static ImageSource FindIconForFilename(string fileName, bool large)
{
var extension = Path.GetExtension(fileName);
if (extension == null)
return null;
var cache = large ? _largeIconCache : _smallIconCache;
ImageSource icon;
if (cache.TryGetValue(extension, out icon))
return icon;
icon = IconReader.GetFileIcon(fileName, large ? IconReader.IconSize.Large : IconReader.IconSize.Small, false).ToImageSource();
cache.Add(extension, icon);
return icon;
}
/// <summary>
/// http://stackoverflow.com/a/6580799/1943849
/// </summary>
static ImageSource ToImageSource(this Icon icon)
{
var imageSource = Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return imageSource;
}
/// <summary>
/// Provides static methods to read system icons for both folders and files.
/// </summary>
/// <example>
/// <code>IconReader.GetFileIcon("c:\\general.xls");</code>
/// </example>
static class IconReader
{
/// <summary>
/// Options to specify the size of icons to return.
/// </summary>
public enum IconSize
{
/// <summary>
/// Specify large icon - 32 pixels by 32 pixels.
/// </summary>
Large = 0,
/// <summary>
/// Specify small icon - 16 pixels by 16 pixels.
/// </summary>
Small = 1
}
/// <summary>
/// Returns an icon for a given file - indicated by the name parameter.
/// </summary>
/// <param name="name">Pathname for file.</param>
/// <param name="size">Large or small</param>
/// <param name="linkOverlay">Whether to include the link icon</param>
/// <returns>System.Drawing.Icon</returns>
public static Icon GetFileIcon(string name, IconSize size, bool linkOverlay)
{
var shfi = new Shell32.Shfileinfo();
var flags = Shell32.ShgfiIcon | Shell32.ShgfiUsefileattributes;
if (linkOverlay) flags += Shell32.ShgfiLinkoverlay;
/* Check the size specified for return. */
if (IconSize.Small == size)
flags += Shell32.ShgfiSmallicon;
else
flags += Shell32.ShgfiLargeicon;
Shell32.SHGetFileInfo(name,
Shell32.FileAttributeNormal,
ref shfi,
(uint)Marshal.SizeOf(shfi),
flags);
// Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly
var icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone();
User32.DestroyIcon(shfi.hIcon); // Cleanup
return icon;
}
}
/// <summary>
/// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code
/// courtesy of MSDN Cold Rooster Consulting case study.
/// </summary>
static class Shell32
{
private const int MaxPath = 256;
[StructLayout(LayoutKind.Sequential)]
public struct Shfileinfo
{
private const int Namesize = 80;
public readonly IntPtr hIcon;
private readonly int iIcon;
private readonly uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxPath)]
private readonly string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Namesize)]
private readonly string szTypeName;
};
public const uint ShgfiIcon = 0x000000100; // get icon
public const uint ShgfiLinkoverlay = 0x000008000; // put a link overlay on icon
public const uint ShgfiLargeicon = 0x000000000; // get large icon
public const uint ShgfiSmallicon = 0x000000001; // get small icon
public const uint ShgfiUsefileattributes = 0x000000010; // use passed dwFileAttribute
public const uint FileAttributeNormal = 0x00000080;
[DllImport("Shell32.dll")]
public static extern IntPtr SHGetFileInfo(
string pszPath,
uint dwFileAttributes,
ref Shfileinfo psfi,
uint cbFileInfo,
uint uFlags
);
}
/// <summary>
/// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example.
/// </summary>
static class User32
{
/// <summary>
/// Provides access to function required to delete handle. This method is used internally
/// and is not required to be called separately.
/// </summary>
/// <param name="hIcon">Pointer to icon handle.</param>
/// <returns>N/A</returns>
[DllImport("User32.dll")]
public static extern int DestroyIcon(IntPtr hIcon);
}
}
It can be done much simpler:
System.Drawing.Icon.ExtractAssociatedIcon("<fullPath>");
Important note: it will throw an exception if the file does not exists so worth to add validation.
Like #astef I also needed to use this for WPF, however I did require the Icons for Folders.
Since Drives and Folders don't have an extension, I utilized DirectoryInfo to determine which one is which.
For folders I always use its Closed Icon, you could however easily extend this to take Open or Closed into account.
/// <summary>
/// Internals are mostly from here: http://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using
/// Caches all results.
/// </summary>
public static class IconManager
{
private static readonly Dictionary<string, ImageSource> _smallIconCache = new Dictionary<string, ImageSource>();
private static readonly Dictionary<string, ImageSource> _largeIconCache = new Dictionary<string, ImageSource>();
/// <summary>
/// Get an icon for a given filename
/// </summary>
/// <param name="fileName">any filename</param>
/// <param name="large">16x16 or 32x32 icon</param>
/// <returns>null if path is null, otherwise - an icon</returns>
public static ImageSource FindIconForFilename(string fileName, bool large)
{
DirectoryInfo di = new DirectoryInfo(fileName);
string extension = di.Extension;
if (extension == null)
return null;
if (extension == string.Empty && di.Root.FullName == di.FullName) {
extension = "ROOT";
}
if (extension == string.Empty && di.Attributes.HasFlag(FileAttributes.Directory)) {
extension = "FOLDER";
} else {
if (di.Attributes.HasFlag(FileAttributes.Directory) && extension != "ROOT") {
extension = "FOLDER";
}
}
var cache = large ? _largeIconCache : _smallIconCache;
ImageSource icon;
if (cache.TryGetValue(extension, out icon))
return icon;
if (di.Attributes.HasFlag(FileAttributes.Directory) && extension != "ROOT") {
icon = IconReader.GetFolderIcon(fileName, large ? IconReader.IconSize.Large : IconReader.IconSize.Small, IconReader.FolderType.Closed).ToImageSource();
} else {
icon = IconReader.GetFileIcon(fileName, large ? IconReader.IconSize.Large : IconReader.IconSize.Small, false).ToImageSource();
}
if (extension != "ROOT") cache.Add(extension, icon);
return icon;
}
/// <summary>
/// http://stackoverflow.com/a/6580799/1943849
/// </summary>
static ImageSource ToImageSource(this System.Drawing.Icon icon)
{
var imageSource = Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return imageSource;
}
/// <summary>
/// Provides static methods to read system icons for both folders and files.
/// </summary>
/// <example>
/// <code>IconReader.GetFileIcon("c:\\general.xls");</code>
/// </example>
static class IconReader
{
/// <summary>
/// Options to specify the size of icons to return.
/// </summary>
public enum IconSize
{
/// <summary>
/// Specify large icon - 32 pixels by 32 pixels.
/// </summary>
Large = 0,
/// <summary>
/// Specify small icon - 16 pixels by 16 pixels.
/// </summary>
Small = 1
}
/// <summary>
/// Returns an icon for a given file - indicated by the name parameter.
/// </summary>
/// <param name="name">Pathname for file.</param>
/// <param name="size">Large or small</param>
/// <param name="linkOverlay">Whether to include the link icon</param>
/// <returns>System.Drawing.Icon</returns>
public static System.Drawing.Icon GetFileIcon(string name, IconSize size, bool linkOverlay)
{
var shfi = new Shell32.SHFILEINFO();
var flags = Shell32.SHGFI_ICON;
if (linkOverlay) flags += Shell32.SHGFI_LINKOVERLAY;
/* Check the size specified for return. */
if (IconSize.Small == size)
flags += Shell32.SHGFI_SMALLICON;
else
flags += Shell32.SHGFI_SMALLICON;
Shell32.SHGetFileInfo(name,
Shell32.FILE_ATTRIBUTE_NORMAL,
ref shfi,
(uint)Marshal.SizeOf(shfi),
flags);
// Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly
var icon = (System.Drawing.Icon)System.Drawing.Icon.FromHandle(shfi.hIcon).Clone();
User32.DestroyIcon(shfi.hIcon); // Cleanup
return icon;
}
/// <summary>
/// Options to specify whether folders should be in the open or closed state.
/// </summary>
public enum FolderType
{
/// <summary>
/// Specify open folder.
/// </summary>
Open = 0,
/// <summary>
/// Specify closed folder.
/// </summary>
Closed = 1
}
/// <summary>
/// Used to access system folder icons.
/// </summary>
/// <param name="size">Specify large or small icons.</param>
/// <param name="folderType">Specify open or closed FolderType.</param>
/// <returns>System.Drawing.Icon</returns>
public static System.Drawing.Icon GetFolderIcon(string name, IconSize size, FolderType folderType)
{
// Need to add size check, although errors generated at present!
uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_SYSICONINDEX;
if (FolderType.Open == folderType) {
flags += Shell32.SHGFI_OPENICON;
}
if (IconSize.Small == size) {
flags += Shell32.SHGFI_SMALLICON;
} else {
flags += Shell32.SHGFI_LARGEICON;
}
// Get the folder icon
Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();
Shell32.SHGetFileInfo(name,
Shell32.FILE_ATTRIBUTE_DIRECTORY,
ref shfi,
(uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi),
flags);
System.Drawing.Icon.FromHandle(shfi.hIcon); // Load the icon from an HICON handle
// Now clone the icon, so that it can be successfully stored in an ImageList
System.Drawing.Icon icon = (System.Drawing.Icon)System.Drawing.Icon.FromHandle(shfi.hIcon).Clone();
User32.DestroyIcon(shfi.hIcon); // Cleanup
return icon;
}
}
}
/// <summary>
/// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code
/// courtesy of MSDN Cold Rooster Consulting case study.
/// </summary>
public class Shell32
{
public const int MAX_PATH = 256;
[StructLayout(LayoutKind.Sequential)]
public struct SHITEMID
{
public ushort cb;
[MarshalAs(UnmanagedType.LPArray)]
public byte[] abID;
}
[StructLayout(LayoutKind.Sequential)]
public struct ITEMIDLIST
{
public SHITEMID mkid;
}
[StructLayout(LayoutKind.Sequential)]
public struct BROWSEINFO
{
public IntPtr hwndOwner;
public IntPtr pidlRoot;
public IntPtr pszDisplayName;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpszTitle;
public uint ulFlags;
public IntPtr lpfn;
public int lParam;
public IntPtr iImage;
}
// Browsing for directory.
public const uint BIF_RETURNONLYFSDIRS = 0x0001;
public const uint BIF_DONTGOBELOWDOMAIN = 0x0002;
public const uint BIF_STATUSTEXT = 0x0004;
public const uint BIF_RETURNFSANCESTORS = 0x0008;
public const uint BIF_EDITBOX = 0x0010;
public const uint BIF_VALIDATE = 0x0020;
public const uint BIF_NEWDIALOGSTYLE = 0x0040;
public const uint BIF_USENEWUI = (BIF_NEWDIALOGSTYLE | BIF_EDITBOX);
public const uint BIF_BROWSEINCLUDEURLS = 0x0080;
public const uint BIF_BROWSEFORCOMPUTER = 0x1000;
public const uint BIF_BROWSEFORPRINTER = 0x2000;
public const uint BIF_BROWSEINCLUDEFILES = 0x4000;
public const uint BIF_SHAREABLE = 0x8000;
[StructLayout(LayoutKind.Sequential)]
public struct SHFILEINFO
{
public const int NAMESIZE = 80;
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)]
public string szTypeName;
};
public const uint SHGFI_ICON = 0x000000100; // get icon
public const uint SHGFI_DISPLAYNAME = 0x000000200; // get display name
public const uint SHGFI_TYPENAME = 0x000000400; // get type name
public const uint SHGFI_ATTRIBUTES = 0x000000800; // get attributes
public const uint SHGFI_ICONLOCATION = 0x000001000; // get icon location
public const uint SHGFI_EXETYPE = 0x000002000; // return exe type
public const uint SHGFI_SYSICONINDEX = 0x000004000; // get system icon index
public const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon
public const uint SHGFI_SELECTED = 0x000010000; // show icon in selected state
public const uint SHGFI_ATTR_SPECIFIED = 0x000020000; // get only specified attributes
public const uint SHGFI_LARGEICON = 0x000000000; // get large icon
public const uint SHGFI_SMALLICON = 0x000000001; // get small icon
public const uint SHGFI_OPENICON = 0x000000002; // get open icon
public const uint SHGFI_SHELLICONSIZE = 0x000000004; // get shell size icon
public const uint SHGFI_PIDL = 0x000000008; // pszPath is a pidl
public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute
public const uint SHGFI_ADDOVERLAYS = 0x000000020; // apply the appropriate overlays
public const uint SHGFI_OVERLAYINDEX = 0x000000040; // Get the index of the overlay
public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
[DllImport("Shell32.dll")]
public static extern IntPtr SHGetFileInfo(
string pszPath,
uint dwFileAttributes,
ref SHFILEINFO psfi,
uint cbFileInfo,
uint uFlags
);
}
/// <summary>
/// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example.
/// </summary>
static class User32
{
/// <summary>
/// Provides access to function required to delete handle. This method is used internally
/// and is not required to be called separately.
/// </summary>
/// <param name="hIcon">Pointer to icon handle.</param>
/// <returns>N/A</returns>
[DllImport("User32.dll")]
public static extern int DestroyIcon(IntPtr hIcon);
}
}
I'm trying to write general interactive shell wrapper class from c#/.Net using CreateProcess() for Dos, Powershell, Plink, etc, and I've found the article Why does StandardOutput.Read() block when StartInfo.RedirectStandardInput is set to true? to write wrapper classes which redirect child process's stdin/stdout for getting powershell command execution output. As he directed, I got his source code from http://sixfeetsix.blogspot.com/2012/08/interacting-with-sub-processed-shell-in.html. However, any command line execution such as plink.exe, cmd.exe works great for redirection of stdin/stdout but powershell.exe doesn't get me the input/output correctly. It looks like powershell.exe doesn't inherit from parant process and thread for pipe. Would you give me any feedbacks for getting retValue as of "get-help" powershell command successfully?
When I run "dir" command from DosShell, it returns the output of dos command "dir" successfully. However, Powershell doesn't return "get-help" command from powershell prompt.
using System;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Diagnostics;
namespace PowershellWrapperPOC
{
class Program
{
static void Main(string[] args)
{
StringBuilder testOutput = new StringBuilder();
string retValue = null;
DosShell ds = new DosShell();
retValue = ds.Start(#"C:\Windows\System32\cmd.exe /k", #"C:\Windows\System32\");
testOutput.Append(retValue.ToString());
retValue = ds.SendAndReceive("dir");
testOutput.Append(retValue.ToString());
ds.Terminate();
Debug.Print(testOutput.ToString());
testOutput = new StringBuilder();
PowerShell ps = new PowerShell();
retValue = ps.Start(#"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe", #"C:\Windows\System32\");
testOutput.Append(retValue.ToString());
retValue = ps.SendAndReceive("get-help");
testOutput.Append(retValue.ToString());
ps.Terminate();
Debug.Print(testOutput.ToString());
}
}
public class PowerShell : CommonShell
{
public PowerShell()
{
base.SetPrintSendCommand(false);
base.SetEncoding("utf8");
base.SetExitCommand("exit");
base.SetPrompts("> ; ");
}
}
public class DosShell : CommonShell
{
public DosShell()
{
base.SetPrintSendCommand(false);
base.SetEncoding("utf8");
base.SetExitCommand("exit");
base.SetPrompts(">");
}
}
public class CommonShell : ShellProcess
{
private StringBuilder _strOutput;
private StringBuilder _strLastOutput;
private static string _escapeCharsPattern = "[\\[|\\(][0-9;?]*[^0-9;]";
private int _timeout;
public CommonShell()
{
_strOutput = new StringBuilder();
_strLastOutput = new StringBuilder();
}
public bool RemoveEscChars
{
get;
set;
}
protected override string Prompt
{
get;
set;
}
protected override string ExitCommand
{
get;
set;
}
protected override Encoding Encoding
{
get;
set;
}
public bool PrintSendCommand
{
get;
set;
}
new public string Start(string applicationName, string workDirectory)
{
if (PrintSendCommand == true)
{
_strOutput.Append(applicationName + "\r\n");
_strLastOutput.Append(applicationName + "\r\n");
}
var results = base.Start(applicationName, workDirectory);
// if remove esc chars?
if (RemoveEscChars == true)
{
string str = results.Item3;
str = Regex.Replace(str, _escapeCharsPattern, "");
_strOutput.Append(str);
_strLastOutput.Append(str);
}
else
{
_strOutput.Append(results.Item3);
_strLastOutput.Append(results.Item3);
}
return _strLastOutput.ToString();
}
new public string SendAndReceive(string toSend)
{
_strLastOutput = new StringBuilder();
if (PrintSendCommand == true)
{
_strLastOutput.Append(toSend + "\r\n");
_strOutput.Append(toSend + "\r\n");
}
// Wait forever till getting the expected prompt
var results = base.SendAndReceive(toSend + "\r\n");
// if remove esc chars?
if (RemoveEscChars == true)
{
string str = results.Item3;
str = Regex.Replace(str, _escapeCharsPattern, "");
_strOutput.Append(str);
_strLastOutput.Append(str);
}
else
{
_strOutput.Append(results.Item3);
_strLastOutput.Append(results.Item3);
}
return _strLastOutput.ToString();
}
public void SetPrompts(string prompt)
{
var enc = this.Encoding;
byte[] utfBytes = enc.GetBytes(prompt);
Prompt = enc.GetString(utfBytes);
}
public void SetEncoding(string enc)
{
string l_enc = enc.ToLower();
switch (l_enc)
{
case "utf8":
this.Encoding = Encoding.UTF8;
break;
case "utf7":
this.Encoding = Encoding.UTF7;
break;
case "utf32":
this.Encoding = Encoding.UTF32;
break;
case "ascii":
this.Encoding = Encoding.ASCII;
break;
default:
return;
}
}
public void SetExitCommand(string command)
{
ExitCommand = command;
}
public void SetPrintSendCommand(bool bPrintSendCommand)
{
PrintSendCommand = bPrintSendCommand;
}
public void SetRemoveEscChars(bool bRemove)
{
RemoveEscChars = bRemove;
}
public void SetTimeout(int timeout)
{
this._timeout = timeout;
}
public void Flush()
{
_strOutput = new StringBuilder();
_strLastOutput = new StringBuilder();
}
public string GetLastOutput()
{
return _strLastOutput.ToString();
}
public string GetOutput()
{
return _strLastOutput.ToString();
}
}
/// <summary>
/// Kernel32 Marshaling
/// </summary>
public static class Kernel32
{
/// <summary>
/// HANDLE_FLAG_INHERIT
///
/// If this flag is set, a child process created with the bInheritHandles parameter of CreateProcess set to TRUE will inherit the object handle.
///
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724935(v=vs.85).aspx
/// </summary>
public const int HANDLE_FLAG_INHERIT = 1;
/// <summary>
/// STARTF_USESTDHANDLES
///
/// The hStdInput, hStdOutput, and hStdError members contain additional information.
/// If this flag is specified when calling one of the process creation functions, the handles must be inheritable and the function's
/// bInheritHandles parameter must be set to TRUE. For more information, see Handle Inheritance.
///
/// If this flag is specified when calling the GetStartupInfo function, these members are either the handle value specified during
/// process creation or INVALID_HANDLE_VALUE.
///
/// Handles must be closed with CloseHandle when they are no longer needed.
/// This flag cannot be used with STARTF_USEHOTKEY.
///
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspx
/// </summary>
public const UInt32 STARTF_USESTDHANDLES = 0x00000100;
/// <summary>
/// STARTF_USESHOWWINDOW
///
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspx
/// </summary>
public const UInt32 STARTF_USESHOWWINDOW = 0x00000001;
/// <summary>
/// SECURITY_ATTRIBUTES
/// </summary>
public struct SECURITY_ATTRIBUTES
{
/// <summary>
/// The size, in bytes, of this structure. Set this value to the size of the SECURITY_ATTRIBUTES structure.
/// </summary>
public int length;
/// <summary>
/// A pointer to a SECURITY_DESCRIPTOR structure that controls access to the object.
/// If the value of this member is NULL, the object is assigned the default security descriptor associated with the access token of the calling process.
/// This is not the same as granting access to everyone by assigning a NULL discretionary access control list (DACL).
/// By default, the default DACL in the access token of a process allows access only to the user represented by the access token.
///
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379560(v=vs.85).aspx
/// </summary>
public IntPtr lpSecurityDescriptor;
/// <summary>
/// A Boolean value that specifies whether the returned handle is inherited when a new process is created.
/// If this member is TRUE, the new process inherits the handle.
/// </summary>
[MarshalAs(UnmanagedType.Bool)]
public bool bInheritHandle;
}
/// <summary>
/// STARTUPINFO
/// </summary>
public struct STARTUPINFO
{
/// <summary>
/// The size of the structure, in bytes.
/// </summary>
public uint cb;
/// <summary>
/// Reserved; must be NULL.
/// </summary>
public string lpReserved;
/// <summary>
/// The name of the desktop, or the name of both the desktop and window station for this process.
/// A backslash in the string indicates that the string includes both the desktop and window station names.
/// </summary>
public string lpDesktop;
/// <summary>
/// For console processes, this is the title displayed in the title bar if a new console window is created.
/// If NULL, the name of the executable file is used as the window title instead.
/// This parameter must be NULL for GUI or console processes that do not create a new console window.
/// </summary>
public string lpTitle;
/// <summary>
/// If dwFlags specifies STARTF_USEPOSITION, this member is the x offset of the upper left corner of a window if a new window is created, in pixels.
/// Otherwise, this member is ignored.
///
/// The offset is from the upper left corner of the screen. For GUI processes, the specified position is used the first time the new process calls
/// CreateWindow to create an overlapped window if the x parameter of CreateWindow is CW_USEDEFAULT.
/// </summary>
public uint dwX;
/// <summary>
/// If dwFlags specifies STARTF_USEPOSITION, this member is the y offset of the upper left corner of a window if a new window is created, in pixels.
/// Otherwise, this member is ignored.
///
/// The offset is from the upper left corner of the screen. For GUI processes, the specified position is used the first time the new process calls
/// CreateWindow to create an overlapped window if the y parameter of CreateWindow is CW_USEDEFAULT.
/// </summary>
public uint dwY;
/// <summary>
/// If dwFlags specifies STARTF_USESIZE, this member is the width of the window if a new window is created, in pixels.
/// Otherwise, this member is ignored.
///
/// For GUI processes, this is used only the first time the new process calls CreateWindow to create an overlapped window
/// if the nWidth parameter of CreateWindow is CW_USEDEFAULT.
/// </summary>
public uint dwXSize;
/// <summary>
/// If dwFlags specifies STARTF_USESIZE, this member is the height of the window if a new window is created, in pixels.
/// Otherwise, this member is ignored.
///
/// For GUI processes, this is used only the first time the new process calls CreateWindow to create an overlapped window
/// if the nHeight parameter of CreateWindow is CW_USEDEFAULT.
/// </summary>
public uint dwYSize;
/// <summary>
/// If dwFlags specifies STARTF_USECOUNTCHARS, if a new console window is created in a console process,
/// this member specifies the screen buffer width, in character columns. Otherwise, this member is ignored.
/// </summary>
public uint dwXCountChars;
/// <summary>
/// If dwFlags specifies STARTF_USECOUNTCHARS, if a new console window is created in a console process,
/// this member specifies the screen buffer height, in character rows. Otherwise, this member is ignored.
/// </summary>
public uint dwYCountChars;
/// <summary>
/// If dwFlags specifies STARTF_USEFILLATTRIBUTE, this member is the initial text and background colors
/// if a new console window is created in a console application. Otherwise, this member is ignored.
///
/// This value can be any combination of the following values:
/// FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN,
/// BACKGROUND_RED, and BACKGROUND_INTENSITY. For example, the following combination of values produces red text on a white background:
///
/// FOREGROUND_RED| BACKGROUND_RED| BACKGROUND_GREEN| BACKGROUND_BLUE
/// </summary>
public uint dwFillAttribute;
/// <summary>
/// A bitfield that determines whether certain STARTUPINFO members are used when the process creates a window.
/// This member can be one or more of the following values.
///
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspx
/// </summary>
public uint dwFlags;
/// <summary>
/// If dwFlags specifies STARTF_USESHOWWINDOW, this member can be any of the values that can be specified in the nCmdShow parameter for the
/// ShowWindow function, except for SW_SHOWDEFAULT. Otherwise, this member is ignored.
///
/// For GUI processes, the first time ShowWindow is called, its nCmdShow parameter is ignored wShowWindow specifies the default value.
/// In subsequent calls to ShowWindow, the wShowWindow member is used if the nCmdShow parameter of ShowWindow is set to SW_SHOWDEFAULT.
/// </summary>
public short wShowWindow;
/// <summary>
/// Reserved for use by the C Run-time; must be zero.
/// </summary>
public short cbReserved2;
/// <summary>
/// Reserved for use by the C Run-time; must be NULL.
/// </summary>
public IntPtr lpReserved2;
/// <summary>
/// If dwFlags specifies STARTF_USESTDHANDLES, this member is the standard input handle for the process.
/// If STARTF_USESTDHANDLES is not specified, the default for standard input is the keyboard buffer.
///
/// If dwFlags specifies STARTF_USEHOTKEY, this member specifies a hotkey value that is sent as the wParam parameter of a
/// WM_SETHOTKEY message to the first eligible top-level window created by the application that owns the process.
/// If the window is created with the WS_POPUP window style, it is not eligible unless the WS_EX_APPWINDOW extended window style is also set.
///
/// For more information, see CreateWindowEx.
///
/// Otherwise, this member is ignored.
/// </summary>
public IntPtr hStdInput;
/// <summary>
/// If dwFlags specifies STARTF_USESTDHANDLES, this member is the standard output handle for the process.
/// Otherwise, this member is ignored and the default for standard output is the console window's buffer.
///
/// If a process is launched from the taskbar or jump list, the system sets hStdOutput to a handle to the monitor
/// that contains the taskbar or jump list used to launch the process. For more information, see Remarks.
///
/// Windows 7, Windows Server 2008 R2, Windows Vista, Windows Server 2008, Windows XP, and Windows Server 2003:
/// This behavior was introduced in Windows 8 and Windows Server 2012.
/// </summary>
public IntPtr hStdOutput;
/// <summary>
/// If dwFlags specifies STARTF_USESTDHANDLES, this member is the standard error handle for the process.
/// Otherwise, this member is ignored and the default for standard error is the console window's buffer.
/// </summary>
public IntPtr hStdError;
}
/// <summary>
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684873(v=vs.85).aspx
/// </summary>
public struct PROCESS_INFORMATION
{
/// <summary>
/// A handle to the newly created process. The handle is used to specify the process in all functions that perform operations on the process object.
/// </summary>
public IntPtr hProcess;
/// <summary>
/// A handle to the primary thread of the newly created process. The handle is used to specify the thread in all functions that perform operations on the thread object.
/// </summary>
public IntPtr hThread;
/// <summary>
/// A value that can be used to identify a process. The value is valid from the time the process is created until all handles to the process are closed and the process object is freed; at this point, the identifier may be reused.
/// </summary>
public uint dwProcessId;
/// <summary>
/// A value that can be used to identify a thread. The value is valid from the time the thread is created until all handles to the thread are closed and the thread object is freed; at this point, the identifier may be reused.
/// </summary>
public uint dwThreadId;
}
/// <summary>
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
/// </summary>
/// <param name="lpApplicationName"></param>
/// <param name="lpCommandLine"></param>
/// <param name="lpProcessAttributes"></param>
/// <param name="lpThreadAttributes"></param>
/// <param name="bInheritHandles"></param>
/// <param name="dwCreationFlags"></param>
/// <param name="lpEnvironment"></param>
/// <param name="lpCurrentDirectory"></param>
/// <param name="lpStartupInfo"></param>
/// <param name="lpProcessInformation"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateProcess(string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
/// <summary>
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx
/// </summary>
/// <param name="hObject"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
/// <summary>
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365152(v=vs.85).aspx
/// </summary>
/// <param name="hReadPipe"></param>
/// <param name="hWritePipe"></param>
/// <param name="lpPipeAttributes"></param>
/// <param name="nSize"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreatePipe(out IntPtr hReadPipe,
out IntPtr hWritePipe,
ref SECURITY_ATTRIBUTES lpPipeAttributes,
uint nSize);
/// <summary>
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365779(v=vs.85).aspx
/// </summary>
/// <param name="hNamedPipe"></param>
/// <param name="pBuffer"></param>
/// <param name="nBufferSize"></param>
/// <param name="lpBytesRead"></param>
/// <param name="lpTotalBytesAvail"></param>
/// <param name="lpBytesLeftThisMessage"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern unsafe bool PeekNamedPipe(IntPtr hNamedPipe,
IntPtr pBuffer,
int nBufferSize,
IntPtr lpBytesRead,
int* lpTotalBytesAvail,
IntPtr lpBytesLeftThisMessage);
/// <summary>
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx
/// </summary>
/// <param name="hFile"></param>
/// <param name="pBuffer"></param>
/// <param name="nNumberOfBytesToRead"></param>
/// <param name="lpNumberOfBytesRead"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern unsafe bool ReadFile(IntPtr hFile,
void* pBuffer,
int nNumberOfBytesToRead,
int* lpNumberOfBytesRead,
IntPtr lpOverlapped);
/// <summary>
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx
/// </summary>
/// <param name="hFile"></param>
/// <param name="pBuffer"></param>
/// <param name="nNumberOfBytesToWrite"></param>
/// <param name="lpNumberOfBytesWritten"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern unsafe bool WriteFile(IntPtr hFile,
void* pBuffer,
int nNumberOfBytesToWrite,
int* lpNumberOfBytesWritten,
IntPtr lpOverlapped);
/// <summary>
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724935(v=vs.85).aspx
/// </summary>
/// <param name="hObject"></param>
/// <param name="dwMask"></param>
/// <param name="dwFlags"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetHandleInformation(IntPtr hObject, int dwMask, uint dwFlags);
}
public abstract class ShellProcess
{
IntPtr _hChildStdoutR, _hChildStdoutW, _hChildStderrR, _hChildStderrW, _hChildStdinR, _hChildStdinW;
Kernel32.SECURITY_ATTRIBUTES _sa, _sa_process, _sa_thread;
Kernel32.STARTUPINFO _si;
Kernel32.PROCESS_INFORMATION _pi;
string _applicationName;
protected abstract string Prompt { get; set; }
protected abstract string ExitCommand { get; set; }
protected abstract Encoding Encoding { get; set; }
static unsafe int Write(IntPtr h, byte[] buffer, int index, int count)
{
int n = 0;
fixed (byte* p = buffer)
{
if (!Kernel32.WriteFile(h, p + index, count, &n, IntPtr.Zero))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return n;
}
static unsafe int Peek(IntPtr h)
{
int n = 0;
if (!Kernel32.PeekNamedPipe(h, IntPtr.Zero, 0, IntPtr.Zero, &n, IntPtr.Zero))
throw new Win32Exception(Marshal.GetLastWin32Error());
return n;
}
static unsafe int Read(IntPtr h, byte[] buffer, int index, int count)
{
int n = 0;
fixed (byte* p = buffer)
{
if (!Kernel32.ReadFile(h, p + index, count, &n, IntPtr.Zero))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return n;
}
public virtual void SendCommand(string s)
{
byte[] bytesToWrite = Encoding.GetBytes(s);
Write(_hChildStdinW, bytesToWrite, 0, bytesToWrite.Length);
}
Tuple<string, string, string> ReadToPrompt()
{
StringBuilder strOutput = new StringBuilder();
const int bufferLength = 128;
byte[] buffer = new byte[bufferLength];
int bytesReadCount;
var stdOut = new StringBuilder(4096);
var stdErr = new StringBuilder();
string[] prompts = Prompt.Split(';');
bool foundPrompt = false;
while (!foundPrompt)
{
while (Peek(_hChildStdoutR) > 0)
{
bytesReadCount = Read(_hChildStdoutR, buffer, 0, bufferLength);
stdOut.Append(Encoding.GetString(buffer, 0, bytesReadCount));
strOutput.Append(Encoding.GetString(buffer, 0, bytesReadCount));
}
foreach (string prompt in prompts)
{
if (stdOut.ToString().Contains(prompt))
{
foundPrompt = true;
break;
}
}
//strOutput.Append(stdOut);
while (Peek(_hChildStderrR) > 0)
{
bytesReadCount = Read(_hChildStderrR, buffer, 0, bufferLength);
stdErr.Append(Encoding.GetString(buffer, 0, bytesReadCount));
strOutput.Append(Encoding.GetString(buffer, 0, bytesReadCount));
}
foreach (string prompt in prompts)
{
if (stdErr.ToString().Contains(prompt))
{
foundPrompt = true;
break;
}
}
//strOutput.Append(stdErr);
Thread.Sleep(20);
}
while (Peek(_hChildStderrR) > 0)
{
bytesReadCount = Read(_hChildStderrR, buffer, 0, bufferLength);
stdErr.Append(Encoding.GetString(buffer, 0, bytesReadCount));
strOutput.Append(Encoding.GetString(buffer, 0, bytesReadCount));
}
return new Tuple<string, string, string>(stdOut.ToString(), stdErr.ToString(), strOutput.ToString());
}
public virtual Tuple<string, string, string> SendAndReceive(string toSend)
{
SendCommand(toSend);
return ReadToPrompt();
}
public virtual Tuple<string, string, string> Start(string applicationName, string workDirectory)
{
_sa = new Kernel32.SECURITY_ATTRIBUTES
{
bInheritHandle = true,
lpSecurityDescriptor = IntPtr.Zero,
length = Marshal.SizeOf(typeof(Kernel32.SECURITY_ATTRIBUTES))
};
_sa.lpSecurityDescriptor = IntPtr.Zero;
_sa_process = new Kernel32.SECURITY_ATTRIBUTES
{
bInheritHandle = true,
lpSecurityDescriptor = IntPtr.Zero,
length = Marshal.SizeOf(typeof(Kernel32.SECURITY_ATTRIBUTES))
};
_sa_process.lpSecurityDescriptor = IntPtr.Zero;
_sa_thread = new Kernel32.SECURITY_ATTRIBUTES
{
bInheritHandle = true,
lpSecurityDescriptor = IntPtr.Zero,
length = Marshal.SizeOf(typeof(Kernel32.SECURITY_ATTRIBUTES))
};
_sa_thread.lpSecurityDescriptor = IntPtr.Zero;
if (!Kernel32.CreatePipe(out _hChildStdoutR, out _hChildStdoutW, ref _sa, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Kernel32.CreatePipe(out _hChildStderrR, out _hChildStderrW, ref _sa, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Kernel32.CreatePipe(out _hChildStdinR, out _hChildStdinW, ref _sa, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Kernel32.SetHandleInformation(_hChildStdoutR, Kernel32.HANDLE_FLAG_INHERIT, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Kernel32.SetHandleInformation(_hChildStderrR, Kernel32.HANDLE_FLAG_INHERIT, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Kernel32.SetHandleInformation(_hChildStdinW, Kernel32.HANDLE_FLAG_INHERIT, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
_si = new Kernel32.STARTUPINFO
{
wShowWindow = 0,
dwFlags = Kernel32.STARTF_USESTDHANDLES | Kernel32.STARTF_USESHOWWINDOW,
hStdOutput = _hChildStdoutW,
hStdError = _hChildStderrW,
hStdInput = _hChildStdinR
};
_si.cb = (uint)Marshal.SizeOf(_si);
_pi = new Kernel32.PROCESS_INFORMATION();
if (!Kernel32.CreateProcess(null, applicationName, IntPtr.Zero, IntPtr.Zero, true, 0, IntPtr.Zero, workDirectory, ref _si, out _pi))
throw new Win32Exception(Marshal.GetLastWin32Error());
_applicationName = applicationName;
return ReadToPrompt();
}
public void Terminate()
{
SendCommand(ExitCommand);
if (!Kernel32.CloseHandle(_hChildStderrW))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Kernel32.CloseHandle(_hChildStdoutW))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Kernel32.CloseHandle(_hChildStdinW))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Kernel32.CloseHandle(_pi.hProcess))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Kernel32.CloseHandle(_pi.hThread))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
powershell is different. I think you can not simple redirect its input and output. that's why we need to use runspace to get the output object. search "powershell c# example", lots code. here is a simple one:
Calling PowerShell From C#
depends on the powershell you use (exchange powers shell, sharepoint power shell..), you will need to add the correct snapin.
It sounds like you don't want to just call powershell commands from C#, but to act as a powershell host. Being a powershell host allows you to receive the output from commands like Write-Host and Out-String and just have a stream of strings as input and output. Examples of hosts are powershell.exe and powershell_ise.exe, but it can be a lot of work and won't make processing the results of powershell commands easier, only harder. The power of powershell is that the input and output of commands are real objects, not just strings. You can read more about it here.
If you just want to execute some powershell commands and receive their output you would be better of with this here and work with the objects the powershell commands are returning instead of wanting them to be strings. This means you have to stop using commands like Write-Host, Out-String, Format-Table, etc. Those are for formatting, not for processing results.
I have the problem that I can't seem to make GetRawInputDeviceInfo in combination with RIDI_DEVICEINFO (to try to retrieve a RID_DEVICE_INFO) is not working at all.
I get the error -1 back from the function, what should mean that there is not enough space to store the RID_DEVICE_INFO, buy I tried already to increase it to the more then needed but the effect the same.
I used the following DLLImports :
[DllImport("User32.dll")]
extern static uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);
[DllImport("User32.dll")]
unsafe extern static uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, IntPtr pcbSize);
Both with no result, but when I try these with RIDI_DEVICENAME they both work just fine.
In this case I call the function like this :
first to get the size: GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICENAME, IntPtr.Zero, pSize);
and then : GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICENAME, pData, pSize);
to get the name. Both work fine, but when I call the function like this :
int intReturn = (int)GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICEINFO, IntPtr.Zero, pInfoSize);
intReturn = (int)GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICEINFO, pInfoData, pInfoSize);
Then at first I get 0 into intReturn and also can get the correct size,
but then I get -1 into return, and whan I do a PtrToStructure it just returns wrong and seemingly random values.
Also when I after that do a GetLastWin32Error(), it return sometime 1008 or 87 , what also seems not to make any logic to me, because I don't see where I could have made the wrong parameters.
I defined RIDI_DEVICENAME and RIDI_DEVICEINFO as :
internal const uint RIDI_DEVICENAME = 0x20000007;
internal const uint RIDI_DEVICEINFO = 0x2000000b;
Can anyone help with this problem or show me a working C# example for GetRawInputDeviceInfo ?
Thanks,
Peter
I have it working in Windows 8.1 x64 (let me know if I have missed an enum or struct somewhere):
/// <summary>
/// Retrieves information about the raw input device.
/// </summary>
/// <param name="hDevice">A handle to the raw input device. This comes from the lParam of the WM_INPUT message, from the hDevice member of RAWINPUTHEADER, or from GetRawInputDeviceList. It can also be NULL if an application inserts input data, for example, by using SendInput.</param>
/// <param name="uiCommand">Specifies what data will be returned in pData.</param>
/// <param name="pData">A pointer to a buffer that contains the information specified by uiCommand. If uiCommand is RIDI_DEVICEINFO, set the cbSize member of RID_DEVICE_INFO to sizeof(RID_DEVICE_INFO) before calling GetRawInputDeviceInfo. </param>
/// <param name="pcbSize">The size, in bytes, of the data in pData. </param>
/// <returns>If successful, this function returns a non-negative number indicating the number of bytes copied to pData. If pData is not large enough for the data, the function returns -1. If pData is NULL, the function returns a value of zero. In both of these cases, pcbSize is set to the minimum size required for the pData buffer. Call GetLastError to identify any other errors.</returns>
/// <remarks>http://msdn.microsoft.com/en-us/library/windows/desktop/ms645597%28v=vs.85%29.aspx</remarks>
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern uint GetRawInputDeviceInfo(
[In] IntPtr hDevice,
[In] RawInputDeviceInformationCommand uiCommand,
[In, Out] IntPtr pData,
[In, Out] ref uint pcbSize);
public enum RawInputDeviceInformationCommand : int
{
/// <summary>
/// pData points to a string that contains the device name. For this uiCommand only, the value in pcbSize is the character count (not the byte count).
/// </summary>
RIDI_DEVICENAME = 0x20000007,
/// <summary>
/// pData points to an RID_DEVICE_INFO structure.
/// </summary>
RIDI_DEVICEINFO = 0x2000000b,
/// <summary>
/// pData points to the previously parsed data.
/// </summary>
RIDI_PREPARSEDDATA = 0x20000005
}
[StructLayout(LayoutKind.Explicit)]
public struct RID_DEVICE_INFO
{
/// <summary>
/// The size, in bytes, of the RID_DEVICE_INFO structure.
/// </summary>
[FieldOffset(0)]
public int cbSize;
/// <summary>
/// The type of raw input data.
/// </summary>
[FieldOffset(4)]
public RawInputDeviceType dwType;
/// <summary>
/// If dwType is RIM_TYPEMOUSE, this is the RID_DEVICE_INFO_MOUSE structure that defines the mouse.
/// </summary>
[FieldOffset(8)]
public RID_DEVICE_INFO_MOUSE mouse;
/// <summary>
/// If dwType is RIM_TYPEKEYBOARD, this is the RID_DEVICE_INFO_KEYBOARD structure that defines the keyboard.
/// </summary>
[FieldOffset(8)]
public RID_DEVICE_INFO_KEYBOARD keyboard;
/// <summary>
/// If dwType is RIM_TYPEHID, this is the RID_DEVICE_INFO_HID structure that defines the HID device.
/// </summary>
[FieldOffset(8)]
public RID_DEVICE_INFO_HID hid;
}
/// <summary>
/// Defines the raw input data coming from the specified mouse.
/// </summary>
/// <remarks>http://msdn.microsoft.com/en-us/library/windows/desktop/ms645589%28v=vs.85%29.aspx</remarks>
[StructLayout(LayoutKind.Sequential)]
public struct RID_DEVICE_INFO_MOUSE
{
/// <summary>
/// The identifier of the mouse device.
/// </summary>
public int dwId;
/// <summary>
/// The number of buttons for the mouse.
/// </summary>
public int dwNumberOfButtons;
/// <summary>
/// The number of data points per second. This information may not be applicable for every mouse device.
/// </summary>
public int dwSampleRate;
/// <summary>
/// TRUE if the mouse has a wheel for horizontal scrolling; otherwise, FALSE.
/// Windows XP: This member is only supported starting with Windows Vista.
/// </summary>
public bool fHasHorizontalWheel;
}
/// <summary>
/// Defines the raw input data coming from the specified keyboard.
/// </summary>
/// <remarks>http://msdn.microsoft.com/en-us/library/windows/desktop/ms645587%28v=vs.85%29.aspx</remarks>
[StructLayout(LayoutKind.Sequential)]
public struct RID_DEVICE_INFO_KEYBOARD
{
/// <summary>
/// The type of the keyboard.
/// </summary>
public int dwType;
/// <summary>
/// The subtype of the keyboard.
/// </summary>
public int dwSubType;
/// <summary>
/// The scan code mode.
/// </summary>
public int dwKeyboardMode;
/// <summary>
/// The number of function keys on the keyboard.
/// </summary>
public int dwNumberOfFunctionKeys;
/// <summary>
/// The number of LED indicators on the keyboard.
/// </summary>
public int dwNumberOfIndicators;
/// <summary>
/// The total number of keys on the keyboard.
/// </summary>
public int dwNumberOfKeysTotal;
}
/// <summary>
/// Defines the raw input data coming from the specified Human Interface Device (HID).
/// </summary>
/// <remarks>http://msdn.microsoft.com/en-us/library/windows/desktop/ms645584%28v=vs.85%29.aspx</remarks>
[StructLayout(LayoutKind.Sequential)]
public struct RID_DEVICE_INFO_HID
{
/// <summary>
/// The vendor identifier for the HID.
/// </summary>
public int dwVendorId;
/// <summary>
/// The product identifier for the HID.
/// </summary>
public int dwProductId;
/// <summary>
/// The version number for the HID.
/// </summary>
public int dwVersionNumber;
/// <summary>
/// The top-level collection Usage Page for the device.
/// </summary>
public ushort usUsagePage;
/// <summary>
/// The top-level collection Usage for the device.
/// </summary>
public ushort usUsage;
}
/// <summary>
/// The type of raw input data.
/// </summary>
public enum RawInputDeviceType : int
{
/// <summary>
/// Data comes from a mouse.
/// </summary>
RIM_TYPEMOUSE = 0,
/// <summary>
/// Data comes from a keyboard.
/// </summary>
RIM_TYPEKEYBOARD = 1,
/// <summary>
/// Data comes from an HID that is not a keyboard or a mouse.
/// </summary>
RIM_TYPEHID = 2,
}
//somewhere in your code:
IntPtr pData = IntPtr.Zero;
uint strsize = 0;
IntPtr deviceHandle = <your device handle here>;
result = GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInformationCommand.RIDI_DEVICENAME, pData, ref strsize);
pData = Marshal.AllocHGlobal(((int)strsize)*2);
result = GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInformationCommand.RIDI_DEVICENAME, pData, ref strsize);
Console.WriteLine("Result = " + result + " ErrorCode = " + Marshal.GetLastWin32Error());
string name = Marshal.PtrToStringAuto(pData);
Console.WriteLine("Name = " + name);
uint structsize = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));
RID_DEVICE_INFO di = new RID_DEVICE_INFO();
di.cbSize = (int)structsize;
pData = Marshal.AllocHGlobal((int)structsize);
result = GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInformationCommand.RIDI_DEVICEINFO, pData, ref structsize);
di = (RID_DEVICE_INFO)Marshal.PtrToStructure(pData, typeof(RID_DEVICE_INFO));
Console.WriteLine("di.dwType = " + Enum.GetName(typeof(RawInputDeviceType), di.dwType));
switch (di.dwType)
{
case RawInputDeviceType.RIM_TYPEHID:
Console.WriteLine("di.hid.dwVendorId = " + di.hid.dwVendorId);
Console.WriteLine("di.hid.dwProductId = " + di.hid.dwProductId);
Console.WriteLine("di.hid.dwVersionNumber = " + di.hid.dwVersionNumber);
Console.WriteLine("di.hid.usUsagePage = " + di.hid.usUsagePage);
Console.WriteLine("di.hid.usUsage = " + di.hid.usUsage);
break;
case RawInputDeviceType.RIM_TYPEKEYBOARD:
Console.WriteLine("di.keyboard.dwType = " + di.keyboard.dwType);
Console.WriteLine("di.keyboard.dwSubType = " + di.keyboard.dwSubType);
Console.WriteLine("di.keyboard.dwNumberOfFunctionKeys = " + di.keyboard.dwNumberOfFunctionKeys);
Console.WriteLine("di.keyboard.dwNumberOfIndicators = " + di.keyboard.dwNumberOfIndicators);
Console.WriteLine("di.keyboard.dwNumberOfKeysTotal = " + di.keyboard.dwNumberOfKeysTotal);
break;
case RawInputDeviceType.RIM_TYPEMOUSE:
Console.WriteLine("di.mouse.dwId = " + di.mouse.dwId);
Console.WriteLine("di.mouse.dwNumberOfButtons = " + di.mouse.dwNumberOfButtons);
Console.WriteLine("di.mouse.dwSampleRate = " + di.mouse.dwSampleRate);
Console.WriteLine("di.mouse.fHasHorizontalWheel = " + di.mouse.fHasHorizontalWheel);
break;
default:
break;
}
Basically I made console app that performs some task that takes a few minutes. I'd like to have it flash in the taskbar to let me know when it's done doing its thing.
Using the answer that #Zack posted and another one to find the handle of a console app I came up with this and it works great.
class Program
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
[StructLayout(LayoutKind.Sequential)]
public struct FLASHWINFO
{
public UInt32 cbSize;
public IntPtr hwnd;
public UInt32 dwFlags;
public UInt32 uCount;
public Int32 dwTimeout;
}
public const UInt32 FLASHW_ALL = 3;
static void Main(string[] args)
{
Console.WriteLine("Flashing NOW");
FlashWindow(Process.GetCurrentProcess().MainWindowHandle);
Console.WriteLine("Press any key to continue");
Console.ReadKey();
}
private static void FlashWindow(IntPtr hWnd)
{
FLASHWINFO fInfo = new FLASHWINFO();
fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
fInfo.hwnd = hWnd;
fInfo.dwFlags = FLASHW_ALL;
fInfo.uCount = UInt32.MaxValue;
fInfo.dwTimeout = 0;
FlashWindowEx(ref fInfo);
}
}
Combining the answer in the question linked in #Zack's comment and getting the hwnd of a console window using this I was able to get it working. This is the class I created:
public static class FlashWindow
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[StructLayout(LayoutKind.Sequential)]
public struct FLASHWINFO
{
public UInt32 cbSize;
public IntPtr hwnd;
public UInt32 dwFlags;
public UInt32 uCount;
public UInt32 dwTimeout;
}
public const UInt32 FLASHW_ALL = 3;
public static void Flash()
{
FLASHWINFO fInfo = new FLASHWINFO();
fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
fInfo.hwnd = GetConsoleWindow();
fInfo.dwFlags = FLASHW_ALL;
fInfo.uCount = UInt32.MaxValue;
fInfo.dwTimeout = 0;
FlashWindowEx(ref fInfo);
}
}
It doesn't ever stop flashing until it's closed but that wasn't important for my purposes.
I read that it wasn't possible to get the window handle of a console window through any direct means, but it seems to be pretty simple in .NET actually. So, it's pretty much the same as this question:
class Program
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
[StructLayout(LayoutKind.Sequential)]
public struct FLASHWINFO
{
public UInt32 cbSize;
public IntPtr hwnd;
public UInt32 dwFlags;
public UInt32 uCount;
public UInt32 dwTimeout;
}
public const UInt32 FLASHW_STOP = 0;
public const UInt32 FLASHW_CAPTION = 1;
public const UInt32 FLASHW_TRAY = 2;
public const UInt32 FLASHW_ALL = 3;
public const UInt32 FLASHW_TIMER = 4;
public const UInt32 FLASHW_TIMERNOFG = 12;
static void Main(string[] args)
{
// Give you a few seconds to alt-tab away :)
Thread.Sleep(2000);
// Flash on the task bar, until the window becomes the foreground window.
// Constants for other behaviors are defined above.
FLASHWINFO fInfo = new FLASHWINFO();
fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
fInfo.hwnd = Process.GetCurrentProcess().MainWindowHandle;
fInfo.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
fInfo.uCount = UInt32.MaxValue;
fInfo.dwTimeout = 0;
FlashWindowEx(ref fInfo);
// Wait for input so the app doesn't finish right away.
Console.ReadLine();
}
}
I looked into the issue #Davy8 had in which the flashing doesn't stop. The solution was pretty simple, just pass the FLASHW_STOP constant. To show this, I further augmented #Davy8's static class to include a StopFlashing static function. I also decided to add comments based on the Microsoft Documentation such that it is easy to see why these are applied in C#.
/// <summary>
/// Class for flashing a console window
/// <see cref="https://learn.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-flashwinfo"/>
/// </summary>
public static class FlashWindow
{
/// <summary>
/// Flashes the specified window. It does not change the active state of the window.
/// </summary>
/// <param name="pwfi">FLASHWINFO</param>
/// <see cref="https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-flashwindowex"/>
/// <returns>If the window caption was drawn as active before the call, the return value is nonzero. Otherwise, the return value is zero.</returns>
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
/// <summary>
/// Retrieves the window handle used by the console associated with the calling process.
/// </summary>
/// <see cref="https://learn.microsoft.com/en-us/windows/console/getconsolewindow"/>
/// <returns>The return value is a handle to the window used by the console associated with the calling process or NULL if there is no such associated console.</returns>
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
/// <summary>
/// Contains the flash status for a window and the number of times the system should flash the window.
/// <see cref="https://learn.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-flashwinfo"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct FLASHWINFO
{
/// <summary>
/// The size of the structure, in bytes
/// </summary>
public UInt32 cbSize;
/// <summary>
/// A handle to the window to be flashed. The window can be either opened or minimized.
/// </summary>
public IntPtr hwnd;
/// <summary>
/// The flash status. This parameter can be one or more of the following values.
/// </summary>
public UInt32 dwFlags;
/// <summary>
/// The number of times to flash the window.
/// </summary>
public UInt32 uCount;
/// <summary>
/// The rate at which the window is to be flashed, in milliseconds. If dwTimeout is zero, the function uses the default cursor blink rate.
/// </summary>
public UInt32 dwTimeout;
}
/// <summary>
/// Flash both the window caption and taskbar button. This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.
/// </summary>
public const UInt32 FLASHW_ALL = 0x00000003;
/// <summary>
/// Flash the window caption.
/// </summary>
public const UInt32 FLASHW_CAPTION = 0x00000001;
/// <summary>
/// Stop flashing. The system restores the window to its original state.
/// </summary>
public const UInt32 FLASHW_STOP = 0x00000004;
/// <summary>
/// Flash continuously, until the FLASHW_STOP flag is set.
/// </summary>
public const UInt32 FLASHW_TIMER = 4;
/// <summary>
/// Flash continuously until the window comes to the foreground.
/// </summary>
public const UInt32 FLASHW_TIMERNOFG = 0x0000000C;
/// <summary>
/// Flash the taskbar button.
/// </summary>
public const UInt32 FLASHW_TRAY = 0x00000002;
/// <summary>
/// Create an instance of the FLASHWINFO structure
/// </summary>
/// <param name="flashwConstant">One of the provided FLASHW contant values</param>
/// <param name="uCount">uCount to initialize the struct</param>
/// <param name="dwTimeout">dwTimeout to initalize the struct</param>
/// <returns>A fully instantiated FLASHWINFO struct</returns>
private static FLASHWINFO GetFLASHWINFO(UInt32 flashwConstant, UInt32 uCount = UInt32.MaxValue, UInt32 dwTimeout = 0)
{
FLASHWINFO fInfo = new FLASHWINFO
{
hwnd = GetConsoleWindow(),
dwFlags = flashwConstant,
uCount = uCount,
dwTimeout = dwTimeout
};
fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
return fInfo;
}
/// <summary>
/// Flashes the console window (continues indefinitely)
/// </summary>
public static void Flash()
{
FLASHWINFO fInfo = GetFLASHWINFO(FLASHW_ALL);
FlashWindowEx(ref fInfo);
}
/// <summary>
/// Stops the flashing of the console window
/// </summary>
public static void StopFlash()
{
FLASHWINFO fInfo = GetFLASHWINFO(FLASHW_STOP);
FlashWindowEx(ref fInfo);
}
}