Thursday 26 November 2015

How to make the Windows Desktop application work well on High-DPI Displays and Fix Blurry Fonts

If you change the DPI of your machine from 100% to any other higher value, your desktop applications may appear somewhat blurry when you compare them with other applications on the screen. Alternately, display problems may exist such as truncated text.



In order to fix this issue, you would need to Disable DPI virtualization for the application. To do this, right-click the application’s shortcut and then click Properties. On the Compatibility tab, select Disable Display Scaling on High DPI Settings, and then click OK.




Alternatively, you may also disable this setting using the below Registry keys.

Registry key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers

String: “Path to your application exe”
Value:   ~ HIGHDPIAWARE
Please note there is a space between ‘tilde’ and ‘HIGHDPIAWARE’.



There are number of ways to set a value in the registry. Below steps will show the process to set this value in registry using Inno setup:

var
str_MyAppFullExePath: String;

str_MyAppFullExePath := ExpandConstant('{app}') ;

RegWriteStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers', str_MyAppFullExePath + '\' + '{#MyAppExeName}' , '~ HIGHDPIAWARE');

Possible Issues:

If your application is 32 bit, then the above command will set the value at

“HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers” 

instead of 

“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers”. 

This will not set the “Disable Display Scaling on High DPI Settings” property. This can be fixed by using the below command:

if IsWin64 then
 begin
 RegWriteStringValue(HKLM64, 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers', str_MyAppFullExePath + '\' + '{#MyAppExeName}' , '~ HIGHDPIAWARE');
 end
 else
 begin
 RegWriteStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers', str_MyAppFullExePath + '\' + '{#MyAppExeName}' , '~ HIGHDPIAWARE');
 end ;

It will force the setup to store value in 64 bit registry.

Monday 23 November 2015

How to extract the associated icon of any file in C#.Net

To extract icon of any file, define the below class and the structure:

[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);

            [DllImport("User32.dll")]
            public static extern int DestroyIcon(IntPtr hIcon);
        }

Now define the following function:

SHFILEINFO shinfo = new SHFILEINFO();
/* Define it globally so that you can use the same object for all  the files. */
public Bitmap extractAssociatedIcon(string fName)
        {
            Icon myIcon = null;
            try
            {
                IntPtr hImgSmall;    //the handle to the system image list              

                hImgSmall = Win32.SHGetFileInfo(fName, 0, ref shinfo,
                                 (uint)Marshal.SizeOf(shinfo),
                                  Win32.SHGFI_ICON |
                                  Win32.SHGFI_SMALLICON);

                if (shinfo.hIcon != IntPtr.Zero)
                    myIcon = Icon.FromHandle(shinfo.hIcon);              

            }
            catch (Exception ex)
            {
                // Handle any exception here
            }
            return myIcon.ToBitmap();
        }


Get the icon by calling the above defined function.

Bitmap image = extractAssociatedIcon("fullPath to the file");

Once you get the icon, make sure you destroy the icon. This is very important, else you will run into memory issues.

Win32.DestroyIcon(shinfo.hIcon);




Friday 20 November 2015

Dealing with “Application has stopped responding” issue in C#.Net

Suppose in your application, on a click event you are doing some calculations which is taking a lot of time. During that time, if a user perform unnecessarily clicks on the screen, it might give a “Page is not responding” or "Application has stopped responding" error.

This can be resolved by following the below steps:

1.   Put your long running code in a thread.

2. Set “Cursor.Current = Cursors.WaitCursor;”

3. UseWaitCursor = true;

4. Inside the thread use the try-finally block.

5. In the finally block, set “this.Cursor = Cursors.Default;”

6. UseWaitCursor = false;

7. Start that thread.

Example:
     Cursor.Current = Cursors.WaitCursor;
     UseWaitCursor = true;

            new Thread(() =>
            {
     try
            {                             
                // Your long running code                                   
            }
            catch (Exception ex)
            {
                 // Handle any exception here
            }
            finally
            {                           
  Cursor.Current = Cursors.Default;
                UseWaitCursor = false;
            }
           }) { Name = "longTask" }.Start();


Now even if you click 100 times, the page will not show “Not Responding” error.

Wednesday 18 November 2015

Adding a new item to context menu of Windows Explorer in C#.Net



Requirement: Whenever user right clicks on any folder in windows explorer, display a new option and if user selects that option, launch your application. The below steps will add a new option on right click of any folder:

You would need to add 2 sub keys in registry at the below location:

HKEY_CLASSES_ROOT\Folder\shell

Key 1: Folder\\shell\\MyProduct

Set the value of above key and the same will be shown in the context menu. You can also add a icon to the context menu item by adding a value to the key 1 and name it "Icon" as shown below:

Icon  "Path to your icon file"

Key 2: Folder\\shell\\MyProduct\\command

Set the value of above key and it will launch the application:

Eg. C:\Program Files (x86)\myProduct.exe "%1"

Here "%1" will give the path of the folder which is right clicked.



Programmatically this can be done as below:

private static void updateRegistryToAddContextMenu()
        {
            string MenuName = "Folder\\shell\\MyProduct";
            string Command = "Folder\\shell\MyProduct\\command";

            RegistryKey regmenu = null;
            RegistryKey regcmd = null;
            try
            {
                regmenu = Registry.ClassesRoot.CreateSubKey(MenuName);
                if (regmenu != null)
                    regmenu.SetValue("","New context menu option");
                regcmd = Registry.ClassesRoot.CreateSubKey(Command);
                if (regcmd != null)
                {
                    string exePath = Application.ExecutablePath;
                    regcmd.SetValue("", exePath + " " + "\"" + "%1" + "\"");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);

            }
            finally
            {
                if (regmenu != null)
                    regmenu.Close();
                if (regcmd != null)
                    regcmd.Close();
            }
        }