如何确定一个类是在控制台应用程序还是WPF中实例化的?

8
我需要编写一个第三方API的包装器,它浏览消息泵,因此根据包装器是否在UI线程(例如在WPF应用程序中)实例化或不是(例如在控制台应用程序中)需要进行非常不同的处理。
如果它没有在UI线程上运行,则我需要一个调度程序并实现自己的消息泵。
为此,我需要知道包装器是否在WPF应用程序中实例化。仅确定实例化是否发生在UI线程上是不够的(因为即使在WPF应用程序中,实例化包装器的线程可能不是UI线程)。
有没有办法可以弄清楚我是否在具有消息泵的WPF或Windows窗体环境中,或者在必须实现自己的消息泵的控制台应用程序中?
谢谢

5
为什么不把它直接作为包装器构造函数的参数呢?让消费者告诉你它将如何被使用。 - InBetween
这不会起作用,因为包装器是插件的一部分,该插件仅公开接口,具有相同接口的其他插件不需要消息泵。 - Matt
2
你可以给它一个合理的默认值,忽略那些没有意义的参数,并记录下这种行为。 - InBetween
4个回答

9

我认为你最好建立三个独立的软件包。

若要使它自动选择,你需要在软件包中同时引用WPF和WinForms。最坏情况下,你的软件包需要在我的控制台应用程序中同时导入这两者。其他人可能会认为将WinForms导入到WPF应用程序中是最糟糕的情况,还有一群人可能因为无法访问WPF而使用WinForms(因此你完全割断了他们使用你的软件包的途径)。


1
但是,如果OP只需要检测是否在WPF\WinForms下运行,而不实际使用这些平台的任何功能-拥有3个包似乎有点过头了。确实像某个评论建议的那样,最好将参数传递给构造函数。 - Evk
@Evk 或许是正确的(我不知道原帖作者想要处理多少个消息泵,或者他只需要知道一个存在)。传递参数而不是自动选择可能也可以起作用。 - nvoigt

6
如果没有其他回答符合您的需求 - 您可以使用反射来检查Application.Current是否为空,而不直接引用WPF程序集(同样适用于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;
}

请注意,这可能会将PresentationFramework dll加载到当前应用程序域中,即使是控制台应用程序也是如此。如果这对您造成了问题-您可以通过检查已在应用程序域中加载的程序集来执行相同的操作:
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;
}

1
你能否判断我是在一个具有消息泵的wpf或Windows窗体环境中,还是在一个需要实现自己的消息泵的控制台应用程序中?
你可以检查是否有顶级窗口可用:
if (Process.GetCurrentProcess().MainWindowHandle != IntPtr.Zero)
    //WPF

MainWindowHandle 应该返回一个句柄,前提是 WPF 应用程序有一个主窗口。

您还应该能够使用本地 GetConsoleWindow 函数来确定是否在控制台应用程序的上下文中。


请记住,控制台可以附加到WinForms / Wpf应用程序进程。 https://dev59.com/Km855IYBdhLWcg3wZzff - vasil oreshenski
即使是针对调试(日志消息的最佳位置)也很常见为您的WPF应用程序添加控制台窗口,所以请小心。 - Voo

0

这可能有效:

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

需要引用PresentationFramework,以及根据Resharper的建议,还需要引用WindowsBase和System.Xaml。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接