为了消除任何混淆,System.Drawing 确实在 ASP.NET 和服务下工作,它只是不受支持。可能存在高负载(用尽非托管资源)、内存或资源泄漏(实施不当或称为处置模式)和/或在没有桌面显示它们时弹出对话框的问题。
测试会处理后者,而监控会提醒您注意前者。但是,如果/当您遇到问题时,不要指望能够致电 PSS 并要求修复。
那么,你有什么选择?好吧,如果您不需要完全支持的路线,并且您不期望极端负载 - 很多人无视 MSDN 警告并成功使用 System.Drawing。他们中的一些人被咬了,但成功的故事比失败的故事多得多。
如果您想要支持某些东西,那么您需要知道您是否正在交互式运行。就个人而言,我可能只是将它留给托管应用程序在某处或其他地方设置非交互式标志。毕竟,应用程序最适合确定它们是否处于托管环境中和/或是否愿意冒 GDI+ 问题的风险。
但是,如果您想自动检测您的环境,我想有比SO 上提供的服务更糟糕的答案。总而言之,您可以检查 EntryAssembly 以查看它是否继承自 ServiceBase,或者尝试访问 System.Console。对于 ASP.NET,同理,检测 HttpContext.Current 就足够了。
我认为会有一种托管或 p/invoke 方式来查找桌面(我认为这确实是所有这一切的决定性因素)和/或 AppDomain 之外的东西会提示你。但我我不确定它是什么,而 MSDN 对它的启发不足。
编辑:Trolling MSDN,我记得它实际上是一个Window Station(托管桌面),这是这里的重要部分。有了这些信息,我就能找到GetProcessWindowStation(),它返回当前窗口站的句柄。将该句柄传递给GetUserObjectInformation()将为您提供一个USEROBJECTFLAGS结构,如果您有一个可见的桌面,则该结构应该有一个带有 WSF_VISIBLE 的 dwFlags。
或者,EnumWindowsStations会给你一个你可以检查的电台列表——WinSta0 是交互式的。
但是,是的,我仍然认为让应用程序设置一个属性或其他东西是更容易的方法......
再次编辑:7 年后,我被提示进入Environment.UserInteractive,MS为您执行我上面为您描述的确切 GetProcessWindowStation 舞蹈....我仍然建议委托给托管应用程序(他们可能希望更快,但稍微风险更高的 System.Drawing 路径),但 UserInteractive 似乎是一个很好的默认设置,而不需要自己调用它。