2011年3月13日日曜日

C#でアイコン取得2 (マイコンピュータ)

やりたいこと
前回の方法で、ファイルやフォルダのパスがわかれば、そのアイコンを取得することが可能になりました。

ただ、この方法だとマイコンピュータのアイコンがとれない。。。

で、いろいろ調べたら方法がわかったのでまとめておきます。

こんなのをつくる。
OKボタンを押すとマイコンピュータのアイコンが表示される。

ポイント

前回との差異を中心に説明すると。

①SHGetFileInfo()の第一引数がポインタのものを準備する。またフラグにpidl用のフラグを追加。
※ここがよくわからず、ずっとpidlをstringに変換して渡そうなどとして壁にぶつかっていた。。。

②SHGetSpecialFolderLocation()にて、mycomputerのpidlを取得。
※pidlはパスの代わりになるようなものという理解でよさそう。

③ウィンドウハンドルはFormがもっており、this.handleで取り出すことができる。
これをapiにわたせばよい。(GetActiveWindowなどでとろうとしてちょっと苦労した。。。)

④pidlは解放する必要がある。

コード
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace GetMyComputerIcon
{
    public partial class Form1 : Form
    {
        private int nIndex = 0;

        public Form1()
        {
            InitializeComponent();
        }
        //===================
        // ボタン押下時のイベントハンドラ
        //===================
        private void button1_Click(object sender, EventArgs e)
        {

            IntPtr hImgSmall; //the handle to the system image list
            IntPtr hImgLarge; //the handle to the system image list
            SHFILEINFO shinfo = new SHFILEINFO();

            listView1.SmallImageList = imageList1;
            listView1.LargeImageList = imageList1;

            FolderID startLocation = FolderID.MyComputer;
            IntPtr pidlRoot = IntPtr.Zero;

            Win32.SHGetSpecialFolderLocation(this.Handle, (int)startLocation, out pidlRoot);

            //Use this to get the small Icon
            hImgSmall = Win32.SHGetFileInfo(pidlRoot, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON | Win32.SHGFI_PIDL);

            //Use this to get the large Icon
            //hImgLarge = Win32.SHGetFileInfo(pidlRoot, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON | Win32.SHGFI_PIDL);

            //The icon is returned in the hIcon member of the shinfo struct
            System.Drawing.Icon myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);

            imageList1.Images.Add(myIcon);

            //Add file name and icon to listview
            listView1.Items.Add("my computer", nIndex++);

            // pidlを解放する。 
            if (pidlRoot != IntPtr.Zero)
            {
                Win32.IMalloc malloc;
                int nret = Win32.SHGetMalloc(out malloc);
                malloc.Free(pidlRoot);
            }
        }
    }

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

    //===================
    // win 32 api dll import
    //===================
    class Win32
    {
        // SHGetFileInfo用のフラグ。 
        public const uint SHGFI_ICON = 0x100;
        public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
        public const uint SHGFI_SMALLICON = 0x1; // 'Small icon
        public const uint SHGFI_PIDL = 0x8; // pidl

        //[DllImport("shell32.dll")]   こちらはパスからアイコン取得するときに必要。今回は不要。
        //public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

        [DllImport("shell32.dll")] // これが重要。
        public static extern IntPtr SHGetFileInfo(IntPtr pIDL, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);


        [DllImport("Shell32.DLL")] // こちらで特殊フォルダのpidlを取得する。
        public static extern int SHGetSpecialFolderLocation(IntPtr hwndOwner, int nFolder, out IntPtr ppidl);

        // pidlのfree用 
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
           Guid("00000002-0000-0000-C000-000000000046")]
        public interface IMalloc
        {
            [PreserveSig]
            IntPtr Alloc([In] int cb);
            [PreserveSig]
            IntPtr Realloc([In] IntPtr pv, [In] int cb);
            [PreserveSig]
            void Free([In] IntPtr pv);
            [PreserveSig]
            int GetSize([In] IntPtr pv);
            [PreserveSig]
            int DidAlloc(IntPtr pv);
            [PreserveSig]
            void HeapMinimize();
        }
        [DllImport("Shell32.DLL")]
        public static extern int SHGetMalloc(out IMalloc ppMalloc);
    }

    //===================
    // SHGetSpecialFolderLocationに使用するFolderのIDの定義。
    // ここをかえるといろいろな特殊フォルダpidlが取得できる。
    //===================
    public enum FolderID
    {
        Desktop = 0x0000,
        Printers = 0x0004,
        MyDocuments = 0x0005,
        Favorites = 0x0006,
        Recent = 0x0008,
        SendTo = 0x0009,
        StartMenu = 0x000b,
        MyComputer = 0x0011,
        NetworkNeighborhood = 0x0012,
        Templates = 0x0015,
        MyPictures = 0x0027,
        NetAndDialUpConnections = 0x0031,
    }
}

参考
・Visual C# を使用して [フォルダの参照] コモン ダイアログ ボックスをラップするマネージ コンポーネントを実装する方法
http://support.microsoft.com/kb/306285/ja

・シェルネームスペースとPIDL
http://yokohama.cool.ne.jp/chokuto/urawaza/com/shell3.html

2011年3月8日火曜日

C#でアイコン取得(フォルダ)

やりたいこと

フォルダやドライブのアイコンを取得したいと思い、
ググってたところ、こちらのページにたどりつきました。


記載の通りに書いたところアイコンがとれました。

こんなのができる。


コード


参考のページの通りに書いてみたもの。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace GetIconSample
{
    public partial class Form1 : Form
    {
        private int nIndex = 0;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            IntPtr hImgSmall; //the handle to the system image list
            IntPtr hImgLarge; //the handle to the system image list
            string fName; //  'the file name to get icon from
            SHFILEINFO shinfo = new SHFILEINFO();

            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            openFileDialog1.InitialDirectory = "c:\\temp\\";
            openFileDialog1.Filter = "All files (*.*)|*.*";
            openFileDialog1.FilterIndex = 2;
            openFileDialog1.RestoreDirectory = true;

            listView1.SmallImageList = imageList1;
            listView1.LargeImageList = imageList1;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                fName = openFileDialog1.FileName;
                //Use this to get the small Icon
                hImgSmall = Win32.SHGetFileInfo(fName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON);

                //Use this to get the large Icon
                //hImgLarge = Win32.SHGetFileInfo(fName, 0, 
                //    ref shinfo, (uint)Marshal.SizeOf(shinfo), 
                //    Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);

                //The icon is returned in the hIcon member of the shinfo struct
                System.Drawing.Icon myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);

                imageList1.Images.Add(myIcon);

                //Add file name and icon to listview
                listView1.Items.Add(fName, nIndex++);
            }
        }
    }

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

    class Win32
    {
        public const uint SHGFI_ICON = 0x100;
        public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
        public const uint SHGFI_SMALLICON = 0x1; // 'Small icon

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
    }
}

2011年3月5日土曜日

office 2010 段落番号が振りなおされて あわわわとなるとき

■あわわわとなったとき
(こうしたいのに)
1.1 ABC
1.2 CDE
あいうえお
1.3 FGH
1.4 GHI

(こうなった)

1.1 ABC
1.2 CDE
あいうえお
1.1 FGH
1.2 GHI


あわわわわ。

■こうする
ホーム -> 段落 -> アウトライン -> 新しいアウトラインの定義
で"リストを開始するレベルを指定する"をOFFにする。



■参考にしたページ
Word 2007/2010: 段落番号を振り直すことができない
http://www.office-qa.com/Word/wd220.htm