How to Avoid a Win32 Exception When Accessing Process.Mainmodule.Filename in C#

How to avoid a Win32 exception when accessing Process.MainModule.FileName in C#?

The exception is thrown when you try to access the MainModule property. The documentation for this property does not list Win32Exception as a possible exception, but looking at the IL for the property it is evident that accessing it may throw this exception. In general it will throw this exception if you are trying to do something that is impossible or not allowed in the OS.

Win32Exception has the property NativeErrorCode and also a Message that will explain what the problem is. You should use that information to troubleshoot your problem. NativeErrorCode is the Win32 error code. We can guess all day long what the problem is but the only way to actually figure this out is to inspect the error code.

But to continue guessing, one source of these exceptions is accessing 64 bit processes from a 32 bit process. Doing that will throw a Win32Exception with the following message:

A 32 bit processes cannot access modules of a 64 bit process.

You can get the number of bits of your process by evaluating Environment.Is64BitProcess.

Even running as a 64 bit process you will never be allowed to access MainModule of process 4 (System) or process 0 (System Idle Process). This will throw a Win32Exception with the message:

Unable to enumerate the process modules.

If you problem is that you want to make a process listing similar to the one in Task Manager you will have to handle process 0 and 4 in a special way and give them specific names (just as Task Manager does). Note that on older versions of Windows the system process has ID 8.

Process MainModule - can I avoid Win32 exception?

This exception occurs when you're trying to do something which your OS doesn't allow. You can check the NativeErrorCode property to see more details about the exception.

You can find a solution here to deal with that issue.

As mentioned by @steeeve in comment, you can use GetProcessByName, if performance is the only criteria for you.

Access denied exception while accessing process.MainModule.FileName

It may not be UAC at all. It may be that your process is x32 and the process being queried is x64 or vice versa. process.MainModule seems to choke when that happens with a Win32Exception, "Only part of a ReadProcessMemory or WriteProcessMemory request was completed"

Could that be it?

Unexpected Win32Exception on getMainModule

As expected it was a permissions issue.

The way i've solved it is by getting the JAVA_HOME variable from registry and appending "\bin\java.exe" to it to get the full path.

how to get FileName of process.MainModule?

There are some processes that you aren't allowed to access even as administrator. You can trap the exception and keep going:

foreach (Process proc in processlist)
{
try
{
Console.WriteLine(proc.MainModule.FileName);
}
catch (Win32Exception e)
{
Console.WriteLine(proc.ToString() + " " + e.Message);
}
}

Path.GetDirectoryName produces Win32Exception 'Access is denied'

If you look at the documentation for the Process.MainModule property, you can see that it throws a Win32Exception if a 32-bit process tries to access a 64-bit process. You can check whether this is the case by looking at the Win32Exception.ErrorCode (I assume 0x00000005 in this case) and Win32Exception.Message properties. And you can retrieve the bitness of your process by evaluating Environment.Is64BitProcess.

Even running as a 64-bit process your program won't be allowed to access MainModule of a System process (4) or a System Idle Process (0). This will throw a Win32Exception with the message:

Unable to enumerate the process modules.

You can use Process.Id to check for 0 or 4.

Alternatively the Win32 API allows you to query every process with the LimitedQueryInformation flag, which means you can check the path without receiving an exception. Unfortunately the .NET Base Class Library doesn't expose this flag, so you need P/Invoke to do that. The following C# console program never triggers an exception (when run on my local machine). If it's run with local admin privileges, it returns all path names except for process 0 and process 4. If it's run as a normal user, it understandably only lists the pathnames for those processes to which it has access.

using System;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace NewCmd
{
class Program
{
[Flags]
private enum ProcessAccessFlags : uint
{
QueryLimitedInformation = 0x00001000
}

[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", SetLastError = true)]
private static extern IntPtr OpenProcess
(
ProcessAccessFlags processAccess,
bool bInheritHandle,
int processId
);

static void Main(string[] args)
{
foreach (Process p in Process.GetProcesses())
{
Console.WriteLine(String.Format("Id: {0} Name: {1}", p.Id, p.ProcessName));
Console.WriteLine(String.Format("Path: {0}", GetProcessFilename(p)));
}
Console.ReadLine();
}

static String GetProcessFilename(Process p)
{
int capacity = 2000;
StringBuilder builder = new StringBuilder(capacity);
IntPtr ptr = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, p.Id);
if (QueryFullProcessImageName(ptr, 0, builder, ref capacity))
{
return builder.ToString();
}
else
{
return "[Missing]";
}
}
}
}


Related Topics



Leave a reply



Submit