C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: SHGetFileInfoで取得すると特定フォルダ名でエラー


(過去ログ 79 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■46805 / inTopicNo.1)  SHGetFileInfoで取得すると特定フォルダ名でエラー
  
□投稿者/ Crowe (1回)-(2010/02/11(Thu) 11:06:44)

分類:[C#] 

Windowsのフォルダを指定して、その内容をリストビューに表示するものを作成しています。

WinAPIのSHGetFileInfoを使用してファイル情報(アイコン)を取得する場合ですが、
フォルダ名に中国語と思われるものが含まれるとうまくデータを取得できず
下記のエラーが発生します。(この掲示板でも文字化けとなるような文字)
>Icon に渡された Win32 ハンドルが有効ではないか、または型が正しくありません。

エラーとならずにファイル情報を取得するにはどのようにすればよろしいでしょうか?

#フォルダ名にそんな名前をつけるな!とは言えないもので
引用返信 編集キー/
■46807 / inTopicNo.2)  Re[1]: SHGetFileInfoで取得すると特定フォルダ名でエラー
□投稿者/ 魔界の仮面弁士 (1488回)-(2010/02/11(Thu) 11:24:20)
No46805 (Crowe さん) に返信
> WinAPIのSHGetFileInfoを使用してファイル情報(アイコン)を取得する場合ですが、
現象を再現可能な、最低限のソースコードを掲載できますか?

> フォルダ名に中国語と思われるものが含まれるとうまくデータを取得できず
Unicode 版ではなく、ANSI 版を呼び出してしまっているのだと思います。
元コードを提示してもらえれば、何か指摘できるかも知れません。

# 恐らくは、DllImport か MarshalAs の指定に問題があると予想…。
引用返信 編集キー/
■46809 / inTopicNo.3)  Re[2]: SHGetFileInfoで取得すると特定フォルダ名でエラー
□投稿者/ Crowe (2回)-(2010/02/11(Thu) 12:24:55)
No46807 (魔界の仮面弁士 さん) に返信
エラー時にshfiの中身が
shfi.dwAttributes : 0
shfi.hIcon : 0
shfi.iIcon : 0
shfi.szDisplayName : ""
shfi.szTypeName : ""
となっているせいでエラーになるようです。

----

[DllImport("shell32.dll")]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttribs, out SHFILEINFO psfi, uint cbFileInfo, SHGFI uFlags);

[Flags]
public enum SHGFI
{
    SHGFI_ICON = 0x000000100,
    SHGFI_DISPLAYNAME = 0x000000200,
    SHGFI_TYPENAME = 0x000000400,
    SHGFI_LARGEICON = 0x000000000,
    SHGFI_SMALLICON = 0x000000001,
    SHGFI_OPENICON = 0x000000002,
    SHGFI_USEFILEATTRIBUTES = 0x000000010
}

public struct SHFILEINFO
{
    public IntPtr hIcon;
    public int iIcon;
    public uint dwAttributes;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string szDisplayName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
    public string szTypeName;
}

private void GetExplorerListviewFile(string dir)
{
    IntPtr hImageSmall;
    IntPtr hImageLarge;
    int i = 0;
    lvExplorer.Clear();
    imageList32x.Images.Clear();
    imageList16x.Images.Clear();
    foreach (string s in System.IO.Directory.GetFileSystemEntries(dir))
    {
        ShellAPI.SHFILEINFO shfi = new ShellAPI.SHFILEINFO();
        FileInfo fi = new FileInfo(s);

        // アイコン取得
        hImageLarge = ShellAPI.SHGetFileInfo(
            s, 0, out shfi, (uint)Marshal.SizeOf(shfi),
            ShellAPI.SHGFI.SHGFI_ICON | ShellAPI.SHGFI.SHGFI_LARGEICON);
        imageList32x.Images.Add(Icon.FromHandle(shfi.hIcon));
        hImageSmall = ShellAPI.SHGetFileInfo(
            s, 0, out shfi, (uint)Marshal.SizeOf(shfi),
            ShellAPI.SHGFI.SHGFI_ICON | ShellAPI.SHGFI.SHGFI_SMALLICON);
        imageList16x.Images.Add(Icon.FromHandle(shfi.hIcon));

        //リストビューにアイテムを追加
        lvExplorer.Items.Add(
            new ListViewItem(new string[]{fi.Name,Directory.GetCreationTime(fi.FullName).ToString(),
			    Directory.GetLastAccessTime(fi.FullName).ToString()}
            , i++)
        );
    }
}

----

下記のサイトのコードでも実験してみましたが、同じエラーとなりました。
http://support.microsoft.com/kb/319350/ja
#適当な中国語に翻訳したファイル名のものを開く

引用返信 編集キー/
■46810 / inTopicNo.4)  Re[3]: SHGetFileInfoで取得すると特定フォルダ名でエラー
□投稿者/ Hongliang (559回)-(2010/02/11(Thu) 13:15:21)
魔界の仮面弁士さんのご指摘通り、ANSI 版を呼び出してますね。
DllImport 属性や StructLayout 属性は、C# ではデフォルトが CharSet = CharSet.Ansi なので、関数のエントリが A と W 両方あるものは A の方を呼び出し、String は ANSI(日本語環境の場合は Shift_JIS)に変換されて関数に渡されます。

DllImport 属性、および現在は付けていないようですが使用する構造体の方にも StructLayout 属性によって CharSet を CharSet.Unicode か CharSet.Auto にしてください。
DllImport の CharSet が CharSet.Unicode だと自動的に W の方の関数が呼び出されます。CharSet.Auto の場合 NT 系の OS では Unicode として、9x 系 OS では ANSI として扱われます。
// 9x 系では SHGetFileInfoW は実装されてないらしいので、CharSet.Unicode にするとまともに動かないですが。
引用返信 編集キー/
■46811 / inTopicNo.5)  Re[4]: SHGetFileInfoで取得すると特定フォルダ名でエラー
□投稿者/ Crowe (3回)-(2010/02/11(Thu) 13:44:35)
魔界の仮面弁士さん、Hongliangさん、ありがとうございました。

[DllImport("shell32.dll", CharSet = CharSet.Auto)]
としたところ、うまく名称を取得することができました。
キャラセットを明示的に指定する必要があるのですね。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -