Ответы с форумов MSDN

WPF - Отобразить в WebBrowser содержимое системной папки Мой компьютер

Date: 26.08.2019 12:14:49

Например так:

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Net;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        const string prefix = "MyComputer";
        const int port = 8080;
        ShellItemsHttpListener listener;
        public static Guid FOLDERID_ComputerFolder = new Guid("0AC0837C-BBF8-452A-850D-79D08E667CA7");        

        public MainWindow()
        {         
            InitializeComponent();
            List<ShellItem> items = GetItems(FOLDERID_ComputerFolder); //получаем список элементов каталога
            listener = new ShellItemsHttpListener(items, prefix, port);
            listener.Start(); //запускаем HTTP-сервер
            webbrowser.Navigate("http://localhost:" + port.ToString() + "/" + prefix + "/"); //открываем страницу в WebBrowser
            webbrowser.Navigating += webbrowser_Navigating;
        }

        void webbrowser_Navigating(object sender, System.Windows.Navigation.NavigatingCancelEventArgs e)
        {
            //обработка перенаправлений URL с http:// на file://
            Uri uri = listener.ProcessRedirect(e.Uri.AbsoluteUri);
            if (uri != null) { webbrowser.Navigate(uri); e.Cancel = true; }            
        }

        private void bHome_Click(object sender, RoutedEventArgs e)
        {            
            webbrowser.Navigate("http://localhost:" + port.ToString() + "/" + prefix + "/");    
        }

        public static List<ShellItem> GetItems(Guid FolderID) //Получает список элементов каталога по GUID
        {            
            IntPtr p = IntPtr.Zero;
            IShellFolder pFolder = null;
            IEnumIDList pEnum = null;
            IntPtr pItem = IntPtr.Zero;                      
            IntPtr lpStr = IntPtr.Zero;
            STRRET strret;
            Guid guid = typeof(IShellFolder).GUID;
            List<ShellItem> items = new List<ShellItem>();
            ShellItem si;          

            try
            {
                int hr = SHGetKnownFolderIDList(ref FolderID, 0, IntPtr.Zero, out p);
                if (hr != 0) throw Marshal.GetExceptionForHR(hr);

                hr = SHBindToObject(null, p, null, ref guid, out pFolder);
                if (hr != 0) throw Marshal.GetExceptionForHR(hr);
                                
                pFolder.EnumObjects(IntPtr.Zero, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, out pEnum); 

                while (true)
                {
                    pItem = IntPtr.Zero; 
                    uint res = pEnum.Next(1, out pItem, IntPtr.Zero);
                    if (res != 0) break;
                    si = new ShellItem();

                    //display name
                    lpStr = IntPtr.Zero;
                    strret = new STRRET();
                    pFolder.GetDisplayNameOf(pItem, SHGDN_NORMAL, out strret); 
                    hr = StrRetToStr(ref strret, pItem, out lpStr);
                    if (hr != 0) throw Marshal.GetExceptionForHR(hr);
                    string s = Marshal.PtrToStringUni(lpStr);
                    si.DisplayName = s;
                    CoTaskMemFree(lpStr);

                    //path
                    lpStr = IntPtr.Zero;
                    strret = new STRRET();
                    pFolder.GetDisplayNameOf(pItem, SHGDN_FORPARSING, out strret);
                    hr = StrRetToStr(ref strret, pItem, out lpStr);
                    if (hr != 0) throw Marshal.GetExceptionForHR(hr);
                    s = Marshal.PtrToStringUni(lpStr);
                    try { si.Path = new Uri(s); }
                    catch (UriFormatException) { si.Path = new Uri("file://localhost/"); }
                    CoTaskMemFree(lpStr);

                    //icon
                    Guid iid_IIExtractIcon = typeof(IExtractIcon).GUID;
                    IExtractIcon pExtract;
                    pFolder.GetUIObjectOf(IntPtr.Zero, 1, new IntPtr[] { pItem }, ref iid_IIExtractIcon, 0, out pExtract);
                    
                    StringBuilder sbIcon = new StringBuilder(260);
                    int index=0;
                    uint flags; 
                    hr = pExtract.GetIconLocation(GIL_FORSHELL, sbIcon, 260, out index, out flags);
                    if (hr == 0)
                    {
                        IntPtr hIconSmall = IntPtr.Zero, hIconLarge = IntPtr.Zero;
                        hr = pExtract.Extract(sbIcon.ToString(), (uint)index, out hIconLarge, out hIconSmall, 0x00140014);
                        if (hr == 0 && hIconSmall != IntPtr.Zero)
                        {
                            var icon = System.Drawing.Icon.FromHandle(hIconSmall);
                            var bitmap = icon.ToBitmap();

                            using (bitmap)
                            {
                                MemoryStream ms = new MemoryStream();
                                bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                                si.Image = ms.ToArray();
                            }

                            DestroyIcon(hIconSmall);
                            DestroyIcon(hIconLarge);
                        }
                        else { si.Image = new byte[0]; }                       
                    }
                    else
                    {
                        si.Image = new byte[0];
                    }
                    items.Add(si);
                    CoTaskMemFree(pItem);
                }

                return items;
            }
            finally
            {
                if (p != IntPtr.Zero) CoTaskMemFree(p);
                if (pFolder != null) Marshal.ReleaseComObject(pFolder);
                if (pEnum != null) Marshal.ReleaseComObject(pEnum);
            }

        }                     

        public const uint SHGFI_DISPLAYNAME = 0x000000200;
        public const uint SHGFI_ICON = 0x000000100;
        public const uint SHGFI_PIDL = 0x000000008;
        public const uint GIL_FORSHELL = 0x0002;
        public const int SHGDN_NORMAL = 0x0000;
        public const int SHGDN_FORPARSING = 0x8000;
        public const int SHCONTF_FOLDERS = 0x0020;
        public const int SHCONTF_NONFOLDERS = 0x0040;                

        [DllImport("shell32.dll")]
        public static extern int SHGetKnownFolderIDList(ref Guid rfid, int dwFlags, IntPtr hToken, out IntPtr ppidl);
        
        [DllImport("ole32.dll")]
        static extern void CoTaskMemFree(IntPtr pv);
        
        [DllImport("shell32.dll")]        
        static extern int SHBindToObject(
            IShellFolder psf,
            IntPtr pidl,
            [MarshalAs(UnmanagedType.IUnknown)] object pbc,
            ref Guid riid,
            out IShellFolder ppv);

        [DllImport("Shlwapi.dll", CharSet = CharSet.Unicode)]
        static extern int StrRetToStr( ref STRRET pstr,  IntPtr pidl, out IntPtr ppsz);
        
        [DllImport("user32.dll")]
        static extern bool DestroyIcon(IntPtr hIcon);
    }

    public struct ShellItem
    {
        public string DisplayName { get; set; }
        public Uri Path { get; set; }
        public byte[] Image { get; set; }
    }

    public class ShellItemsHttpListener //возвращает содержимое каталога в виде веб-страницы
    {
        Dictionary<string, byte[]> images; //таблица изображений
        Dictionary<string, Uri> redirects; //таблица редиректов
        string html;
        string urlprefix;
        int httpport;
        HttpListener listener;        

        public ShellItemsHttpListener(List<ShellItem> items, string prefix, int port)
        {
            StringBuilder sb = new StringBuilder();
            int n = 1;

            //генерируем веб-страницу...
            //устанавливаем режим IE8, чтобы работали стили
            sb.Append("<html><head><meta charset=\"utf-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=8\" /><style>");

            //устанавливаем стили, имитирующий внешний вид проводника (в режиме просмотра "Список")
            sb.Append("a { color: black; text-decoration: none;  } a:hover { color: black; text-decoration: underline;} ");
            sb.Append("tr:hover { background-color: lightblue;} img {border:none;}");
            sb.Append("</style></head><body>");

            //формируем список элементов
            sb.Append("<table cellspacing=\"0\" border=\"0\">");
            images = new Dictionary<string, byte[]>();
            redirects = new Dictionary<string, Uri>();
            
            foreach (ShellItem item in items)
            {                
                sb.Append("<tr><td><a href=\"" + n.ToString() + ".html\" >");
                sb.Append("<img width=\"20\" height=\"20\" src=\"" + n.ToString() + ".png\"/></a></td>");  
                sb.Append("<td><a href=\"" + n.ToString() + ".html\" >");
                sb.Append(item.DisplayName + "</a></td></tr>");
                images[n.ToString() + ".png"] = item.Image;
                redirects[n.ToString() + ".html"] = item.Path;
                n++;
            }
            sb.Append("</table></body></html>");
            html = sb.ToString();

            //инициализация HttpListener...
            listener = new HttpListener();            
            listener.Prefixes.Add("http://localhost:"+port.ToString()+"/" + prefix+"/");
            urlprefix = prefix;
            httpport = port;
        }

        public void Start() //запускает HTTP-сервер     
        {           
            Task.Run(() =>
            {
                try
                {
                    listener.Start();
                    while (true)
                    {                        
                        HttpListenerContext context = listener.GetContext(); //ожидаем запроса
                        HttpListenerRequest request = context.Request;
                        HttpListenerResponse response = context.Response;

                        //анализ URL...
                        byte[] buffer = new byte[0];
                        string urlbegin = "/" + urlprefix + "/";
                        string urlfile = request.RawUrl.Substring(urlbegin.Length);
                        if (urlfile == "" || urlfile.StartsWith("index") || urlfile.StartsWith("default"))
                        {
                            //отдаем основную страницу
                            buffer = System.Text.Encoding.UTF8.GetBytes(html);
                            response.ContentLength64 = buffer.Length;
                            response.ContentEncoding = Encoding.UTF8;
                        }
                        else if (urlfile.EndsWith(".png"))
                        {
                            //отдаем изображение
                            buffer = images[urlfile];
                            response.ContentLength64 = buffer.Length;
                            response.ContentType = "image/png";
                        }
                        else
                        {
                            buffer = System.Text.Encoding.UTF8.GetBytes("Ошибка: Страница не найдена");
                            response.StatusCode = 404;
                            response.ContentType = "text/plain";
                        }

                        //возвращаем ответ
                        System.IO.Stream output = response.OutputStream;
                        output.Write(buffer, 0, buffer.Length);
                        output.Close();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString(), "HttpListener error");
                }
            });
        }

        public Uri ProcessRedirect(string inputurl)
        {
            //обработка перенаправлений...            
            string urlbegin = "http://localhost:" + httpport.ToString() + "/" + urlprefix + "/";

            if (inputurl.StartsWith(urlbegin))
            {
                string urlfile = inputurl.Substring(urlbegin.Length);
                if (!urlfile.EndsWith(".html")) return null;

                if (redirects.ContainsKey(urlfile))
                {
                    return redirects[urlfile];
                }
                else return null;
            }
            else return null;
        }
    }    
    
    /* COM Interfaces */

    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("000214E6-0000-0000-C000-000000000046")]
    public interface IShellFolder
    {
        void ParseDisplayName(IntPtr hwnd, IntPtr pbc, String pszDisplayName, UInt32 pchEaten, out IntPtr ppidl, UInt32 pdwAttributes);
        void EnumObjects(IntPtr hwnd, int grfFlags, out IEnumIDList ppenumIDList);
        void BindToObject(IntPtr pidl, IntPtr pbc, [In]ref Guid riid, out IntPtr ppv);
        void BindToStorage(IntPtr pidl, IntPtr pbc, [In]ref Guid riid, out IntPtr ppv);
        [PreserveSig]  Int32 CompareIDs(Int32 lParam, IntPtr pidl1, IntPtr pidl2);
        void CreateViewObject(IntPtr hwndOwner, [In] ref Guid riid, out IntPtr ppv);
        void GetAttributesOf(UInt32 cidl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]IntPtr[] apidl, ref uint rgfInOut);
        void GetUIObjectOf(IntPtr hwndOwner, UInt32 cidl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]IntPtr[] apidl, 
            [In] ref Guid riid, UInt32 rgfReserved, out IExtractIcon ppv);
        void GetDisplayNameOf(IntPtr pidl, int uFlags, out STRRET pName);
        void SetNameOf(IntPtr hwnd, IntPtr pidl, String pszName, int uFlags, out IntPtr ppidlOut);
    }   
    
    [StructLayout(LayoutKind.Explicit, Size = 520)]
    public struct STRRETinternal
    {
        [FieldOffset(0)] public IntPtr pOleStr;

        [FieldOffset(0)] public IntPtr pStr;  

        [FieldOffset(0)] public uint uOffset;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct STRRET
    {
        public uint uType;
        public STRRETinternal data;
    }

    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("000214F2-0000-0000-C000-000000000046")]
    public interface IEnumIDList
    {
        [PreserveSig()] uint Next(uint celt, out IntPtr rgelt, IntPtr pceltFetched);
        [PreserveSig()] uint Skip(uint celt);
        [PreserveSig()] uint Reset();
        [PreserveSig()] uint Clone(out IEnumIDList ppenum);
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    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;
    }

    [ComImport()]
    [Guid("000214fa-0000-0000-c000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IExtractIcon
    {
        [PreserveSig] int GetIconLocation(
            uint uFlags,
            [Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 2)] StringBuilder szIconFile,
            int cchMax,
            out int piIndex,
            out uint pwFlags);


        [PreserveSig] int Extract(
            [MarshalAs(UnmanagedType.LPWStr)] string pszFile, uint nIconIndex, out IntPtr phiconLarge,
            out IntPtr phiconSmall, uint nIconSize);
    }   
}

Источник: https://devblogs.microsoft.com/oldnewthing/?p=9773

Это, конечно, не настоящий "Мой компьютер", но подделано довольно качественно:

mycomputer

Картину только портит багнутый "Мои веб-узлы MSN", который ведет в никуда и для которого не работает извлечение иконки. Извращения с обработкой webbrowser_Navigating здесь нужны из-за того, что настройки безопасности не позволяют просто так переходить с http://localhost/ на file://localhost/


Автор: VadimTagil

Главная страница - Список тем - Репозиторий на GitHub