I need to show a PDF file in a browser, by pressing a button in my C# app.
So the browser is eternal to my app.
On Win 10 I do it like this:
....
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = FindBrowser(),
Arguments = $"\"file:///{PDF_File}\""
}
process.Start();
....
private static string FindBrowser()
{
GroupCollection groups;
try
{
// finding the default browser in the registry is a two-step process:
using var key = Registry.CurrentUser.OpenSubKey(
#"SOFTWARE\Microsoft\Windows\Shell\Associations\URLAssociations\http\UserChoice");
var s = (string) key?.GetValue("ProgId");
using var command = Registry.ClassesRoot.OpenSubKey($"{s}\\shell\\open\\command");
var browserCommand = (string) command?.GetValue(null);
var regexpr = new Regex("^\"([^\"]*)\"");
groups = regexpr.Match(browserCommand).Groups;
if (!File.Exists(groups[1].Value))
{
throw new FileNotFoundException("NoBrowser");
}
}
but my customer says this does not work on Win 11 (I have no Win 11)
Is there a foolproof way to program this?
I use VS 2019 myself to develop and debug.
My solution works OK there.
Related
I have sideloaded a UWP application onto my clients machine.
I would now like to uninstall the program, but without admin access.
I have found Remove-AppxPackage but this uses powershell and so would need an executionpolicy set which would require admin access
For my WPF applications I would just delete the directory containing the application but with a UWP app I'm not even sure what to delete.
Essentially I would like to programatically click the uninstall button on from the Add and remove programs
I did look at this link How to uninstall application programmatically with the code:
public static string GetUninstallCommandFor(string productDisplayName)
{
RegistryKey localMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,RegistryView.Registry64);
string productsRoot = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products";
RegistryKey products = localMachine.OpenSubKey(productsRoot);
string[] productFolders = products.GetSubKeyNames();
foreach (string p in productFolders)
{
RegistryKey installProperties = products.OpenSubKey(p + #"\InstallProperties");
if (installProperties != null)
{
string displayName = (string)installProperties.GetValue("DisplayName");
Debug.WriteLine(displayName);
if ((displayName != null) && (displayName.Contains(productDisplayName)))
{
string uninstallCommand = (string)installProperties.GetValue("UninstallString");
return uninstallCommand;
}
}
}
return "";
}
But this didn't find my application - eventhough it is in the "Apps and features" settings page
Ok my solution as advised by Nico Zhu was to use powershell. I created a method like so:
private static void LaunchProcess(string uri, string args)
{
var psi = new ProcessStartInfo();
psi.UseShellExecute = true;
psi.CreateNoWindow = false;
psi.Arguments = args;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.FileName = uri;
var proc = Process.Start(psi);
proc.WaitForExit();
var exitcode = proc.ExitCode;
}
and used it like so:
LaunchProcess("powershell.exe", "get-appxpackage *AppPackageNameThatOnlyMatchesYourAppPackage* | remove-appxpackage");
This process surprisingly didn't require admin rights.
I must say though from a microsoft developer point of view UX. For managing distribution of my UWP apps, this is another thumbs down for UWP vs WPF
I'm trying to do a virus scan on uploaded files.
I have no control over the installed virus scanner, the product hosted by multiple parties with different scanners.
I tried the following library but it always returns VirusNotFound on the eicar file.
https://antivirusscanner.codeplex.com/
Do you know any other solutions?
ClamAV has pretty bad detection scores.
VirusTotal is not on premises.
I decided to create CLI wrappers for multiple scanners, nuget packages can be found here: https://www.nuget.org/packages?q=avscan
And its documentation and source code available at https://github.com/yolofy/AvScan
I used this library for .net (It uses the VirusTotal public api):
https://github.com/Genbox/VirusTotal.NET
A little example from github :
static void Main(string[] args)
{
VirusTotal virusTotal = new VirusTotal("INSERT API KEY HERE");
//Use HTTPS instead of HTTP
virusTotal.UseTLS = true;
FileInfo fileInfo = new FileInfo("testfile.txt");
//Create a new file
File.WriteAllText(fileInfo.FullName, "This is a test file!");
//Check if the file has been scanned before.
Report fileReport = virusTotal.GetFileReport(fileInfo).First();
bool hasFileBeenScannedBefore = fileReport.ResponseCode == 1;
if (hasFileBeenScannedBefore)
{
Console.WriteLine(fileReport.ScanId);
}
else
{
ScanResult fileResults = virusTotal.ScanFile(fileInfo);
Console.WriteLine(fileResults.VerboseMsg);
}
}
A full example can be found here :
https://github.com/Genbox/VirusTotal.NET/blob/master/VirusTotal.NET%20Client/Program.cs
Clam AV is pretty good.
https://www.clamav.net/downloads
C# Api here:
https://github.com/michaelhans/Clamson/
I just tried various ways, But some didn't work.
Then I decided to use ESET NOD32 command line tools .
It works fine for me:
public bool Scan(string filename)
{
var result = false;
try
{
Process process = new Process();
var processStartInfo = new ProcessStartInfo(#"C:/Program Files/ESET/ESET Security/ecls.exe")
{
Arguments = $" \"{filename}\"",
CreateNoWindow = true,
ErrorDialog = false,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false
};
process.StartInfo = processStartInfo;
process.Start();
process.WaitForExit();
if (process.ExitCode == 0) //if it doesn't exist virus ,it returns 0 ,if not ,it returns 1
{
result = true;
}
}
catch (Exception)
{ //nothing;
}
return result;
}
Following on from this thread Starting application before target application
I have an application which gets passed a parameter (a filename) and does some registry work before opening Microsoft InfoPath.
I need to open InfoPath with the parameter that was passed to the original application.
Here is how I open InfoPath
System.Diagnostics.Process prc = new System.Diagnostics.Process();
prc.StartInfo.Arguments = ConvertArrayToString(Constants.Arguments);
//prc.StartInfo.Arguments = "hello";
prc.StartInfo.FileName = Constants.PathToInfoPath;
prc.Start();
Note that when I set the Arguments to "hello" InfoPath pops up a message saying cannot find file "hello" however when I set it Constants.Arguments I get an error and Windows asks me if I want to debug or close the applicatiion.
Here is how I set Constants.Arguments in the Main(string[] args)
static void Main(string[] args)
{
Constants.Arguments = args;
//...
}
And here is ConvertArrayToString
private string ConvertArrayToString(string[] arr)
{
string rtn = "";
foreach (string s in arr)
{
rtn += s;
}
return rtn;
}
I suppose the format of the parameter is causing the error, any idea why?
The value of Arguments after being stringed is
c:\users\accountname\Desktop\HSE-000403.xml
Edit:
Thanks to N K's answer.
The issue is in order for my application to open when InfoPath files are opened, I have changed the name of INFOPATH.EXE to INFOPATH0.EXE and my application is called INFOPATH.EXE and is in the InfoPath folder, so when files are opened my application opens.
Now when I do not change the name (eg I leave it as INFOPATH.EXE) it works as expected, however if it is called anything other than that then I get the error.
Unfortunately I need my application to open first.
I tried the below and it's works fine. Let me know what you get with this. (Don't forget to change path to files)
class Program
{
static void Main(string[] args)
{
System.Diagnostics.Process prc = new System.Diagnostics.Process();
prc.StartInfo.Arguments = string.Join("", Constants.Arguments);
prc.StartInfo.FileName = Constants.PathToInfoPath;
prc.Start();
}
}
public class Constants
{
public static string PathToInfoPath = #"C:\Program Files (x86)\Microsoft Office\Office14\INFOPATH.EXE";
public static string[] Arguments = new string[] { #"c:\users\accountname\Desktop\HSE-000403.xml" };
}
GOAL : I need to find if an app is installed on a device AND find it's path..
I see using PackageManager, you can do this in general but I would like to refine it.
I know if you use com.google.chrome you can find chrome explorer installed,
but this fails when you look simply for Chrome.
On some devices Chrome (and other apps, like Opera, Mini,etc) is not installed as com.google.chrome.
So how would one find an app without the com.google and just use Chrome as the search criteria ?
Simple, just combine PackageManager and ApplicationInfo, and then check if app name contain your search string. Here is some example code:
var searchQuery = "chrome";
var flag = PackageInfoFlags.Activities;
var apps = PackageManager.GetInstalledApplications(flag);
foreach(var app in apps)
{
try
{
var appInfo = PackageManager.GetApplicationInfo(app.PackageName, 0);
var appLabel = PackageManager.GetApplicationLabel(appInfo);
if (appLabel.ToLower().Contains(searchQuery.ToLower()))
{
var builder = new AlertDialog.Builder(this);
builder.SetTitle("Found it!");
builder.SetMessage(appLabel + " installed at: " + app.SourceDir);
builder.Show();
}
}
catch (PackageManager.NameNotFoundException e) { continue; }
}
I have ASP.NET web pages for which I want to build automated tests (using WatiN & MBUnit). How do I start the ASP.Net Development Server from my code? I do not want to use IIS.
This is what I used that worked:
using System;
using System.Diagnostics;
using System.Web;
...
// settings
string PortNumber = "1162"; // arbitrary unused port #
string LocalHostUrl = string.Format("http://localhost:{0}", PortNumber);
string PhysicalPath = Environment.CurrentDirectory // the path of compiled web app
string VirtualPath = "";
string RootUrl = LocalHostUrl + VirtualPath;
// create a new process to start the ASP.NET Development Server
Process process = new Process();
/// configure the web server
process.StartInfo.FileName = HttpRuntime.ClrInstallDirectory + "WebDev.WebServer.exe";
process.StartInfo.Arguments = string.Format("/port:{0} /path:\"{1}\" /virtual:\"{2}\"", PortNumber, PhysicalPath, VirtualPath);
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
// start the web server
process.Start();
// rest of code...
From what I know, you can fire up the dev server from the command prompt with the following path/syntax:
C:\Windows\Microsoft.NET\Framework\v2.0.50727\Webdev.WebServer.exe /port:[PORT NUMBER] /path: [PATH TO ROOT]
...so I could imagine you could easily use Process.Start() to launch the particulars you need through some code.
Naturally you'll want to adjust that version number to whatever is most recent/desired for you.
Building upon #Ray Vega's useful answer, and #James McLachlan's important update for VS2010, here is my implementation to cover VS2012 and fallback to VS2010 if necessary. I also chose not to select only on Environment.Is64BitOperatingSystem because it went awry on my system. That is, I have a 64-bit system but the web server was in the 32-bit folder. My code therefore looks first for the 64-bit folder and falls back to the 32-bit one if necessary.
public void LaunchWebServer(string appWebDir)
{
var PortNumber = "1162"; // arbitrary unused port #
var LocalHostUrl = string.Format("http://localhost:{0}", PortNumber);
var VirtualPath = "/";
var exePath = FindLatestWebServer();
var process = new Process
{
StartInfo =
{
FileName = exePath,
Arguments = string.Format(
"/port:{0} /nodirlist /path:\"{1}\" /virtual:\"{2}\"",
PortNumber, appWebDir, VirtualPath),
CreateNoWindow = true,
UseShellExecute = false
}
};
process.Start();
}
private string FindLatestWebServer()
{
var exeCandidates = new List<string>
{
BuildCandidatePaths(11, true), // vs2012
BuildCandidatePaths(11, false),
BuildCandidatePaths(10, true), // vs2010
BuildCandidatePaths(10, false)
};
return exeCandidates.Where(f => File.Exists(f)).FirstOrDefault();
}
private string BuildCandidatePaths(int versionNumber, bool isX64)
{
return Path.Combine(
Environment.GetFolderPath(isX64
? Environment.SpecialFolder.CommonProgramFiles
: Environment.SpecialFolder.CommonProgramFilesX86),
string.Format(
#"microsoft shared\DevServer\{0}.0\WebDev.WebServer40.EXE",
versionNumber));
}
I am hoping that an informed reader might be able to supply the appropriate incantation for VS2013, as it apparently uses yet a different scheme...
You can easily use Process Explorer to find complete command line options needed for manually start it.
Start Process Explorer while debugging your website. For VS2012, expand 'devenv.exe' node. Right-click on 'WebDev.WebServer20.exe' and from there you can see Path and Command Line values.