How should I run a exe on startup when it has app files - winforms

I made a windows forms app and exported it to a release folder.
I am trying to make it run on startup but the application needs to be in the same folder as it's application files.
I understand that you put it in shell:startup folder. But I cannot run just the exe because it depends on the other applications.
Is there a way that I can just run the application while keeping it in the folder. Or any other solutions?

You don't need to put the whole app in the startup folder. You just need to put the shortcut of your application there. Here's a Windows 10 help topic: Add an app to run automatically at startup in Windows which shows you how to do it manually:
Press Win + R keys to open Run window
Type shell:startup and press Enter
Right click and Add new shortcut to your application.
How to add the application to startup folder using C#
You can use either of the following options to add an application to the startup folder using C#:
Put application in startup folder using an installer
Put application is startup folder using code
Example 1 - Put application in startup folder using an installer
Follow these steps:
Download and install Microsoft Visual Studio Installer Projects extension. (VS2022, VS2017 & VS2019)
Add a new Windows Forms Project
Add a new Setup project to the solution
Right click on the Setup project → Add → Project Output, then select primary output from your windows forms project.
Right click on the Setup project → View → File System
Right click on the FileSystem → Add Special Folder → User's Startup Folder
Right click In the User's Startup Folder (in the list with two columns, name and type) → Create New Shortcut → Browse Application Folder and choose Primary output from the Windows Application and click OK.
Edit the name of the shortcut or set an icon for it.
Rebuild all the projects (including the setup).
Install the setup (approve if requested to modify system)
if you sign out and sign in again, you will see the application is in startup folder.
To verify and see if the app is inside the folder:
Press Win + R keys to open Run window
Type shell:startup and press Enter
See the shortcut of your application in the startup folder.
Example 2 - Put application is startup folder using code
Follow these steps:
Create Windows Forms Application
Drop a CheckBox on the form and change its text to "Run at startup of Windows"
Drop a Button on the form and change its text to "Save".
Add a the following code to the project (Thanks to the ref1, ref2):
using System;
using System.Runtime.InteropServices;
using System.Text;
[ComImport]
[Guid("00021401-0000-0000-C000-000000000046")]
class ShellLink
{
}
/// <summary>The IShellLink interface allows Shell links to be created, modified, and resolved</summary>
[ComImport()]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214F9-0000-0000-C000-000000000046")]
interface IShellLinkW
{
/// <summary>Retrieves the path and file name of a Shell link object</summary>
void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out IntPtr pfd, int fFlags);
/// <summary>Retrieves the list of item identifiers for a Shell link object</summary>
void GetIDList(out IntPtr ppidl);
/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary>
void SetIDList(IntPtr pidl);
/// <summary>Retrieves the description string for a Shell link object</summary>
void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
/// <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary>
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
/// <summary>Retrieves the name of the working directory for a Shell link object</summary>
void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
/// <summary>Sets the name of the working directory for a Shell link object</summary>
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
/// <summary>Retrieves the command-line arguments associated with a Shell link object</summary>
void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
/// <summary>Sets the command-line arguments for a Shell link object</summary>
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
/// <summary>Retrieves the hot key for a Shell link object</summary>
void GetHotkey(out short pwHotkey);
/// <summary>Sets a hot key for a Shell link object</summary>
void SetHotkey(short wHotkey);
/// <summary>Retrieves the show command for a Shell link object</summary>
void GetShowCmd(out int piShowCmd);
/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary>
void SetShowCmd(int iShowCmd);
/// <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary>
void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
int cchIconPath, out int piIcon);
/// <summary>Sets the location (path and index) of the icon for a Shell link object</summary>
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
/// <summary>Sets the relative path to the Shell link object</summary>
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary>
void Resolve(IntPtr hwnd, int fFlags);
/// <summary>Sets the path and file name of a Shell link object</summary>
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
Doubleclick on the Button and add the following code to the event handler
private void button1_Click(object sender, EventArgs e)
{
var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
var exeFilePath = Application.ExecutablePath;
var appName = Path.GetFileNameWithoutExtension(exeFilePath);
var lnkFilePath = Path.Combine(startupPath, $"{appName}.lnk");
if (checkBox1.Checked)
{
if (File.Exists(lnkFilePath))
return;
var lnk = (IShellLinkW)new ShellLink();
lnk.SetPath(exeFilePath);
lnk.SetDescription("My application!");
lnk.SetIconLocation(exeFilePath, 0);
var file = (IPersistFile)lnk;
file.Save(lnkFilePath, false);
}
else
{
if (File.Exists(lnkFilePath))
File.Delete(lnkFilePath);
}
}
Double click on the Form and add the following code:
private void Form2_Load(object sender, EventArgs e)
{
checkBox1.Checked = IsInStartup();
}
bool IsInStartup()
{
var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
var exeFilePath = Application.ExecutablePath;
var appName = Path.GetFileNameWithoutExtension(exeFilePath);
var lnkFilePath = Path.Combine(startupPath, $"{appName}.lnk");
if (File.Exists(lnkFilePath))
return true;
return false;
}
Run the application and you can put the checkmark or remove it to save/remove the application in/from startup:

