I had originally created a windows form to be a dialog of my projects main form. Now the dialog is getting complex enough that it needs to be started in its own process. Is there a way to do this in code or do i need to create a new project and link my files to it?
I question the premise here - there is no reason to necessarily start a new "form" in a separate process. If the form is getting that complex, however, I would recommend simplifying it, if for no reason other than usability.
That being said, you can always launch a new process via Process.Start in code. If you want it to be in the same project, but start a separate process, you could launch the executing exe with a command line argument that allows you to switch which "form" is loaded at startup.
You will need to set up a communication layer (WCF using named pipes would probably be the best way to go).
But I would seriously question why you need a new process for your form? Make sure that whatever work you do on your form is done on a separate thread. That way you can have dozens of forms open but your app will remain very responsive.
It's not the best solution, but if you are trying to avoid a rewrite, a call to Application.DoEvents will pump the message queue and get you some responsiveness back if you have a whole lot of updates happening on your UI. Band aid solution to your problem though.
Related
What I thought would be pretty easy is quickly defeating me. I'm not a native C# programmer, but was asked to create a WinForm application that has a single instance. I''ve seen the Mutex examples already on StackOverflow, but the one thing that eludes me is the ability to pass parameters to window on the command line, parse the values and repaint the form with the new values.
Anyone have an example of this? The main thing that seems to be tripping me up is the threading. I want to run my.exe and show the window. Each time the form is run, I don't want a new form -- just to get the new parameters and show them in the form.
Any/All replies are appreciated!
When you starting another instance of your application, you are running same code, but on different process. So, you need to look on passing data between processes. Something like Named Pipes or Remoting.
#lazyberezovsky is right. Invoking again the application from the command line will spawn a different, unrelated process and you would require inter-process communication to forward the new parameters to the previously running app instance, before quitting the new process being invoked.
IMHO, the easiest way (not the best certainly) to communicate between these two processes would be using the Windows Registry, as this is already thread-safe and the API is very simple.
First, when the application runs, before showing the main form, I would perform a check to see if another instance of the app is running.
If false, it is the first time the app runs and I would process the command line and show the form as regular. I would also clear the registry key used for inter-process communication (see below).
If true, then I would store the command line in the registry on a specific key that will serve for inter-process communication and then I would terminate the application without even showing the main form.
Your running application (the first instance) will require to start a polling mechanism (could be a Windows timer firing once each second) that regularly examines the registry key where a new command line is expected . It would normally find and empty string and do nothing, but if the retrieved value is not empty, then it would mean the user spawned again the application with a different set of parameters, then you can proceed to decode your command line and repaint the window as necessary. After this, make sure you clear the registry entry again, so the polling mechanism resumes and detects the next time the application is invoked by the user.
Named pipes, WCF, .remoting or TCP sockets are IPC mechanisms that can be used and won't require a polling mechanism, that may be frowned upon by some. ;)
Hope this helps!
I've got a .Net windows form application where a lot of variables are initialized in the Main_Load event and I have a situation where I want my DB re-queried and all vars set to null and re-initialized (basically the form 100% reloaded from the start), but I wrote my Main-Load in such a way (my fault) that it's not that easy to do...
I know I could get exactly what I want by simply calling Application.Restart and it does the trick beautifully, but I'm not sure if this is good programming practice or considered really bad.
Are there any problems that I'm likely to run into by using Application.Restart in this context?
Not friendly to debug, but there's nothing really wrong with it. It is the exact same as terminating the app and starting it again.
You can avoid it by simply creating a new instance of your main form and closing the old one. That however does require you to prevent the program from exiting. Code is here.
It's not that the method doesn't work; rather, many times programmers forget that they've put something in their code that would stop the application from automatically shutting down, or starting up.
Please follow this Thread
You can also do the job with
System.Diagnostics.Process.Start(Application.ExecutablePath);
Application.Exit();
To directly answer the question in the title, yes restarting an application to re-initialize variables is bad practice.
There are cases where restarting an application is usefull (in example self-update), but restarting to mimic a ReInitialize() method is bad in my opinion.
I had problems with this.
I really needed to restart a large Winforms Application, when a user logs off, to ensure all cached (my) data are purged.
Solved my problem by adding the Application.restart() into the Application Shutdown Event.
This works inside the VS environment and when running the EXE
If you want to find that event select your main project properties and from the Application (Side Tab) select View Application Events at the bottom.
My guess is that this works because it is very late on in the closing process. Hope this helps someone and, more importantly, it continues to work.
First, what I need is - n WebBrowser-s, each in its own window doing its own job. The user should be able to see them all, or just one of them (or none), and to execute commands on each one. There is a main form, without a browser, this one contains control panel for my application.
The key feautre is, each browser logs on to secured web page and it needs to stay logged in as long as possible. Well, I've done it, but I'm afraid something is wrong with my approach.
The question is:
Is code below valid, or rather a nasty hack which can cause problems:
internal class SessionList : List<Session> {
public SessionList(Server main) {
MyRecords.ForEach(record => {
var st = new System.Threading.Thread((data) => {
var s = new Session(main, data as MyRecord);
this.Add(s);
Application.Run(s);
Application.ExitThread();
});
st.SetApartmentState(System.Threading.ApartmentState.STA);
st.Start(record);
});
}
// some other uninteresting methods here...
}
What's going on here? Session inherits from Form, so it creates a form, puts WebBrowser into it, and has methods to operate on websites. WebBrowser requires to be run in STA thread, so we provide one for each browser. The most interesting part of it is Application.Run(s). It makes the newly created forms alive and interactive. The next Application.ExitThread() is called after browser window is closed and its controls disposed. Main application stays alive to perform the rest of the cleanup job.
When user select "Exit" or "Shutdown" option - first the browser threads are ended, so Application.ExitThread() is called. It all works, but everywhere I can read about "main GUI thread" - and here - I've created many GUI threads. I handle communication between main form and my new forms (sessions) with thread-safe methods using Invoke(). It all works, so is it right or is it wrong?
Is everything right with using Application.Run() more than once in one application? :) An ugly hack or a normal practice? This code dies if I start a WebBrowser from the session form thread. It beats me why. It works however if I start WebBrowser (by changing its Url property) from any other thread. I'd like to know more what is really happening in such application. But most of all - I'd like to know if my idea of "applications in application" is OK.
I'm not sure what exactly does Application.Run() do. Without it forms created in new threads were dead unresponsive. How is it possible I can call Application.Run() many times? It seems to do exactly what it should, but it seems a little undocumented feature to me. I'm almost sure, that the crashes are caused by WebBrowser component itself (since it's not completely "managed" and "native"). But maybe it's something else.
Is everything right with using Application.Run() more than once in one application? :) An ugly hack or a normal practice?
Some of both ;) This is perfectly acceptable, in that it will function as you are expecting, but it's not exactly a "normal practice."
I'm not sure what exactly does Application.Run() do.
Application.Run basically does a couple of things. First, it installs the property SynchronizationContext into the thread for Windows Forms to run properly. It then starts the windows message processing in that thread, which processes all messages from Windows going into the thread. This is what allows forms to work properly.
There's nothing particularly wrong with doing this, but it isn't a standard practice. Given your design goals, I do question whether this would be better served by just launching a separate process instead of trying to run each operation within a separate thread.
I'm having a bit of a trouble trying to create a multi window'ed console application. Currently, my application's main console window is used to collect user input and display output.
Much of this output comes from a separate thread, as live data comes in. I was wondering if there is a way for me to separate my application into two windows, where the second window was either a console window or even any other kind of window that could display the text of the incoming strings... In particular, the main console window would be where the user input commands etc, and the second window displayed what the system was currently working on. This second window could be entirely readonly.
Any suggestions would be greatly appreciated! I would post code, but I don't really have anything relevant (that I can think of) to post....
This will be hard to do.
Here is answer for similar question: Can you have multiple .net Consoles (as in Console.Writeline)
If you really want to do it, you can find logic here: http://www.codeproject.com/KB/cpp/MultipleConsoles.aspx
Maby better approach will be to start another process (console app) and communicate between them thru IPC ( Interprocess communication ) - like named pipes .
More about IPC you can find: http://www.infoq.com/news/2008/01/wcf-comm-options
It is probably easier to just pop-up a Windows Form with a TextBox containing the data you wish to show. You can simply start a new thread and call Form.ShowDialog() to get the form to show.
I have a windows form application which needs to be the TopMost. I've set my form to be the TopMost and my application works as I'd like it to except for in one case.
There is a 3rd party application (referred to as player.exe) that displays SWF movie files on a portion of the screen that popup on top of my application.
Using Process Monitor I determined that player.exe application calls
flash.exe <PositionX> <PositionY> <Width> <Height> <MovieFile>
in my case:
flash.exe 901 96 379 261 somemovie.swf
Since flash.exe is being spawned in a new process after my form has been set to the TopMost it is appearing on top of my application.
First thing I did was make my application minimize the player.exe main application window hoping that this would prevent the Flash from appearing also. But, unfortunately it doesn't... even with the window minimized whenever the flash movie starts it shows up at the pixel location (901,96). I then tried creating a timer to keep setting the form.TopMost property to true every 10ms. This sort of works but you still see a very quick blip of the swf file.
Is there some type of Windows API call which can be used to temporarily prevent player.exe from spawning child processes which are visible? I admit it sounds a little far fetched. But, curious if anyone else has had a similar problem.
Addendum:
This addendum is to provide a reply to some of the suggestions layed out in Mathew's post below.
For the emergency situation described in the comments, I would look at possible solutions along these lines:
1) How does the third party application normally get started and
stopped? Am I permitted to close it
the same way? If it is a service, the
Service Control Manager can stop it.
If it is a regular application,
sending an escape keystroke (with
SendInput() perhaps) or WM_CLOSE
message to its main window may work.
Easiest way to close the app is to CTRL-ALT-DEL, then kill process. -OR-
The proper way is to Hold ESC while clicking the left mouse button... then input your username and password, navigate some menu's to stop the player.
There is no PAUSE command... believe it or not.
I don't think using WM_CLOSE will help since minimizing the application doesn't. Would that kill the process also? If not, how do you reopen it.
2) If I can't close it nicely, am I permitted to kill it? If so,
TerminateProcess() should work.
I can't kill the process for two reasons. 1) Upon relaunch you need to supply username/password credentials... There may be a way to get around this since it doesn't prompt when the machine is rebooted but... 2) Whenever I kill the process in task manager it doesn't die gracefully and asks if you want to send an error report.
3) If I absolutely have to leave the other process running, I would try
to see if I can programmatically
invoke fast user switching to take me
to a different session (in which there
will be no competing topmost windows).
I don't know where in the API to start
with this one. (Peter Ruderman
suggests SwitchDesktop() for this
purpose in his answer.)
I got really excited by this idea... I found this article on CodeProject which provides a lot of the API Wrapper methods. I stopped implementing it because I think that in order for desktop's to work you must have explorer.exe running (which I do not).
EDIT2: On second thought... maybe explorer.exe isn't needed. I'll give it a try and report back.
Edit3: Was unable to get the code in that article working. Will have to put this on hold for a moment.
Answer Summary
As one might have expected, there is no simple answer to this problem. The best solution would be to problematically switch to a different desktop when you need to guarantee nothing will appear over it. I was unable to find a simple C# implementation of desktop switching that worked and I had a looming doubt that I would just be opening a whole new set of worms once it was implemented. Therefore, I decided not to implement the desktop switching. I did find a C++ Implementation that works well. Please post working C# virtual desktop implementations for others.
Setting the TopMost property (or adding the WS_EX_TOPMOST style to a window) does not make it unique in the system. Any number of topmost windows may be created by any number of applications; the only guarantee is that all topmost windows will be drawn 'above' all non-topmost windows. If there are two or more topmost windows, the Z-order still applies. From your description, I suspect that flash.exe is also creating a topmost window.
Aside from periodically forcing your window to the top of the Z-order, I think there is little you can do. Be warned, however, that this approach is dangerous: if two or more windows are simultaneously trying to force themselves to the top of the Z-order, the result will be a flickering mess that the user will likely have to use the task manager to escape.
I recommend that your program not attempt to meddle with other processes on the computer (unless that is its explicit purpose, e.g. a task manager clone). The computer belongs to the user, and he may not value your program more highly than all others.
Addendum:
For the emergency situation described in the comments, I would look at possible solutions along these lines:
How does the third party application normally get started and stopped? Am I permitted to close it the same way? If it is a service, the Service Control Manager can stop it. If it is a regular application, sending an escape keystroke (with SendInput() perhaps) or WM_CLOSE message to its main window may work.
If I can't close it nicely, am I permitted to kill it? If so, TerminateProcess() should work.
If I absolutely have to leave the other process running, I would try to see if I can programmatically invoke fast user switching to take me to a different session (in which there will be no competing topmost windows). I don't know where in the API to start with this one. (Peter Ruderman suggests SwitchDesktop() for this purpose in his answer.)
You can use the Process class to start flash.exe directly - and use an appropriate ProcessStartInfo settings to show the window in a hidden state - or with a WindowStyle of hidden or minimized.
You could also consider using the SetWindowsHookEx API to intercept the process start API calls, and when the process is flash.exe run some code to restore you window to top-most status.
Matthew's answer is excellent, but I suspect you may be asking the wrong question. Why does your application need to be topmost? If you're trying to create a kiosk or some such, then topmost is not the way to go.
Edit: After reading your response to Matthew's comment, I'd suggest creating a new desktop and switching to it before displaying your alert. (See CreateDesktop and SwitchDesktop in MSDN.)