Process and Executable Filenames - c#

The C# Process class allows you to run a command-line executable in Windows. The Process.StartInfo class holds information about the command line job you want to run, including its path and filename.
My problem is that Process.Start() will throw an exception if the file does not exist. To try and avoid the exception, I coded a check to see if the file existed, but this did not work properly in all instances because a name might not exist as a file with that exact name, but might have an executable counterpart. For example, "C:\SoAndSo" might not exist as a file, but "C:\SoAndSo*.exe*" does, and would have been found successfully when starting the Process command.
I have hacked my checks to try the name given to me, and the name + ".exe" and ".bat", but this feels cludgy, and perhaps I am missing other executable extensions.
So: is there a command to ask the question: 'Do you have an executable version of the filename starting 'SoAndSo'?

Why not try to start the Process and wrap that in a try/catch and when you get a FileNotFoundException then you can simply print the output of that and exit? I see you want to try and avoid the exception but you might have more overhead trying to prevent it than just incurring it.

id had a similar requirment.. & i solved it using the environment variable %PATHEXT%.
reference can be found here,
say I'm trying to find a program called abcd then the app would look for
*abc*. with all extension combo available ion the %PATHEXT% variable..
I'd say this is a crude implementation.. but it worked for me.. I;m quite sure there is a better way to do this.

Related

Can I prevent invalid minidump file names

I have a WinForms (.NET C#) OLTP application based on Oracle.
From our support environment we regularly experience loss of connectivity to the database, and a resulting minidump file is generated (by what, i am not entirely certain of) - apparently it does not cause the application to crash, but in order to actually do anything you have to close it and start it again.
After a many such minidumps have been created in the same directory, all of a sudden the minidumps starts getting rather strange file names, filenames that are apparently "illegal" on windows.
For instance we have a file name like:
"°÷ƒ
_minidump_default_pid_20248_tid_x19AC_2015_9_1_8_31_51.dmp"
And yes the carriage return is PART of the file name.
We discovered this because log4net watches the directory and all of a sudden starts to bark unhandled exceptiosn due to these invalid file names.
So we are trying to figure out why the minidump is generated in the first place, but the question here is, can we somehow prevent the minidump from being generated with an invalid filename or otherwise control the naming process?
Secondly, does anybody know why is it even possible to create invalid file names in the first place?
Update:
For anyone looking at this trying to figure out why the dump files are created in the first place, our issue was that Windows was generating them when it was near running out of memory, but for some reason we would'nt always get an OOMException.
First, you should really try to find out how those dumps are generated. Microsoft e.g. provides a nice way using a Registry key called LocalDumps which has provided great help for me. I am sure that this approach won't generate invalid file names like above.
Second, if the application does not crash, it has probably registered an unhandled exception handler. This is basically ok and designed to write crash dumps, but the unhandled exception is handled by the crashing process itself. How can the code to handle the situation be sure he himself is not affected by the crash? The better option is to let Windows as the OS handle the crash. Then the Windows kernel (which is not affected by the crash) can really handle the situation. That's what LocalDumps does.
Third, direct file system access is possible in Windows via paths that start with \\.\ when passing it to the Windows API. Starting a path like that will skip any file name check so you can generate files with reserved characters such as *, ?, : or newlines as observed by you. The unhandled exception handler of your application is probably doing that and is affected by the crash in a way that parts of the file name are overwritten.
Chkdsk should be able to repair the file system.
pls check if you are installing from network path like \remoteserver\d$\client.
then change it to \remoteserver\d\clinet
"$" in share path create issue while extration on elevated permission files

Launching a file using Process.Start works, but adding conditions does not

So I am trying to launch a printer script using cscript from C#, and cscript launches a visual basic file. So sort of a daisy chain (and I want to keep this daisy chain intact for certain reasons).
Here's the code:
Process.Start("c:/windows/system32/cscript.exe c:/windows/System32/Printing_Admin_Scripts/en-US/prnport.vbs");
Now, when I launch ONLY cscript, no problems.
However when I add the condition of prnport.vbs to the cscript launch, I get this error in Visual Studio:
"The system cannot find the file specified"
But I can confirm the file path is correct - prnport.vbs DOES exist in /en-US.
So what am I doing wrong here? Can you not pass arguments (and in this case, the file path is being passed as an argument to cscript.exe) when using Process.Start?
New to C# and confused about the proper way to do this.
You have to specify the arguments separately from the file to run. Try the Process.Start(string, string) overload:
Process.Start("c:/windows/system32/cscript.exe",
"c:/windows/System32/Printing_Admin_Scripts/en-US/prnport.vbs");
That's an Argument, you'll need to use another overload of Process.Start
Have a look at the method's documentation.
Process.Start (String, String) will do, others are possible and offer more flexibility, if you should need that, too.
The Process.Start expects the file name as the first parameter. The arguments are given in separate argument.

How can I delete a file that is in use by another process?

When I try to delete a file occurs the following exception:
The process cannot access the file ''
because it is being used by another
process.
My code looks like:
string[] files = Directory.GetFiles(#"C:\SEDocumentConverter\SOURCE");
foreach (string file in files)
{
File.Delete(file);
}
How can I solve this problem?
There is no way to delete a file that's currently being used by another process. You have to close whatever program has that file open first, before you can delete it.
If you don't already know which program that is, you can figure it out using Handle or Process Explorer.
You can P/Invoke the Windows MoveFileEx function, and use the MOVEFILE_DELAY_UNTIL_REBOOT flag, with a NULL destination name. This will delete the file when you reboot.
If the file is being used you're out of luck in trying to delete it. I can't tell you based on your code what process might be using the file(s), but try looking here or here or here, or at any of the other questions that show up as related to this one for guidance regarding this issue, and by all means follow the guidance from #Cody Gray about using Process Explorer.
slightly off topic: But it seems from your code that you are trying to delete all files of your folder.
Well instead of deleting them one by one we have another method Directory.Delete(path, True) which will delete the directory as contained in the string named path. Then you may recreate the directory if you want. But your problem may persist here too.
Another way is to find all open handles to the file and close them forcibly.
Works nice for you, bad for any apps which were using the file.
Could try that in UI with SysInternals ProcessExplorer.
Just rename this file. This will do the thing for whoever tries to write to that location.
Notes:
1) Of course the file is not deleted physically yet. Nice to do the MoveFileEx trick mentioned here around to complete the job.
2) If you want to delete a locked file to write smth new in its place (e.g. during build), just rename the file to a GUID name. If you need the folder to be clean, either use an ignored extension / hidden attribute, or rename the file to a path under %TEMP% (if on the same drive).
3) Not all locked files can be renamed, but it works for me for like 90% practical applications. You can move a file without affecting an open read/write/execute handle, it will continue working with the moved file just good (if moved within the same NTFS volume of course).
4) That's what Windows Installer would basically do before it asks you to please reboot somewhen soon: move the file away from your eyes, schedule to be removed upon reboot. Usually the newly-installed app can be used right away.
Practical Use:
My favorite is with MSBuild. Overriding the <Copy/> task with this stuff makes all the build go linux-way. You don't care if a prev version is still running somewhere, can still build&run. The old app keeps using the old version of the files. The new app loads the newly-written version.
Might be moving to %TEMP% if on the same drive (not my case though). I'd just rename them to an extension which is ignored with the current source control client.