Related

Cannot access files in output directory when running under Desktop Bridge

In my WPF project, I have some JSON files that are set as Content/Copy to Output Folder. When running as standard WPF, I access them as follows and it works fine.
foreach (var config in Directory.GetFiles("HostConfigs", "*.json"))
But when I run the app under the Desktop Bridge using the packaging project, it throws the following exception
System.IO.DirectoryNotFoundException: 'Could not find a part of the path 'C:\WINDOWS\SysWOW64\HostConfigs'.'
Desktop Bridge projects don't automatically set your current directory to your project's output folder... they use Windows' default directory instead.
To fix this across your project, at the main launching point (App.xaml.cs), simply add the following...
public partial class App : Application
{
public App()
{
SetCurrentDirectory();
}
/// <summary>
/// Sets the current directory to the app's output directory. This is needed for Desktop Bridge, which
/// defaults to the Windows directory.
/// </summary>
private void SetCurrentDirectory()
{
// Gets the location of the EXE, including the EXE name
var exePath = typeof(App).Assembly.Location;
var outputDir = Path.GetDirectoryName(exePath);
Directory.SetCurrentDirectory(outputDir);
}
}

Add command line option to my WPF application

I want to add command line options to my WPF application but in case command line is sent into my EXE file i don't want the UI open but only command line options.
Is it possible to do something like this ?
public partial class MainWindow : MetroWindow
{
public MainWindow()
{
string[] args = Environment.GetCommandLineArgs();
if (args.Length > 1)
{
this.Hide();
ParseArgs(args);
}
else
{
InitializeComponent();
}
}
private void ParseArgs(string[] args)
{
// bla bla
}
}
You should do this in your app.xaml.
I explain :
You put an application startup method handler(instead of using the startup uri). Here you can parse the cl arguments and then set StartupUri = MainWindow.xaml which will open your window. and if you won't open main window then you don't set startup uri.
This Replacing WPF entry point is what you want to do.
In there you can get the command line arguments and decide if you want to show the main window or not.
If you need to write output that is shown in the command line when the application is run, you need to do something like this :
Right click on the project, "Properties", "Application" tab, change "Output Type" to "Console Application", and then it will also have a console.
However, once you do that then you will have a console window pop up even if you start the application not from a command line. There is no way to have it both ways - either the application is a command line application which can launch a window, or it is a window application which cannot write to the console which started it. It is a limitation in Windows - the bit that decides it is in the PE header.
This question discusses this point in great detail, and offers several hacks to achieve what you want.
You might want to actually search for your problems, because I count at least 5 SO questions dedicated to this (new) topic already.

Visual Studio 2010 Project - can't adjust the relative path

I have a Windows Forms project. I have a Resources folder and I wan to use the files there using relative path. Here is a printscreen of my project tree
As you may see I have folder UserControls where I have FileExplorer.cs it contains aa openFileDialog + pictureBox. I use this control in some of my forms which are in Forms folder. The case is that in Resources folder I have this T380.jpg image that I want to load by default but for now I can do it only by inserting the full path to it. Here is my code where I try to load the image:
private void FileExplorer_Load(object sender, EventArgs e)
{
pictureBox1.ImageLocation = #"ShoesUnlimitedAdmin\Resources\T380.jpg";
pictureBox1.Load();
}
I use the Load event of the user control to load my image but it only works when I set the full path to the image like C:\\... and so. How can I point to the Resources folder of the project using relative path?
If these images are small then favor adding them as resources in the executable file so you can use Properties.Resources in your code and don't have to deploy the files on the user's machine. Use Project + Properties, Resources. Click the arrow on the "Add Resource" button and select Add Existing File.
If they are big (more than a couple of megabytes) then you'll indeed want to deploy them as separate files. You can find them back by using the location of the EXE program, here's a helper method, spelled out for clarity:
public static string GetResourcePath(string filename) {
string exepath = System.Reflection.Assembly.GetEntryAssembly().Location;
string exedir = System.IO.Path.GetDirectoryName(exepath);
string resdir = System.IO.Path.Combine(exedir, "Resources");
return System.IO.Path.Combine(resdir, filename);
}

