C# Windows Forms How to Blank Out all other monitors - c#

I am building a log in form for a shared environment.
This form will automatically pop up whenever a user logs in and asks for credentials (via RDP).
I discovered an issue that if the user has multiple monitors, they could disable the form pop up by accessing the Task Scheduler via the task view button on the taskbar.
(Currently it will log a user out if they use any hot key navigation methods)
So I would like to have my form put up a blank screen on all other monitors so the user is forced to address the log in form.
I have found the System.Windows.Forms.Screen.AllScreens array but I am not sure how I can draw a rectangle on every monitor except where the form actually sits.
Any help would be greatly appreciated.

I figured it out so I thought I would share.
I created a new blank form (called monitorBlackOut), set it manual positioning and to be maximized.
In the main form I added the following code:
if (System.Windows.Forms.Screen.AllScreens.Length > 1)
{
for (int i = 1; i < System.Windows.Forms.Screen.AllScreens.Length; i++)
{
int xPos = System.Windows.Forms.Screen.AllScreens[i].Bounds.Location.X;
int yPos = System.Windows.Forms.Screen.AllScreens[i].Bounds.Location.Y;
monitorBlackOut screen = new monitorBlackOut();
screen.Location = new Point(xPos, yPos);
screen.Show();
screens.Add(screen);
}
}
Then when the user successfully logs in I can execute:
foreach(monitorBlackOut screen in screens)
screen.Close();
Works exactly how its supposed to and will work on any number of monitors.

Related

winform app webbrowser error changes are not allowed while code is running

i am facing an issue in winform app, i am using webbrowser control. At one point i am using for loop and in the loop i have to invoke the Enter button event programatically. It is something like below:
for (int i = 1; i <= 4; i++)
{
htmlElement = webBrowser1.Document.GetElementById(PagerTxtBoxID);
htmlElement.InnerText = i.ToString();
SendKeys.Send("{ENTER}");
}
now every time at SendKeys.Send("{ENTER}"); the page should gets refreshed with new values (inside webbrowser control).
However it is not working and the page is not refreshing and when i am trying ti debug, it shows changes are not allowed while code is running.
Requesting you folks to please guide me from here.
SendKeys.Send(...) actually send the keyboard signals as when you are hitting keys on whatever is focused now. If you are on debug, it probably tries to send enter key to visual studio, modifying the C# code. You have to figure out another way of interacting with the webbrowser. One method is to programatically click a html button.

teststack white get the main window after the login window

I am working on automating a windows application using Teststack white, the current issues that I have is that after logging in the main application, white doesn't seems to find the new window.
var pathAp = appPath(path);
Application application = Application.Launch(pathAp);
Window window = application.GetWindow("login");
TextBox userName = window.Get<TextBox>("userName");
TextBox pass = window.Get<TextBox>("pass");
userName.Enter("user1");
pass.Enter("pass");
Button login = window.Get<Button>("login");
login.Click();
//now the program will wait and the main window will show up
Window mainWindow = application.GetWindow("main");
for some reason the program throws an error message saying that it can't find the window.
any ideas guys thanks
so I figured out what happened after logging in to the application the new process ID appears instead of the old one, so I used the Application.Attach() method to get hold of the new "Application", the attach method takes a PID as parameter, to get that you can use the following method, Process.GetProcessesByName(), and you can then get the ID of the process that can eventually pass it to the attach method.

ShowDialog(IWin32Owner) from Class Library

