C#メモ SHGetFileInfo()メソッドを使ってファイルのプロパティの全般タブに表示されるファイルの種類の文字列を取得してみる

C#

ファイルの種類は拡張子でも判別できるんだけど同じアプリでもいろんな拡張子(例えばExcelだとxls、xlsx、xlsmとか)だったりする場合があるので、別の判別方法はないものかと。
ファイルのプロパティにファイルの種類ってのがあるからとりあえずこいつを使ってみようと思ったのが発端。

ネットに聞いてみたけど、C#のAPIになくて..調べるのに予想以上に時間かかったのでメモっとくことに。
ポイントはこんな感じ。

  • IWshRuntimeLibrary(Windows Script Host Object Model)を参照する
  • Windows APIのうちSHGetFileInfoメソッドを使う

今回はコンソールアプリで試すことにして準備としてはCOMのうち"Windows Script Host Object Model"ってのの参照を追加するように設定する。

設定できると、ソリューションエクスプローラーのプロジェクトのツリーの中で参照ってとこに"IWshRuntimeLibrary"ってのが追加される。

んで、実際のコードはこんな感じ。
まずは、Windows APIのSHGetFileInfoメソッドをインポートする定義はこんな感じ。

/// <summary>
/// SHGetFileInfoメソッドの定義
/// </summary>
/// <param name="location">ファイルの場所</param>
/// <param name="attribute">情報を取得するファイルの属性</param>
/// <param name="information">ファイル情報の構造体</param>
/// <param name="size">構造体のサイズ</param>
/// <param name="flag">取得する情報のフラグ</param>
/// <returns>ファイル情報のポインタ</returns>
[System.Runtime.InteropServices.DllImport("shell32.dll")]
private static extern IntPtr SHGetFileInfo(string location, uint attribute, ref ShellFileInformation information, uint size, uint flag);

次にファイル情報を保持する構造体の定義はこんな感じ。
上で定義したメソッドの出力引数になる。

/// <summary>
/// ファイル情報の構造体
/// <para>AttributeとTypeNameはサイズを指定する必要がある</para>
/// </summary>
private struct ShellFileInformation
{
	public IntPtr HandleIcon;
	public IntPtr IndexIcon;
	public int Attribute;
	[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst =260)]
	public string DisplayName;
	[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 80)]
	public string TypeName;
}

それから、エントリーポイントのコードはこんな感じ。

/// <summary>
/// エントリーポイント
/// </summary>
/// <param name="arguments"></param>
static void Main(string[] arguments)
{
	try
	{
		// ファイル情報を取得する
		// ※引数の指定はこんな感じ
		//    indexはflagが0(SHGFI_USEFILEATTRIBUTES[0x00000010]のときにだけ使うみたい)
		//    flagはSHGFI_TYPENAME[0x000000400]
		ShellFileInformation information = new ShellFileInformation();
		string location = @"C:\Users\tetsuyanbo\Desktop\sample.docx";
		uint index = 0;
		uint flag = 0x400;
		IntPtr pointer = SHGetFileInfo(location, index, ref information, (uint)System.Runtime.InteropServices.Marshal.SizeOf(information), flag);
		if(pointer == IntPtr.Zero)
		{
			throw new Exception("pointer is null");
		}
		Console.WriteLine("{0}のファイルの種類:" + information.TypeName, location);
	}
	catch(Exception exception)
	{
		Console.WriteLine(exception.Message);
	}
	finally
	{
		// 速攻で終わってしまうのでキー入力待ちにして確認できるようにしとく
		Console.ReadKey();
	}
}

実行してみたらこんな感じ…今回はWordのファイルを試してみたんだけど、ちゃんと"Microsoft Word 文章"ってダイアログに表示されている文字列と同じ内容になっとる。

んまま、明日への自分へのメモってことで。