C#でWin APIのShell Lightweight Utility Functionsを用いてバイトの単位を変換する補助関数のコードです。拡張メソッドとして定義していますが、thisを外せば関数として利用することもできます。this UInt64 value等のUInt64部分を変更することで対応する型を増やすことができます。
StrFormatByteSizeExWの対応バージョンがWindows Vista with SP1 [desktop apps only]&Shlwapi.dll (version 6.0 or later)、StrFormatByteSizeWの対応バージョンがWindows 2000 Professional, Windows XP [desktop apps only]&Shlwapi.dll (version 4.71 or later)で後者の方が対応範囲が広いことから、フラグなしバージョンはStrFormatByteSizeWを利用しています。
// StringByteFormatExtensions.cs using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Text; namespace Potisan.Windows.ByteFormat { [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)] public static class StringByteFormatExtensions { [SuppressUnmanagedCodeSecurity] private static class NativeMethods { [DllImport("shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr StrFormatByteSizeW( Int64 qdw, StringBuilder pszBuf, UInt32 cchBuf); [DllImport("shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr StrFormatByteSizeExW( UInt64 qdw, StrFormatByteSizeExFlags flags, StringBuilder pszBuf, UInt32 cchBuf); } private const int ERROR_INSUFFICIENT_BUFFER = 122; [Flags] public enum StrFormatByteSizeExFlags { RoundToNearestDisplayedDigit = 1, TruncateUndisplayedDEcimalDigits = 2, } public static String FormatByteSize(this Int64 value, int expanding = 256) { StringBuilder buffer = new StringBuilder(expanding); while (NativeMethods.StrFormatByteSizeW( value, buffer, checked((uint)buffer.Capacity)) != IntPtr.Zero && buffer.Length + 1 == buffer.Capacity) { buffer.Capacity += expanding; } if (Marshal.GetLastWin32Error() != 0) throw new Win32Exception(); return buffer.ToString(); } public static String FormatByteSize(this Int32 value, int expanding = 256) { return FormatByteSize((Int64)value, expanding); } public static String FormatByteSize(this UInt32 value, int expanding = 256) { return FormatByteSize((Int64)value, expanding); } public static String FormatByteSize(this UInt64 value, int expanding = 256) { return FormatByteSize((Int64)value, expanding); } public static String FormatByteSize(this UInt64 value, StrFormatByteSizeExFlags flags, int expanding = 256) { StringBuilder buffer = new StringBuilder(expanding); while (NativeMethods.StrFormatByteSizeExW( value, flags, buffer, checked((uint)buffer.Capacity)) != IntPtr.Zero && buffer.Length + 1 == buffer.Capacity) { buffer.Capacity += expanding; } if (Marshal.GetLastWin32Error() != 0) throw new Win32Exception(); return buffer.ToString(); } public static String FormatByteSize(this UInt32 value, StrFormatByteSizeExFlags flags, int expanding = 256) { return FormatByteSize((UInt64)value, flags, expanding); } public static String FormatByteSize(this Int32 value, StrFormatByteSizeExFlags flags, int expanding = 256) { return FormatByteSize((UInt64)value, flags, expanding); } public static String FormatByteSize(this Int64 value, StrFormatByteSizeExFlags flags, int expanding = 256) { return FormatByteSize((UInt64)value, flags, expanding); } } }
using System.Text; using System.Windows.Forms; using Potisan.Windows.ByteFormat; namespace VolumeDeviceIoControl1 { static class Program { static void Main() { StringBuilder builder = new StringBuilder(); long i = 12345678910; builder.AppendLine(i.FormatByteSize()); builder.AppendLine(i.FormatByteSize( StringByteFormatExtensions.StrFormatByteSizeExFlags.RoundToNearestDisplayedDigit)); // 11.4 GB // 11.5 GB MessageBox.Show(builder.ToString()); } } }
2021/3/10:この記事は別のブログで投稿した記事を移動したものです。