【问题标题】:Windows service: using of BitmapEncoder or BitmapDecoder ends with «The operation completed successfully»Windows 服务:使用 BitmapEncoder 或 BitmapDecoder 以«操作成功完成»结束
【发布时间】:2015-12-21 10:46:51
【问题描述】:

我遇到了一个我无法解决的问题,也无法在任何地方使用谷歌解决方案。

我正在运行加载或保存图像并使用BitmapEncoderBitmapDecoder 类的服务。一段时间后(取决于我保存/加载图像的频率)服务拒绝保存/加载图像。首先,我在事件日志中看到警告

堆分配失败

我用谷歌搜索了它是什么意思,它与 Windows 服务拥有的有限数量的 GDI 对象有关。可以修改注册表以增加这些对象的数量,但我认为这不是很好的解决方案,而且对我也不起作用。

我的代码在保存时抛出以下异常并带有堆栈跟踪

Error while storing image : System.ComponentModel.Win32Exception (0x80004005): The operation completed successfully
   at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
   at System.Windows.Threading.Dispatcher..ctor()
   at System.Windows.Threading.DispatcherObject..ctor()
   at System.Windows.Media.Imaging.BitmapEncoder..ctor(Boolean isBuiltIn)
   at Imaging.TiffReadWrite.Save(String filename, Image img)

加载时

Error while loading image : System.ComponentModel.Win32Exception (0x80004005): The operation completed successfully
   at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
   at System.Windows.Threading.Dispatcher..ctor()
   at System.Windows.Threading.DispatcherObject..ctor()
   at System.Windows.Media.Imaging.BitmapDecoder..ctor(Stream bitmapStream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, Guid expectedClsId)
   at Imaging.TiffReadWrite.Load(String filename)

我保存图片的代码如下:

public static void Save(string filename, BitmapSource img)
{
    using (FileStream stream = new FileStream(filename, FileMode.Create))
    {
        TiffBitmapEncoder encoder = new TiffBitmapEncoder();
        encoder.Compression = TiffCompressOption.None;

        BitmapFrame frm = BitmapFrame.Create(img);

        encoder.Frames.Add(frm);
        encoder.Save(stream);
    }
}

加载图片的方式如下:

public static BitmapSource Load(string filename)
{
    BitmapSource resultImage = null;

    using (Stream imSource = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        var decoder = new TiffBitmapDecoder(imSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
        resultImage = decoder.Frames[0];
    }
    return resultImage;
}

因此,服务拒绝保存/加载图像。我可以尝试/捕获此异常,以便服务可以继续运行,但无法保存/加载图像。有时在第一次发生此异常后,可能会保存/加载很少的图像,并且在一段时间后不会执行保存/加载。

我唯一解决此问题的方法不是在服务中运行此代码,而是在应用程序中运行。然后它运行得很好,但这不是我正在寻找的解决方案。如果有人有更好的建议,请告诉我。

有一些类似的帖子(异常的堆栈跟踪或多或少相同)实际上并没有解决:

【问题讨论】:

  • 嗯,这是一个非常无用的异常消息。服务在会话 0 中运行,它有一个故意小的桌面堆。这使得 CreateWindowEx() 更有可能失败。顺便说一句,可能是另一项服务占据了不公平的份额。或者您的,任务管理器中的“用户对象”计数器是您的第一个诊断。您还冒着没有足够频繁地收集 GC 的风险,您可能需要通过每 N 个位图自己调用 GC.Collect() 来提供帮助。然而,没有有意义的错误代码这一事实确实表明存在环境问题。
  • 感谢您的回复。我知道它含糊不清,这就是为什么我无法解决它。我检查了任务管理器并使用 dheapmon 跟踪 GDI 对象,我只发现 WinLogon 的使用率很高,但仅此而已。它可能是另一种服务,但在使用我发布的代码的不同服务的不同 PC 上观察到。所以可能性不大。我想我已经有足够多的 GC.Collect() 调用了。所以这也无济于事。
  • @TomKos,考虑使用BitmapCacheOption.None 值作为TiffBitmapDecoder 类的构造函数参数和BitmapFrame.Create() 方法调用的参数。
  • WPF 不使用 GDI。但这可能与线程模型有关。您的代码是否在 STA 线程中运行?能否分享更多代码以便我们重现(PS:服务器代码不支持 WPF)?
  • 我知道它不容易重现,因为它会在一段时间(几小时,几天)后发生。但除此之外,您所需要的一切。只需创建一个循环,您将在其中保存/加载图像(最好是 >100MB 的大图像)并在 Windows 服务中执行。

标签: c# wpf image service


【解决方案1】:

操作成功完成

这个神秘的消息缩小了 HwndWrapper 构造函数中失败的确切代码的范围。 WPF 在GetStockObject pinvoke 声明中有一个错误。它的SetLastError = true 属性是错误的,GetStockObject() 实际上不会产生错误代码。您会看到错误代码 0 的描述,“没有出错”。

GetStockObject() 是一个 winapi 函数,如果它得到正确的参数,它永远不会失败。库存对象是预先分配的,从不释放。您有非常有力的证据表明进程状态已彻底损坏。在事件日志中看到“堆分配失败”消息肯定是痛苦的一部分。

如果您不知道什么会导致这种损坏,机器已知良好且具有可靠的 RAM,您没有运行任何危险的本机代码并且机器没有运行任何其他可能损坏桌面堆的服务,那么唯一的您的替代方法是创建崩溃进程的小型转储。致电 Microsoft 支持,他们可以跟踪 GetStockObject() 失败的跟踪。请注意,您必须通过第一个支持层,这些支持层会告诉您更换机器:)

【讨论】:

  • 感谢您的回复。我很欣赏你的解释。我可能会尝试致电 Microsoft 支持,但我对此没有太大希望。同时我不知道我该如何解决这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-17
  • 1970-01-01
  • 2018-12-03
  • 2011-10-01
  • 2015-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多