I'm creating a C# app that should use lpr.exe and pass arguments to it. I'm currently trying to do it this way:
DirectoryInfo filePathDirectory = new DirectoryInfo(filePath);
Process a = new Process();
a.StartInfo.FileName = #"C:\Windows\System32\lpr.exe";
a.StartInfo.Arguments = "-SServerName.Domain.net -Plp " + "\"" + filePathDirectory + "\"";
a.StartInfo.UseShellExecute = false;
a.Start();
a.WaitForExit();
But whenever I get to a.Start(); I get an unhandled Win32 exception which states "The system cannot find the file specified". This is really confusing me becuase, at first I thought it was my arguments, but turns out, I can pass the exact same arguments from a VB app and get it to work.
Update 1:
The VB code that works is:
Dim RPname As String
RPname = FileName.ToString
Dim a As New Process
a.StartInfo.FileName = "C:\Windows\system32\lpr.exe"
a.StartInfo.Arguments = "-SServerName.Domain.net -Plp " & Chr(34) & RPname & Chr(34)
a.StartInfo.UseShellExecute = False
a.Start()
a.WaitForExit()
What's more is that my issue doesn't seem to be with the arguments statement, as I can comment it out and I still receive the error.
Update 2:
The error I get at the start of the process is: The system cannot find the file specified. I do not get the error if I change the FileName to "C:\Windows\System32\cmd.exe", that works fine...
You are using a DirectoryInfo object in your c# code and concetanate it. Try to change your code to this:
try
{
DirectoryInfo filePathDirectory = new DirectoryInfo(filePath);
Process a = new Process();
a.StartInfo.FileName = #"C:\Windows\syswow64\lpr.exe"; // ADAPTED to the new path!! worked!
// use filePathDirectory.FullName!!
a.StartInfo.Arguments = "-SServerName.Domain.net -Plp " + "\"" + filePathDirectory.FullName + "\"";
// or change it to - found it more readable imo
a.StartInfo.Arguments = string.Format(
"-SServerName.Domain.net -Plp \"{0}\"",
filePathDirectory.FullName);
a.StartInfo.UseShellExecute = false;
a.Start();
a.WaitForExit();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
EDIT
Found the solution to your problem! First - credits go to #Sundeep according to his given answer. He pointet me to a webSite indicating that
Yes I have, but 64-bit files located in c:\windows\system32 is not
seen by a 32-bit command prompt (c:\windows\syswow64\cmd.exe) which is
launched when call at batch file from a 32-bit application.
And furthermore
... trying to get a 32 bit program to launch
lpr.exe inside of Windows 2008 R2. It fails because lpr.exe does not
exist in the 32 bit view of the O/S. ...
For a work-around, I copied lpr*.* from a 32 bit O/S system32 folder
into SYSWOW64 on the 2008 R2 machine...
Change your code to this:
DirectoryInfo filePathDirectory = new DirectoryInfo(filePath);
Process a = new Process();
a.StartInfo.FileName = #"C:\Windows\Sysnative\lpr.exe";
a.StartInfo.Arguments = "-SServerName.Domain.net -Plp " + "\"" + filePathDirectory + "\"";
a.StartInfo.UseShellExecute = false;
a.Start();
a.WaitForExit();
Pilgerstorfer Franz' explanation is exactly right, but especially in an environment like mine, going and moving the location of the lpr.exe on every machine is a lot of work. The simple solution is to use the sysnative directory.
http://www.samlogic.net/articles/sysnative-folder-64-bit-windows.htm
The 'Sysnative' folder is invisible in Windows Explorer If you
start Windows Explorer and open the Windows folder on your hard disk,
you may notice that the Sysnative folder is not shown. The main reason
to this is that Windows Explorer is a 64-bit program (when run in a
64-bit Windows), and the Sysnative folder is only visible and
accessible from 32-bit software. If 64-bit software need access to the
64-bit system folder in Windows, the only option is to use the
System32 folder name (for example: C:\Windows\System32).
Using the 'Sysnative' folder will help you access 64-bit tools from
32-bit code Some tools in a 64-bit Windows only exist in a 64-bit
version; there is no 32-bit version available. And some of these tools
are located in the 64-bit System32 folder. One example is the nbtstat
tool that is used to help troubleshoot NetBIOS name resolution
problems. If you try to run the nbtstat tool from 32-bit code (for
example from an application or from script) and use a path like
C:\Windows\System32, you will get a "File not found" error. The file
can not be found; although Windows Explorer shows that the nbtstat
program file actually is located in the C:\Windows\System32 folder.
The solution to this (somewhat confusing) problem is to include the
virtual Sysnative folder in the folder path when you want to run the
tool. For example like this: C:\Windows\Sysnative\nbtstat.exe The
file path above will give you access to the 64-bit nbtstat tool from a
32-bit application or from a 32-bit script. We recommend you to read
this article / blog post (at Scottieās Tech.Info) to get more details
about this.
Related
I am running a VBS file that needs to be executed on the 64-bit version of cscript. On the command line, when I call cscript, it opens the 64-bit version located at C:\Windows\System32\cscript.exe and the VBS file works fine.
However, I'd like to call this VBS file through C# as a Process. Starting the process with the FileName as cscript does open cscript, but only opens the 32-bit version, located at C:\Windows\SysWoW64\cscript.exe.
Even when I set the FileName to specifically point to the 64-bit version of cscript, it only loads the 32-bit version.
How can I force the process to open the 64-bit version of cscript?
Here is my code, including the 64-bit version file path explained above:
string location = #"C:\location";
Process process = new Process();
process.StartInfo.FileName = #"C:\Windows\System32\cscript.exe";
process.StartInfo.WorkingDirectory = location+#"\VBS\";
process.StartInfo.Arguments = "scriptName.vbs";
process.Start();
Depending on your requirements there is another solution.
Some background: When you run a 64-Bit application and try to start cscript.exe then you call C:\Windows\System32\cscript.exe (or more general %windir%\System32\cscript.exe)
However, when you run a 32-Bit application then each call to %windir%\System32\ is automatically redirected to %windir%\SysWOW64\. In this directory you will find all your 32-Bit DLL's. This redirection is done by Windows internally and your application does not recognize any difference.
In order to access %windir%\System32\ from a 32-Bit application you can use %windir%\Sysnative\, i.e. process.StartInfo.FileName = #"C:\Windows\Sysnative\cscript.exe"; should work even if you compile your application as 32-Bit.
Note, folder %windir%\Sysnative\ does not exist in 64-Bit environment, thus you may check your run-environment by Environment.Is64BitProcess, so
if Environment.Is64BitProcess {
process.StartInfo.FileName = #"C:\Windows\System32\cscript.exe";
} else {
process.StartInfo.FileName = #"C:\Windows\Sysnative\cscript.exe";
}
See also File System Redirector
Note, a similar mechanism exists also for the Registry, see Registry Redirector
A simple answer has arose:
In my C# application I am creating, in Visual Studio (2017) had selected my Platform target to Prefer 32-bit, which should perhaps better be called as "force 32-bit".
By unselecting this option, my process ran as 64-bit, both by specifying the 64-bit path as the code above, but also by just running the cscript by name.
process.StartInfo.FileName = "cscript";
Toggle this option inside Properties > Build > Prefer 32-bit
I need to start updater application by passing URL of the patch file. Basic Process.Run works fine, however when I pass argument nothing happens. (This is Linux Mint and Mono)
I have already checked SO, net, etc. and tried solutions such as setting UseShellExecute to false or using ProcessStartInfo.
What am I doing wrong ?
Updater is located in the same folder where the main exe is.
Mono console shows no errors.
Works : (works for everyone so no surprise there)
Process.Start (Application.StartupPath + #"/Updater.exe");
Doesn't work (Nothing happens, also expected ?) :
Process.Start(Application.StartupPath + #"/Updater.exe", "URLToFile");
From other solutions I have tried :
Process.Start(new ProcessStartInfo(Application.StartupPath + #"/Updater.exe", #"URLToFile.zip") { UseShellExecute = false });
I also tried many solutions proposed here :
How to use Process.Start() or equivalent with Mono on a Mac and pass in arguments
And I checked some other blogs and google results. No solution ever worked for me sadly.
More info that might not be as important but could help :
Code works in Windows
I run Mono code separated from Windows code by checking platform
Application checks for updates then starts updater and closes itself
Updater is located in the same folder in which the main exe is
Updater is separated project
This is an portable application
What am I doing wrong? Thanks.
Try to prefix "mono " since you want in fact to run mono with your .exe as an argument. Also I determine the application path in another way:
string sAppPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Process.Start("mono " + sAppPath + #"/Updater.exe");
Sorry, I did not test my code. Now I did a small project and tested it - just a form with a label and a button. Working fine. I'm getting the right path and the HelloWorld App gets started and processes the CmdLineArg. Here the core content comes:
private void DoIt()
{
string sAppPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
psi.FileName = "mono";
psi.Arguments = sAppPath + #"/HelloWorld.exe CmdLineArg";
System.Diagnostics.Process.Start(psi);
}
I have an ASP .NET application that starts sqlcmd.exe as a Process. In two of our three test environments, we have no problems. However, on the third machine, even though sqlcmd.exe was installed along with client connectivity tools, Process.exe cannot find sqlcmd.exe. The error shown is:
Error running process: System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at L3_CNM.Utilities.Common.SqlcmdHelper.RunRemoteScript(String ServerAddress, String datbaseName, String filePath, String outputFilePath
I am at a loss for why this happens. The differences between the case when everything is fine as opposed to when it fails are:
1) When it works, there is a full SQL server installation. When it fails, we are only installing sqlcmd as a downloaded installation package which points to a SQL server that resides elsewhere.
2) When it works, the application is running from the same disk volume as Windows installation. On the machine that fails, the application is installed on another volume from the Windows installation.
Other key points - the PATH variable shows the location to sqlcmd.exe, the user that is the application pool identity is a part of the local system administrators, when running sqlcmd.exe through command prompt the results are expected.
Any help would be highly appreciated.
Thanks
EDIT: Adding code:
try
{
Process process = new Process();
process.StartInfo.FileName = "sqlcmd.exe";
Logging.Instance.Log(Logging.Levels.Message, "Process start arguments: " + process.StartInfo.Arguments);
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.CreateNoWindow = true;
if (process.Start())
Logging.Instance.Log(Logging.Levels.Message, "Process successfully started");
else
{
Logging.Instance.Log(Logging.Levels.Message, "Unable to start process");
}
string output = process.StandardOutput.ReadToEnd();
output += process.StandardError.ReadToEnd();
process.WaitForExit();
Logging.Instance.Log(Logging.Levels.Message, "Process exited with output: " + output);
return output;
}
catch (Exception e)
{
Logging.Instance.Log(Logging.Levels.Error, "Error running process: " + e.ToString());
return e.ToString();
}
I would guess it's about the PATH environment variable.
Couple of tests! One, open a command window and type
WHERE SQLCMD
This will print out anywhere SQLCMD can be seen. If you get nothing, you'll need to update your path. If you get something, it may be a user environment variable, not the system environment variable, which is what ASP.NET would use.
Can you check that the SYSTEM version of this variable contains the right folder? On win8 and above, open start menu and type "edit the system environment variables". Then click "environment variables" and make sure, under System Variables, that PATH contains the folder returned by WHERE SQLCMD If not, put it in, separating from other folders with a semicolon.
A simple Reboot. God I hate Windows sometimes.
Thanks #Methodman for the suggestion.
i'm starting a child application from my main process with the following code:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = DestinationNameEXE;
startInfo.WorkingDirectory = Toolbox.AssemblyDirectory;
startInfo.UseShellExecute = true;
startInfo.Arguments =
binParameter + #" """ + _BINPath + #" """
+ tmpParameter + #" """ + binFolder_ForExtration + #" """;
Process.Start(startInfo);
before i do this i check if the process has write rights in the binFolder_ForExtration and _BInPath with following code (source) and a simple write file check:
try
{
using (File.Create(tmpfile)) { }
File.Delete(tmpfile);
createFilesAllow = true;
}
catch
{
createFilesAllow = false;
}
in the main process i can write & create files. also the function HasWritePermissionOnDir returns true.
in the new process i'm doing the same test, but in this case i got from HasWritePermissionOnDir true, but if i try to create a file, i got an exception. the new process has the rights to change existing files.
how can this be? what i'm doing wrong?
how can the new process have less rights then the first process?
i don't change the user context.
i' have also tested to start the process with ProcessAsUser.Launch (source) but without any change. the new process dond't have the right to create new files in the given folder.
if i start the process with elevated rights:
startInfo.Verb = "runas";
everything works finde. the new process can write, create and change files in the given folder.
thx for any help
Update:
i'm testing on a windows 7 x86
the main process is compiled with target x86 and .Net 4.5. its a dll called from a vb6 application
the user i'm testing with has admin rights (but it's not the user administrator). the main process is started with normal rights settings (not elevated rights)
the new process is compiled with target any CPU and .Net 4.5.
since i require access to Process.GetProcesses in the new process it should be compiled as any CPU to be used on x86 and x64 systems (as far as i know)
currently all folder tests and occured errors happend in the folder *c:\Program Files (x86)\appname\BIN*. in the code i'm using full path and test the correctness of the path with direcotry.exist() bevore any execution.
I am trying to create a manager for my autostarts. It should read an XML file and then start my programs with a custom delay. For example:
<startup id="0">
<name>Realtek Audio Manager</name>
<process arguments="-s">C:\Program Files\Realtek\Audio\HDA\RtkNGUI64.exe</process>
<delay>5</delay>
</startup>
This runs the specified process (C:\Program Files\...\RtkNGUI64.exe -s) after 5 seconds.
Now, three of the programs won't start, giving me a System.ComponentModel.Win32Exception: "Das System kann die angegebene Datei nicht finden." ("The system was not able to find the specified file.")
But the XML is parsed correctly, and the file I want to start is at the location I specified in the XML file.
The problem concerns only these three files:
Intel HotkeysCmd - C:\Windows\System32\hkcmd.exe
Intel GFX Tray - C:\Windows\System32\igfxtray.exe
Intel Persistance - C:\Windows\System32\igfxpers.exe
I think that the problem comes from the location of the files: they all are located in C:\Windows\System32, and all the other, working programs are located outside (C:\Program Files, C:\Program Files (x86), D:\Program Files, %AppData%)
Do I have to give my program some kind of access rights to start programs in C:\Windows\System32? How would I do that?
If not, what could be the reason I get errors with these programs?
EDIT - my code:
delegate(object o)
{
var s = (Startup) o;
var p = new System.Diagnostics.Process
{
StartInfo =
new System.Diagnostics.ProcessStartInfo(s.Process, s.Arguments)
};
try
{
s.Process = #"C:\Windows\System32\igfxtray.exe"; // For debugging purposes
System.Diagnostics.Process.Start(s.Process);
icon.ShowBalloonTip(2000, "StartupManager",
"\"" + s.Name + "\" has been started.",
System.Windows.Forms.ToolTipIcon.Info);
}
catch (System.ComponentModel.Win32Exception)
{
icon.ShowBalloonTip(2000, "StartupManager",
"\"" + s.Name + "\" could not be found.",
System.Windows.Forms.ToolTipIcon.Error);
}
}
Clearly you are using a 64-bit version of Windows. The c:\windows\system32 and c:\program files directories are subject to a feature called "file system redirection". It is an appcompat feature, it helps to ensure that 32-bit processes don't try to use 64-bit executables. They'll get redirected to c:\windows\syswow64 and c:\program files (x86).
So when you try to start a file in c:\program files\realtek\etcetera, your 32-bit program will be redirected to c:\program files (x86)\realtek\etcetera. A directory that doesn't exist, kaboom. Same ingredient for igfxtray.exe
You'll need to change your program's platform target so it can run as a native 64-bit process and avoid the redirection problem you now have. Project + Properties, Build tab, change the "Platform target" setting to AnyCPU.