Как получить связанный значок из общего сетевого файла
Я использую Icon.ExtractAssociatedIcon, чтобы получить значок файла, который пользователь выбирает, в openfiledialog.
Проблема в том, что если пользователь выбирает значок из общего сетевого ресурса, то свойство имени файла openfiledialog имеет формат UNC, и это вызывает ArgumentException
в ExtractAssocaitedIcon
:
Value of '\\server\share\filename' is not valid for 'filePath'.
Stack Trace:
at System.Drawing.Icon.ExtractAssociatedIcon(String filePath, Int32 index)
Так что мой вопрос дан файл, указанный как \\server\share\filename
как мне получить иконку?
Примечание:.NET 2.0
4 ответа
Глядя на это с помощью Reflector, это в конечном итоге вызывает ExtractAssociatedIcon
в shell32.dll
,
Вы пробовали обойти BCL, получая доступ через PInvoke?
Пример кода (через PInvoke.Net):
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr ExtractAssociatedIcon(IntPtr hInst, StringBuilder lpIconPath,
out ushort lpiIcon);
// ... snip
ushort uicon;
StringBuilder strB = new StringBuilder(260); // Allocate MAX_PATH chars
strB.Append(openFileDialog1.FileName);
IntPtr handle = ExtractAssociatedIcon(IntPtr.Zero, strB, out uicon);
Icon ico = Icon.FromHandle(handle);
pictureBox1.Image = ico.ToBitmap();
// ... snip
Для полноты, вот ExtractAssociatedIcon
рутина, которая работает:
/// <summary>
/// Returns an icon representation of an image contained in the specified file.
/// This function is identical to System.Drawing.Icon.ExtractAssociatedIcon, xcept this version works.
/// </summary>
/// <param name="filePath">The path to the file that contains an image.</param>
/// <returns>The System.Drawing.Icon representation of the image contained in the specified file.</returns>
/// <exception cref="System.ArgumentException">filePath does not indicate a valid file.</exception>
public static Icon ExtractAssociatedIcon(String filePath)
{
int index = 0;
Uri uri;
if (filePath == null)
{
throw new ArgumentException(String.Format("'{0}' is not valid for '{1}'", "null", "filePath"), "filePath");
}
try
{
uri = new Uri(filePath);
}
catch (UriFormatException)
{
filePath = Path.GetFullPath(filePath);
uri = new Uri(filePath);
}
//if (uri.IsUnc)
//{
// throw new ArgumentException(String.Format("'{0}' is not valid for '{1}'", filePath, "filePath"), "filePath");
//}
if (uri.IsFile)
{
if (!File.Exists(filePath))
{
//IntSecurity.DemandReadFileIO(filePath);
throw new FileNotFoundException(filePath);
}
StringBuilder iconPath = new StringBuilder(260);
iconPath.Append(filePath);
IntPtr handle = SafeNativeMethods.ExtractAssociatedIcon(new HandleRef(null, IntPtr.Zero), iconPath, ref index);
if (handle != IntPtr.Zero)
{
//IntSecurity.ObjectFromWin32Handle.Demand();
return Icon.FromHandle(handle);
}
}
return null;
}
/// <summary>
/// This class suppresses stack walks for unmanaged code permission.
/// (System.Security.SuppressUnmanagedCodeSecurityAttribute is applied to this class.)
/// This class is for methods that are safe for anyone to call.
/// Callers of these methods are not required to perform a full security review to make sure that the
/// usage is secure because the methods are harmless for any caller.
/// </summary>
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
[DllImport("shell32.dll", EntryPoint = "ExtractAssociatedIcon", CharSet = CharSet.Auto)]
internal static extern IntPtr ExtractAssociatedIcon(HandleRef hInst, StringBuilder iconPath, ref int index);
}
Примечание. Любой код публикуется в открытом доступе. Атрибуция не требуется.
Один из способов сделать это - извлечь путь UNC и временно сопоставить его с буквой диска, а затем использовать этот диск в вашем методе.ExtractAssociatedIcon. Когда вы получили значок, вы можете удалить диск. Это не элегантно, но должно работать нормально.
Другой вариант - скопировать файл, выбранный пользователем, в свой%TEMP% и использовать Icon.ExtractAssociatedIcon
там. Просто не забудьте убирать за собой.
Очевидно, что это не лучшее решение, если вы поддерживаете большие файлы!
Просто чтобы дополнить ответ Яна Бойда, если файл является изображением, а не значком файла, вы можете использовать FileStream для его предварительного просмотра:
foreach (string item in Directory.GetFiles(actualPath))
{
fi = new FileInfo(item);
using (FileStream stream = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read))
{
myImageList.Images.Add(Image.FromStream(stream));
}
}