I'm making a C# program and I need to find installation paths of some software that is installed on a computer.
What I have to work with is, I have the Program's name (e.g. Google Chrome), i have the process name (e.g. Chrome.exe).
What I need now is the path to Chrome.exe. How can i use C# to find the path if i was to pass either the program name or process name as a parameter for the search?
Actually I want to make a custom action which will find chrome.exe and invoke a link.
After that I will use the path for search chrome.exe and I want to default open a website via chrome. What should I do..?
Another option to consider is just launching the link using Process.Start() and letting the operating system use the default browser to open the link. That would likely be more what the user would expect.
In the WiX toolset, you can get that behavior for free using ShellExecute standard custom action from the WixUtilExtension.
You could try something like this
public string GetProcessPath(string name)
{
Process[] processes = Process.GetProcessesByName(name);
if (processes.Length > 0)
{
return processes[0].MainModule.FileName;
}
else
{
return string.Empty;
}
}
or you could use Linq
or you could do what you do but use linq
Process element = ( from p in Process.GetProcesses()
where p.ProcessName == "Chrome.exe"
select p ).FirstOrDefault( );
However there can be multiple process with same name .So you have to further modify the code according to your requirement.
hope this helps
Related
Using .NET Core, C#, Linux
I've searched around a bit and can't seem to find anything. Maybe it's not possible and I need a different approach?
Can someone kindly point me in the direction of how I can go about getting the directory listing for a given path for a specific username?
I am running a web application service as Root but need to check and return directories and files for a given username (no password is available) - to report directories and files that a given username has read-access to.
Say for example "/opt/mydata/" and in there I will have a number of directories that I will manually create and set the permissions for each user group. I.e. "/opt/mydata/user_1_readable" will be returned when I do a directory listing for user1 (because this user is in the respective permissions group, or is the owner, or it is set for everyone to read) but will not be returned for user2 (this user is not in the correct group).
Essentially, I want to "impersonate" or in Linux, do the equivalent of "sudo su user1" and report what directories/files are readable within "/opt/mydata/" for a given user.
I can get the directory listing and files fine running as Root. What I can't do / don't know how to is getting the directory listing for a specific user. The examples I found and tried are all Windows Identity and Windows Security specific.
E.g. I found this example but it seemed to apply to "Mono" which I am not running, but essentially I really want to do something along the lines of this:
// Impersonate a user
using (WindowsIdentity newId = new WindowsIdentity("user1"))
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
var content = _fileProvider.GetDirectoryContents(uri);
}
Is there some third party library or some other way please?
Resource:
Change current Linux user in a C# application running with Mono?
If you look at this issue on .net core repository, Proposal: Expose POSIX functions , it looks like it won't be implemented in .net core, but only in Mono.Posix.NETStandard.
The library is compatible with .net core 2.0, and it shouldn't be too hard to implement this yourself.
You could try something like this with the package to filter which files the user can read.
public UserHasReadPermission(string username, string file)
{
var user = new UnixUserInfo(username);
var file = new UnixFileInfo(file);
// Everyone has read permission
if (file.FileAccessPermissions.HasFlag(FileAccessPermissions.OtherRead))
return true;
// User owns the file and has read permission
if (file.OwnerUser == user && file.FileAccessPermissions.HasFlag(FileAccessPermissions.UserRead))
return true;
// User group owns the file and has read permission
if (file.OwnerGroup == user.Group && file.FileAccessPermissions.HasFlag(FileAccessPermissions.GroupRead))
return true;
return false;
}
Perhaps you want to read the /etc/passwd file to get users' directories?
Once you have that, you can then get all subdirs inside the folders:
List<string> AllFiles = new List<string>();
void ParsePath(string path)
{
string[] SubDirs = Directory.GetDirectories(path);
AllFiles.AddRange(SubDirs);
AllFiles.AddRange(Directory.GetFiles(path));
foreach (string subdir in SubDirs)
ParsePath(subdir);
}
I want to open a file's location and select the file in explorer on Mac, Ubuntu from MonoDevelop.
This code is working on Windows (but it is not working on Mac and Ubuntu):
System.Diagnostics.Process.Start("explorer.exe", "/select, " + fileaddress);
Dim dir_path As String = "/media/os/test"
' Windows path example: dir_path = "C:\test"
Process.Start("file://" & dir_path)
Tested and worked on Ubuntu and Windows XP.
Source: http://www.stevenbrown.ca/blog/archives/156
By 2020-10, in mono 6.10, the above method didn't work on Ubuntu 20.04. The below approach solved the problem.
System.Diagnostics.Process.Start("mimeopen", "/var/tmp");
You can use 'open' on Mac, like this
System.Diagnostics.Process.Start("open", $"-R \"{File_Path_You_Wanna_Select}\"");
Here -R means reveal, to select in the Finder instead of opening.
To find more usage for open, just type open in terminal.
Using Process.Start() you bypass the .NET framework and move into the platform you're running onto, executing an arbitrary process.
On Windows you want to open the Windows Explorer, on Mac you want to open Finder and on Ubuntu it's simply called File Browser.
There is no Environment.OpenFileBrowser(string path) method in the framework, so you will have to let your program determine which platform it is running on, and open the approperiate file viewer.
See How to check the OS version at runtime e.g. windows or linux without using a conditional compilation statement to perform the former.
You are calling an OS specific (Windows) method. That won't work cross-platform.
Try the following inside a function/method:
Example - inside click event:
protected void OnOpen (object sender, EventArgs e)
{
using(FileChooserDialog chooser =
new FileChooserDialog(null,
"Select document to open...",
null,
FileChooserAction.Open,
"Open Selected File",
ResponseType.Accept,
"Discard & Return to Main Page",
ResponseType.Cancel))
{
if (chooser.Run () == (int)ResponseType.Accept)
{
System.IO.StreamReader file = System.IO.File.OpenText (chooser.Filename);
/* Copy the contents to editableTxtView <- This is the Widget Name */
editableTxtView.Buffer.Text = file.ReadToEnd ();
/* If you want to read the file into explorer, thunar, Notepad, etc.,
* you'll have to research that yourself. */
//Close file - - KEEP IT CLEAN - - & deAllocated memory!!
file.Close ();
}
}
}
The file has now been copied into an editable (Default) or read only (set in properties pad) textviewer Gtk widget. From there you should be able to manipulate it as you so choose.
It is sometimes desirable to have your application open the default application for a file. For example, to open a PDF file you might use:
System.Diagnostics.Process.Start("Filename.pdf");
To open an image, you'd just use the same code with a different filename:
System.Diagnostics.Process.Start("Filename.gif");
Some extensions (.gif for example) just about always have a default handler, even in a base Windows installation. However, some extensions (.pdf for example) often don't have an application installed to handle them.
In these cases, it'd be desirable to determine if an application is associated with the extension of the file you wish to open before you make the call to Process.Start(fileName).
I'm wondering how you might best implement something like this:
static bool ApplicationAssociated(string extension)
{
var extensionHasAssociatedApplication = false;
var condition = // Determine if there is an application installed that is associated with the provided file extension.;
if (condition)
{
extensionHasAssociatedApplication = true;
}
return extensionHasAssociatedApplication;
}
I would recommend following the advice in David's answer BUT since you need to detect an association:
To check whether a file has an association you can use the native function FindExecutable which is basically what Windows Explorer uses internally... it gives a nice error code (SE_ERR_NOASSOC) if there is no association. Upon success it gives a path to the respective executable.
Thee DllImport for it is
[DllImport("shell32.dll")]
static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult);
Another option would be to walk the registry for example (not recommended since complex due to several aspets like WoW64 etc.):
The real association is stored in the key that HKEY_CLASSES_ROOT\.pdf points to - in my case AcroExch.Document, so we checkoutHKEY_CLASSES_ROOT\AcroExch.Document. There you can see (and change) what command is going to be used to launch that type of file:
HKEY_CLASSES_ROOT\AcroExch.Document\shell\open\command
#Yahia gets the nod. I'm posting my quick solution for posterity so you can see what I went with. There are lots of possible improvements to this code, but this will give you the idea:
public static bool HasExecutable(string path)
{
var executable = FindExecutable(path);
return !string.IsNullOrEmpty(executable);
}
private static string FindExecutable(string path)
{
var executable = new StringBuilder(1024);
FindExecutable(path, string.Empty, executable);
return executable.ToString();
}
[DllImport("shell32.dll", EntryPoint = "FindExecutable")]
private static extern long FindExecutable(string lpFile, string lpDirectory, StringBuilder lpResult);
In a situation like this the best approach is to try to open the document and detect failure. Trying to predict whether or not a file association is in place just leads to you reimplementing the shell execute APIs. It's very hard to get that exactly right and rather needless since they already exist!
You will have too look at the registry to get that information.
You can follow from:
HKEY_CLASSES_ROOT\.extension
and it usually leads to something like HKEY_CLASSES_ROOT\extfile\Shell\Open\Command
and you will come to the command to open the file type.
Depending on what you are doing, it may be ideal to just ask for forgiveness ( that is, just open the file and see)
All of that information lives in the registry.. you could navigate to HKEY_CLASSES_ROOT, find the extension and go from there to find the default handler. But depending on the type of file and the associated handler(s) you'll need to wade into CLSIDs and whatnot... you're probably better off catching an exception instead.
This information is in the registry. For example:
# Mount the HKCR drive in powershell
ps c:\> new-psdrive hkcr registry hkey_classes_root
ps c:\> cd hkcr:\.cs
# get default key for .cs
PS hkcr:\.cs> gp . ""
(default) : VisualStudio.cs.10.0
...
# dereference the "open" verb
PS hkcr:\.cs> dir ..\VisualStudio.cs.10.0\shell\open
Hive: hkey_classes_root\VisualStudio.cs.10.0\shell\open
Name Property
---- --------
Command (default) : "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" /dde
ddeexec (default) : Open("%1")
I have a c# program which open *.postfix file.
If a user runs a (.lnk)shortcut which points to my type of file, my program will open the target.
So, how could my program know it is started by a (.lnk)shortcut (and get it's file path)?
In some circumstances,i need to replace the .lnk file.
Thanks!
Edited
First, thanks to guys who answered my question.
By following #Anders answer, i find out my problem lays here.
I made some changes to windows registry, so browser knows to throw customized protocol string to certain program.
some thing like this..
[InternetShortcut]
URL=myProtocol://abcdefg.....
That's maybe why i lost lpTitle. :(
I'm going to try this way:
Whenever my program invoked, of course fed with %1, program checks current opened explorer(Window), and try to get it's current path with IWebBrowserApp. With that path and desktop of course, scan and analyze *.lnk to determine which one to replace.
I think this will probably work, but not be sure. I will try.
continued
In native code you can call GetStartupInfo, if the STARTF_TITLEISLINKNAME bit is set in STARTUPINFO.dwFlags then the path to the .lnk is in STARTUPINFO.lpTitle. I don't know if there is a .NET way to get this info, you probably have to P/Invoke...
You don't. There's no way to do it. End of story.
So this has been brought to my attention due to a recent downvote. There's an accepted answer showing an idea that gets the path to the launching shortcut most of the time. However my answer is to the whole. OP wants the link to the shortcut so he can change it. That is what can't be done most of the time.
Most likely case is the shortcut file exists in the start menu but is unwritable. However other cases involve the shortcut coming from another launching application that didn't even read it from a disk but from a database (I've seen a lot of corporate level restricted application launch tools). I also have a program that launches programs from shortcuts not via IShellLink but by parsing the .lnk file (because it must not start COM for reasons) and launching the program contained. It doesn't pass STARTF_TITLEISLINKNAME because it's passing an actual title.
If you're using Visual Studio Setup Project to build an installer and do the file type association, you should follow these instructions http://www.dreamincode.net/forums/topic/58005-file-associations-in-visual-studio/
Open up your solution in Visual studio.
Add a Setup Project to your solution by file , add project,New project, Setup & Deployment projects,Setup project
Right-click on your setup project in the "Solution Explorer" window,Select view,then select file types.
you'll see the "file types" window displayed in Visual studio.At the top of the window will be "File types on target machine"
Right-click on "File types on target machine".the menu will pop up with Add "file type" Click on this.
you'll see "New document Type#1" added,and "&open"underneath it.
The "new document type#1" can be anything you want - change it to something descriptive.although the user never sees this,never use something common- be as unique as possible,Because you can overlay current file associations without even realizing it.For example,you might think"pngfile" might be a useful name- but using that will now send all"*.png" files to your application,instead of to an image viewer.A good practice maybe "YourCompantName.Filetype",where your company name is your name of your company's name, and "Filetype" is a descriptive text of your file.
In the "properties" window for your new type,you will need to change a few properties.:
Command:Change to the application that you want to run.If you click on the "..." and you will proberly want to locate and use the "primary Output..." File
Description: This is the description of the file type(if it doesn't describe it's self"
Extensions:This your list of extensions for you chosen Program.Separate each one with a ","
Icon:This will associate the icon with your file type,This shows up in the window explorer.
Now we move to that "&open ".This is an action that is available if your right-click on the file.The default action("&Open" is currently set as the default) is what happens when you double click on the file.Right click on your "New document type#1" to add actions,but for the moment,lets define our "&open" action
Click on "&Open".You will see in the properties window "Name","Arguments","Verbs". Verb is hidden from the user,but is the key that is stored in the registry.Leave it same as the name,But without the "&".The default for"Arguments" is "%1",Which means to pass the full path and filename to your application.You can add other stuff here as well,if you need to pass flags to your application to do special stuff.All this infomaton is getting passed to your application on the command line,so you'll need to be familiar with the "Environment.CommandLine" object.
If you need to set a different action as your default,just right click on the action and "set as default"
Basically, you'll pass the file path as an argument to your program. Then if it's a console application or Windows Forms , you should check the arguments in Program.Main
static void Main(string[] args)
{
//if file association done with Arguments %1 as per forum post above
//you file path should be in args[0]
string filePath = null;
if(args != null && args.Length > 0)
filePath = args[0];
}
For a WPF application you'll need to handle that in the StartUp event for your Application
void App_Startup(object sender, StartupEventArgs e)
{
string filePath = null;
if ((e.Args != null) && (e.Args.Length > 0))
{
filePath = e.Args[0];
}
}
I'm building a web application in which I need to scan the user-uploaded files for viruses.
Does anyone with experience in building something like this can provide information on how to get this up and running? I'm guessing antivirus software packages have APIs to access their functionality programatically, but it seems it's not easy to get a hand on the details.
FYI, the application is written in C#.
Important note before use:
Be aware of TOS agreement. You give them full access to everything: "When you upload or otherwise submit content, you give VirusTotal (and those we work with) a worldwide, royalty free, irrevocable and transferable licence to use, edit, host, store, reproduce, modify, create derivative works, communicate, publish, publicly perform, publicly display and distribute such content."
Instead of using a local Antivirus program (and thus binding your program to that particular Antivirus product and requesting your customers to install that Antivirus product) you could use the services of VirusTotal.com
This site provides a free service in which your file is given as input to numerous antivirus products and you receive back a detailed report with the evidences resulting from the scanning process. In this way your solution is no more binded to a particular Antivirus product (albeit you are binded to Internet availability)
The site provides also an Application Programming Interface that allows a programmatically approach to its scanning engine.
Here a VirusTotal.NET a library for this API
Here the comprensive documentation about their API
Here the documentation with examples in Python of their interface
And because no answer is complete without code, this is taken directly from the sample client shipped with the VirusTotal.NET library
static void Main(string[] args)
{
VirusTotal virusTotal = new VirusTotal(ConfigurationManager.AppSettings["ApiKey"]);
//Use HTTPS instead of HTTP
virusTotal.UseTLS = true;
//Create the EICAR test virus. See http://www.eicar.org/86-0-Intended-use.html
FileInfo fileInfo = new FileInfo("EICAR.txt");
File.WriteAllText(fileInfo.FullName, #"X5O!P%#AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*");
//Check if the file has been scanned before.
FileReport fileReport = virusTotal.GetFileReport(fileInfo);
bool hasFileBeenScannedBefore = fileReport.ResponseCode == ReportResponseCode.Present;
Console.WriteLine("File has been scanned before: " + (hasFileBeenScannedBefore ? "Yes" : "No"));
//If the file has been scanned before, the results are embedded inside the report.
if (hasFileBeenScannedBefore)
{
PrintScan(fileReport);
}
else
{
ScanResult fileResult = virusTotal.ScanFile(fileInfo);
PrintScan(fileResult);
}
... continue with testing a web site ....
}
DISCLAIMER
I am in no way involved with them. I am writing this answer just because it seems to be a good update for these 4 years old answers.
You can use IAttachmentExecute API.
Windows OS provide the common API to calling the anti virus software which is installed (Of course, the anti virus software required support the API).
But, the API to calling the anti virus software provide only COM Interface style, not supported IDispatch.
So, calling this API is too difficult from any .NET language and script language.
Download this library from here Anti Virus Scanner for .NET or add reference your VS project from "NuGet" AntiVirusScanner
For example bellow code scan a file :
var scanner = new AntiVirus.Scanner();
var result = scanner.ScanAndClean(#"c:\some\file\path.txt");
Console.WriteLine(result); // console output is "VirusNotFound".
I would probably just make a system call to run an independent process to do the scan. There are a number of command-line AV engines out there from various vendors.
Take a look at the Microsoft Antivirus API. It makes use of COM, which should be easy enough to interface with from .NET. It refers specifically to Internet Explorer and Microsoft Office, but I don't see why you wouldn't be able to use to to on-demand scan any file.
All modern scanners that run on Windows should understand this API.
Various Virus scanners do have API's. One I have integrated with is Sophos. I am pretty sure Norton has an API also while McAfee doesn't (it used to). What virus software do you want to use? You may want to check out Metascan as it will allow integration with many different scanners, but there is an annual license cost. :-P
I also had this requirement. I used clamAv anti virus which provides on-demand scanning by sending the file to their tcp listening port. You can use nClam nuget package to send files to clamav.
var clam = new ClamClient("localhost", 3310);
var scanResult = clam.ScanFileOnServerAsync("C:\\test.txt"); //any file you would like!
switch (scanResult.Result.Result)
{
case ClamScanResults.Clean:
Console.WriteLine("The file is clean!");
break;
case ClamScanResults.VirusDetected:
Console.WriteLine("Virus Found!");
Console.WriteLine("Virus name: {0}", scanResult.Result.InfectedFiles[0].FileName);
break;
case ClamScanResults.Error:
Console.WriteLine("Woah an error occured! Error: {0}", scanResult.Result.RawResult);
break;
}
A simple and detailed example is shown here. Note:- The synchronous scan method is not available in the latest nuget. You have to code like I done above
For testing a virus you can use the below string in a txt file
X5O!P%#AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
Shameless plug but you might want to check out https://scanii.com, it's basically malware/virus detection as a (REST) service. Oh also, make sure you read and understand virustotal's API terms (https://www.virustotal.com/en/documentation/public-api/) - they are very clear about not allowing commercial usage.
I would recommend using this approach:
using System;
using System.Diagnostics;
using Cloudmersive.APIClient.NET.VirusScan.Api;
using Cloudmersive.APIClient.NET.VirusScan.Client;
using Cloudmersive.APIClient.NET.VirusScan.Model;
namespace Example
{
public class ScanFileAdvancedExample
{
public void main()
{
// Configure API key authorization: Apikey
Configuration.Default.AddApiKey("Apikey", "YOUR_API_KEY");
var apiInstance = new ScanApi();
var inputFile = new System.IO.FileStream("C:\\temp\\inputfile", System.IO.FileMode.Open); // System.IO.Stream | Input file to perform the operation on.
var allowExecutables = true; // bool? | Set to false to block executable files (program code) from being allowed in the input file. Default is false (recommended). (optional)
var allowInvalidFiles = true; // bool? | Set to false to block invalid files, such as a PDF file that is not really a valid PDF file, or a Word Document that is not a valid Word Document. Default is false (recommended). (optional)
var allowScripts = true; // bool? | Set to false to block script files, such as a PHP files, Pythong scripts, and other malicious content or security threats that can be embedded in the file. Set to true to allow these file types. Default is false (recommended). (optional)
var allowPasswordProtectedFiles = true; // bool? | Set to false to block password protected and encrypted files, such as encrypted zip and rar files, and other files that seek to circumvent scanning through passwords. Set to true to allow these file types. Default is false (recommended). (optional)
var restrictFileTypes = restrictFileTypes_example; // string | Specify a restricted set of file formats to allow as clean as a comma-separated list of file formats, such as .pdf,.docx,.png would allow only PDF, PNG and Word document files. All files must pass content verification against this list of file formats, if they do not, then the result will be returned as CleanResult=false. Set restrictFileTypes parameter to null or empty string to disable; default is disabled. (optional)
try
{
// Advanced Scan a file for viruses
VirusScanAdvancedResult result = apiInstance.ScanFileAdvanced(inputFile, allowExecutables, allowInvalidFiles, allowScripts, allowPasswordProtectedFiles, restrictFileTypes);
Debug.WriteLine(result);
}
catch (Exception e)
{
Debug.Print("Exception when calling ScanApi.ScanFileAdvanced: " + e.Message );
}
}
}
}
Note that this way you can even control whether you filter out non-virus threat payloads such as executables, scripts, encrypted/password-protected files, etc.
This approach has a free tier and can also validate the contents of the files that you upload.
We tried two options:
clamav-daemon installed on a tiny linux container + "nClam" .NET library to interact with it. Works fine, but Clam AV misses a lot (a lot!) of viruses, especially dangerous macros hidden in MS Office files. Also ClamAV virus database has to be kept in memory at all times, which uses around 3.5GB of memory, which requires a rather expensive cloud virtual machine.
Ended up using Windows Defender via MpCmdRun.exe CLI api. See answer here
You can try to use DevDragon.io.
It is a web service with an API and .NET client DevDragon.Antivirus.Client you can get from NuGet. Scans are sub 200ms for 1MB file.
More documentation here:
https://github.com/Dev-Dragon/Antivirus-Client
Disclosure: I work for them.
From my experience you can use COM for interfacing with some anti-virus software. But what I would suggest is a bit easier, just parse scan results after scanning. All you need to do is to start the scanner process and point it to file/folder you want to scan, store scan results into file or redirect stdout to your application and parse results.
//Scan
string start = Console.ReadLine();
System.Diagnostics.Process scanprocess = new System.Diagnostics.Process();
sp.StartInfo.WorkingDirectory = #"<location of your antivirus>";
sp.StartInfo.UseShellExecute = false;
sp.StartInfo.FileName = "cmd.exe";
sp.StartInfo.Arguments = #"/c antivirusscanx.exe /scan="+filePath;
sp.StartInfo.CreateNoWindow = true;
sp.StartInfo.RedirectStandardInput = true;
sp.StartInfo.RedirectStandardError = true; sp.Start();
string output = sp.StandardOutput.ReadToEnd();
//Scan results
System.Diagnostics.Process pr = new System.Diagnostics.Process();
pr.StartInfo.FileName = "cmd.exe";
pr.StartInfo.Arguments = #"/c echo %ERRORLEVEL%";
pr.StartInfo.RedirectStandardInput = true;
pr.StartInfo.RedirectStandardError = true; pr.Start();
output = processresult.StandardOutput.ReadToEnd();
pr.Close();