[prev in list] [next in list] [prev in thread] [next in thread] 

List:       mono-winforms-list
Subject:    [Mono-winforms-list] Win32ShellIcon preview
From:       Kornél Pál <kornelpal () hotmail ! com>
Date:       2005-09-14 15:35:30
Message-ID: 001601c5b941$f8155e90$0100a8c0 () kornelpal ! hu
[Download RAW message or body]

Hi,

I found a solution that requires a bit more system resources but can be done
without modifying ImageList. This solution copies icons from system image
list but maintains a Hashtable to map system image list indexes to the
managed imagelist.

I modified the driver to handle system icons as well.

Note that I want to move well known (Desktop, My Computer, ...) icons to
driver as well so this is a preview-only patch.

ListView seems to be extremely bugous on Windows and I wasn't able to
display a FileDialog on Mono because the process stars to eat all the memory
(including virtual memory) and all the CPU time but displays no window.

Using .NET Framework I was able to test the dialog but it is very bugous.

Furthermore the current ImageList is copying image instead of storing the
original ones like MS.NET does and this results in the loss of
alpha-blending of icons.

Please comment this preview implementation.

Kornél

["Win32ShellIcon.diff" (application/octet-stream)]

Index: XplatUI.cs
===================================================================
--- XplatUI.cs	(revision 50037)
+++ XplatUI.cs	(working copy)
@@ -152,6 +152,13 @@
 			}
 		}
 
+		static public ImageList LargeIcons {
+			get 
+			{
+				return driver.LargeIcons;
+			}
+		}
+
 		static public Size MaxWindowTrackSize {
 			get {
 				return driver.MaxWindowTrackSize;
@@ -182,6 +189,14 @@
 			}
 		}
 
