1

How would I be able to extract the icon from processlist instead of filenames as of currently? As of now the this works by opening Form Dialog, they click on a file, then it adds it into listView with icon. How to do I just get the processes icon's and display them int he listView?

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

private int nIndex = 0;
private void materialFlatButton13_Click_1(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);

        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++);
    }
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
Rohan Pas
  • 177
  • 1
  • 14
  • 1
    What's difference between this question and your [previous question](https://stackoverflow.com/questions/42893541/c-sharp-how-to-display-processes-with-icons-in-listbox)? – Reza Aghaei Mar 25 '17 at 00:08
  • @RezaAghaei Well now this works on any bit. – Rohan Pas Mar 25 '17 at 00:11

3 Answers3

3

You can find processes information using a WMI query on Win32_Process and use ExecutablePath to find executable path of the process. Then you can use Icon.ExtractAssociatedIcon to extract the associated icon of the process:

Example

Drop an ImageList on the form and set its ColorDepth to Depth32Bit and its ImageSize to 32,32. The drop a ListView on the form and set its LargImageList to imageList1 which you created in the first step.

Add reference to System.Management.dll and add using System.Management; and use below code to fill listView1 with icons:

var query = "SELECT ProcessId, Name, ExecutablePath FROM Win32_Process";
using (var searcher = new ManagementObjectSearcher(query))
using (var results = searcher.Get())
{
    var processes = results.Cast<ManagementObject>().Select(x => new
    {
        ProcessId = (UInt32)x["ProcessId"],
        Name = (string)x["Name"],
        ExecutablePath = (string)x["ExecutablePath"]
    });
    foreach (var p in processes)
    {
        if (System.IO.File.Exists(p.ExecutablePath))
        {
            var icon = Icon.ExtractAssociatedIcon(p.ExecutablePath);
            var key = p.ProcessId.ToString();
            this.imageList1.Images.Add(key, icon.ToBitmap());
            this.listView1.Items.Add(p.Name, key);
        }
    }
}

Then you will have such result:

enter image description here

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
2

Solution for 32-bit AND 64-bit processes

(with only System.Diagnostics)

This will get the icon of the main module (The exe file). It will also work if the architecture of the accessing and the targeted process differs:

var icon = Process.GetProcessById(1234).GetIcon()

With the extension methods:

public static class ProcessExtensions {
    [DllImport("Kernel32.dll")]
    private static extern uint QueryFullProcessImageName([In] IntPtr hProcess, [In] uint dwFlags, [Out] StringBuilder lpExeName, [In, Out] ref uint lpdwSize);

    public static string GetMainModuleFileName(this Process process, int buffer = 1024) {
        var fileNameBuilder = new StringBuilder(buffer);
        uint bufferLength = (uint)fileNameBuilder.Capacity + 1;
        return QueryFullProcessImageName(process.Handle, 0, fileNameBuilder, ref bufferLength) != 0 ?
            fileNameBuilder.ToString() :
            null;
    }

    public static Icon GetIcon(this Process process) {
        try {
            string mainModuleFileName = process.GetMainModuleFileName();
            return Icon.ExtractAssociatedIcon(mainModuleFileName);
        }
        catch {
            // Probably no access
            return null;
        }
    }
}
Bruno Zell
  • 7,761
  • 5
  • 38
  • 46
0

See here: C#: How to get the full path of running process?

foreach(var process in Process.GetProcesses()){
    string fullPath = process.MainModule.FileName;
    // do your stuff here
}

You can substitute this into your existing code. Or, tailor it to what you're doing now.

Edit: added the code to get processes

Community
  • 1
  • 1
Cory
  • 1,794
  • 12
  • 21
  • The goal is to get the icons to all the processes. Not get the processes. – Rohan Pas Mar 25 '17 at 00:26
  • Right, you get the processes, then you use the code you already have to do the rest. Instead of using the filename in code you have, you substitute this code in it's place. – Cory Mar 25 '17 at 01:00
  • Access is denied. Only works on 32 bit. Any solution where it does not only work on 32 bit? – Rohan Pas Mar 25 '17 at 01:13
  • For a solution with no `ManagementObjectSearcher` but for both 32-bit and 64-bit look at [my answer](https://stackoverflow.com/a/48316821/5185376). – Bruno Zell Jan 18 '18 at 11:17