How can I determine whether a window from another application is visible? - c#

I recently obtained a license for WinX DVD Ripper Platinum, and am annoyed by the fact that, when it's done ripping a DVD, it doesn't tell me so. There's no popup, no system "beep"- nothing. The progress dialog simply closes. The main window doesn't even focus itself...
To speed up my DVD-ripping proccess, I'm making a simple console application (using C# and VS2010) that:
Finds the handle of the process named "WinX_DVD_Ripper_Platinum" (the process name of the WinX DVD Ripper Platinum software)
Finds the handle of the progress dialog on that process using the GetChildWindows method defined in this sample at pinvoke.net
Starts a System.Timers.Timer instance that checks (or is supposed to check) whether the progress dialog has closed every 5 seconds (using the GetWindowLong function, and
Plays a few beeps with the System.Console.Beep method to tell the user that the rip is complete. The timer auto-resets, performing the check (or repeating the beep if the dialog has closed) every 5 seconds until the user presses a key in the console window.
Steps 1, 2, and 4 are working fine, but I'm having problems with step 3- this, my question is, which of the window style constants should I use to check if the window is visible? (WS_VISIBLE did NOT work...)
For more details, this is the function I'm using to check the dialog's visibility:
private static bool IsWindowVisible(IntPtr hwnd)
{
var style = GetWindowLong(hwnd, GWL.GWL_EXSTYLE);
var visible = style & (WS flag goes here);
return visible != 0;
}

Have you tried using IsWindowVisible() instead?

Related

Getting a console window out of "select mode" to prevent a crash

In my C# application, I am trying to prevent a crash in my application, basically, I am using a Console window as a log display window. I already solved the "Close Button" issue by disabling the close window, and I show/hide the menu with Show and Hide calls, all of that is working just fine.
My final hurtle is if Text Selection is active and the window attempting to be hidden.
I either need to:
A. Kick the window out of select mode. (not sure how I would do this, since selection pauses all output.)
B. Disable the "Edit" menu in the same way I disabled the Close menu, in a hope that it would also disable the mouse selection, but I have yet to find any way to remove the "Edit" menu, and I am not even sure that would prevent mouse selection.
C. This seems the most obvious, disable mouse selection, and this is the one I have currently in my code, but it's not working, so I am not sure what I am missing.
The Code in Question:
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
....
[DllImport("Kernel32.dll", ExactSpelling = true)]
private static extern int SetConsoleMode(IntPtr hWnd, int wFlag);
....
public static void HideConsoleLog () {
if (handle != IntPtr.Zero) {
SetConsoleMode(handle, 0x0080); // ENABLE_EXTENDED_FLAGS 0x0080
ShowWindow(handle, (int)WinCntrlOpt.SW_HIDE);
LogVisible = false;
}
}
According to the Documentation:
ENABLE_EXTENDED_FLAGS 0x0080 Required to enable or disable extended
flags. See ENABLE_INSERT_MODE and ENABLE_QUICK_EDIT_MODE.
And...
ENABLE_QUICK_EDIT_MODE 0x0040 This flag enables the user to use the
mouse to select and edit text.
To enable this mode, use ENABLE_QUICK_EDIT_MODE |
ENABLE_EXTENDED_FLAGS. To disable this mode, use ENABLE_EXTENDED_FLAGS
without this flag.
So, it seems I am doing this correctly, and it does run, but it does not prevent mouse selection. I do know that not to long ago, Microsoft tinkered with Consoles, and I don't know if that's broke this or not.
There is a similar question on stack exchange, but that nether gives a working solution, and is in-fact the reverse to what I am trying to do and in C or C++. I can interpolate, but it's basically what I am already trying here.
It seems to be the same suggestion, use ENABLE_EXTENDED_FLAGS without any other flags to disable the option, and that's what I have. But it doesn't work.
So, I am either scratching at the wrong solution or am not doing something else correctly.
The effect is, while the console window is open, you can use the mouse to select text which automatically puts the console in that "select mode" that Microsoft's tinkering added. That's not a problem, but it's when it's left IN that mode, and you select "Show Log" (a check-marked toggle menu option in the main application window) The console window does indeed hide, but then the main window locks up and the application crashes. (my guess is because the window is blocked by that select mode.) It doesn't crash when the 'select mode' is not active.
I would also like to try this from the same documentation:
ENABLE_MOUSE_INPUT 0x0010 If the mouse pointer is within the borders
of the console window and the window has the keyboard focus, mouse
events generated by mouse movement and button presses are placed in
the input buffer. These events are discarded by ReadFile or
ReadConsole, even when this mode is enabled.
Problem is, it says:
When a console is created, all input modes except ENABLE_WINDOW_INPUT
are enabled by default.
So, how do I disable it?
I am fine with any solution that either kicks it out of select mode, or prevents it to begin with, and I have here what I have tried.
When the "Show Log" menu option is selected, the window is going to minimize.
Before the window minimizes, you have to check whether the user has selected any input to prevent the crash. You can check whether the user is selecting anything by using GetConsoleSelectionInfo.
The CONSOLE_SELECTION_INFO out parameter should be equal to 0x00, and if it's not, you need to process the selection. As the documentation from GetConsoleMode/SetConsoleMode shows, you either need to call ReadFile or ReadConsole to discard the selection event that might be going on.
When you've implemented this, it shouldn't crash anymore.

Window ignores ShowWindow Minimized the first time, then obeys every time after

I have a C# application that I am kicking off a separate win32 window from. I'm marshaling Win32 api calls into my C# application and trying to control the win32 from that. I'm toggling the window from a button press to be either maximized on top of all windows always or minimized.
It will show maximized, then ignore the first button press to hide, it then stays showing when I press the button again, then finally hides once I press the button a 3rd time with the same code. It behaves as desired from here on out. I'm sure it must be some Windows flags that aren't set properly until it goes through a maximize/minimize cycle first.
Here is the life cycle of the window:
Create window maximized
A:
Hide:
target_hwnd = FindWindowHandleByCaption()
ShowWindow(target_hwnd, SW_SHOWMINIMIZED);
Show:
target_hwnd = FindWindowHandleByCaption()
ShowWindow(target_hwnd, SW_SHOWMAXIMIZED);
Goto A:
What am I doing wrong? I've been at this for hours trying various code snippets to no avail.
Thanks in advance!
EDIT:
Solved my problem by just doing:
SendMessage(target_hwnd.ToInt32(), WM_SYSCOMMAND, SC_MINIMIZE, 0);
SendMessage(target_hwnd.ToInt32(), WM_SYSCOMMAND, SC_MAXIMIZE, 0);
Instead of using ShowWindow.
Per the ShowWindow() documentation:
nCmdShow
Type: int
Controls how the window is to be shown. This parameter is ignored the first time an application calls ShowWindow, if the program that launched the application provides a STARTUPINFO structure. Otherwise, the first time ShowWindow is called, the value should be the value obtained by the WinMain function in its nCmdShow parameter.
...
The first time an application calls ShowWindow, it should use the WinMain function's nCmdShow parameter as its nCmdShow parameter. Subsequent calls to ShowWindow must use one of the values in the given list, instead of the one specified by the WinMain function's nCmdShow parameter. As noted in the discussion of the nCmdShow parameter, the nCmdShow value is ignored in the first call to ShowWindow if the program that launched the application specifies startup information in the structure. In this case, ShowWindow uses the information specified in the STARTUPINFO structure to show the window. On subsequent calls, the application must call ShowWindow with nCmdShow set to SW_SHOWDEFAULT to use the startup information provided by the program that launched the application. This behavior is designed for the following situations:
Applications create their main window by calling CreateWindow with the WS_VISIBLE flag set.
Applications create their main window by calling CreateWindow with the WS_VISIBLE flag cleared, and later call ShowWindow with the SW_SHOW flag set to make it visible.

Mono Gtk Window require focus for input

I haven't been able to find an example containing this functionality, and either i missed it in the documentation or it's not there.
I have a fullscreen GUI program, and when a user is required to type in a number, a calculator window popup has to appear in the center of the screen. The user types a number and clicks on enter, or hits cancel to continue past the window.
The problem is clicking on the fullscreen window behind the calculator brings that window to the front and hides the calculator without the intended entry being completed, which could get annoying for the user.
I guess the functionality I'm trying to create is what happens in most text editors/IDE's when you press the Open File button. Let me know if you want to see code, it's just two separate Window classes at the moment.
The Present() function of the Window object brings that particular window to the front. So adding a FocusOutEvent listener on the window you wish to keep in front like:
windowObj.FocusOutEvent += (obj, args) => windowObj.Present();
will work.
The alternative to this (and the better way) is to set the Modal property of the window to true.
If you've stumbled across this and you were looking for a popup window that suspends whatever called it to wait for input, see this question:
gtk# thread for window
You basically use the Dialog class instead of Window and add your elements to the ActionArea of the Dialog.
Hope this helps.

Resolving crash to desktop when application loses focus

I'm working on a simulation code where I have a "Project" which can hold numerous simulations. You can choose to run them one at a time, or you can run them all in sequence. In this specific case, I have 18 simulations which run one by one, and overall the process takes about 20 sec.
In short, a button is pressed on a form, and the following actions occur:
1) Create simulation object
2) Perform simulation start command
3) Write simulation data to file
4) Dispose simulation object
5) Update DataGridView which holds the simulation list (rewrites "Processing" to "Complete")
6) Update progress bar value in user control.
7) Refresh user control.
Rough source code is as follows:
for (int i = 0; i < dataSet.Count; i++)
{
using (Processor p = new Processor())
{
bool didTestPass = p.RunTest(dataSet[i]);
if (didTestPass)
dataGridViewProcessList.Rows[i].Cells[5].Value = "Run complete.";
else
dataGridViewProcessList.Rows[i].Cells[5].Value = "Run completed with errors.";
}
progressBarRuntime.Value = ((i+1) / dataSet.Count) * 100;
this.Refresh();
this.OnUpdateMainForm(this, null);
}
What I've found is, if you remain within the application's focus, all 18 simulations run fine. However, if you drop focus (say, switch to another program), it consistently behaves erratically at the 8th simulation. I say erratically because it acts differently:
When debugging through Visual Studio, the form freezes briefly, then suddenly all remaining simulations are processed and the progress bar snaps to full.
When running as a standalone program, it crashes straight to desktop. No warning, no exception throw, nothing.
I've also found that if I stay focused and let it reach, say, simulation 14, then drop focus from the program, it will immediately exhibit the above behavior.
I'm not particularly familiar with the concept of performing large calculation efforts under the hood while a Windows Form is active. At first I felt like maybe the Form needed to be refreshed (since this is all happening on a UserControl) but I saw no difference when I put in an event to force the Form to Refresh().
I ended up discovering that the source of my problem was that I was performing work on the interface's main thread, and as a result it was causing my program to hang and crash to desktop.
I created a BackgroundWorker and placed my work code into the DoWork event, then moved the ProgressBar indicator update into the ProgressChanged event.
More details regarding BackgroundWorker and its implementation at MSDN.
In short, the lesson learned for me is that if an activity in a Form is going to take longer than a few seconds, it should be done using a BackgroundWorker to prevent hanging up the interface.