+		static public ImageList SmallIcons 
+		{
+			get 
+			{
+				return driver.SmallIcons;
+			}
+		}
+
 		static public Size SmallIconSize {
 			get {
 				return driver.SmallIconSize;
@@ -421,6 +436,14 @@
 			return driver.GetFontMetrics(g, font, out ascent, out descent);
 		}
 			
+		internal static int GetLargeDirectoryIconIndex(string path) {
+			return driver.GetLargeDirectoryIconIndex(path);
+		}
+
+		internal static int GetLargeFileIconIndex(string path) {
+			return driver.GetLargeFileIconIndex(path);
+		}
+
 		internal static Graphics GetMenuDC(IntPtr handle, IntPtr ncpaint_region) {
 			#if DriverDebug
 				Console.WriteLine("GetMenuDC({0:X}): Called", handle.ToInt32());
@@ -446,6 +469,14 @@
 			return driver.GetParent(hWnd);
 		}
 
+		internal static int GetSmallDirectoryIconIndex(string path) {
+			return driver.GetSmallDirectoryIconIndex(path);
+		}
+
+		internal static int GetSmallFileIconIndex(string path) {
+			return driver.GetSmallFileIconIndex(path);
+		}
+
 		internal static bool GetText(IntPtr hWnd, out string text) {
 			#if DriverDebug
 				Console.WriteLine("GetText(): Called");
Index: Mime.cs
===================================================================
--- Mime.cs	(revision 50037)
+++ Mime.cs	(working copy)
@@ -212,60 +212,51 @@
 		
 		private bool CheckForInode( )
 		{
-			if ( ( platform == 4 ) || ( platform == 128 ) )
-			{
 #if __MonoCS__
-				// *nix platform
-				Mono.Unix.UnixFileInfo ufi = new Mono.Unix.UnixFileInfo( current_file_name );
-				
-				if ( ufi.IsFile )
-				{
-					return false;
-				}
-				else
-				if ( ufi.IsDirectory )
-				{
-					global_result = "inode/directory";
-					return true;
-				}
-				else
-				if ( ufi.IsBlockDevice )
-				{
-					global_result = "inode/blockdevice";
-					return true;
-				}
-				else
-				if ( ufi.IsSocket )
-				{
-					global_result = "inode/socket";
-					return true;
-				}
-				else
-				if ( ufi.IsSymbolicLink )
-				{
-					global_result = "inode/symlink";
-					return true;
-				}
-				else
-				if ( ufi.IsCharacterDevice )
-				{
-					global_result = "inode/chardevice";
-					return true;
-				}
-				else
-				if ( ufi.IsFIFO )
-				{
-					global_result = "inode/fifo";
-					return true;
-				}
-#endif
+			// *nix platform
+			Mono.Unix.UnixFileInfo ufi = new Mono.Unix.UnixFileInfo( current_file_name );
+			
+			if ( ufi.IsFile )
+			{
+				return false;
 			}
 			else
+			if ( ufi.IsDirectory )
 			{
-				// TODO!!!!
-				// windows platform
+				global_result = "inode/directory";
+				return true;
 			}
-			
+			else
+			if ( ufi.IsBlockDevice )
+			{
+				global_result = "inode/blockdevice";
+				return true;
+			}
+			else
+			if ( ufi.IsSocket )
+			{
+				global_result = "inode/socket";
+				return true;
+			}
+			else
+			if ( ufi.IsSymbolicLink )
+			{
+				global_result = "inode/symlink";
+				return true;
+			}
+			else
+			if ( ufi.IsCharacterDevice )
+			{
+				global_result = "inode/chardevice";
+				return true;
+			}
+			else
+			if ( ufi.IsFIFO )
+			{
+				global_result = "inode/fifo";
+				return true;
+			}
+#endif
 			return false;
 		}
 		
Index: Win32ShellIcon.cs
===================================================================
--- Win32ShellIcon.cs	(revision 0)
+++ Win32ShellIcon.cs	(revision 0)
@@ -0,0 +1,144 @@
+//
+// System.Windows.Forms.Win32ShellIcon.cs
+//
+// Author:
+//   Kornél Pál <http://www.kornelpal.hu/>
+//
+// Copyright (C) 2005 Kornél Pál
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+namespace System.Windows.Forms
+{
+	internal
+#if NET_2_0
+	static
+#else
+	sealed
+#endif
+	class Win32ShellIcon
+	{
+#if !NET_2_0
+		private Win32ShellIcon()
+		{
+		}
+#endif
+
+		private const int MAX_PATH = 260;
+
+		private const int SHGFI_ICON = 0x000000100;
+		private const int SHGFI_SMALLICON = 0x000000001;
+		private const int SHGFI_ADDOVERLAYS = 0x000000020;
+		private const int SHGFI_OVERLAYINDEX = 0x000000040;
+
+		[StructLayout(LayoutKind.Sequential)]
+		private struct SHFILEINFO
+		{
+			internal IntPtr hIcon;
+			internal int iIcon;
+			internal int dwAttributes;
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_PATH)]
+			internal string szDisplayName;
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst=80)]
+			internal string szTypeName;
+		}
+
+		[DllImport("shell32.dll")]
+		private static extern IntPtr SHGetFileInfo(string pszPath, int dwFileAttributes, \
out SHFILEINFO psfi, int cbFileInfo, int uFlags); +
+		[DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet.Unicode)]
+		private static extern int DestroyIcon(IntPtr hIcon);
+
+		internal readonly static ImageList LargeIcons = new ImageList();
+		internal readonly static ImageList SmallIcons = new ImageList();
+
+		private readonly static Hashtable largeIconIndexes = new Hashtable();
+		private readonly static Hashtable smallIconIndexes = new Hashtable();
+
+		static Win32ShellIcon()
+		{
+			LargeIcons.ColorDepth = ColorDepth.Depth32Bit;
+			LargeIcons.ImageSize = XplatUI.IconSize;
+
+			SmallIcons.ColorDepth = ColorDepth.Depth32Bit;
+			SmallIcons.ImageSize = XplatUI.SmallIconSize;
+		}
+
+		internal static int GetLargeIconIndex(string path)
+		{
+			return GetIconIndex(path, LargeIcons, largeIconIndexes, 0);
+		}
+
+		internal static int GetSmallIconIndex(string path)
+		{
+			return GetIconIndex(path, SmallIcons, smallIconIndexes, SHGFI_SMALLICON);
+		}
+
+		private static int GetIconIndex(string path, ImageList icons, Hashtable indexes, \
int flags) +		{
+			SHFILEINFO shellFileInfo;
+			object indexObject;
+			int index;
+
+			// Shell bug: SHGFI_OVERLAYINDEX has no effect without
+			// SHGFI_ICON but causes hIcon to be NULL when there is
+			// an overlay because iIcon contains an invalid index.
+
+			if (SHGetFileInfo(path, 0, out shellFileInfo, Marshal.SizeOf(typeof(SHFILEINFO)), \
SHGFI_ICON | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX | flags) == IntPtr.Zero) \
+				return -1; +
+			lock (indexes)
+			{
+				if ((indexObject = indexes[shellFileInfo.iIcon]) != null)
+				{
+					// Can be NULL because of Shell bug
+					if (shellFileInfo.hIcon != IntPtr.Zero)
+						DestroyIcon(shellFileInfo.hIcon);
+					index = (int)indexObject;
+				}
+				else
+				{
+					// Works around Shell bug
+					if (shellFileInfo.hIcon == IntPtr.Zero)
+					{
+						index = shellFileInfo.iIcon;
+						if (SHGetFileInfo(path, 0, out shellFileInfo, \
Marshal.SizeOf(typeof(SHFILEINFO)), SHGFI_ICON | SHGFI_ADDOVERLAYS | flags) == \
IntPtr.Zero || shellFileInfo.hIcon == IntPtr.Zero) +							return -1;
+						shellFileInfo.iIcon = index;
+					}
+
+					index = icons.Images.Count;
+					icons.Images.Add(Icon.FromHandle(shellFileInfo.hIcon));
+					indexes.Add(shellFileInfo.iIcon, index);
+				}
+			}
+
+			return index;
+		}
+	}
+}
Index: FileDialog.cs
===================================================================
--- FileDialog.cs	(revision 50037)
+++ FileDialog.cs	(working copy)
@@ -1507,8 +1507,8 @@
 		
 		public MWFFileView( )
 		{
-			SmallImageList = MimeIconEngine.SmallIcons;
-			LargeImageList = MimeIconEngine.LargeIcons;
+			SmallImageList = XplatUI.SmallIcons;
+			LargeImageList = XplatUI.LargeIcons;
 			
 			View = View.List;
 		}
