8

I need to write a wrapper around a third party api that peruses message pumps and hence needs to be handled very differently depending on whether the wrapper is instantiated on a UI thread (such as within a wpf application) or not (such as a console application).

If it does not run on a UI thread then I need a dispatcher and implement my own message pump.

For that purpose I need to know whether the wrapper is instantiated within a wpf application or not. It is not enough to determine whether the instantiation happens on a UI thread or not (as even in a wpf application the thread on which the wrapper is instantiated might not be the UI thread).

Is there any way I can figure out whether I am in a wpf or windows form environment with message pump or a console application where I have to implement my own message pump?

Thanks

Matt
  • 7,004
  • 11
  • 71
  • 117
  • 5
    Why not simply make it an argument of your wrapper's constructor? Let the consumer tell you how it will be used. – InBetween Dec 18 '17 at 15:03
  • This will not work because the wrapper is part of a plugin that only exposes interfaces, other plug-ins of identical interfaces do not need message pumps. – Matt Dec 18 '17 at 15:19
  • 2
    Well, you could always give it a sensible default value and ignore the argument where it doesn't make sense and document the behavior. – InBetween Dec 18 '17 at 15:21

4 Answers4

9

I think you might be best off to have three separate packages.

To make it auto-select, you would need to have references to both WPF and WinForms in your package. Assuming worstcase, your package just made me import both into my console application. Others might consider importing WinForms into an WPF application worst case and another group of people might do WinForms because they cannot access WPF (and therefor you just cut them of from using your package altogether).

nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • 1
    But if OP only needs to detect if running under WPF\WinForms, without actually using any functionality from these platforms - having 3 packages looks like overkill. It's better to pass argument to constructor indeed, like one comment suggests. – Evk Dec 18 '17 at 15:21
  • @Evk Maybe that's correct (I don't know how much the OP wants to do with the message pumps or if he only needs to know one exists). Passing an argument instead of auto-select would probably work, too. – nvoigt Dec 18 '17 at 15:24
6

If no other answer satisfies your needs - you can use reflection to check if Application.Current is null or not, without directly referencing WPF assemblies (and the same works with WinForms):

private static bool IsWpfApplication() {
    var type = Type.GetType("System.Windows.Application, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
    if (type == null)
        return false;
    var currentProp = type.GetProperty("Current", BindingFlags.Public | BindingFlags.Static);
    if (currentProp == null)
        return false;
    return currentProp.GetValue(null, new object[0]) != null;
}

Note that this might load PresentationFramework dll into current app domain, even in console application. If that is a problem for you - you can do the same by inspecting assemblies already loaded in app domain:

private static bool IsWpfApplication2() {
    var wpfAsm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(c => c.GetName().Name == "PresentationFramework"); 
    if (wpfAsm == null)
        return false;
    var type = wpfAsm.GetType("System.Windows.Application");
    if (type == null)
        return false;
    var currentProp = type.GetProperty("Current", BindingFlags.Public | BindingFlags.Static);
    if (currentProp == null)
        return false;
    return currentProp.GetValue(null, new object[0]) != null;
}
Evk
  • 98,527
  • 8
  • 141
  • 191
1

Is there any way I can figure out whether I am in a wpf or windows form environment with message pump or a console application where I have to implement my own message pump?

You could check whether there is a top-level window available:

if (Process.GetCurrentProcess().MainWindowHandle != IntPtr.Zero)
    //WPF

MainWindowHandle should return a handle provided that the WPF application has a main window.

You should also be able to use the native GetConsoleWindow function to determine whether you're in the context of a console application.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • Keep in mind that Console could be attached to WinForms / Wpf application process. https://stackoverflow.com/questions/4362111/how-do-i-show-a-console-output-window-in-a-forms-application – vasil oreshenski Dec 18 '17 at 15:10
  • It's very common to have a console window even for your WPF application - for debugging at least (best place for log messages), so careful there. – Voo Dec 18 '17 at 16:10
0

This might work:

public static void Main(string[] args)
{
    var application = Application.Current;
    Console.WriteLine($"Application is {(application == null ? "null": "not-null")}");
    Console.ReadKey();
}

Requires references to PresentationFramework and, according to Resharper, WindowsBase and System.Xaml

Adam Brown
  • 1,667
  • 7
  • 9