Self-updating WPF application, launcher process load WPF app via reflection - c#

In a Winforms application, we have developed a self updating application launcher and I'm trying to mimic the same with WPF but am facing some issues. The way this worked with Winforms:
Launcher process (with not reference to main application) will check for newer libraries and download as necessary
Launcher will then load the assembly (Assembly.Load) from an STA Thread and then via reflection, call an Init method in that assembly (that performs a bunch of init logic while the launcher is acting as a splash screen and displaying progress)
After Init is complete, Laucher will call a Handoff method via reflection in the loaded assembly which will create a new ApplicationContext with the new MainForm and then call Application.Run(newAppContext).
Launcher will close its Window
I'm trying to mimic the same in WPF but the issues I'm having:
There doesn't appear to be the concept of ApplicationContext that I could transfer the MainForm to
I'm not sure how to handle App.xaml/resources since I can't put a "second" App.xaml in the application dll, so I'm not sure how to handle loading of resources/styles
When I Show a new MainWindow in the "Handoff" call that is called via reflection, the window opens briefly but then disappears
Appreciate any guidance on how I can implement the desired behavior in a Wpf application.

WPF apps derive from a base class of System.Windows.Application. The basic template that VS uses creates a App.xaml and App.xaml.cs. This class has an static entry point of
public static void Main()
This is what I use:
var type = yourloadedassembly.GetType( "YourNamespace.App" );
type.InvokeMember( "Main", BindingFlags::Public | BindingFlags::Static | BindingFlags::InvokeMethod, null, null, null );

For anyone interesting, solving this was actually quite trivial:
Create a Wpf Application (the launcher)
Create an "Application" assembly (can be a dll) that hosts the entry point for your application specific code
Have the launcher load the application assembly dynamically (Assembly.Load)
In your application assembly, have some static entry point that can be called via reflection from the launcher.
When the launcher calls the entry point method via reflection, add your resources and new a MainWindow from the application assembly to assign to Application.Current.MainWindow:
Application.Current.Resources = new ResourceDictionary() {Source = new Uri("pack://application:,,,/MyApp.UI.Styling;component/Common.xaml")};
Application.Current.MainWindow = new MainWindow();
Application.Current.MainWindow.Show();
Back in the Launcher, Close() the Launcher window

Related

Is it possible to open winform form from dependency?

I have a visual studio windows forms application that has multiple projects, each having multiple forms. The project that loads on startup calls another project's form and closes its own. Referring to the startup program as "setup" and the other as "main". I have a scenario where I want to skip setup and be able to return to it later. Since setup is a dependency of main, and not the other way around, I cannot seem to create an instance of the setup form. Is this the case, or am I doing something wrong?
The call from setup to open main is as so
this.Hide();
frmDemo demo = new frmDemo();
demo.ShowDialog();
this.Close();
I want to do the same thing from main to setup form, but I am having trouble.
Essentially it should just be
frmSetup setup = new frmSetup();
setup.show();
But this isn't working because it cannot find the form.
Well if you want to reference Setup from Main then you need to add a reference in Main.
The problem then is that you will create a circular dependency, which is bad design (and I think you will also get compiler errors).
There are some ways to get around this, but the best approach it to make your Main program the first one that starts-up (not setup). Then during startup it launches the set-up form and waits until it is finished and then continues. And then when it needs to launch setup again, then it is no problem.
So you are effectively reversing the dependency.

Launch a WPF application in a DLL from a console application exe

Currently I have two separate C# projects under the same solution, let's call it Window.exe and Console.exe. Window.exe is a WPF MVVM application that works well standalone.
To eliminate one small issue, my goal is to convert Window.exe into Window.dll, and then use Console.exe to load Window.dll. I tried to call App.Run(), or move the routine in App_Startup, that is used to launch the main window onto a separate method and called it. The new thread that runs Window.dll couldn't really last. It was able to populate the GUI when I stepped into it in debug, but I could not interact with it.
Any ideas on how I should proceed?
I was able to accomplish this by doing two things:
You need to mark the Main method in your console applicaiton as an STAThread method because the UI will need to be on an STA thread. If you don't, you'll get an exception when the constructor for the main window is called.
Make sure you also call InitializeComponent() before Run(). If you don't, the app will run, but the window won't have been set up first.
I was able to get this to work in a solution where I, as well, have a WPF main application and console application for testing things:
[STAThread]
static void Main(string[] args)
{
WpfApp.App app = new WpfApp.App();
app.InitializeComponent();
app.Run();
}

Events of .net class not raised in second appdomain

