Firstly I am using VS2013 Winforms .net 4.0.
After excluding all other possibilities (from my set of possibilities) the culprit appears to be Me.close() in one specific form. After the me.close() method executes the coded-ui-test application seems to freeze and does not give any feedback about the buttons i am pressing or text i am entering. When I ask it to generate the code it goes as long as 1 hour before I decide to give up and kill the process. When I try the same test without the me.close it works as expected. Does anyone have any idea how to fix this bug in the automated ui testing? If not can you suggest any alternatives please?
Edit: This does not happen when I simply press the forms 'X' button in the top right. This is very strange.
Edit2: I have tried this in a fresh project. It is indeed me.close that causes the coded ui test application to 'freeze' such that I cannot generate the automated code and I will end up stuck at the 'please wait' loading bar.
Edit3: It appears to be specific to calling me.close in an infragistics click handler of a ultrabutton. Wow, here is example.
Designer
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class closemepls
Inherits System.Windows.Forms.Form
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.UltraButton1 = New Infragistics.Win.Misc.UltraButton()
Me.SuspendLayout()
'
'UltraButton1
'
Me.UltraButton1.Location = New System.Drawing.Point(45, 47)
Me.UltraButton1.Name = "UltraButton1"
Me.UltraButton1.Size = New System.Drawing.Size(232, 157)
Me.UltraButton1.TabIndex = 0
Me.UltraButton1.Text = "UltraButton1"
'
'closemepls
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(284, 262)
Me.Controls.Add(Me.UltraButton1)
Me.Name = "closemepls"
Me.Text = "closemepls"
Me.ResumeLayout(False)
End Sub
Friend WithEvents UltraButton1 As Infragistics.Win.Misc.UltraButton
End Class
Code
Public Class closemepls
Private Sub UltraButton1_Click(sender As Object, e As EventArgs) Handles UltraButton1.Click
Me.Close()
End Sub
End Class
If I call closemepls.showdialog() and click the button the coded ui test application freezes! Infragistics FTW.
This is the result, it does not complete even after 1 hour.
I had problems like that in WPF before.
Here's how I found it: Comment everything out then find the code that causes the problem by adding blocks back one by one.
It's something that is binded (anything though, not data and more than likely a control) not being released.
I haven't tried mixing CodedUI and VB much, but I was hoping this question may help you:
Me.Close does not work
Alone, that doesn't mean much, right? But in conjunction with how CodedUI works it may provide a clue. Remember that when you're running a test you're technically initiating a UITesting.Playback, which is a process. You may want to add something to your TestCleanup method that makes sure all the processes are terminated, like so (Keep in mind that this is for a browser test):
/// <summary>
/// Closes the test browser and ends test playback
/// </summary>
[TestCleanup]//The decorator is what makes this a method a test cleanup
public void CleanTest()
{
if (Playback.IsInitialized) //This is the important part.
{
Playback.Cleanup();
}
if (browserWindow.Exists)
{
browserWindow.Close();
}
}
This is just a shot in the dark and I may even be misunderstanding what you need, really but I'm assuming that in both your real and example areas you're closing the entire application? This may be a question for Infragistics at the end of the day. Good luck!
This might be the same issue I've experienced when using MTM, on a few machines if they were running any form of capture for the resulting test. They where trying to save it to a illegal path(Found in Event Viewer). After performing a repair on VS thus MTM to was repaired and it worked for some machines. Others only seamed to be fixed when going to update 4.
But code wise I would suggest trying to click the close button on the form itself to see if you get a different behavior.
Dim closeButton = New WinButton(YourWindow);
closeButton.SearchProperties(UITestControl.PropertyNames.Name) = "Close";
Mouse.Click(closeButton);
Related
In .NET 4.0 I'm dealing with an app which has a long loading time (about 20 seconds), so I wanted to display a swish scrolling marquee on a form that comes on top of the application whilst it is loading.
Since the main UI thread is doing all the loading of data UI elements, I couldn't get that to execute on a separate thread, so I ended up trying to run the form on a new thread. I ended up sticking this code in the form itself, to have it show itself on a new thread, like this:
Public Class frmWait
Public Property Message As String
Get
Return Me.lblMessage.Text
End Get
Set(value As String)
If Not String.IsNullOrEmpty(value) Then
Me.lblMessage.Text = value
Else
Me.lblMessage.Text = DefaultMessage
End If
End Set
End Property
Private OwnerThread As Thread
Private OwnerForm As Form
Private Const DefaultMessage As String = "しばらくお待ちください..."
Public Sub New(ByVal ParentForm As Form)
InitializeComponent()
Me.Message = DefaultMessage
Me.OwnerForm = ParentForm
End Sub
Public Sub New(ByVal Message As String, ByVal ParentForm As Form)
Call InitializeComponent()
Me.Message = Message
Me.OwnerForm = ParentForm
End Sub
Public Sub ShowOnThread()
' Position the form in the center of the owner
With Me.OwnerForm
Dim ownerCenter As New Point(.Location.X + CInt(.Width / 2), .Location.Y + CInt(.Height / 2))
Me.Location = New Point(ownerCenter.X - CInt(Me.Width / 2), ownerCenter.Y - CInt(Me.Height / 2))
End With
Me.OwnerThread = New Thread(New ThreadStart(AddressOf Me.ShowDialog))
Call Me.OwnerThread.Start()
End Sub
Public Shadows Sub Close()
If Me.OwnerThread IsNot Nothing AndAlso Me.OwnerThread.IsAlive Then
Call Me.OwnerThread.Abort()
Else
Call MyBase.Close()
End If
End Sub
End Class
This is probably quite clumsy, but I am showing it in different places in the application, so this seemed the most code-efficient way of doing this...
It actually works quite well, but I am encountering problems from time to time with this and need some help on how to address these issues.
Sometimes when the form gets closed I get an error about the thread being aborted in an unsafe manner.
At the moment I position the form manually in the centre of the form I want it to cover form. Ideally I'd like to be able to call .ShowDialog(ParentForm) on it, but of course that raises an exception because of cross-thread access from one form to the other.
Any suggestions on how to resolve this would be most appreciated.
Because I know virtually nothing about threading I probably coded this like a monkey, so if there is a better method to get this done, I would very much like to know about it.
The code I list is in VB.NET, but answer code in C# is fine too (for any overzealous retaggers)
UPDATE:
I realise now that I should have given a lot more details in my question... The wait form is actually not the first form I am displaying the app. There first is a login screen. When the user is authenticated, the login form launches the main interface of the app, which is the form which actually takes a long time to load.
I am displaying the wait form in between the login form and the main interface. I also use this form to cover for any long running tasks launched on the main interface by the user.
VisualStudio can do this for you. You can certainly write your own, of course, but if you look at your project options under Application there is a setting for Splash Screen. You can assign any form (other than the startup form) to be your splash screen. This runs on its own thread and you can marshall calls to it during startup to advance a progress bar, etc.
MSDN : Splash Screen
Instead of trying to show a dialog on a separate thread you should be moving your loading code to a separate thread / background worker.
Then just start your threads and show the progressbar on form_load and hide the progressbar when the thread completes:
Dim _progressForm As frmLoading
Private Sub frmMain_Load(sender As System.Object, e As System.EventArgs) Handles Me.Load
'start loading on a separate thread
BackgroundWorker1.RunWorkerAsync()
'show a marquee animation while loading
_progressForm = New frmLoading
_progressForm.ShowDialog(Me)
End Sub
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'simulate a long load
For i As Integer = 1 To 10
System.Threading.Thread.Sleep(1000)
Next
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
_progressForm.Close()
End Sub
Have a look at TaskFactory.New
Run your threaded code of a different thread to keep the UI responsive
http://msdn.microsoft.com/en-us/library/ee782519.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-3
You could use the ApplicationContext class to allow the splash screen to be run first and then swap in the Main form when it is ready. You use it in place of your main form in the call to Application.Run:
Application.Run(new MyApplicationCtx())
Just googled up a article for you as well:
http://www.codeproject.com/Articles/5756/Use-the-ApplicationContext-Class-to-Fully-Encapsul
I'm trying to create a program that will handle updates silently. I am using the wuapilib.dll, which comes with a number of classes (c#). My first revision of the program was as follows (ignore typo problems - its on another computer without internet access so i'm typing it by hand):
IUpdateSession mySess = new UpdateSession();
IUpdateSearcher mySear = mySess.CreateUpdateSearcher();
ISearchResult myRes = mySear.Search("Type='Software'");
IUpdateDownloader myDown = mySess.CreateUpdateDownloader();
IUpdateInstaller myInst = mySess.CreateUpdateInstaller();
myDown.Updates = myRes.Updates;
myDown.Download();
myInst.Updates = myRes.Updates;
myInst.Install();
Ignore the case where an update is already downloaded or installed, I'm omitting the logic above. My problem is that IUpdateInstaller doesn't allow you to force a quiet install - a number of updates require that a user click a confirmation box. The IUpdateInstaller2 class does (I got that from the second post down here), but for the life of me I can't find a way to get an IUpdateInstaller2 object. Nothing seems to return one, and Microsoft's documentation doesn't contain any example code. Extensive googling returned nothing of use.
I think I'm really close - the functionality is there, I just can't quite access it.
Thanks for your help.
I checked that (or rather, I think i did - wasn't too clear on getting it to work), and it looks like the CreateUpdateInstaller only returns an IUpdateInstaller, nothing else.
However, I found code (on a chinese website, interestingly enough) that just directly cast the IUpdateInstaller to an IUpdateInstalelr2, which has solved my problems.
Thanks for the help
I have posted in another Question my app to, search, download and then install Windows updates.
See: C# and WUAPI: BeginDownload function
you can easily change the:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.SetCompatibleTextRenderingDefault(false);
Application.EnableVisualStyles();
Thread thread = new Thread(() =>
{
Form1 form1 = new Form1();
form1.Visible = false;
form1.ShowInTaskbar = false;
Application.Run(form1);
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
}
then handle
Application.Close();
after the events have done their thing. For example, if no Updates have been found, then close the app. I use the async properties of the interfaces so it can do what it needs to async.
Hope this helps.
I also searched a long time for it.
You just need to cast it
IUpdateInstaller2 installer = new UpdateInstaller();
According to Microsoft documentation there are also version 3 and 4 available. But this must be an error. The functions of version 3 are available also in IUpdateInstaller2 and the functions from version 4 I never found somewhere.
I have a winforms app with multiple GUI threads. I want them to be able to access each other's thread objects without having to keep track of that information separately.
Is there a function in .NET that I can feed a winforms control or window object, and get back the thread? Or a function in the API I can pinvoke for the threadID?
(please no comments saying I should do it another way... also this is not about cross-thread window operations.)
Thanks!
Edit
For those of you who for some reason believed my italicized text, congratualations, you're hired!! Here is the problem:
"App is crashing in the wild by locking up totally, that is, it stop responding. Very intermittent, and trying to debug it, it seems to never happen."
So what do do? Install an option in the program that the user can activate under our direction, whereby from another GUI thread in the same app, do a thread.abort on the main GUI thread, then we can look at the call stack in the error log. Viola, found an impossible to debug error in less than a day. (Stop now, it had nothing to do with abusing multithreading:-)
I'll admit I almost didn't ask this, the reason I did was I could see an object reference to the main form, but there wasn't any for its thread. I'm giving Chris Shain the answer a/c it is a quick way, unfortunately when the thread is hanging, I wouldn't be able to do an invoke (it would hang too). A little more digging revealed the GetWindowThreadProcessId API call. But it's an unmanaged thread ID, apparently there are complications turning that into a managed thread ID.
So I bit the bullet and put in a global reference to the main UI thread. Would have posted it to begin with, but hadn't written it yet.
Now if you'll pardon the VB...
In main public module/static class:
Public GUIThread As Threading.Thread
Sub Main()
'' // Create app main window
ShellForm = New frmShell
'' // Save main GUI Thread for abort routine
GUIThread = Threading.Thread.CurrentThread
If GetSetting("MyApp", "Testing", "CrashDebug", "False") = "True" Then
'' // DO NOT run the pgm. like this normally - with try/catch around
'' // Application.Run - or uncaught errors will kill the whole app!!!
Try
'' // This is the other of the ‘Multiple GUI threads’ I talked
'' // about in the Orig Post.
Dim t As New Threading.Thread(AddressOf StartCrashDebug)
t.Start()
Application.Run(ShellForm)
Catch ex As Exception
'' // This error routine passes errors off to another thread which
'' // logs them (and also shows messages)
MyLogError(ex, "CrashDebug - Main Window blew up")
End Try
Else
'' // Normal mode - uncaught errors will get caught by UnhandledException,
'' // logged, and Winforms will keep the GUI alive (since we _do_ care
'' // more about users than computers right ;-)
Application.Run(ShellForm)
End If
End Sub
Sub StartCrashDebug()
Dim f As New frmCrashFinder
'' // Starting a window like this on a separate thread makes it ‘Another
'' // GUI thread’ for winforms, by design
Application.Run(f)
End Sub
In ‘aborter’ WinForm:
Public Class frmCrashFinder
Inherits Windows.Form
Private Sub Abort_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Abort.Click
GUIThread.Abort()
End Sub
End Class
All GUI elements in Windows Forms are typically done on a single thread. I strongly recommend avoiding trying to do this any other way.
You can always marshal code to that thread by using Control.Invoke or Control.BeginInvoke with any Control.
If you really want to get the thread's ID (not sure what use this will be..?), you could use:
int GetControlThreadId(Control control)
{
int threadId;
control.Invoke( new Action( () =>
{
threadId = Thread.CurrentThread.ManagedThreadId;
}));
return threadId;
}
If your code is not in a form or control, you can use
if (System.Windows.Forms.Form.ActiveForm.InvokeRequired)
{
System.Windows.Forms.Form.ActiveForm.Invoke(...);
}
This should do it, however I agree with other posters that this is probably the wrong thing to do for other reasons...
var thatWindowsThread = (Thread)(WhateverWindow.Invoke(()=>Thread.CurrentThread);
WindowsFormsSynchronizationContext.Current has Post and Send methods from which you can delegate command to UI thread
If you don't have access to any forms or windows or controls you can pull the thread or SynchronizationContext from, you can use
System.Windows.Forms.Application.OpenForms
This worked for me. System.Windows.Forms.Form.ActiveForm was null in my case, but Metro's answer made me look closer at static classes in System.Windows.Forms.
Use
System.Windows.Forms.Application.OpenForms.Invoke(...) or BeginInvoke.
You can get the rest from other answers.
Better answer:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsGUIThread([MarshalAs(UnmanagedType.Bool)] bool bConvert);
http://pinvoke.net/default.aspx/Constants.IsGUIThread
I am using a WebBrowser control in VB.NET and calling the Print() method. I am printing out using a PDF printer and when Print() is called it is not immediately kicked off (it waits until it has completed running code for the entire Sub or block.
I need to make sure the file I am printing too is complete and continue process with this file, therefore, I would like to print on demand and get some status of when the operation is complete. I have tried usign printDocument and process without luck.
Anyone have any ideas?
Check out the PrintTemplateTeardown event of the underlying unmanaged WebBrowser object. Sometimes that event gets fired multiple times but hopefully this will point you in the right direction. You need to add a reference to Microsoft Internet Controls.
Private Sub Print()
AddHandler DirectCast(WebBrowser1.ActiveXInstance, SHDocVw.WebBrowser).PrintTemplateTeardown, AddressOf PrintDone
WebBrowser1.Print()
End Sub
Private Sub PrintDone(ByVal obj As Object)
Trace.WriteLine("printed")
RemoveHandler DirectCast(WebBrowser1.ActiveXInstance, SHDocVw.WebBrowser).PrintTemplateTeardown, AddressOf PrintDone
End Sub
Your best bet is to get a handle on your 'printjobscollection' for your default printer and ensure that the jobcount = 0
like this in vb.net:
Dim intprint As Integer = Nothing
retry2:
intprint = GetPrintJobsCollection(printerinuse)
If Not intprint = 0 Then
System.Threading.Thread.Sleep(1000)
GoTo retry2
End If
'do what you want to do after print completes here
This has been a problem that I haven't been able to figure out for sometime. Preventing the second instance is trivial and has many methods, however, bringing back the already running process isn't. I would like to:
Minimized: Undo the minimize and bring the running instance to the front.
Behind other windows: Bring the application to the front.
The language I am using this in is VB.NET and C#.
I found this code to be useful. It does the detection and optional activation of an existing application:
http://www.codeproject.com/KB/cs/cssingprocess.aspx
If you're using .NET, this seems easier and more straightforward using build-in .NET functionality:
The Weekly Source Code 31- Single Instance WinForms and Microsoft.VisualBasic.dll
These link may be of help:
http://www.ai.uga.edu/mc/SingleInstance.html
It has code to detect another instance running, not sure what you can do with it once you've got the instance though.
In
Form_Load this code worked.
If App.PrevInstance = True Then
MsgBox "Already running...."
Unload Me
Exit Sub
End If
Here is a simple and easily understandable method for preventing duplicate concurrent execution (written in c#).
public static void StopProgramOnSecondRun()
{
string
//Get the full filename and path
FullEXEPath = System.Reflection.Assembly.GetEntryAssembly().Location,
//Isolate just the filename with no extension
FilenameWithNoExtension = System.IO.Path.GetFileNameWithoutExtension(FullEXEPath);
//Retrieve a list of processes that have the same name as this one wich is FilenameWithNoExtension
Process[] processes = System.Diagnostics.Process.GetProcessesByName(FilenameWithNoExtension);
//There should always be at least one process returned. If the number is greater than one. Than this is the clone and we must kill it.
if (processes.Length > 1)
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
I used the FileSystemWatcher on the form to solve this. This solution checks for the process, does not start a new instance, and shows the form of the already running process.
Add a FileSystemWatcher to the form that checks for the creation of a file and then shows the form with the created event.
In Program.cs:
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
{
File.Create("AlreadyRunning.log").Dispose();
return;
}
For the form's FileSystemWatcher created event:
if (File.Exists("AlreadyRunning.log"))
{
Show();
WindowState = FormWindowState.Normal;
File.Delete("AlreadyRunning.log");
}