Impossible? Get instance of MainWindow from extern WPF-application
-
I have two WPF-applications. Let's call them
A
andB
. InA
I wan't to startB
as a new process and get the instance ofB
's MainWindow to further gain access of the controls inB
. WhenA
has started it sets up an instance of theProcess
class to startB
. The instance is kept inA
to help in any other way to access or terminateB
. InA
I have aStartB
method and aGetB
method:public partial class MainWindow : Window
{
Process Process { get; set; }public MainWindow() { InitializeComponent(); } private void Window\_Loaded(object sender, RoutedEventArgs e) { StartB(); GetB(); } void StartB() { var path = @"C:\\Some\\Path\\To\\B.exe"; var info = new ProcessStartInfo(path); Process = new Process(); Process.StartInfo = info; Process.Start(); } void GetB() { var title = Process.MainWindowTitle; var visual = System.Windows.Interop.HwndSource.FromHwnd(Process.MainWindowHandle); var window = visual.RootVisual as Window; }
}
The
StartB
method works. But theGetB
method don't work. This line inGetB
returns null:var visual = System.Windows.Interop.HwndSource.FromHwnd(Process.MainWindowHandle);
I have googled and I found somewhere that the call to
System.Windows.Interop.HwndSource.FromHwnd
should work, but it didn't. Is there a solution for this? Best regards, Stefan -
I have two WPF-applications. Let's call them
A
andB
. InA
I wan't to startB
as a new process and get the instance ofB
's MainWindow to further gain access of the controls inB
. WhenA
has started it sets up an instance of theProcess
class to startB
. The instance is kept inA
to help in any other way to access or terminateB
. InA
I have aStartB
method and aGetB
method:public partial class MainWindow : Window
{
Process Process { get; set; }public MainWindow() { InitializeComponent(); } private void Window\_Loaded(object sender, RoutedEventArgs e) { StartB(); GetB(); } void StartB() { var path = @"C:\\Some\\Path\\To\\B.exe"; var info = new ProcessStartInfo(path); Process = new Process(); Process.StartInfo = info; Process.Start(); } void GetB() { var title = Process.MainWindowTitle; var visual = System.Windows.Interop.HwndSource.FromHwnd(Process.MainWindowHandle); var window = visual.RootVisual as Window; }
}
The
StartB
method works. But theGetB
method don't work. This line inGetB
returns null:var visual = System.Windows.Interop.HwndSource.FromHwnd(Process.MainWindowHandle);
I have googled and I found somewhere that the call to
System.Windows.Interop.HwndSource.FromHwnd
should work, but it didn't. Is there a solution for this? Best regards, StefanI suspect you're calling
GetB
too early - the main window hasn't shown up yet. Assuming you have control of both applications, you'd probably be better off using IPC, probably using anonymous named pipes: Pipe Operations in .NET | Microsoft Docs[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
I suspect you're calling
GetB
too early - the main window hasn't shown up yet. Assuming you have control of both applications, you'd probably be better off using IPC, probably using anonymous named pipes: Pipe Operations in .NET | Microsoft Docs[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
I have two WPF-applications. Let's call them
A
andB
. InA
I wan't to startB
as a new process and get the instance ofB
's MainWindow to further gain access of the controls inB
. WhenA
has started it sets up an instance of theProcess
class to startB
. The instance is kept inA
to help in any other way to access or terminateB
. InA
I have aStartB
method and aGetB
method:public partial class MainWindow : Window
{
Process Process { get; set; }public MainWindow() { InitializeComponent(); } private void Window\_Loaded(object sender, RoutedEventArgs e) { StartB(); GetB(); } void StartB() { var path = @"C:\\Some\\Path\\To\\B.exe"; var info = new ProcessStartInfo(path); Process = new Process(); Process.StartInfo = info; Process.Start(); } void GetB() { var title = Process.MainWindowTitle; var visual = System.Windows.Interop.HwndSource.FromHwnd(Process.MainWindowHandle); var window = visual.RootVisual as Window; }
}
The
StartB
method works. But theGetB
method don't work. This line inGetB
returns null:var visual = System.Windows.Interop.HwndSource.FromHwnd(Process.MainWindowHandle);
I have googled and I found somewhere that the call to
System.Windows.Interop.HwndSource.FromHwnd
should work, but it didn't. Is there a solution for this? Best regards, StefanAn exe can be treated as a dll. You haven't said why you need to "start" B. If it's B's main window you want, you can instantiate it via A. That applies to anything public in B.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
-
An exe can be treated as a dll. You haven't said why you need to "start" B. If it's B's main window you want, you can instantiate it via A. That applies to anything public in B.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
It might be time to tell the my idéa. B is a WPF-application my company has. We don't have any unit test for the GUI of B. We want that. So I thought if: * B is a WPF-project in our Visual Studio solution. * A is a unit test project in the same solution. * A has some "code/package/NuGet" to start, terminate B and gain access of all public controls in B. * In A we write the unit tests that use the "code/package/NuGet" to access the controls in B to do our unit tests. For instance if I want to test a button's click event in B: 1) In A: Run a specific test case. 2) In A: Start B. 3) In A: Someway gain access of all public controls of B. 4) In A: Put a text in a TextBox located in B. 5) In A: Trigger the click event of a Button located in B. 6) In B: The Button's click event puts the TextBox's text in a TextBlock. 7) In A: Read the Text from the TextBlock inside of B. 8) In A: Verify the text and pass or fail the test. 9) In A: Terminate B. I have looked at Appium with the WinAppDriver solution. That works, but it requires the WinAppDriver application running in the background to handle all communications between A and B. I don't want a third party or be forced to write any IPC in B. Unit test should be easy to write and run. If each develop must install the WinAppDriver to run tests, it's just tedious. However, I like the way that WinAppDriver use the
AutomationProperties.AutomationId
and other properties on controls to allow "A" to access it "B". I would like a similar solution. @Gerry Schmitz How should I do to instantiate B in A? If that give me access to all public controls, that will be fine! Best regards, /Steffe -
It might be time to tell the my idéa. B is a WPF-application my company has. We don't have any unit test for the GUI of B. We want that. So I thought if: * B is a WPF-project in our Visual Studio solution. * A is a unit test project in the same solution. * A has some "code/package/NuGet" to start, terminate B and gain access of all public controls in B. * In A we write the unit tests that use the "code/package/NuGet" to access the controls in B to do our unit tests. For instance if I want to test a button's click event in B: 1) In A: Run a specific test case. 2) In A: Start B. 3) In A: Someway gain access of all public controls of B. 4) In A: Put a text in a TextBox located in B. 5) In A: Trigger the click event of a Button located in B. 6) In B: The Button's click event puts the TextBox's text in a TextBlock. 7) In A: Read the Text from the TextBlock inside of B. 8) In A: Verify the text and pass or fail the test. 9) In A: Terminate B. I have looked at Appium with the WinAppDriver solution. That works, but it requires the WinAppDriver application running in the background to handle all communications between A and B. I don't want a third party or be forced to write any IPC in B. Unit test should be easy to write and run. If each develop must install the WinAppDriver to run tests, it's just tedious. However, I like the way that WinAppDriver use the
AutomationProperties.AutomationId
and other properties on controls to allow "A" to access it "B". I would like a similar solution. @Gerry Schmitz How should I do to instantiate B in A? If that give me access to all public controls, that will be fine! Best regards, /SteffeTry using the UI Automation library: Test Run: Automating UI Tests In WPF Applications | Microsoft Docs[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
It might be time to tell the my idéa. B is a WPF-application my company has. We don't have any unit test for the GUI of B. We want that. So I thought if: * B is a WPF-project in our Visual Studio solution. * A is a unit test project in the same solution. * A has some "code/package/NuGet" to start, terminate B and gain access of all public controls in B. * In A we write the unit tests that use the "code/package/NuGet" to access the controls in B to do our unit tests. For instance if I want to test a button's click event in B: 1) In A: Run a specific test case. 2) In A: Start B. 3) In A: Someway gain access of all public controls of B. 4) In A: Put a text in a TextBox located in B. 5) In A: Trigger the click event of a Button located in B. 6) In B: The Button's click event puts the TextBox's text in a TextBlock. 7) In A: Read the Text from the TextBlock inside of B. 8) In A: Verify the text and pass or fail the test. 9) In A: Terminate B. I have looked at Appium with the WinAppDriver solution. That works, but it requires the WinAppDriver application running in the background to handle all communications between A and B. I don't want a third party or be forced to write any IPC in B. Unit test should be easy to write and run. If each develop must install the WinAppDriver to run tests, it's just tedious. However, I like the way that WinAppDriver use the
AutomationProperties.AutomationId
and other properties on controls to allow "A" to access it "B". I would like a similar solution. @Gerry Schmitz How should I do to instantiate B in A? If that give me access to all public controls, that will be fine! Best regards, /SteffeSince it's a "formal" test scenario, you add a "reference" to B's exe / namespace in A (versus dynamic assembly referencing); then it's: var windowB = new B.MainWindow(); etc. This assumes there isn't some code in B.App.Startup that MainWindow is dependent on (I use static "data" classes for lazy loading) As for manipulating controls (and methods), you obviously need public accessors (in one form or another).
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
-
Since it's a "formal" test scenario, you add a "reference" to B's exe / namespace in A (versus dynamic assembly referencing); then it's: var windowB = new B.MainWindow(); etc. This assumes there isn't some code in B.App.Startup that MainWindow is dependent on (I use static "data" classes for lazy loading) As for manipulating controls (and methods), you obviously need public accessors (in one form or another).
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food