Following Situation: A .Net4 WPF application is creating multiple appdomains on startup, launching the mainwindow in the first custom created appdomain, simulating a multiple instance behavior inside a single process, e.g. I´m able to start a second, third,... mainwindow where each will run in its own appdomain isolated from the others (lessons learned, that doesn´t affect native components)
AppDomain appDomain = AppDomain.CreateDomain("FancyAppDomainIdentifier");
appDomain.DoCallBack(() =>
{
var thread = new Thread(OnThreadStart);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
});
Where OnThreadStart() is basically doing a
new App().Run();
where App is the Standard System.Windows.Application.
This has been working nicely so far, but now I have a third party component which is basically a .net wrapper for some com components interacting with some hardware. The wrapper component is raising events to relay hardware events (button pressed) but these events are not raised, if I register the eventhandler in the first custom created appdomain.
If I remove the [STAThread] attribute from the method responsible for creating the custom appdomains, making the first custom created appdomain the first thread running STA, the events get raised.
I´ve had issues with native components when running multiple windows using this setup, but since this is currently only one window and only one instance of the wrapper I´m stuck.

Using a 64bit .Net ActiveX control in 64bit MATLAB

We started using MATLAB 64 bits in our system and some of our legacy M code uses a custom version of the MSFlexGrid ActiveX component so we decided to write a .Net 64 bit version of it.
The ActiveX is exposed via a Windows Forms host.
[ProgId("FlexiGrid")]
[Guid("88888888-4444-4444-4444-CCCCCCCCCCCC")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public partial class GridWinFormsHost : UserControl
{
}
The Windows Form User Control embeds a WPF UserControl via ElementHost.
private IGrid grid;
private void GridWinFormsHostLoad(object sender, System.EventArgs e)
{
var host = new ElementHost { Dock = DockStyle.Fill };
this.grid = new GridView();
host.Child = (GridView)this.grid;
this.Controls.Add(host);
}
The control is successfully registered, visible to MATLAB, and can be instantiated via
actxcontrol('FlexiGrid', Position, Fig, CallBack);
Methods and properties exposed in the GridWinForms are visible and can be get/set/invoked.
However after instantiating the ActiveX we eventually need to call into .Net - in the MATLAB process - via a MEX DLL. The call executes successfully in .Net but the MATLAB process freezes when control returns from .Net. Running the same code without instantiating the ActiveX control succeeds and MATLAB doesn't freeze, which means that instantiating the .Net ActiveX control is probably the cause of MATLAB freezing.
When searching for solutions I came across this MSDN thread in which it is stated: "This problem occurs because the message loop that the Windows Form uses and the message loop that the COM client application provides are different." The original poster concludes that he solved the issue with WPF + MFC but doesn't detail the solution.
I also found this MSDN article which states that: "To make a Windows Form work correctly from a COM client application, you must run the form on a Windows Forms message loop." This is also promising except that the solution focus on creating new Windows Form windows but I need to run a Windows Forms user control embedded in a MATLAB window.
So the issue seems to be related to hosting a managed ActiveX control on an unmanaged application - any ideas?
Not a real "solution" to your issue, but maybe a (imho good) alternative for the activeX stuff:
Starting from some MATLAB version (I think ~2009 or so, others might correct me if not) you can use .NET libraries directly from MATLAB, without the need for the COM-interface:
http://www.mathworks.de/de/help/matlab/getting-started.html
Syntax-wise you can use .NET classes almost as good as java-classes.
Particularly, this should be much more comfortable than talking to .NET via MEX - I assume.

Noob question - how to create a new windows form as part of a plugin?

I am writing a plugin for a C# application and would like to add a dialog window. I have no control over the application, rather, the application loads plugins dynamically using reflection. I am a newbie with windows forms (this is a forms application) but would like to have a dialog window come up to control my plugin. How can I accomplish this?
If I just add a windows form to my application via visual studio no form appears. Application.Run has presumably already been called by the main application. I am almost completely new to forms.
How can I start the form with with my plugin (the plugin has a method that is called when it is started) and make it active?
Edit: I should clarify, the main application application window will not respond (even to minimize or maximize the window) when a plugin is running, so presumably whatever thread is devoted to handling windows messages is used to run the plugin and is, temporarily, not handling any windows messages. Thus my form needs its own thread handling windows messages.
You will need to initialize your code from whatever method the plugin architecture defined as the entry point (where the application will call your plugin).
To show a form, you can call the Show method on it.
// In a method that the plugin framework calls
myPluginForm.Show();
The application that loads your plugin should have some facility to load a window. Check the API documentation. Also, do you know if there are other plugins that can create arbitrary new windows? Usually, the host application can allow the plugin to create certain predefined (by the host) types of windows (such as config, load a file, etc...).
It might also be possible to programmaticaly create a new form and then load it. See here for an example: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.aspx and look for the "examples" section.

Categories

Resources