I have a class library that holds a "MessageBox" equivalent with a few more bells and whistles.
If I call the ShowDialog(IWin32Owner) method, this works, and the form will display in the centre of my parent form.
Sometimes, however, this form is invoked from a class in my project, and so I don't have access to the form owner. In this situation, I can pass null to the ShowDialog() method, however it appears this doesn't recognize the "Currently Active Window" and display it in the centre. I am assuming because it is in another class library.
Is there any way then to get the currently active form (or at least the screen) the user is working on?
EDIT
Ok this is more to do with the FormStartPosition Enumeration.
If I use CentreScreen this should default to the currently active monitor as per MSDN. However this seems to default to the default monitor if the form is in a class library.
Ok:
This is the code in question: It Fails to set the form to centre screen:
public static DialogResult ShowYesNoCancel(string message)
{
using (frmMessage form = new frmMessage())
{
form.Text = #"Input Required";
form.lblMessage.Text = message;
form.btnNo.Visible = true;
form.btnOK.Text = #"Yes";
form.btnOK.DialogResult = DialogResult.Yes;
form.StartPosition = FormStartPosition.CenterScreen;
return form.ShowDialog();
}
}
A solution:
/// <summary>
/// Overridden to ensure its in the centre of the current screen
/// </summary>
/// <returns></returns>
public new DialogResult ShowDialog()
{
Screen current = Screen.FromPoint(MousePosition);
Rectangle s = current.WorkingArea;
StartPosition = FormStartPosition.Manual;
Location = new Point(s.Left + s.Width / 2 - Width / 2, s.Top + s.Height / 2 - Height / 2);
return base.ShowDialog();
}
this should default to the currently active monitor
Problem is: which is the "currently active monitor" if you have more than one? If you have two or more then that gets to be a muddled question, a secondary monitor isn't more or less "active" then the primary one, it is equally capable of displaying windows.
The heuristic that Winforms uses is "the monitor that displays the mouse cursor". The underlying call is:
Screen desktop = Screen.FromPoint(Control.MousePosition);
If you want to emulate the behavior that MessageBox.Show() uses to find an owner then write the code so it finds the currently active window. The underlying winapi call is GetActiveWindow(). Which ShowDialog() already uses so there is probably more going on than meets the eye, like an active window that is not a Winforms window. Which the native MessageBox() winapi function doesn't mind, but ShowDialog() does. Use Spy++ to diagnose this.
You can use Form.ActiveForm:
Gets the currently active form for this application.
However, the fact that your class library is showing this message on its own without already knowing about the UI is probably not a good sign.
Form.ActiveForm will only work if any form of your application has the focus. So if your application is in background, that will be of no help.
Use Application.OpenForms instead. Retrieve the last item in the collection, which represents the last openend form.
Caution with special form properties, like ShowInTaskBar... they might not show up in this collection! Described here:
https://stackoverflow.com/a/3751748/2243584

C# change windows form to ontop after opening an AutoCAD drawing

I have written a C# plugin for AutoCAD where the user can enter some information and afterwards the appropriate drawing should be openend.
The actual workflow should be:
I start my plugin in AutoCAD
The user can input some information in a windows form which is on top of the current active drawing
When the user hits the enter button a new drawing should be opend
The form where the user has entered some information should be closed (which works fine)
A new window form should be opend to enter some other information (not the same window as the first one) BUT IN THE NEW DRAWING
The problem is that I can correctly close the first window and correclty open the new drawing. Like this:
DocumentCollection documentCollection = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager;
if (File.Exists(absoultePathOfDrawing))
{
Document newDrawing = documentCollection.Open(absoultePathOfDrawing, false);
Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument = newDrawing; // this sets the new drawing as the active one ==> is on top
}
Dispose(); // closes the first form
DialogResult = DialogResult.OK; // tells my applciation that the first window was successfully closed
The form closes correctly and afterwards I try to open the new form with:
if (result == DialogResult.OK)
{
MessageBox.Show("Test");
}
But now the new drawing is on top and behind is the old drawing. When I switch back to the old drawing, the new MessageBox will be shown but actually this should be shown in the new drawing, because I set the active document to the new drawing.
What am I doing wrong?
I have found the solution.
I had to load my plugin with the following option:
[CommandMethod("PluginName", Autodesk.AutoCAD.Runtime.CommandFlags.Session)]
Without this my plugin is only valid in one document (the one where I started my plugin)

C# Multiple mouse macros within form windows

I want to make a windows form application that I can open multiple times.
When I click the "GO" button on the first form, I want the mouse to perform a series of clicks within the form (given by specific coordinates), while I still have control over the cursor using my hand-held mouse, so essentially there are 2 mice.
If I click the "GO" button on all forms, I want all the mice to perform a series of clicks within the corresponding form (all running in unison, not effecting one another), while I still have control over the hand-held mouse to do what I want I.E. browse the web.
Is this possible to do? IF so where would I start?
You can use PInvoke and call the SendInput API.
http://www.pinvoke.net/default.aspx/user32.sendinput
To the best of my knowledge it is impossible to have two mice on one windows system, if you simulate a click somewhere it normally moves the mouse to that location.
You can try the lib Wolfgang suggested or you can use the code from this question
As for it running multiple times you could just load up multiple threads all running the same code, like this:
static void Main(string[] args)
{
Thread[] threads = new Thread[5]; // replace 5 with how many times you want to run it.
for(int i = 0; i < threads.Length;i++)
{
threads[i] = new Thread(new ThreadStart(MyCode));
threads[i].Start();
}
}
static void MyCode()
{
//put code here
}

Categories

Resources