C#:foreach循环中的ImageList导致应用程序在终端服务器上崩溃

时间:2014-08-07 12:12:26

标签: c# .net icons windows-server-2008 gdi

我是(小)开发团队的一员,他接管了C#.Net计划的开发和支持。它有大约300,000个LOC,软件设计使得在不造成数百万副作用的情况下无法改变任何大的东西。这就像试图将充满毒蛇的丛林变成一个漂亮的小花园。只使用一个小剪刀。

该应用程序是一个具有数据库访问权限的大型WinForms应用程序。

关于问题:客户收到我们的软件但无法运行。与其他客户不同,他们拥有多个Windows Server 2008 R1终端服务器,并将软件安装在网络驱动器上。他们的用户连接到其中一个终端服务器并从网络驱动器运行我们的应用程序(以及其他,如Windows办公室等)。然而,我们的应用程序在约5秒后崩溃而没有任何通知。我们的加载屏幕出现并再次关闭。该应用程序生成一个日志文件,显示此异常:

2014-08-04 11:15:23 [3372] ERROR – An exception occurred:
'OutOfMemoryException': Not enough memory. 
System.Drawing

at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
at System.Drawing.Graphics.DrawImage(Image image, Rectangle destRect, Int32 srcX, Int32 srcY, Int32 srcWidth, Int32 srcHeight, GraphicsUnit srcUnit, ImageAttributes imageAttrs, DrawImageAbort callback, IntPtr callbackData)
at System.Drawing.Bitmap.MakeTransparent(Color transparentColor)
at System.Windows.Forms.ImageList.CreateBitmap(Original original, Boolean& ownsBitmap)
at System.Windows.Forms.ImageList.CreateHandle()
at System.Windows.Forms.ImageList.get_Handle()
at System.Windows.Forms.ImageList.GetBitmap(Int32 index)
at System.Windows.Forms.ImageList.ImageCollection.GetEnumerator()
at <our application>.InitializeHtmlResources()

调用ImageCollection.GetEnumerator()的方法是:

void InitializeHtmlResources()
    {
        string baseDirPath = ... //It's in AppData/Local/<ourFolder>/Icons;


        int index = -1;
        foreach (Image image in UIResources.Icons.Images)
        {
            index += 1;

            image.Save(baseDirPath + Path.DirectorySeparatorChar + index.ToString(), ImageFormat.Png);
        }
    }

这些图像存储在Resource.Icons.dll中。图标在解决方案中有自己的项目,包含一些帮助类(如UIResources),并包含一个文件夹,其中包含我们使用的每个图标+一个xml,它们都列出,命名和索引。 UIResources是一个静态类,允许访问图标和图像列表。这就是物业&#34;图像&#34;已初始化:

...
// Code snippet of Images Initialization
var ilist = new ImageList();
ilist.ColorDepth = ColorDepth.Depth32Bit;
ilist.ImageSize = new Size(16, 16);
ilist.TransparentColor = Color.Fuchsia;
UIResources.Icons.Images = ilist;
...

此方法用于从DLL文件中提取图标。

static IEnumerable<IconInfo> GetIcons()
    {
        XDocument doc;
        using (var stream = GetResourceStream("Our.Namespace.Resources.Icons.Icons.xml"))
        {
            doc = XDocument.Load(stream);
        }

        // ReSharper disable once PossibleNullReferenceException            
        foreach (var elem in doc.Element("Icons").Elements("Icon"))
        {
            int index = (int)elem.Attribute("Index");
            var bmp = ReadIcon("Icons", (string)elem.Attribute("FileName"));
            string name = (string)elem.Attribute("Name");

            yield return new IconInfo(bmp, index, name);
        }

    }
    static Bitmap ReadIcon(string kind, string fileName)
    {
        using (var stream = GetResourceStream("Our.Namespace.Resources." + kind + "." + fileName))
        {
            return new Bitmap(stream);
        }
    }

    static Stream GetResourceStream(string resourceName)
    {
        return typeof(IconProvider).Assembly.GetManifestResourceStream(resourceName);
    }

IconInfo只是包含值的记录。

最后,ImageList充满了值:

foreach (var icon in GetIcons())
            UIResources.Icons.Images.Add(icon.Name, icon.Image);

该应用程序正常。但是当该客户通过远程桌面在其终端服务器上运行该软件时,应用程序崩溃并在foreach循环中的InitializeHtmlResources()中抛出OutOfMemory异常(当访问ImageList的枚举器时)。

令人困惑的部分:A&#34; OutOfMemory&#34;抛出异常,虽然内存既不满,也没有达到32位应用程序的2 GB限制。该应用程序在加载过程中峰值为120 MB。

我完全不知道这个错误是如何造成的,并且花了最近2-3天试图找到解决方案。我没有。

我感谢你能给我的每一点建议。

编辑:

我尝试禁用InitializeHtmlResources-Method。这使应用程序启动。但是:在使用该应用程序几秒钟后,无论如何都会出现一个outofmemory异常。原因是另一个ImageList访问器。

它适用于Server 2012.我们使用Windows Server 2008创建了一个虚拟机,也发生了错误。

2 个答案:

答案 0 :(得分:1)

我们发现了这个问题!而不是

UIResources.Icons.Images.Add(icon.Name, icon.Image);

填写ImageList,我们现在使用

UIResources.Icons.Images.Add(icon.Name, new Bitmap(icon.Image));

现在我们的应用程序适用于Windows Server 2008: - )

答案 1 :(得分:0)