PRISM RegionManager not adding regions of the Shell

I have a Main WPF application and other modules and I am using PRISM to host the view of the modules in different regions defined in my Shell. This works fine for me.
I now have a requirement to set my Main application as class library and invoke it from another Window Application.
This new Window application has a Main function with the following code.
[System.STAThreadAttribute()]
public static void Main()
{
Application app = new Application();
IStartupUI start = new StartupUI();
start.StartUserInterface();
app.Run();
}
The start.StartUserInterface basically calls the function in the dll which has following code
ABCBootStrapper bootstrapper = new ABCBootStrapper ();
bootstrapper.Run();
The same piece of code was earlier called in OnStartup when the Dll itself was the main application.
Now with this change the Shell does not show any view. On debugging I found that the RegionManager does not recognize any regions that are defined in the Shell. Basically number of regions registered with RegionManager are 0.
All the regions defined in the shell are ContentControl.
My problem seemed to have been solved by doing the following:
I made the class which contains the Main function derive from System.Windows.Application
and instead of directly creating the instance of Application I created the instance of the class and I put the code for starting the user interface into the OnStartup event handler.
class Test : System.Windows.Application
{
[System.STAThreadAttribute()]
public static void Main()
{
Test app = new Test();
app.Startup += new StartupEventHandler(app_Startup);
app.Run();
}
static void app_Startup(object sender, StartupEventArgs e)
{
IStartupUI start = new StartupUI();
start.StartUserInterface();
}
}

WPF; click once; Double Click file to launch; VS 2008

My application is only for me and co-workers, so I don't care if it's Click-Once or copy-the-exe. I want to be able to click a file with given extension in windows explorer and have my program launch and open that file. I can't get it to capture the file name.
Ostensible solution:
Link
The code I'm trying is below and at this point all I'm trying to do is put the name of the clicked file in a text box. I suspect my relevant ignorance is about how to reference the click-once application from windows explorer. When I build I end up with a file called setup.exe, a file called Wis.application, and when I click on "setup" to install it, I end up with a shortcut of type "Click-once application reference" in "C:\Users\ptom\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Wis". I've tried associating files with that shortcut created by install, and associating files with setup.exe. When I click on the file, the application launches but indicates that
AppDomain.CurrentDomain.SetupInformation.ActivationArguments is null. (By "indicates" I mean the text box gets filled in with the text from where I test to see if it's null). If I run the app from debug, or just by running it from the start menu, it does what I'd expect, following the code path that indicates that ActivationArguments is not null, but that its ActivationData (string[]) is of length 0.
Here is the code from app.xaml.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
namespace Wis
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// Check if this was launched by double-clicking a doc. If so, use that as the
// startup file name.
if (AppDomain.CurrentDomain.SetupInformation.ActivationArguments == null)
{
this.Properties["DoubleClickedFileToLoad"] = "There were no activation arguments AGAIN";
}
else
{
if (AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData != null
&& AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData.Length > 0)
{
this.Properties["DoubleClickedFileToLoad"] =
AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[0];
}
else
{
this.Properties["DoubleClickedFileToLoad"] = "Type in a file name";
}
}
}
}
}
Thanks
First of all you should add file assoc for ClickOnce-publish (Select Project->Properties->Publish-Options->File Associations)
Then add Reference to "System.Deployment"
Then you could extract path in App.cs in such a manner, depending on type of startup (ClickOnce or Local)
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
var path = GetPath (e);
}
private static string GetPath(StartupEventArgs e)
{
if (!ApplicationDeployment.IsNetworkDeployed)
return e.Args.Length != 0 ? e.Args[0] : null;
if (AppDomain.CurrentDomain.SetupInformation.ActivationArguments == null)
return null;
var args = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
return args == null || args.Length == 0 ? null : new Uri(args[0]).LocalPath;
}
Have you checked Environment.GetCommandLineArgs()?
That shows the arguments with which your application was started.
If your application is associated with a file, it should contain the filename as one of the arguments.

Resources