HDD容量の取得とLARGE_INTEGERの扱い

Delphi,OS,Programing,Windows,Windows API

HDD容量を取得する場合は、Windows APIにあるGetDiskFreeSpace関数を使うと各変数に色々値をぴったんこしてくれるわけですが

僕、最初普通にこの「GetDiskFreeSpace関数」の方を使ってたんですね。

そしたら正しい値が返ってこないというわけで。

https://msdn.microsoft.com/ja-jp/library/cc429305.aspx

MSDNを読んでみたら、そりゃそうだって感じなんですが
それぞれのポインタ変数はDWORD型で定義されてるんで、32bitしかデータ長がないわけで。

ページ下の方にも書いてありましたけど、2GB以上の容量を持つ場合正確な値を返さないともありますね。

そりゃ無理だわ。

ってことで、上位版(?)の「GetDiskFreeSpaceEx関数」の方を使ってみました。

https://msdn.microsoft.com/ja-jp/library/cc429308.aspx

Exってついてるあたり凄みを感じちゃう!!!ってのはとりあえず置いといて。

この関数はそれぞれPULARGE_INTEGER(ポインタ型でなければULARGE_INTEGER)で定義されてるので、64bitまで扱えます。

ここで引っかかってしまったのが、ULARGE_INTEGERの扱い方。

こいつ、構造体だったんですな(

プロトタイプ宣言だと

typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
};
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER;
typedef LARGE_INTEGER *PLARGE_INTEGER;
typedef union _ULARGE_INTEGER {
struct {
DWORD LowPart;
DWORD HighPart;
};
struct {
DWORD LowPart;
DWORD HighPart;
} u;
ULONGLONG QuadPart;
} ULARGE_INTEGER;
typedef ULARGE_INTEGER *PULARGE_INTEGER;

となってます。
これを見ると分かる通り、上位32bitと下位32bit(それぞれDWORD型)のメンバで構成されてるようで
LowPartが下位32bit、HighPartが上位32bitになります。
2つまとめたのがQuadPartで、これがLONGLONG型。

つまるところ、LARGE_INTEGER64bit分をまとめて数値代入したりなんだりするには、QuadPartを使わなきゃいけないぜ!ってこと。

それをふまえて。。。

Function TForm1.HDDFreeSpace:ULARGE_INTEGER;
var
lpRootPathName : PWideChar;
FreeByteAvailable, TotalNumberOfByte : Int64;
TotalNumberOfFreeByte : ULARGE_INTEGER;
Root : string;
begin
//  string型をPWideChar型に変換
Root := 'C:\';
GetMem(lpRootPathName,length(root)+1);
StrPCopy(lpRootPathName,root);
FreeMem(lpRootPathName);
GetDiskFreeSpaceEX(lpRootPathName, FreeByteAvailable, TotalNumberOfByte, @TotalNumberOfFreeByte);
Result := TotalNumberOfFreeByte;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Lines.Add(HDDFreeSpace.QuadPart.ToString);
end;

あ、System.SysUtilsをuses句に追加は必要。
このソースだと、Cドライブのみなんで数行追加するなりなんなりで汎用性は高めてください←

普段から「あ、こんな関数あるんだーこれ使えばよくねー?」みたいな軽いノリでざっくり組むから変なところに引っかかる(

ちゃんと読まなきゃダメな(