Get effective executable filename - c#

A .NET application (managed) runs on Windows 7 64 bit. It is actually running on a 64 bit environment.
The application inspect running process (for example, calc.exe) which is located in c:\windows\syswow64\calc.exe.
So, why the function
Process.MainModule.Filename
returns c:\windows\system32\calc.exe? Is it possible to get the effective executable main module location, when is unredirected from SYSWOW64 directory?
What are possible workarounds? The quickest I wrote is the following snippet:
bool iWindows = pFilename.StartsWith(#"c:\windows\", StringComparison.InvariantCultureIgnoreCase);
bool iWindowsSystem32 = pFilename.StartsWith(#"c:\windows\system32\", StringComparison.InvariantCultureIgnoreCase);
if ((iWindows == true) || (iWindowsSystem32 == true)) {
string pActualFileName;
if (iWindowsSystem32 == true)
pActualFileName = pFilename.Replace(#"c:\windows\system32\", #"c:\windows\syswow64\");
else
pActualFileName = pFilename.Replace(#"c:\windows\", #"c:\windows\syswow64\");
Am I missing something?

Try getting the assembly and then getting the assembly location, such as
System.Reflection.Assembly.GetExecutingAssembly().Location

Try to call Wow64DisableWow64FsRedirection before the usage of Process.MainModule.Filename. Verifying that the program are running on 64-bit operation system with IsWow64Process or Environment.Is64BitOperatingSystem (if you use .NET 4.0) before usage of Wow64DisableWow64FsRedirection is recommended.
UPDATED: I am sure that you have a small error in your code or the problem can be on .NET runtines which you have installed. I tested your problem with respect of the following test code
using System;
using System.Diagnostics;
namespace Win64ProcesPath {
class Program {
static void Main (string[] args) {
Process myProcess = new Process ();
try {
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.FileName = "calc.exe";
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start ();
System.Threading.Thread.Sleep (1000);
Console.WriteLine ("{0}", myProcess.MainModule.FileName);
Process p = Process.GetProcessById (myProcess.Id);
Console.WriteLine ("{0}", p.MainModule.FileName);
//Process p32 = Process.GetProcessById (8048);
//Console.WriteLine ("{0}", p32.MainModule.FileName);
}
catch (Exception e) {
Console.WriteLine (e.Message);
}
}
}
}
with .NET 4.0 and Visual Studio 2010 installed on Vindows 7 64-bit (x64). On Vindows 7 64-bit there are two version of calc.exe: one 32-bit under C:\Windows\SysWOW64\calc.exe and another 64-bit under C:\Windows\system32\calc.exe. How can easy verify the files has different file size (776,192 and 918.528 bytes). If I compile the program as 64-bit program it starts C:\Windows\system32\calc.exe and Process.GetProcessById(processId).MainModule.FileName shows also correct file name. One can also use Process.GetProcessById() to get correct path of 32-bit version of calc.exe which are started separately (see commented lines). So 64-bit versin of this program has no problem in my envoronment.
If you do have 32-bit application you will be able to access to the full filesystem after the call of Wow64DisableWow64FsRedirection, but you will not be able to access the memory of 64-bit programs and Process.MainModule will throw the excepion System.ComponentModel.Win32Exception with the code NativeErrorCode: 299 and the Message: "A 32 bit processes cannot access modules of a 64 bit process." To be able to get the full filename of 64-bit application you should use API with get you results produced from a 64-bit operation system component (like WMI and so on). But it's already another probelm, because how you wrote your program is 64-bit program.

Related

An attempt was made to load a program with an incorrect format (.dll)

My program compiles nicely, but when I run the program I get this error:
"System.BadImageFormatException thrown calling IO_Init(). Message=An
attempt was made to load a program with an incorrect format.
(Exception from HRESULT: 0x8007000B)"
As far as I understand, this error is because my program tries to use a dll which is not the same bitness as my program (which is compiled in 64-bit). I have a 32-bit version of the dll as well, and when I run the 32-bit version of the program, it doesn't throw any error, which is fine.
At the start of my program, I run this to check if we're in 64-bit and if so, go to a folder containing the 64-bit file:
if ((IntPtr.Size > 4) && ((ad.RelativeSearchPath == null) || !ad.RelativeSearchPath.Contains(ad.BaseDirectory + "64\\")))
{
AppDomainSetup aset = new AppDomainSetup();
aset.PrivateBinPath = ad.BaseDirectory + "64\\;" + ad.BaseDirectory;
aset.PrivateBinPathProbe = ad.BaseDirectory + "64\\;" + ad.BaseDirectory;
ad = AppDomain.CreateDomain("_NM64SWITCH_", Assembly.GetAssembly(typeof(NaviModel.Program)).Evidence, aset);
ad.ExecuteAssemblyByName(Assembly.GetAssembly(typeof(NaviModel.Program)).FullName, par);
return;
}
I'm a little lost as to where to look now.
Switching from ANY CPU To x86 fixed this problem for me.

Retrieving Java installation directory in any situation using C#

So I'm creating an installer for the Java Access Bridge for my application and it is required to find the Java installation directory. I was using this piece of code which worked..
public static string GetJavaInstallationPath()
{
try
{
string environmentPath = Environment.GetEnvironmentVariable("JAVA_HOME");
if (!string.IsNullOrEmpty(environmentPath))
{
return environmentPath;
}
string javaKey = "SOFTWARE\\JavaSoft\\Java Runtime Environment\\";
using (Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(javaKey))
{
string currentVersion = rk.GetValue("CurrentVersion").ToString();
using (Microsoft.Win32.RegistryKey key = rk.OpenSubKey(currentVersion))
{
return key.GetValue("JavaHome").ToString();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
return null;
}
}
until.. I ran a clean Windows 7 64 bit install on my Virtual Machine and installed Java from java.com. It installed the 32 bit version of Java by default but I really thought it wouldn't matter because 32 bit would also require or the JAVA_HOME variable or the Registry Key. Well, this wasn't the case! There was no Registry Key, no entry in the PATH variable and there was no JAVA_HOME variable either. So this code wouldn't work! My question is, how would I detect the java installation directory even when it's the 32 bit Java version that's installed. There is nothing I know of that I can use..
You're forgetting about the registry path being different for 32bit application. See this MS article: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724072%28v=vs.85%29.aspx

Why can't I programatically replace perfc009.dat in windows 7?

We have an application that uses the Windows 7 performance counters to track the total CPU usage. Every so often the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009 will become corrupted and just be empty.
Manually following the steps found here http://support.microsoft.com/kb/300956 works perfectly. But when I make a C# program to programatically replace the 2 files mentioned no errors, exceptions, etc. But the files are not saved to the proper directory.
Here's what I've been using to test:
static void Main(string[] args)
{
string fileToReadPath1 = #"perfc009.dat";
string fileToReadPath2 = #"perfh009.dat";
FileInfo fileToRead1 = new FileInfo(fileToReadPath1);
FileInfo fileToRead2 = new FileInfo(fileToReadPath2);
FileInfo fileToReplaceInfo1 = new FileInfo(#"C:\Windows\System32\perfc009.dat");
FileInfo fileToReplaceInfo2 = new FileInfo(#"C:\Windows\System32\perfh009.dat");
File.Copy(fileToRead1.FullName, fileToReplaceInfo1.FullName, true);
File.Copy(fileToRead2.FullName, fileToReplaceInfo2.FullName, true);
}
I do make sure to run it with Administrative privileges.
Anyone know why the program would seem to run fine, but not copy the files to that directory? Is there some Windows security thing stopping this?
Thanks to Mike Z and the link shared in the comments above. Turns out because I was running in a 32-bit process, the OS did not allow it to edit those files. Compiling to 64-bit did work.
Reposting the link:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa384187(v=vs.85).aspx

Windows\System32\drivers\etc and GetDirectories

Does anyone know what's so special about 'etc' in terms of directory enumeration, are there others like it and how to get around it being invisible?
public class Foo
{
[Test]
public void Etc()
{
var etc = new DirectoryInfo(#"C:\Windows\System32\drivers\etc");
Assert.True(etc.Exists);
/* Expected: not <empty> But was: <empty> */
Assert.IsNotEmpty(etc.Parent.GetDirectories(etc.Name));
}
}
You're running your code on a 64-bit machine as a 32-bit process. And you're seeing the effects of the file system redirector
C:\Windows\system32\drivers\etc is not redirected (it's documented as being exempt from redirection), and so is C:\windows\system32\drivers\etc for both a 32-bit or 64-bit process.
But when you step up to C:\windows\system32\drivers, you're redirected to C:\Windows\SysWow64\drivers if you're running in a 32-bit process. And that directory doesn't have an etc directory under it.
Hmm... It could be a permissions issue ( read permission maybe ), but you would probably get an error if that was the case.
See if it shows up using the Directory.GetDirectories(#"C:\Windows\System32\drivers") method on .
Here is the documentation.

Vista TaskDialog Wrapper: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32'

I'm try to use Vista TaskDialog Wrapper and Emulator and I'm getting the following exception:
"Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32'."
...in a simple Console application:
class Program
{
[STAThread]
static void Main(string[] args)
{
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
PSTaskDialog.cTaskDialog.MessageBox(
"MessageBox Title",
"The main instruction text for the message box is shown here.",
"The content text for the message box is shown here and the text willautomatically wrap as needed.",
PSTaskDialog.eTaskDialogButtons.YesNo,
PSTaskDialog.eSysIcons.Information
);
}
}
What am I doing wrong?
UPDATE:
Actually, I'm working on an Excel plugin using excel-dna. How can I control what dll Excel loads?
http://exceldna.codeplex.com/discussions/286990#post728888
I haven't been at Office programming in a while, but my guess is that Excel loads both versions of comctl32, so you may need to use the Activation Context API to direct your code to the version that includes TaskDialog. Some ideas for fixing the problem (not solutions as such):
For test purposes, make a temporary enumeration of all modules in the active process - just to check if 6.10 is actually loaded (see below for a simple example of such an enumeration, albeit with a different intent).
Use the Activation Context API to get to the right version. Example of use from C# (for enabling themes by way of comctl32 6.0) here.
Alternatively (I never actually got this to work reliably in a WPF application I worked on), make a dialog abstraction class, which falls back to MessageDlg depending on the version available to you. There may be better ways of doing the check, but...:
FileVersionInfo version = ProcessUtils.GetLoadedModuleVersion("comctl32.dll");
if (version != null && version.FileMajorPart >= 6 && version.FileMinorPart >= 1)
{
// We can use TaskDialog...
}
else
{
// Use old style MessageBox
}
The enumeration of modules:
internal static FileVersionInfo GetLoadedModuleVersion(string name)
{
Process process = Process.GetCurrentProcess();
foreach (ProcessModule module in process.Modules)
{
if (module.ModuleName.ToLower() == name)
{
return module.FileVersionInfo;
}
return null;
}
}
In addition to what all the others are saying: This error will disappear if you set the ForceEmulationMode on PSTaskDialog to true.

Categories

Resources