@@ -1634,10 +1634,8 @@
 				
 				ListViewItem listViewItem = new ListViewItem( directoryInfoi.Name );
 				
-				int index = MimeIconEngine.GetIconIndexForMimeType( "inode/directory" );
+				listViewItem.ImageIndex = this.View == View.LargeIcon ? \
XplatUI.GetLargeDirectoryIconIndex (fileStruct.fullname) : \
XplatUI.GetSmallDirectoryIconIndex (fileStruct.fullname);  
-				listViewItem.ImageIndex = index;
-				
 				listViewItem.SubItems.Add( "" );
 				listViewItem.SubItems.Add( "Directory" );
 				listViewItem.SubItems.Add( directoryInfoi.LastAccessTime.ToShortDateString( ) + \
" " + directoryInfoi.LastAccessTime.ToShortTimeString( ) ); @@ -1661,7 +1659,7 @@
 				
 				ListViewItem listViewItem = new ListViewItem( fileInfo.Name );
 				
-				listViewItem.ImageIndex = MimeIconEngine.GetIconIndexForFile( \
fileStruct.fullname ); +				listViewItem.ImageIndex = this.View == View.LargeIcon ? \
XplatUI.GetLargeFileIconIndex (fileStruct.fullname) : XplatUI.GetSmallFileIconIndex \
(fileStruct.fullname);  
 				long fileLen = 1;
 				if ( fileInfo.Length > 1024 )
Index: MimeIcon.cs
===================================================================
--- MimeIcon.cs	(revision 50037)
+++ MimeIcon.cs	(working copy)
@@ -65,7 +65,7 @@
 		Default,
 		KDE,
 		GNOME
-		// Win, Mac OSX...
+		// Mac OSX...
 	}
 	
 	internal class MimeIconEngine
Index: XplatUIDriver.cs
===================================================================
--- XplatUIDriver.cs	(revision 50037)
+++ XplatUIDriver.cs	(working copy)
@@ -226,6 +226,37 @@
 		internal abstract int KeyboardSpeed { get; } 
 		internal abstract int KeyboardDelay { get; } 
 
+		// System icons
+		internal virtual ImageList LargeIcons
+		{
+			get { return MimeIconEngine.LargeIcons; }
+		}
+
+		internal virtual ImageList SmallIcons
+		{
+			get { return MimeIconEngine.SmallIcons; }
+		}
+
+		internal virtual int GetLargeDirectoryIconIndex(string path)
+		{
+			return MimeIconEngine.GetIconIndexForMimeType ("inode/directory");
+		}
+
+		internal virtual int GetSmallDirectoryIconIndex(string path)
+		{
+			return GetLargeDirectoryIconIndex (path);
+		}
+
+		internal virtual int GetLargeFileIconIndex(string path)
+		{
+			return MimeIconEngine.GetIconIndexForFile (path);
+		}
+
+		internal virtual int GetSmallFileIconIndex(string path)
+		{
+			return GetLargeFileIconIndex (path);
+		}
+
 #endregion	// XplatUI Driver Methods
 	}
 
Index: XplatUIWin32.cs
===================================================================
--- XplatUIWin32.cs	(revision 50037)
+++ XplatUIWin32.cs	(working copy)
@@ -1956,6 +1956,36 @@
 				return 1;
 			}
 		}
+
+		internal override ImageList LargeIcons
+		{
+			get { return Win32ShellIcon.LargeIcons; }
+		}
+
+		internal override ImageList SmallIcons
+		{
+			get { return Win32ShellIcon.SmallIcons; }
+		}
+
+		internal override int GetLargeDirectoryIconIndex(string path)
+		{
+			return Win32ShellIcon.GetLargeIconIndex(path);
+		}
+
+		internal override int GetSmallDirectoryIconIndex(string path)
+		{
+			return Win32ShellIcon.GetSmallIconIndex(path);
+		}
+
+		internal override int GetLargeFileIconIndex(string path)
+		{
+			return Win32ShellIcon.GetLargeIconIndex(path);
+		}
+
+		internal override int GetSmallFileIconIndex(string path)
+		{
+			return Win32ShellIcon.GetSmallIconIndex(path);
+		}
 		
 		internal override event EventHandler Idle;
 



_______________________________________________
Mono-winforms-list maillist  -  Mono-winforms-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-winforms-list


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic