I was thinking that WinForms are classes as any other classes. But starting form project get me confuse. Why new Form start with Application.Run and what kind of mechanism happen inside of it ?
As it says in the documentation, it begins running a standard application message loop on the current thread. The message loop handles clicks, keypresses, paint requests, plus many other things.
When called with a form as an argument it also makes that form visible.
This goes way back to the Win32 API. Winforms sits on top the win32 api. Application.Run() plugs your program into (implements) the win32 message loop. Pretty much all mouse and keyboard events (and most anything else initiated by the user) are really win32 messages.
Related
I've been looking around for quite a while, and can't seem to find a good way to do this.
Basically I have a C# process using WPF (which has no visible window), that I need to handle WM_ events in (such as WM_CLOSE or WM_DESTROY for example; so that I can elegantly shutdown when a user chooses to log off or restart their machine).
There are a number of solutions I've seen out there that suggest using System.Windows.InteropServices to call AddHook and provide it a pointer to a function that then becomes the WndProc. The problem with this is, as far as I can tell, it depends on the window actually being visible (and in this case there is no window).
Another way that's suggested but doesn't work is to override the WndProc method of a WinForm, but this process has no visible forms or windows.
I've also found things referring to a Message-only Window. Some kind of invisible window that still receives WM_ events. From what I've seen, this is only available in a Microsoft.WindowsCE.Forms assembly. I added a reference to this assembly in my project and subclassed MessageWindow as indicated at: http://msdn.microsoft.com/en-us/library/microsoft.windowsce.forms.messagewindow.aspx but it still seems to not work. The breakpoints inside the WndProc are not being hit.
Any clue?
Think about what you are asking- if you don't have a window, how could your application receive a window message (considering that messages are sent to a window's handle).
That's like saying "how can I receive email without having an email address?"
Michael Entin covers windows' behavior during shutdown here.
I am 99% sure that all processes running in a user's session are automatically closed when the user logs off anyway, so this shouldn't be an issue. If you really must handle this window message, you can create a hidden window as per Any way to create a hidden main window in C#?
I am having a very difficult time trying to debug/fix an application.
Briefly:
- I created a "wizard" type app that starts with the user taking a photograph (using the common dialog for photos)
If the user tries to use the text input window (SIP) (the little keyboard input window) after a photo is taken the event loop seems to hang - the event is not processed or is delayed for a while.
If the user does not take a picture the SIP keyboard works great.
This only happens on some of my devices. Specifically it is not a problem on an MC65 but is a problem on an ES400.
It appears that the app's event loop gets screwed up with the way I am displaying forms and taking photos.
If created a simple test app with single form containing a button (Event handler takes a photo) and a text box that accepts input. That works fine. But it is only a single form app that does nothing else.
When I combine the photo taking with my form displaying (making a "wizard" ) things go badly.
I wonder what kind of event loop should I be running?
Essentially the user takes a photo then goes through some forms (I hide one form and show another when they click the "next" button.)
The Form.Show is called from the main form after a picture is taken and then I have something like:
while(UserNotFinished)
{
Application.DoEvents()
}
Where UserNotFinished is a flag set from my wizard/forms after the "submit" button is pressed.
I will be happy to provide more code but not sure what would be useful.
I am new to C# and CF development (lots of years of C++/Win32)
The real confusing part is that this works on one device but not on another. In fact, the device hangs completely. It ends the activesync connection and sometimes I have to hard reset by removing the battery.
I think your problem stems from the while(true) { DoEvents(); } and perhaps how you are trying to go between forms. The only time I've used the DoEvents() method is when I'm already in the scope of a windows event and I need to be sure something in the message queue is processed so screen updates are correct. I'd suggest making a controller class to manage the screen flow for your wizard. You can control the screen flow by either using ShowDialog() and execute the flow control directly in the scope of a single call, or you'll have to use Show() and an asynchronous mechanism such as subscribing to and handling specific form and control events in the controller class. Also saw the comment about introducing another thread, beware that Forms belong to the thread they were created in and you must Invoke(...) all Form members in the context of the creating thread.
Hmm. Very strange
I started a new thread and basically call Application.DoEvents() in in as well and it seems to fix the problem...
I don't know why the
while(true)
{
DoEvents()
}
in the main thread doesn't work.
I am new to C# but I have been programming with VB6 for a long time. I have a very simple project that runs without any errors. There is one problem however and it has to do with the Windows itself. If I open up any Window (from any other program) and that window overlaps my application...the moment I close that "other window", my application's Window does not repaint the portion that was overlapped by the "other window".
The same thing happens whenever the Bubbles screensaver comes on for Windows Vista. When I jiggle the mouse to cancel the screen saver, guess what??? I have bubbles scattered all over my Window. In VB, we had a simple "Window.Refresh" and voila! In C# however, this does not work. I have scoured the forum(s) and there seems to be a mention of "refreshing a thread". I'm kind of confused at this point. Why can't things be simple??
You can call Form.Invalidate to invalidate the client area of the form. That will cause it to receive a paint message, and redraw itself.
This is similar to the VB6 Refresh method.
However, this should happen automatically. If your application is doing some processing in the UI thread, however, it will prevent it from processing its messages until the work is completed. If this is the case, you should consider using BackgroundWorker (or some other method) to push the work onto a background thread.
There is nothing special you should need to do to redraw the Form in C# (Form should redraw fine when you bring the window back to the top).
Do you have any third party controls in play? Control.Refresh() does exist in C#, should you should be able to call it from the Form itself (usually this.Refresh() in your Form's codebehind), or any Control which has children (like Panel).
I am attempting to write a specialized onscreen keyboard (OSK) for an application I'm writing in C#. To facilitate this, I've created a form which has several buttons on it representing keys, and clicking them calls SendKeys and sends out the appropriate keys.
This form is owned by the main window that is shown when the application first starts, using the Owner property. This way, the OSK pops up whenever the user focuses the application, and it stays on top of the main window if it said main window is dragged over it.
This all works great, but because I have modal dialogs that I also want to use with the OSK, I attempted to create it in a separate thread, complete with its own message loop (via Application.Run) so it could still be usable with any modal dialogs in the main thread.
The problem with this is that, obviously, being in a separate thread can cause InvalidOperationExceptions because of cross-threaded calls. One specific example of this is when calling Application.Run(osk) from the new thread, a cross thread error occurs because it is attempting to update the window's handle with the owner (the main window).
My question is, is it possible to have an owned form on a thread that is separate from the owner in a safe manner? And, if failing that, is it possible to emulate an owned form's characteristics (namely being Always On Top for only the main window, and popping up when the main window is focused)?
Thanks, and sorry if this is confusing.
I think this is actually a bug in Windows Forms. Somewhat inevitable due to the way it checks for access to the Handle property by the wrong thread. The SDK docs for SetParent are not explicit about it, it states the requirement is that both windows belong to the same application. No mention of having to belong to the same thread. I know for a fact that the 'same application' requirement is not hard, there's appcompat code in Windows that makes this work for windows from different processes. Adobe Acrobat ab/used this for a long time. Which definitely absolves the 'same thread' requirement.
Well, punt the problem and try it out. Set Control.CheckForIllegalCrossThreadCalls to false before you set the owner, back to true afterward. And test the heck out of it. If you have trouble then try pinvoking SetParent() directly instead of setting the Owner. Windows Forms actually uses SetWindowLongPtr which is not recommended by the SDK.
I'll take a stab at this. Try running the OSK as a separate process.
Try using ShowDialog for the OSK as well instead of Application.Run - ShowDialog creates a message loop and ends it when the window is closed, and perhaps will solve your problems.
new Thread(() => new OSK().ShowDialog());
Why not use Control.Invoke to make cross-threaded calls to avoid InvalidOperationException?
This may be a long short or not even possible but no harm in asking.
What I am trying to do is monitor an application for any new windows it creates in its MDI control. I have implemented hooking in C# and can capture the MDICREATE window message but because I need to get information about the window after is has been created the MDICREATE message isn't much help because at that stage the window hasn't been created in the other application yet.
Without going into to much detail I just need to be able to see when a new window has been created.
Is this possible?
Thanks
I'm not aware of another message that gets the info that you are looking for off hand. But if that message works for you, you could hook that message and then do another scan of the windows to find the one you are missing. You can enumerate the child windows of the parent window. Use Spy++ to see the exact window hierarchy.
If you can watch for a particular function call, I would use some kind of hooking library to grab that (EasyHook comes to mind).
You can hook the MDI create function (assuming there is one), watch for that, then inn your code, call the original and do any lookups using the returned value. You'll have access to the returned value and any parameters, so you should be able to get some info out of those.
Two options off the top of my head.
Hook the WM_MDIACTIVATE event, the first time the window is being activated, use a flag to determine the first time the window is being activated.
If you need to run your code after the WM_MDICREATE or WM_MDIACTIVATE, you can post a new custom message from one of these messages, which is then handled after these messages have completed. You then write your code to handle the custom message.