I have an application that can be launched from the explorer context menu for a Windows drive. When you click the menu item the drive letter is passed to the new instance. I want to make sure that any old instance is closed.
I also want to make sure that the last drive that was selected is persisted, so that when I start the application again from the start-menu, it will remember the drive I originally selected.
It would be best if the already running application would receive an event so that it can update without having to kill and restart.
I tried the following, but that doesn't seem to be working:
This is my Class library method(it is just a line that define a variable so just i have a DLL that there a variable in it and no more)
namespace Dispatch
{
public class cls_get_drive_letter
{
public static string drive_letter;
}
}
This is my loading form code: (Here i will fill the DLL's variable)
private void Frm_loading_Load(object sender, EventArgs e)
{
Dispatch.cls_get_drive_letter.drive_letter = "XXX";
Process currentProcess = Process.GetCurrentProcess();
if (Process.GetProcessesByName(currentProcess.ProcessName, currentProcess.MachineName).Length >1)
{
currentProcess.Kill();
}
}
So when i run this for first time the "XXX" will be stored in DLL but when the current instance of application is running and i am going to run next instance of it the application will be closed because of this code:
Process currentProcess = Process.GetCurrentProcess();
if (Process.GetProcessesByName(currentProcess.ProcessName, currentProcess.MachineName).Length >1)
{
currentProcess.Kill();
}
So when closing code occurs with this code the new "XXX" will not stored in DLL and the last string will be in dll.
All variables, in this case a static field, will only remain the same for the running instance of your application.
When the application is started again the field is empty
A static variable is not stored 'inside a dll' but is stored inside the memory of the application that loads the dll. When a second instance of the application starts, it will have its own memory space and it will have its own version of the string variable. The variable is also not kept between instances, so as soon as you start a new instance it will have its own, empty string variable.
When the application is stopped, the memory for that instance is released and the variable is 'forgotten'.
If you want to share state between applications, there are all kinds of solutions, one could be the System.Configuration.Settings API, a file somewhere, a memory mapped file shared between multiple processes, a Named Pipe, a Kernel Semaphore. Options aplenty.
Until we understand exactly what it is you're trying to accomplish with this shared state, we can't provide you with a better alternative than the explanation that what you're doing right now, will not work do to the way static variables work.
Update based on new information:
You can store your currently selected drive in a Settings file for your project. You can add such file from the project properties in Visual Studio. There's a tab called settings. Create a new setting for "Selected Drive" and make it a User setting (that way you can update it without Admin rights).
To communicate a new drive letter to your already running application, you have a number of options.
For one, you could check whether your executable is already running (like you're doing now) and in that case update the settings file and exit the new instance. Your already running instance could periodically refresh the settings to pick up new values.
When your application starts, you can open a named pipe on your machine on which you listen for drive changes. When the 2nd instance starts, it can detect that the pipe is already there, write the new drive to the pipe and close. The already running application can pick up this message and change its configuration.
You can send a WindowMessage to the other application
You can host a simple WCF service to receive the notification
You can write the new drive letter to a file stored in a known location and have the other instance use a FileSystemWatcher to detect the changes to that file.
As I said the possibilities are endless.
If I were you I'd first make sure that the value is persisted between relaunches by implementing the Settings file in your application. Then investigate the options I described above, do some experimentation and then ask new questions when you cannot figure out how to make it work.
Related
In my UWP app I use Launcher to open a file(for instance txt) by default app.
bool isFileOpen = await Windows.System.Launcher.LaunchFileAsync(storageFile);
Above method uses default app (for instance notepad.exe) to open a file (for instance txt). Once app gets launched, the new process is created. I would like to know PID and Status of that Process. Why? I want to monitor it's Status to determine if the app (like notepad.exe which opened the file) gets closed.
Is any solution to get those infos like showed in Task Manager?
The LaunchFileAsync method just tells the operating system (OS) to start the default app associated with the specified file. It doesn't know about nor return any PID or other information about the process that eventually gets started by the OS.
So I am afraid you can't get this information without looking at all processes and somehow trying to figure out which ones that were started as a result of your app calling the LaunchFileAsync method. You might for example get all running processes just before you call the method, and then again immediately afterwards. But the API itself doesn't return anything useful in regards to this.
I've written a win forms application that uses Attachmate EXTRA. The application itself works great but I was just notified that there is a need to be able to switch to different device names for the sessions. The names would be set before the sessions are launched and then the session would go through the connection process. The only way I can think to do this is create and save a separate session with each device name needed and go that route but I would like to be able to do this dynamically instead if possible.
I've tried doing this during debug to look at the object but have been unable to find a method or property to set.
After having a support ticket entered and getting confirmation, the only way to change the device name programatically is to open the .EDP file, replace the string with the new device name, save the file and then run that .EDP file.
Apparently their new application, Reflection, can handle these types of things with calls without making changes to the files.
I'm currently developing a windows service with c# and .net framework 4.5 to extend the functionality of an existing propietary application, this service blocks on an EventWaitHandleClass (msdn link) waiting for a named event signaled from the main application. Something like this:
bool boolWithFalse = false;
string eName = "notification_event";
string usr = Environment.UserDomainName + "\\" + Environment.UserName;
EventWaitHandleSecurity security = new EventWaitHandleSecurity(); //*
EventWaitHandleAccessRule rule = new EventWaitHandleAccessRule(usr, EventWaitHandleRights.Synchronize, AccessControlType.Allow);
security.AddAccessRule(rule);
EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.ManualReset, eName, out boolWithFalse, security);
//... some non relevant code lines here
//This is where the it locks waiting for the named event
var w = EventWaitHandle.WaitAny(new[] { handle }, Timeout.Infinite);
*: EventWaitHandleSecurity MSDN
Now this works like a charm if i execute my program as a console application, i can easily catch events from the main application and handle them as i intend, BUT, when i install the application as a service it locks waiting for this same named event but never receive the signal. The service is set to run using the NT AUTHORITY\LOCALSERVICE account, i've already tried using my own account (wich the progam uses while running as a console application) and yet nothing happens.
If it helps the application that originates the signal is running under my own account. I appreciate any help as i'm a complete beginner developing desktop applications for windows.
You got lost in the security hoopla. Two problems. The first one is that somebody has to create the event and somebody else has to open it so both components share the same event object. One of them has to use the EventWaitHandle constructor, the other has to call the EventWaitHandle.OpenExisting() method. The normal way is for the service to create the event and for the UI program to open it.
Next problem is the event object visibility. Windows implements namespaces for named operating system objects, pretty similar to how you use namespaces in the C# language. The root namespace is named by the session. And a service runs in a different session than the user's desktop programs. To get the desktop session program to see the event created in the service session, you have to use a "global" event name. Which looks like this:
string eName = "Global\\notification_event";
Do be careful of how you name your globally visible named event. There's another programmer somewhere someday that thinks that "notification_event" is a good choice for a name. You don't want to meet him. A {guid} is a good name, you get one from Tools + Create GUID. It is unique in the known universe, possibly beyond.
I am using the Properties.Settings class to save the application settings. I would like to know, once I deploy in the client system, whether the settings would be saved across application restart and system restart.
Consider the scenario :
Once the application is deployed, the user would save the Mobile Number through a UI as
Phone : 1xxxx - 45678
Now, I would save the Phone number as
Properties.Settings.Default.ClientPhone = this.PhoneText.Text;
Properties.Settings.Default.Save();
Am I understand, that the phone number would be saved in the application across app.restarts and reboots?
This is the difference about application and user settings. Application settings are read only. User settings are stored permanently on a per-user basis. Your code is exactly what it takes to change and save a user setting.
Please note: As they are called "user settings", they will be stored separately for every user on the machine! You can not, using the default .NET settings mechanism, create changeable settings that are the same for all users.
Do not re-invent the wheel! Use the .NET settings mechanism - you're doing it right in your example :-)
This will work fine, however one thing to bear in mind is that if you install a new version of the program, it will "lose" the old settings (because the settings are specific to a particular version of your program). (By "version" I mean the AssemblyVersion)
Fortunately, you can deal with this by calling the following function at or near the beginning of Main(). For this to work you will need to add a new boolean setting property called NeedSettingsUpgrade and default it to 'true':
/// <summary>Upgrades the application settings, if required.</summary>
private static void upgradeProgramSettingsIfNecessary()
{
// Application settings are stored in a subfolder named after the full #.#.#.# version
// number of the program. This means that when a new version of the program is installed,
// the old settings will not be available.
//
// Fortunately, there's a method called Upgrade() that you can call to upgrade the settings
// from the old to the new folder.
//
// We control when to do this by having a boolean setting called 'NeedSettingsUpgrade' which
// is defaulted to true. Therefore, the first time a new version of this program is run, it
// will have its default value of true.
//
// This will cause the code below to call "Upgrade()" which copies the old settings to the new.
// It then sets "NeedSettingsUpgrade" to false so the upgrade won't be done the next time.
if (Settings.Default.NeedSettingsUpgrade)
{
Settings.Default.Upgrade();
Settings.Default.NeedSettingsUpgrade = false;
}
}
A quick google should have done it for you.
Yes they will according to msdn: .NET allows you to create and access values (settings) that are persisted between application execution sessions.
http://msdn.microsoft.com/en-us/library/aa730869(v=vs.80).aspx
I want to update my exe from remote server. So when the button clicked on my wpf application it will download the remote and also a remote txt file and replace the current ones in the same folder that exe running. So it will overwrite the current txt and and exe file while my exe is running. How can i achive this ?
Remote host is url like www.mydomain.com/MyAPP.exe
wpf application , c# 4.0
The way that we resolved this issue was to create a shell exe that as the one that was installed and deployed initially to the client machines.
The "real" executable program is stored in a subdirectory of this initial app. When the shell app is launched, after it has downloaded and installed any updates for the real app, it launches the real app's executable in a separate AppDomain.
Here is the core of the "real" app launching from within the shell app:
System.AppDomainSetup oSetup = new System.AppDomainSetup();
string sApplicationFile = null;
// Use this to ensure that if the application is running when the user performs the update, that we don't run into file locking issues.
oSetup.ShadowCopyFiles = "true";
oSetup.ApplicationName = sAppName;
// Generate the name of the DLL we are going to launch
sApplicationFile = System.IO.Path.Combine(sApplicationDirectory, sAppName + ".exe");
oSetup.ApplicationBase = sApplicationDirectory;
oSetup.ConfigurationFile = sApplicationFile + ".config";
oSetup.LoaderOptimization = LoaderOptimization.MultiDomain;
// Launch the application
System.AppDomain oAppDomain = AppDomain.CreateDomain(sAppName, AppDomain.CurrentDomain.Evidence, oSetup);
oAppDomain.SetData("App", sAppName);
oAppDomain.SetData("User", sUserName);
oAppDomain.SetData("Pwd", sUserPassword);
oAppDomain.ExecuteAssembly(sApplicationFile);
// When the launched application closes, close this application as well
Application.Exit();
Note that in our version, the shell app collects the user name and password from the user in order to access the update web site correctly. This data is then passed to the "real" app through the SetData method on the AppDomain.
The solution depends on your particular case. But there's no straight solution, because you can't update assemblies while they are loaded into memory and being used. I can propose 2 solutions: using shadow copying and using some sort of helper executable. I've used both of them.
Shadow copying.
The obvious way is to make your main executable to be shadow copied, replace it while your app is running and then restart the app. But you can't make your default app domain to be shadow copied, only secondary app domains can be. But you still can move all your code into another assembly (say, MainAppLib.dll) and rewrite your main app executable (MainApp.exe) so that it contains only "loader code". This loader code has to create another app domain, set it to be shadow copied and then run your program logic in the secondary app domain. Beware not to have any direct references from your main app domain into MainAppLib.dll because then this assembly will be loaded into your main app domain which is not shadow copied and the assembly file will get locked. In most cases you can go with AppDomain.ExecuteAssembly() methods.
Helper executable
The idea is to use some sort of update finisher. Your main app remains unchanged, you only add a little amount of code into it, so that your app will download update, put it into temporary folder, and then your main app starts update finisher (in separate process) and exits. Update finisher waits till your app closes and then copies new files from temporary folder into your app folder replacing all files. Update finisher can't replace it's own executable but it can be done by main application before it starts the update finisher. After copying files update finisher runs your application.
p.s. Personally I prefer the former solution because it involves some sort of voodoo magic using app domains, reflection, assemblies e.t.c. And it can be evolved into using plugins if you need (e.g. via MEF framework). But the latter is easier to understand especially if you have never worked with app domains and manual assemblies loading, it's quite straightforward.
You could probably use ClickOnce (based on your comment above that you would be prepared to have another assembly get the exe....as the other poster mentioned you can't replace a running assembly). You can configure it to check at various times (e.g. on startup) for new versions and it automatically downloads them. Its a very robust solution and you can do a lot with the deployment assemblies.