Detect change of focus and find it C#

I need an underlying process to gather information about other applications used by Windows. I suspect this would be done using WAPI hooks. What I wish to do is for my program to detect when windows changes focus from one program to another and tell me which one currently has focus.
First I need an event that triggers each time Windows swaps focus between two applications. All events I've found so far only handles changes made from or to the program it's being used by, but I need to find all focus-changes, even if it's between two other programs.
I'll also need a function that gives me the window in focus. Would this work, or is this only internally (windows within the current application and not other programs)?
Cheers
Depending on how accurate you need your focus change detection system to be you might be able to get away with a service that polls for the foreground window using the API function you described GetForegroundWindow (yes this is system-wide, not process specific).
You can then use the handle of that function to determine which process is the current active/focused process. Then retrieve the focused element (child window) of that process..
HWND hwnd = GetForegroundWindow();
DWORD remoteThreadId = GetWindowThreadProcessId(hwnd, NULL);
DWORD currentThreadId = GetCurrentThreadId();
AttachThreadInput(rThreadId, curThreadId, TRUE);
HWND focusElement = GetFocus();
AttachThreadInput(rThreadId, curThreadId, FALSE);
Keep doing this.. and do whatever you need to do with focusElement
UPDATE
Well, apparently, as #Kenneth K. posted in a comment, there is a global EVENT_SYSTEM_FOREGROUND event that you can hook so that you application gets notified when the foreground (focused) window changes. This way you don't need to loop continuously to detect these changes.
EVENT_SYSTEM_FOREGROUND = 3;
WINEVENT_OUTOFCONTEXT = 0;
You can follow the example in this answer to see how to hook this event and get the notifications. Then whenever the foreground (focused) window changes you can hook that window's message loop and look form focus changed events withing that window using the SetWindowsHookEx function.
Another options is to consult the list of system events on MSDN and see if there is one you can use instead of the EVENT_SYSTEM_FOREGROUND, or along with it to detect control-level focus events. Perhaps the EVENT_OBJECT_FOCUS might be useful.
Please let me know if this is still unclear..

Categories

Resources