Writing startup application to registry - c#

My application has a menu bar from which a user can choose from two applications to run (IE and my own custom exe). When the user chooses IE, it should be set as a startup application and if the other app is chosen, the corresponding should become the startup application.
I tried to write the values to the registry using the following, but it does not write any new entry for the startup app (looked inside regedit) and neither does it throw any error.
MenuItem menuoption = (MenuItem)sender;
RegistryKey startupapp = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
//if IE
if (menuoption == menu_IE)
{
startupapp.SetValue("iexplore -k" + url, Assembly.GetExecutingAssembly().Location); //Have to store ProgramFilesx86/InternetExplorer here or is this correct?
startupapp.DeleteValue("MyCustomEXE.exe", false); //Have to delete MyCustomEXE as starup **only if** it is already set as starup
Process.Start("iexplore", "-k " + url);
}
else if (menuoption == menu_myapp) //If myexe
{
startupapp.SetValue("MyCustomEXE.exe", Assembly.GetExecutingAssembly().Location);
startupapp.DeleteValue("iexplore", false);
Process.Start("MyCustomEXE.exe", url);
}

Related

CEFSharp app displays blank screen and then responds on it's own after a minute

I've been working on a app which uses CEFSharp (version 83.4.20) to load my companies VOIP platform (engage.ringcentral.com). The source is up on Github https://github.com/dylanlangston/EngageRC
The app has been working for about a month now and after putting it into production I've received reports of an odd issue. People are seeing a blank screen and unable to interact with the webpage (
Example of issue ). After a few minutes the issue seems to resolve itself and their able to interact with the webpage again. I haven't been able to reproduce the issue myself.
I thought this might be a rendering issue. So far I've tried to adjust the following in my app:
Remove the lines below.
settings.CefCommandLineArgs.Add("disable-gpu");
settings.CefCommandLineArgs.Add("disable-gpu-shader-disk-cache", "1");
Replace them with.
settings.CefCommandLineArgs.Add("disable-gpu-compositing");
Unfortunately this hasn't resolved the issues and I'm unsure what I'm missing.
The relevant code for CEF Initialization is located in https://github.com/dylanlangston/EngageRC/blob/master/Windows/MainWindow.Designer.cs under the InitializeChromium method. See Below
//
// Chrome
//
private CefSharp.WinForms.ChromiumWebBrowser chromeBrowser;
public ChromiumWebBrowser InitializeChromium(string URL, string Name)
{
// Check if already Initialized
if (Cef.IsInitialized == false)
{
CefSettings settings = new CefSettings();
// Enable Logging if debugging or console window
if (!this.debug || !this.console)
{
settings.LogSeverity = LogSeverity.Disable;
}
else
{
settings.LogSeverity = LogSeverity.Verbose;
}
// Enable Microphone settings
settings.CefCommandLineArgs.Add("enable-media-stream", "1");
// Set Custom Browser Paths
settings.CefCommandLineArgs.Add("disable-gpu-shader-disk-cache", "1");
// Disable GPU to fix rendering issues on some machines.
settings.CefCommandLineArgs.Add("disable-gpu");
// Disable CORS protection (cross site scripting) which the engage.ringcentral.com site doesn't seem to like/respect, disabled as the website doesn't seem to improve with this turned on.
//settings.CefCommandLineArgs.Add("disable-web-security");
// Enable session Cookie persistence, disabled as it's unneeded.
//settings.PersistSessionCookies = true;
// Custom Browser paths
settings.BrowserSubprocessPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\CEFSharp\CefSharp.BrowserSubprocess.exe");
settings.LocalesDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\CEFSharp\locales\");
settings.ResourcesDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\CEFSharp\");
// Check if Resources folder is writable. If it isn't then write to application data.
DirectoryInfo di = new DirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\CEFSharp\"));
if ((di.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
{
settings.RootCachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), #"EngageRC\CEFSharp\cache");
settings.CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), #"EngageRC\CEFSharp\cache");
settings.LogFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), #"EngageRC\CEFSharp\debug.log");
}
else
{
settings.RootCachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\CEFSharp\cache");
settings.CachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\CEFSharp\cache");
settings.LogFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\CEFSharp\debug.log");
}
// Initialize cef with the provided settings or add new tab
Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);
}
// Create a browser component
chromeBrowser = new ChromiumWebBrowser(URL);
// Set Name
chromeBrowser.Name = Name;
// Adjust size and scaling
this.chromeBrowser.Dock = DockStyle.Fill;
this.chromeBrowser.Width = this.Width;
this.chromeBrowser.Height = this.Height;
// Add control
this.Controls.Add(chromeBrowser);
// Bring to front
this.chromeBrowser.BringToFront();
// Set label to Goodbye.
this.label1.Text = "Goodbye";
// Return control
return chromeBrowser;
}
I wasn't able to find any previous questions with my Google foo so it seems this isn't something other's are seeing their applications. I'm still learning the ropes when it comes to C# so it's 100% possible this is my own fault and something I'm doing wrong.
I was able to get verbose logging from a machine that experienced the issue. I'm mostly seeing the following error. Full logs at https://gist.github.com/dylanlangston/194e389ead437e6c6fe08b2d4746bf43
[0729/083616.491:ERROR:paint_controller.cc(646)] PaintController::FinishCycle() completed
Any ideas or recommendations to help troubleshoot this is appreciated!
Updated: Based on #amaitland's helpful comments it seems this behavior may be caused by using Thread.Sleep on a thread on I'm not supposed to.
After reviewing my code it looks like I have this in two locations.
First I call thread.sleep to wait until the browsers zoom level matches the value I've saved to the windows isolatedstorage. This shouldn't be running except when the application first starts. I don't think this is the problem but I am posting it here anyways to be safe. (https://github.com/dylanlangston/EngageRC/blob/master/CEFSharpHandlers.cs)
public void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
{
ChromiumWebBrowser chrome = (ChromiumWebBrowser)sender;
if (!args.IsLoading) // Loading finished.
{
// If first load set zoom level to previous level
if (firstLoad < 3)
{
try
{
double zoom = double.Parse(ConfigReader.ReadIsolatedStorage("z"), System.Globalization.CultureInfo.InvariantCulture);
while (args.Browser.GetZoomLevelAsync().Result != zoom) { chrome.SetZoomLevel(zoom); Thread.Sleep(50); }
}
catch { }
firstLoad++;
}
// These JS and CSS modifications built into EngageRC
string hotfixJS = "";
string hotfixCSS = "/* Fix for dropdowns */ ul.dropdown-menu[style=\\\"opacity: 1;\\\"] {display: block !important; } /* End fix for dropdowns */";
// Inject custom javascript and css code on page load
chrome.ExecuteScriptAsync(hotfixJS);
chrome.ExecuteScriptAsync("var engageRCSS = document.getElementById('EngageRCSS'); if (!engageRCSS) { var node = document.createElement('style'); node.setAttribute('id', 'EngageRCSS'); node.innerHTML = \"" + hotfixCSS +"\"; document.body.appendChild(node); }");
if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\Custom.js"))) { chrome.ExecuteScriptAsync(System.IO.File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\Custom.js"))); }
if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\Custom.css"))) { chrome.ExecuteScriptAsync("var customCSS = document.getElementById('customcss'); if (!customCSS) { var node = document.createElement('style'); node.setAttribute('id', 'customcss'); node.innerHTML = \"" + System.IO.File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Resources\Custom.css")).Replace("\n", String.Empty).Replace("\r", String.Empty).Replace("\t", String.Empty).Replace("\"", "\\\"") + "\"; document.body.appendChild(node); }"); }
}
}
I also have it when displaying a notification. This is most likely my problem as this is running in the main application thread... (https://github.com/dylanlangston/EngageRC/blob/master/NotificationSupport.cs)
public void displayNotification(string Title = "EngageRC", string Message = "")
{
// Display notification for 5 seconds
Notify notification = MainWindow.notification;
try
{
if (!IsActive(hWnd)) // Check if application is already active.
{
string config = ConfigReader.GetConfigValue("NotificationsDisabled").ToLower();
if (!(config == "true" || config == "1"))
{
notification.NewNotification(Title, Message, 5000);
}
config = ConfigReader.GetConfigValue("GetFocusOnCallDisabled").ToLower();
if (!(config == "true" || config == "1") && (Message == "You have incoming call"))
{
// Minimize window
ShowWindow(hWnd, 0x02);
// Restore window to previous state.
ShowWindow(hWnd, 0x09);
}
config = ConfigReader.GetConfigValue("GetFocusOnPendingDispositionDisabled").ToLower();
if (!(config == "true" || config == "1") && (Message == "You have a disposition pending"))
{
// Minimize window
ShowWindow(hWnd, 0x02);
// Restore window to previous state.
ShowWindow(hWnd, 0x09);
}
}
}
catch { notification.SetIconVisible(false); }
finally
{
Thread.Sleep(4999);
notification.SetIconVisible(false);
}
}
Based on what I've heard I should make the Notification Form run on a different thread from the main application then? Or am I way off base?
Update:
I was able to move the notification into it's own thread. I'm closing this issue and will have the user's test to see if the blank screen persists.
Thanks for the help again!!
#amaitland's comments were helpful in narrowing this issue down.

How to store persistent User Connection Strings with .NET WPF Click-Once

We're developing a Click-Once WPF Windows Application that retrieves all its data from a database. I implemented a Form where a User could enter the corresponding data and using a SqlConnectionStringBuilder we build the Connection String and that works just fine.
We then add the Connection String to the ConfigurationManager using
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
If we use some other ConfigurationUserLevel, the application crashes (I don't know why yet, but I believe the Entity Framework Model tries to load the connection string and doesn't find it, because the file is not stored in the correct User Level?). Now, we store the connection string in a separate file and load it in App.config so we don't have to check it into Version Control:
<connectionStrings configSource="connections.config"/>
We don't deploy this file because it contains our own development connection strings. Rather, we create an empty file for deployment where the user-entered connection string will be stored. This works completely fine.
Our problem is that with a click-once update, the file will be "lost". What is the best way to store persistent per-user connection strings encrypted in a configuration file? Or should we completely switch to Registry? Or create our own encrypted File somewhere outside the %APPDATA%/Local/Apps/2.0/...../ folders and load it manually when initializing the Entity Framework Context?
You can go to MSDN site it might help you
https://msdn.microsoft.com/en-us/library/dd997001.aspx
with the help of below code, you need to modify this code for your requirement, hope this will help.
To create a custom ClickOnce application installer
In your ClickOnce application, add references to System.Deployment and System.Windows.Forms.
Add a new class to your application and specify any name. This walkthrough uses the name MyInstaller.
Add the following Imports or using statements to the top of your new class.
using System.Deployment.Application;
using System.Windows.Forms;
Add the following methods to your class.
These methods call InPlaceHostingManager methods to download the deployment manifest, assert appropriate permissions, ask the user for permission to install, and then download and install the application into the ClickOnce cache. A custom installer can specify that a ClickOnce application is pre-trusted, or can defer the trust decision to the AssertApplicationRequirements method call. This code pre-trusts the application
Note:- Permissions assigned by pre-trusting cannot exceed the permissions of the custom installer code.
InPlaceHostingManager iphm = null;
public void InstallApplication(string deployManifestUriStr)
{
try
{
Uri deploymentUri = new Uri(deployManifestUriStr);
iphm = new InPlaceHostingManager(deploymentUri, false);
}
catch (UriFormatException uriEx)
{
MessageBox.Show("Cannot install the application: " +
"The deployment manifest URL supplied is not a valid URL. " +
"Error: " + uriEx.Message);
return;
}
catch (PlatformNotSupportedException platformEx)
{
MessageBox.Show("Cannot install the application: " +
"This program requires Windows XP or higher. " +
"Error: " + platformEx.Message);
return;
}
catch (ArgumentException argumentEx)
{
MessageBox.Show("Cannot install the application: " +
"The deployment manifest URL supplied is not a valid URL. " +
"Error: " + argumentEx.Message);
return;
}
iphm.GetManifestCompleted += new EventHandler<GetManifestCompletedEventArgs>(iphm_GetManifestCompleted);
iphm.GetManifestAsync();
}
void iphm_GetManifestCompleted(object sender, GetManifestCompletedEventArgs e)
{
// Check for an error.
if (e.Error != null)
{
// Cancel download and install.
MessageBox.Show("Could not download manifest. Error: " + e.Error.Message);
return;
}
// bool isFullTrust = CheckForFullTrust(e.ApplicationManifest);
// Verify this application can be installed.
try
{
// the true parameter allows InPlaceHostingManager
// to grant the permissions requested in the applicaiton manifest.
iphm.AssertApplicationRequirements(true) ;
}
catch (Exception ex)
{
MessageBox.Show("An error occurred while verifying the application. " +
"Error: " + ex.Message);
return;
}
// Use the information from GetManifestCompleted() to confirm
// that the user wants to proceed.
string appInfo = "Application Name: " + e.ProductName;
appInfo += "\nVersion: " + e.Version;
appInfo += "\nSupport/Help Requests: " + (e.SupportUri != null ?
e.SupportUri.ToString() : "N/A");
appInfo += "\n\nConfirmed that this application can run with its requested permissions.";
// if (isFullTrust)
// appInfo += "\n\nThis application requires full trust in order to run.";
appInfo += "\n\nProceed with installation?";
DialogResult dr = MessageBox.Show(appInfo, "Confirm Application Install",
MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (dr != System.Windows.Forms.DialogResult.OK)
{
return;
}
// Download the deployment manifest.
iphm.DownloadProgressChanged += new EventHandler<DownloadProgressChangedEventArgs>(iphm_DownloadProgressChanged);
iphm.DownloadApplicationCompleted += new EventHandler<DownloadApplicationCompletedEventArgs>(iphm_DownloadApplicationCompleted);
try
{
// Usually this shouldn't throw an exception unless AssertApplicationRequirements() failed,
// or you did not call that method before calling this one.
iphm.DownloadApplicationAsync();
}
catch (Exception downloadEx)
{
MessageBox.Show("Cannot initiate download of application. Error: " +
downloadEx.Message);
return;
}
}
/*
private bool CheckForFullTrust(XmlReader appManifest)
{
if (appManifest == null)
{
throw (new ArgumentNullException("appManifest cannot be null."));
}
XAttribute xaUnrestricted =
XDocument.Load(appManifest)
.Element("{urn:schemas-microsoft-com:asm.v1}assembly")
.Element("{urn:schemas-microsoft-com:asm.v2}trustInfo")
.Element("{urn:schemas-microsoft-com:asm.v2}security")
.Element("{urn:schemas-microsoft-com:asm.v2}applicationRequestMinimum")
.Element("{urn:schemas-microsoft-com:asm.v2}PermissionSet")
.Attribute("Unrestricted"); // Attributes never have a namespace
if (xaUnrestricted != null)
if (xaUnrestricted.Value == "true")
return true;
return false;
}
*/
void iphm_DownloadApplicationCompleted(object sender, DownloadApplicationCompletedEventArgs e)
{
// Check for an error.
if (e.Error != null)
{
// Cancel download and install.
MessageBox.Show("Could not download and install application. Error: " + e.Error.Message);
return;
}
// Inform the user that their application is ready for use.
MessageBox.Show("Application installed! You may now run it from the Start menu.");
}
void iphm_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// you can show percentage of task completed using e.ProgressPercentage
}
To attempt installation from your code, call the InstallApplication method. For example, if you named your class MyInstaller, you might call InstallApplication in the following way.
MyInstaller installer = new MyInstaller();
installer.InstallApplication(#"\\myServer\myShare\myApp.application");
MessageBox.Show("Installer object created.");

creating notify icon in system tray and adding shortcut to startup using .net setup creation wizard

I have searched a lot but still not able to find the right solution.
I want to create a setup using .net setup wizard and add 2 checkbox in the setup wizard.
1st checkbox will ask user to "add program in startup". If it is checked then it will add software to startup.
2nd checkbox will ask for "create system tray notify icon". If checked then it will create a notify icon in system tray. The notify icon must be displayed permanently not only when application runs).
I know it had to do with custom actions but still not able to figure it out. Please provide me some article or code for this with proper explanation.
Actually, the custom actions is the right place to do this. Here's the code I use to create two custom checkboxes during the installation process.
[RunInstaller(true)]
public class DeploymentManager : Installer{
public override void Install(IDictionary stateSaver) {
base.Install (stateSaver);
const string DESKTOP_SHORTCUT_PARAM = "DESKTOP_SHORTCUT";
const string QUICKLAUNCH_SHORTCUT_PARAM = "QUICKLAUNCH_SHORTCUT";
const string ALLUSERS_PARAM = "ALLUSERS";
// The installer will pass the ALLUSERS, DESKTOP_SHORTCUT and QUICKLAUNCH_SHORTCUT
// parameters. These have been set to the values of radio buttons and checkboxes from the
// MSI user interface.
// ALLUSERS is set according to whether the user chooses to install for all users (="1")
// or just for themselves (="").
// If the user checked the checkbox to install one of the shortcuts, then the corresponding
// parameter value is "1". If the user did not check the checkbox to install one of the
// desktop shortcut, then the corresponding parameter value is an empty string.
bool allusers = true; // Context.Parameters[ALLUSERS_PARAM] != string.Empty;
bool installDesktopShortcut = true; //Context.Parameters[DESKTOP_SHORTCUT_PARAM] != string.Empty;
bool installQuickLaunchShortcut = true;// Context.Parameters[QUICKLAUNCH_SHORTCUT_PARAM] != string.Empty;
if (installDesktopShortcut){
// If this is an All Users install then we need to install the desktop shortcut for
// all users. .Net does not give us access to the All Users Desktop special folder,
// but we can get this using the Windows Scripting Host.
string desktopFolder = null;
if (allusers){
try{
// This is in a Try block in case AllUsersDesktop is not supported
object allUsersDesktop = "AllUsersDesktop";
WshShell shell = new WshShellClass();
desktopFolder = shell.SpecialFolders.Item(ref allUsersDesktop).ToString();
}
catch {}
}
if (desktopFolder == null)
desktopFolder = Environment.GetFolderPathEnvironment.SpecialFolder.DesktopDirectory);
CreateShortcut(desktopFolder, ShortcutName, Path.Combine(TargetAssemblyFolder, TargetAssembly), ShortcutDescription, Path.Combine(TargetAssemblyFolder, "your.ico"));
}
if (installQuickLaunchShortcut){
CreateShortcut(QuickLaunchFolder, ShortcutName, ShortcutFullName, ShortcutDescription, Path.Combine(TargetAssemblyFolder, "your.ico"));
}
}
private void CreateShortcut(string folder, string name, string target, string description, string targetIcon){
string shortcutFullName = Path.Combine(folder, name + ".lnk");
try{
WshShell shell = new WshShellClass();
IWshShortcut link = (IWshShortcut)shell.CreateShortcut(shortcutFullName);
link.TargetPath = target;
link.Description = description;
FileInfo fi = new FileInfo(targetIcon);
link.IconLocation = Path.Combine(fi.Directory.FullName, fi.Name);
link.Save();
}catch (Exception ex){
MessageBox.Show(string.Format("The shortcut \"{0}\" could not be created.\n\n{1}", shortcutFullName, ex.ToString()),
"Create Shortcut", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
After you have this code, you can add the Custom Action to the installer to the Install Custom Actions area.
The notification code would be similar for the install process but needs to be added to the registry.

What is the best way to add an application to Windows Start up?

The code i'm using in my program is the below :
public static void SetStartup(string AppName, bool enable, string newpath)
{
if (Autostart == true)
{
string runKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
Microsoft.Win32.RegistryKey startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey);
if (enable)
{
if (startupKey.GetValue(AppName) == null)
{
startupKey.Close();
startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey, true);
// Add startup reg key
startupKey.SetValue(AppName, newpath);
startupKey.Close();
}
}
else
{
// remove startup
startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey, true);
startupKey.DeleteValue(AppName, false);
startupKey.Close();
}
}
}
But When i click on the apply button, the AVG Antivirus Popup fire-up and says that my Program is a unknown Malware !?
I tried to copy my program to the StartUp folder instead, but the copied file become Limited ( must Run as administrator ), that doesn't work.
How could this be ? if it is impossible to use the function above, then how other Programs such as uTorrent start used to start automatically on each windows startup.
How can i add an option on my Program which let me make it autostart on windows start up without getting this annoying antivirus popup?
If you don't want to get this annoying antivirus popup, you should simply click on the button "Allow" in the AVG window/popup.

Taking multiple files (arguments) from Windows shell context menu on C#

I am writing a C# application and it takes files as argument, I added it to shell context menu with code listed below;
if (((CheckBox)sender).CheckState == CheckState.Checked)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Classes\\*\\shell\\" + KEY_NAME + "\\command");
if (key == null)
{
key = Registry.CurrentUser.CreateSubKey("Software\\Classes\\*\\shell\\" + KEY_NAME + "\\command");
key.SetValue("", Application.ExecutablePath + " \"%1\"");
}
}
else if (((CheckBox)sender).CheckState == CheckState.Unchecked)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Classes\\*\\shell\\" + KEY_NAME);
if (key != null)
{
Registry.CurrentUser.DeleteSubKeyTree("Software\\Classes\\*\\shell\\" + KEY_NAME);
}
It is working good, but if I select multiple files, multiple instances of application running.
for example if I select 5 files 5 application is opening, how can I fix this?
Detect if an instance of your application is already running on startup.
If it does, send the command line arguments to the running instance and exit the new instance.

Categories