Kernel: Obtendo o caminho do executável de um Processo – C#

Pode parecer tarefa fácil, mas não é. O fato é que, obter o caminho do executável de um processo pode acabar tendo um destino trágico se você não estiver com sorte.

A maneira tradicional de fazer isso é utilizando a propriedade Process.MainModule.FileName.

Mas há um grande porém! Se o seu processo está executando em x64 (Processo 64 bits) e o outro processo, que você deseja obter o caminho, está executando em x86 (Processo 32 bits) você receberá a belíssima exceção abaixo:

Cross Plat Exception

A situação inversa também resulta neste exceção.

Esse é um problema cada vez mais fácil de ocorrer devido à maior adoção de sistemas operacionais x64.

Mas, contudo, todavia, começando com a versão Vista, o Windows possui uma função no Kernel que nos permite contornar este problema. Ela se chama QueryFullProcessImageName. Essa rotina não é afetada pela situação descrita acima.

Dessa forma, com algumas linhas de código, podemos implementar um método de extensão para a classe Process que irá facilitar as coisas:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace System.Diagnostics
{
    public static class ProcessExtensions
    {
        /// <summary>
        /// Returns the process executable full path
        /// </summary>
        /// <param name="Process">The process</param>
        /// <returns>A string containing the process executable path</returns>
        public static string GetProcessPath(this Process Process)
        {
            int capacity = 1024;
            StringBuilder sb = new StringBuilder(capacity);

            IntPtr handle = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, Process.Id);

            QueryFullProcessImageName(handle, 0, sb, ref capacity);

            string fullPath = sb.ToString(0, capacity);
            CloseHandle(handle);
            return fullPath;
        }

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr hObject);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags, [Out]StringBuilder lpExeName, ref int lpdwSize);

        [DllImport("kernel32.dll")]
        private static extern IntPtr OpenProcess(
             ProcessAccessFlags processAccess,
             bool bInheritHandle,
             int processId
        );

        [Flags]
        private enum ProcessAccessFlags : uint
        {
            All = 0x001F0FFF,
            Terminate = 0x00000001,
            CreateThread = 0x00000002,
            VirtualMemoryOperation = 0x00000008,
            VirtualMemoryRead = 0x00000010,
            VirtualMemoryWrite = 0x00000020,
            DuplicateHandle = 0x00000040,
            CreateProcess = 0x000000080,
            SetQuota = 0x00000100,
            SetInformation = 0x00000200,
            QueryInformation = 0x00000400,
            QueryLimitedInformation = 0x00001000,
            Synchronize = 0x00100000
        }
    }
}

Após implementar o código acima, você poderá fazer coisas assim no seu código:

                foreach (Process pr in System.IO.Kernel.GetProcessesLockingFile(dialog.FileName))
                {
                    DataRow r = dt.NewRow();
                    r[0] = pr.ProcessName;
                    r[1] = pr.Id;
                    r[2] = pr.GetProcessPath(); // Uso da função
                    dt.Rows.Add(r);
                }

Como diria um amigo meu: Nice and flexible.

Anúncios

Deixe um comentário :)

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s