You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在运行时判断类库加载至控制台、桌面或UWP应用?

如何在运行时判断类库所在的.NET应用类型

针对你提到的控制台、桌面(WPF等)、UWP三种应用场景,我整理了几个经过验证的判断方法——之前做类库适配时踩过不少坑,这些方式算是比较靠谱的:

一、判断是否为控制台应用

判断控制台应用的核心是确认当前进程是否关联了控制台窗口,这里推荐用Win32 API的方式,比单纯检查Console类属性更准确(毕竟有些非控制台应用也可能手动分配控制台):

using System;
using System.Runtime.InteropServices;

public static class AppTypeDetector
{
    [DllImport("kernel32.dll")]
    private static extern IntPtr GetConsoleWindow();

    public static bool IsConsoleApp()
    {
        // 控制台窗口句柄不为空,说明当前进程关联了控制台
        return GetConsoleWindow() != IntPtr.Zero;
    }
}

注意事项:

  • 如果你在WPF/WinForms应用中手动调用了AllocConsole(),这个方法会误判为控制台应用,这种特殊场景需要额外加逻辑排除。
  • 在.NET Core/.NET 5+跨平台场景下,可以先判断是否为Windows系统再调用这个API。

二、判断是否为UWP应用

UWP应用运行在沙箱环境中,最直接的判断方式是检查Windows.ApplicationModel.Package.Current属性——只有UWP进程能正常获取到这个对象,非UWP环境下要么返回null,要么无法访问该类型。为了让类库不依赖UWP程序集,推荐用反射实现:

using System;
using System.Reflection;

public static class AppTypeDetector
{
    public static bool IsUwpApp()
    {
        try
        {
            // 尝试获取WinRT的Package类
            var packageType = Type.GetType("Windows.ApplicationModel.Package, Windows, ContentType=WindowsRuntime");
            if (packageType == null)
                return false;

            // 获取Current静态属性
            var currentProperty = packageType.GetProperty("Current", BindingFlags.Public | BindingFlags.Static);
            if (currentProperty == null)
                return false;

            // 属性值不为null则是UWP应用
            var packageInstance = currentProperty.GetValue(null);
            return packageInstance != null;
        }
        catch
        {
            // 任何异常都说明不是UWP环境
            return false;
        }
    }
}

注意事项:

  • 这个方法不需要类库引用UWP相关NuGet包,兼容性拉满。
  • 对于Desktop Bridge打包的桌面应用,Package.Current也会存在,如果需要区分纯UWP和桥接应用,可以额外检查Package.Identity.PublisherId等属性。

三、判断是否为桌面应用(WPF/WinForms等)

桌面GUI应用的核心特征是拥有UI消息循环和对应的应用对象,我们可以用排除法+UI对象检查来判断:

using System;
using System.Windows.Forms; // 支持WinForms需引用System.Windows.Forms.dll

public static class AppTypeDetector
{
    public static bool IsDesktopGuiApp()
    {
        // 先排除控制台和UWP应用
        if (IsConsoleApp() || IsUwpApp())
            return false;

        // 检查WPF应用对象
        try
        {
            var wpfAppType = Type.GetType("System.Windows.Application, PresentationFramework");
            if (wpfAppType != null)
            {
                var currentProperty = wpfAppType.GetProperty("Current", BindingFlags.Public | BindingFlags.Static);
                if (currentProperty?.GetValue(null) != null)
                    return true;
            }
        }
        catch { }

        // 检查WinForms应用
        try
        {
            if (Application.OpenForms.Count > 0 || Application.MessageLoop)
                return true;
        }
        catch { }

        // 针对无UI的桌面后台应用(比如Windows服务),可以补充PE子系统检查
        return IsWindowsGuiSubsystem();
    }

    // 补充:通过PE头判断进程的原生子系统类型
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr GetModuleHandle(string lpModuleName);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool GetModuleInformation(IntPtr hModule, out MODULEINFO lpmodinfo, uint cb);

    [StructLayout(LayoutKind.Sequential)]
    private struct MODULEINFO
    {
        public IntPtr lpBaseOfDll;
        public uint SizeOfImage;
        public IntPtr EntryPoint;
    }

    private static bool IsWindowsGuiSubsystem()
    {
        var hModule = GetModuleHandle(null);
        if (hModule == IntPtr.Zero)
            return false;

        if (!GetModuleInformation(hModule, out var moduleInfo, (uint)Marshal.SizeOf(typeof(MODULEINFO))))
            return false;

        // 读取PE头的子系统字段:2=Windows GUI子系统,3=Windows Console子系统
        var peHeader = (IntPtr)((long)moduleInfo.lpBaseOfDll + Marshal.ReadInt32((IntPtr)((long)moduleInfo.lpBaseOfDll + 0x3C)));
        var optionalHeader = (IntPtr)((long)peHeader + 0x18);
        var subsystem = Marshal.ReadUInt16((IntPtr)((long)optionalHeader + 0x5C));

        return subsystem == 2;
    }
}

注意事项:

  • 无UI的桌面后台应用(比如Windows服务)无法通过UI对象判断,这时PE子系统检查的方法就派上用场了,能准确判断进程的原生类型。

内容的提问来源于stack exchange,提问作者Jack Miller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:30:48