0

我正在尝试编辑位图并将其用作我的系统托盘图标的图标。我想知道是否有一种方法可以编辑和使用它,而不必将其保存为本地文件,因为这看起来很乱,并且在 .exe 的根目录中留下了一个 .ico 文件。我的代码如下。

//To Save icon to disk
bitmap.Save("icon.ico", System.Drawing.Imaging.ImageFormat.Icon);
Icon createdIcon = Icon.FromHandle(bitmap.GetHicon());
bitmap.Dispose();
return createdIcon;

有没有更优雅的方法来做到这一点,将其保存为内部资源?还是在内存流中?另一件事,就是这个函数每5分钟运行一次更新系统托盘图标,它必须通过图标,所以我可以在我必须关闭流的时候工作。

任何帮助将不胜感激,因为这让我很难过。

4

1 回答 1

1

The problem is simpler to solve than you're making it. There is no reason to write the bitmap out to a file on disk. You can simply omit the call to the Save method.

The GetHIcon method is the real trick, as it allows you to convert a Bitmap into an Icon, and you've already found that one.

Here's my sample code. I added a NotifyIcon and Timer control to a form, and wired up the event handlers in the obvious manner. rnd is a class-level instance of Random, just for testing purposes.

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool DestroyIcon(IntPtr hIcon);

private void timer1_Tick(object sender, EventArgs e)
{
   Icon icon;

   // Create a temporary new Bitmap with the size of a notification icon.
   using (Bitmap bmp = new Bitmap(SystemInformation.SmallIconSize.Width, SystemInformation.SmallIconSize.Height))
   {
      // Fill the temporary bitmap with a random number.
      using (Graphics g = Graphics.FromImage(bmp))
      {
         g.DrawString(rnd.Next().ToString(),
                        SystemFonts.MessageBoxFont,
                        SystemBrushes.ControlText,
                        0.0F, 0.0F);
      }

      // Convert this bitmap to an icon.
      icon = Icon.FromHandle(bmp.GetHicon());
   }

   // Update the notification icon to use our new icon,
   // and destroy the old icon so we don't leak memory.
   Icon oldIcon = notifyIcon1.Icon;
   notifyIcon1.Icon = icon;
   DestroyIcon(oldIcon.Handle);
   oldIcon.Dispose();
}

Works perfectly, no temporary files required.

Edit: Modified the above code sample to solve a GDI object leak that would eventually bring your application to its knees. How quickly would depend on the interval at which the Timer was set to tick (or however you're determining that the icon should change in your app).

It turns out that when you call the Dispose method on an icon that was created using Icon.FromHandle, the associated native GDI object is not destroyed. I think that's a bug in the WinForms implementation since it defies programmer expectations, but apparently Icon.FromHandle does not assume ownership of the handle. To be fair, the documentation does say this in the "Remarks" section, but who reads that?

If you don't know to do this, you've got a memory leak on your hands. To fix it, you have to P/Invoke the Win32 function for destroying a GDI icon object (DestroyIcon) and call it explicitly.

Please make sure that your application does this, however and wherever appropriate, to ensure that the old icons get destroyed and the associated memory is freed!

于 2013-03-14T07:20:10.463 回答