What steps shall I take before building a command line application using C#

I want to develop a command line tool. I didn't build one before, but I used a few, (like mercurial). What steps do I need to take to know how to do that? So what is the problem:
Regular console application need to be invoked from the command line only from it's directory. Like: C:\Projects\CommanLineProject\MyProjectConsole.exe. I want to use it from the command line from any directory, like mercurial.
I don't sure how to parse and how to use the command-line arguments. There are programs that taking this arguments: c:\>MyProject "c:\point to this path" /xml:"here is the another path" /r.
A command line tool is just a regular console application. You can use the string[] args parameter from the Main method to retrieve any arguments that are passed to the application.
I would go look at this stack overflow question as it has links to some good command line parsing libraries in the answers.
One thing you'll need to do, if the application is to take any but the most basic arguments, is select a cmd line parsing library, as there is not one provided by the Framework.
I would look into the following link before making a significant command line application.
http://commandline.codeplex.com/
For question/edit #1:
If you add the path to the executable to your operating system's 'Path' environment variable, you can run the application from any directory. More info on setting it for Windows XP.
Also, you may need to retrieve the current working directory when the application is started. I believe you can use Environment.CurrentDirectory to get this. I'd suggest saving it in case you need to do something that might change the current directory for your process.
For question/edit #2:
You can use something like this to parse the actual arguments that are passed into the application via the args string array. However, what you do with the arguments after that point is completely up to you. There's nothing stopping you from just going through the array and dealing with the arguments manually (foreach (string arg in args) {...}) if you prefer.
If you want to make the first command line argument the path to a file to write to, so be it. If you want to have an optional argument like /verbose then that works as well. You are really only limited to your imagination (and the limits of what can be legally typed on the command line :) )

Is it worth it to lookup the default application in the registry when opening a file from a C# application?

I'm building an application (a side project which is likely to enlist the help of the stackoverflow community on more than one occasion) which will need to open a variety of file types (i.e. open Word documents in Word, not natively in my application).
I've been playing with some code for looking up the default application for the file type in the registry and passing this to Process.Start(). There seem to be two issues with this approach:
1) The application name is quoted in some instances, and not in others.
2) Process.Start() requires that the application path and it's arguments are passed separately (i.e. Process.Start("notepad.exe", #"C:\myfile.txt"); rather than Process.Start(#"notepad.exe C:\myfile.txt");).
This means when I retrieve the path from the registry, I have to split it (after determining if I need to split on quotes or spaces) to determine what part is the application path and what parts are arguments, then pass those separately to Process.Start().
The alternative seems to be to just pass the filename, as in Process.Start(#"C:\myfile.txt"), but I think this only works if the application is in the Path environment variable.
Which way is better? In the case of the registry, is there a common solution for how to do the argument parsing?
Thanks for any and all help!
Update:
I guess the short answer is 'No.'
It seems like I was really going the overkill route, and that passing just the filename will work whenever there's an associated value in the registry. I.e. anything I find in the registry myself, Process.Start() already knows how to do.
I did discover that when I try this with a "new" filetype, I get a Win32Exception stating "No application is associated with the specified file for this operation." Fredrik Mörk mentions in a comment that this doesn't occur for him in Vista. What's the proper way to handle this?
If the extension is registered to be opened with a certain application, it doesn't need to be in the PATH in order to run.
The application does not need to be in the PATH if you only specify the filename. The following code worked fine for me:
System.Diagnostics.Process.Start(#"C:\Users\Dan\Desktop\minors.pdf");
You typically do not need to lookup the program for registered types, and the program does not typically need to be in the PATH environment variable. Usually the command in the registry contains the full path. This is how the command for .kml files (Google Earth) looks (in my computer):
C:\Program Files\Google\Google Earth\googleearth.exe "%1"
Given that, you can safely just use Process.Start together with the document file names. Should it be that the file type is not registered you will invoke the default Windows behaviour for this (asking you which program to use, and so on).

Categories

Resources