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
Running Scripts in HTMLagilitypack
How Does the Ternary Operator Work
What Is the Equivalent of the Java Bigdecimal Class in C#
Automatically Set Appsettings.JSON for Dev and Release Environments in ASP.NET Core
Turn a Simple C# Dll into a Com Interop Component
Conversion of System.Array to List
Cancellation Token in Task Constructor: Why
How to Print the Current Stack Trace in .Net Without Any Exception
Handle Modelstate Validation in ASP.NET Web API
How to Read an Entire File to a String Using C#
Replace Multiple Characters in a C# String
Close a Messagebox After Several Seconds
Sending Arguments to Background Worker
Does Xaml Have a Conditional Compiler Directive for Debug Mode
Difference Between Convert.Tostring() and .Tostring()
How to Use the Paint Event to Draw Shapes at Mouse Coordinates