当前位置:编程学习 > C#/ASP.NET >>

winform 支持背景透明的textbox 出现内存泄漏,大家帮忙看看都哪些地方需要修改?


代码是codeproject上的,功能很强大, 但内存泄漏,大概每秒30-100k不等,找到了几个地方,但是似乎还有很多地方需要修改
请大家帮忙看看

AlphaBlendTextBox .cs代码如下

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

using System.Drawing.Imaging;

namespace ZBobb
{
/// <summary>
/// AlphaBlendTextBox: A .Net textbox that can be translucent to the background.
/// (C) 2003 Bob Bradley / ZBobb@hotmail.com
/// </summary>
/// 



public class AlphaBlendTextBox : System.Windows.Forms.TextBox
{
#region private variables

private uPictureBox myPictureBox;
private  bool   myUpToDate = false;
private  bool   myCaretUpToDate = false;
private  Bitmap myBitmap;
private  Bitmap myAlphaBitmap;

private int myFontHeight = 10;

private System.Windows.Forms.Timer myTimer1;

private bool myCaretState = true;

private bool myPaintedFirstTime = false;

private Color myBackColor = Color.White;
private int myBackAlpha = 10;

/// <summary> 
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

#endregion // end private variables


#region public methods and overrides

public AlphaBlendTextBox()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
// TODO: Add any initialization after the InitializeComponent call

this.BackColor = myBackColor; 

this.SetStyle(ControlStyles.UserPaint,false);
this.SetStyle(ControlStyles.AllPaintingInWmPaint,true);
this.SetStyle(ControlStyles.DoubleBuffer,true);


myPictureBox = new uPictureBox();
this.Controls.Add(myPictureBox);
myPictureBox.Dock = DockStyle.Fill;
}


protected override void OnResize(EventArgs e)
{

base.OnResize (e);
this.myBitmap = new Bitmap(this.ClientRectangle.Width,this.ClientRectangle.Height);//(this.Width,this.Height);
this.myAlphaBitmap = new Bitmap(this.ClientRectangle.Width,this.ClientRectangle.Height);//(this.Width,this.Height);
myUpToDate = false;
this.Invalidate();
}


//Some of these should be moved to the WndProc later

protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown (e);
myUpToDate = false;
this.Invalidate();
}

protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp (e);
myUpToDate = false;
this.Invalidate();

}

protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress (e);
myUpToDate = false;
this.Invalidate();
}

protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp (e);
this.Invalidate();
}

protected override void OnGiveFeedback(GiveFeedbackEventArgs gfbevent)
{
base.OnGiveFeedback (gfbevent);
myUpToDate = false;
this.Invalidate();
}


protected override void OnMouseLeave(EventArgs e)
{
//found this code to find the current cursor location
//at http://www.syncfusion.com/FAQ/WinForms/FAQ_c50c.asp#q597q

Point ptCursor = Cursor.Position; 

Form f = this.FindForm();
ptCursor = f.PointToClient(ptCursor); 
if( !this.Bounds.Contains(ptCursor) )  
base.OnMouseLeave (e);
}


protected override void OnChangeUICues(UICuesEventArgs e)
{
base.OnChangeUICues (e);
myUpToDate = false;
this.Invalidate();
}


//--
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus (e);
myCaretUpToDate = false;
myUpToDate = false;
this.Invalidate();


myTimer1 = new System.Windows.Forms.Timer(this.components);
myTimer1.Interval = (int) win32.GetCaretBlinkTime(); //  usually around 500;

myTimer1.Tick +=new EventHandler(myTimer1_Tick);
myTimer1.Enabled = true;

}

protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus (e);
myCaretUpToDate = false;
myUpToDate = false;
this.Invalidate();

myTimer1.Dispose();
}

//--

protected override void OnFontChanged(EventArgs e)
{
if (this.myPaintedFirstTime)
this.SetStyle(ControlStyles.UserPaint,false);

base.OnFontChanged (e);

if (this.myPaintedFirstTime)
this.SetStyle(ControlStyles.UserPaint,true);


myFontHeight = GetFontHeight();


myUpToDate = false;
this.Invalidate();
}

protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged (e);
myUpToDate = false;
this.Invalidate();
}


protected override void WndProc(ref Message m)
{

base.WndProc (ref m);

// need to rewrite as a big switch

if (m.Msg == win32.WM_PAINT)
{
myPaintedFirstTime = true;

if (!myUpToDate || !myCaretUpToDate)
GetBitmaps();
myUpToDate = true;
myCaretUpToDate = true;

if (myPictureBox.Image != null) myPictureBox.Image.Dispose();
myPictureBox.Image = (Image)myAlphaBitmap.Clone();

}

else if (m.Msg ==  win32.WM_HSCROLL || m.Msg == win32.WM_VSCROLL)
{
myUpToDate = false;
this.Invalidate();
}

else if (m.Msg == win32.WM_LBUTTONDOWN 
|| m.Msg == win32.WM_RBUTTONDOWN
|| m.Msg == win32.WM_LBUTTONDBLCLK
//  || m.Msg == win32.WM_MOUSELEAVE  ///****
)
{
myUpToDate = false;
this.Invalidate();
}

else if (m.Msg == win32.WM_MOUSEMOVE )
{
if (m.WParam.ToInt32() != 0)  //shift key or other buttons
{
myUpToDate = false;
this.Invalidate();
}
}



//System.Diagnostics.Debug.WriteLine("Pro: " + m.Msg.ToString("X"));

}
/// <summary> 
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
//this.BackColor = Color.Pink;
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#endregion //end public method and overrides


#region public property overrides

public new BorderStyle BorderStyle
{
get {return base.BorderStyle;}
set 
{
if (this.myPaintedFirstTime)
this.SetStyle(ControlStyles.UserPaint,false);

base.BorderStyle = value;

if (this.myPaintedFirstTime)
this.SetStyle(ControlStyles.UserPaint,true);

this.myBitmap = null;
this.myAlphaBitmap = null;
myUpToDate = false;
this.Invalidate();
}
}

public  new Color BackColor
{
get
{
return Color.FromArgb(base.BackColor.R, base.BackColor.G, base.BackColor.B);
}
set
{
myBackColor = value;
base.BackColor = value;
myUpToDate = false;
}
}
public override bool Multiline
{
get{return base.Multiline;}
set
{
if (this.myPaintedFirstTime)
this.SetStyle(ControlStyles.UserPaint,false);

base.Multiline = value;

if (this.myPaintedFirstTime)
this.SetStyle(ControlStyles.UserPaint,true);

this.myBitmap = null;
this.myAlphaBitmap = null;
myUpToDate = false;
this.Invalidate();
}
}


#endregion    //end public property overrides

#region private functions and classes

private int GetFontHeight()
{
Graphics g = this.CreateGraphics();
SizeF sf_font = g.MeasureString("X",this.Font);
g.Dispose();
return  (int) sf_font.Height;
}


private void GetBitmaps()
{

if (myBitmap == null
|| myAlphaBitmap == null
|| myBitmap.Width != Width 
|| myBitmap.Height != Height
|| myAlphaBitmap.Width != Width 
|| myAlphaBitmap.Height != Height)
{
myBitmap = null;
myAlphaBitmap = null;
}



if (myBitmap == null)
{
myBitmap = new Bitmap(this.ClientRectangle.Width,this.ClientRectangle.Height);//(Width,Height);
myUpToDate = false;
}


if (!myUpToDate)
{
//Capture the TextBox control window

this.SetStyle(ControlStyles.UserPaint,false);

win32.CaptureWindow(this,ref myBitmap);

this.SetStyle(ControlStyles.UserPaint,true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor,true);
this.BackColor = Color.FromArgb(myBackAlpha,myBackColor);

}
//--



Rectangle r2 = new Rectangle(0,0,this.ClientRectangle.Width,this.ClientRectangle.Height);
ImageAttributes tempImageAttr = new ImageAttributes();


//Found the color map code in the MS Help

ColorMap[] tempColorMap = new ColorMap[1];
tempColorMap[0] = new ColorMap();
tempColorMap[0].OldColor = Color.FromArgb(255,myBackColor); 
tempColorMap[0].NewColor = Color.FromArgb(myBackAlpha,myBackColor);

tempImageAttr.SetRemapTable(tempColorMap);

if (myAlphaBitmap != null)
myAlphaBitmap.Dispose();


myAlphaBitmap = new Bitmap(this.ClientRectangle.Width,this.ClientRectangle.Height);//(Width,Height);

Graphics tempGraphics1 = Graphics.FromImage(myAlphaBitmap);

tempGraphics1.DrawImage(myBitmap,r2,0,0,this.ClientRectangle.Width,this.ClientRectangle.Height,GraphicsUnit.Pixel,tempImageAttr);

tempGraphics1.Dispose();

//----

if (this.Focused && (this.SelectionLength == 0))
{
Graphics tempGraphics2 = Graphics.FromImage(myAlphaBitmap);
if (myCaretState)
{
//Draw the caret
Point caret = this.findCaret();
Pen p = new Pen(this.ForeColor,3);
tempGraphics2.DrawLine(p,caret.X,caret.Y + 0,caret.X,caret.Y + myFontHeight);
tempGraphics2.Dispose();
}

}



}

--------------------编程问答-------------------- //我继续贴

private Point findCaret() 
{

Point pointCaret = new Point(0);
int i_char_loc = this.SelectionStart;
IntPtr pi_char_loc = new IntPtr(i_char_loc);

int i_point = win32.SendMessage(this.Handle,win32.EM_POSFROMCHAR,pi_char_loc,IntPtr.Zero);
pointCaret = new Point(i_point);

if (i_char_loc == 0) 
{
pointCaret = new Point(0);
}
else if (i_char_loc >= this.Text.Length)
{
pi_char_loc = new IntPtr(i_char_loc - 1);
i_point = win32.SendMessage(this.Handle,win32.EM_POSFROMCHAR,pi_char_loc,IntPtr.Zero);
pointCaret = new Point(i_point);

Graphics g = this.CreateGraphics();
String t1 = this.Text.Substring(this.Text.Length-1,1) + "X";
SizeF sizet1 = g.MeasureString(t1,this.Font);
SizeF sizex  = g.MeasureString("X",this.Font);
g.Dispose();
int xoffset = (int)(sizet1.Width - sizex.Width);
pointCaret.X = pointCaret.X + xoffset;

if (i_char_loc == this.Text.Length)
{
String slast = this.Text.Substring(Text.Length-1,1);
if (slast == "\n")
{
pointCaret.X = 1;
pointCaret.Y = pointCaret.Y + myFontHeight;
}
}

}



return pointCaret;
}


private void myTimer1_Tick(object sender, EventArgs e)
{
//Timer used to turn caret on and off for focused control

myCaretState = !myCaretState;
myCaretUpToDate = false;
this.Invalidate();
}


private class uPictureBox : PictureBox 
{
public uPictureBox() 
{
this.SetStyle(ControlStyles.Selectable,false);
this.SetStyle(ControlStyles.UserPaint,true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint,true);
this.SetStyle(ControlStyles.DoubleBuffer,true);

this.Cursor = null;
this.Enabled = true; 
this.SizeMode = PictureBoxSizeMode.Normal;

}




//uPictureBox
protected override void WndProc(ref Message m)
{
if (m.Msg == win32.WM_LBUTTONDOWN 
|| m.Msg == win32.WM_RBUTTONDOWN
|| m.Msg == win32.WM_LBUTTONDBLCLK
|| m.Msg == win32.WM_MOUSELEAVE
|| m.Msg == win32.WM_MOUSEMOVE )
{
//Send the above messages back to the parent control
win32.PostMessage(this.Parent.Handle,(uint) m.Msg,m.WParam,m.LParam);
}

else if (m.Msg == win32.WM_LBUTTONUP)
{
//??  for selects and such
this.Parent.Invalidate();
}


base.WndProc (ref m);
}


}   // End uPictureBox Class


#endregion  // end private functions and classes


#region Component Designer generated code
/// <summary> 
/// Required method for Designer support - do not modify 
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion


#region New Public Properties

[
Category("Appearance"),
Description("The alpha value used to blend the control's background. Valid values are 0 through 255."),
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)

]
public int BackAlpha
{
get { return myBackAlpha; }
set 
{
int v = value;
if (v > 255)
v = 255;
myBackAlpha = v;
myUpToDate = false; 
Invalidate();
}
}

#endregion



}  // End AlphaTextBox Class


}  // End namespace ZBobb


//----


  



win32.cs代码如下
using System;
using System.Runtime.InteropServices;

using System.Drawing;


namespace ZBobb
{
/// <summary>
/// Win32 support code.
/// (C) 2003 Bob Bradley / ZBobb@hotmail.com
/// </summary>
public class win32
{
 
public const int  WM_MOUSEMOVE      =              0x0200;
public const int  WM_LBUTTONDOWN     =             0x0201;
public const int  WM_LBUTTONUP       =             0x0202;
public const int  WM_RBUTTONDOWN     =             0x0204;
public const int  WM_LBUTTONDBLCLK   =             0x0203;

public const int  WM_MOUSELEAVE      =             0x02A3;



public const int WM_PAINT     =                   0x000F;
public const int WM_ERASEBKGND   =                0x0014;

public const int WM_PRINT         =               0x0317;

//const int EN_HSCROLL       =   0x0601;
//const int EN_VSCROLL       =   0x0602;

public const int WM_HSCROLL       =              0x0114;
public const int WM_VSCROLL       =              0x0115;


public const int EM_GETSEL              = 0x00B0;
public const int EM_LINEINDEX           = 0x00BB;
public const int EM_LINEFROMCHAR        = 0x00C9;

public const int EM_POSFROMCHAR         = 0x00D6;



[DllImport("USER32.DLL", EntryPoint= "PostMessage")]
public static extern bool PostMessage(IntPtr hwnd, uint msg,
IntPtr wParam, IntPtr lParam);

/*
BOOL PostMessage(          HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);
*/

// Put this declaration in your class   //IntPtr
[DllImport("USER32.DLL", EntryPoint= "SendMessage")]
public static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wParam,
IntPtr lParam);




[DllImport("USER32.DLL", EntryPoint= "GetCaretBlinkTime")]
public static extern uint GetCaretBlinkTime();




const int WM_PRINTCLIENT = 0x0318;

const long PRF_CHECKVISIBLE=0x00000001L;
const long PRF_NONCLIENT = 0x00000002L;
const long PRF_CLIENT = 0x00000004L;
const long PRF_ERASEBKGND = 0x00000008L;
const long PRF_CHILDREN = 0x00000010L;
const long PRF_OWNED = 0x00000020L;

/*  Will clean this up later doing something like this
enum  CaptureOptions : long
{
PRF_CHECKVISIBLE= 0x00000001L,
PRF_NONCLIENT = 0x00000002L,
PRF_CLIENT = 0x00000004L,
PRF_ERASEBKGND = 0x00000008L,
PRF_CHILDREN = 0x00000010L,
PRF_OWNED = 0x00000020L
}
*/


public static bool CaptureWindow(System.Windows.Forms.Control control, 
ref System.Drawing.Bitmap bitmap)
{
//This function captures the contents of a window or control

Graphics g2 = Graphics.FromImage(bitmap);

//PRF_CHILDREN // PRF_NONCLIENT
int meint = (int)(PRF_CLIENT | PRF_ERASEBKGND); //| PRF_OWNED ); //  );
System.IntPtr meptr = new System.IntPtr(meint);

System.IntPtr hdc = g2.GetHdc();
win32.SendMessage(control.Handle,win32.WM_PRINT,hdc,meptr);

g2.ReleaseHdc(hdc);
g2.Dispose();

return true;

}



}
}


--------------------编程问答-------------------- 这个类可以直接使用

大家可以试试看 --------------------编程问答-------------------- 大哥,太长了!! --------------------编程问答-------------------- 太长 --------------------编程问答-------------------- 我贴的全部代码 ,其实真正的部分很少的 --------------------编程问答-------------------- 这里 其实是2个 文件 别被唬住了 --------------------编程问答-------------------- http://www.codeproject.com/KB/edit/alphablendtextbox.aspx


这是原始地址,这个Demo下载下来没有你说的问题啊,你如何操作出现你说的问题? --------------------编程问答-------------------- 有的  有人提出了 memory leak 仔细看评论 我忘记是那一页了
但是那个评论的标题就是 memory leak

  --------------------编程问答-------------------- 不信你 可以建一个form
创建一个这样的控件


我忘记说了
当焦点落在该textbox中的时候 内存泄漏现象开始出现,打字的时候尤其严重
我怀疑是uPicture的东西 没有被释放但是我找不到合适的地方 --------------------编程问答-------------------- 那个回帖的人好像是提出了内存没释放的问题,而且提出了解决方法了么

 
Memory Leaks?   Kuling 1:49 24 Jan '05   
 
 Hi... 
At first I want to congratulate you beautyful work. You got my five. 

I use your control like help window. When user moves mouse over button I show AlphaBlendTextBox window, when mouse is out of button then I hide it.

I'm use .NET for short time and I'm not sure if it is an error.
You do not dispose myBitmap and myAlphaBitmap. Then after several Show/Hide usage of memory rise drastically.

I think that at least GetBitmaps should be fixed.



private void GetBitmaps()
{
if (myBitmap == null
|| myAlphaBitmap == null
|| myBitmap.Width != Width 
|| myBitmap.Height != Height 
|| myAlphaBitmap.Width != Width 
|| myAlphaBitmap.Height != Height)
{
if (myBitmap != null) 
{
myBitmap.Dispose();
}
myBitmap = null;

if (myAlphaBitmap != null)
{
myAlphaBitmap.Dispose();
}
myAlphaBitmap = null;
}

...
 


他不是已经写得很明确了么
You do not dispose myBitmap and myAlphaBitmap
指出作者没有释放myBitmap 和 myAlphaBitmap
于是在给出的解决代码里先判断它们是不是null,如果不是,先调用dispose,然后才是=null
--------------------编程问答-------------------- 好象在回贴里看到有人和你问一样的问题,象楼上说的那样,先判断是否null,然后dispos(). --------------------编程问答-------------------- 学习 --------------------编程问答--------------------
引用 10 楼 wartim 的回复:
那个回帖的人好像是提出了内存没释放的问题,而且提出了解决方法了么

Assembly codeMemory Leaks?   Kuling1:4924 Jan'05   
 
 Hi... 
At first I want to congratulate you beautyful work. You got my five. 

I use your control like help window. When user moves mouse over button I show AlphaBlendTextBox window, when mouse is out of button then I hide it.

I'm use .NET for short timeand I'm not sure if it is an error.
You do not dispose myBitmap and myAlphaBitmap. Then after several Show/Hide usage of memory rise drastically.

I think that at least GetBitmaps should be fixed.



private void GetBitmaps()
{
if (myBitmap == null
|| myAlphaBitmap == null
|| myBitmap.Width != Width 
|| myBitmap.Height != Height 
|| myAlphaBitmap.Width != Width 
|| myAlphaBitmap.Height != Height)
{
if (myBitmap != null) 
{
myBitmap.Dispose();
}
myBitmap = null;

if (myAlphaBitmap != null)
{
myAlphaBitmap.Dispose();
}
myAlphaBitmap = null;
}

...

 他不是已经写得很明确了么
 You do not dispose myBitmap and myAlphaBitmap
 指出作者没有释放myBitmap 和 myAlphaBitmap
 于是在给出的解决代码里先判断它们是不是null,如果不是,先调用dispose,然后才是=null



 怪我 没说清楚   那人说的地方 我早都已经修改了,在我公司的机器上,公司机器为了保密不许上网 我就用另一台机器 传的源文件
但还是 有泄漏,而且那个人说了 “I think that at least GetBitmaps should be fixed.”
是 at least  还有别的地方需要修正 --------------------编程问答-------------------- 自己发的帖子居然无法 支持编辑功能?本想把原帖修改下的 可惜
--------------------编程问答-------------------- 我 在顶一边  --------------------编程问答-------------------- 我是很楼主马甲
现在我已经在所有的dispose()
后面跟上了=null操作
在加上
private void GetBitmaps()
{

if (myBitmap == null
|| myAlphaBitmap == null
|| myBitmap.Width != Width
|| myBitmap.Height != Height
|| myAlphaBitmap.Width != Width
|| myAlphaBitmap.Height != Height)
{
myBitmap = null;
myAlphaBitmap = null;
}
 被我修改成
private void GetBitmaps()
{
if (myBitmap == null
|| myAlphaBitmap == null
|| myBitmap.Width != Width
|| myBitmap.Height != Height
|| myAlphaBitmap.Width != Width
|| myAlphaBitmap.Height != Height)
{
if (myBitmap != null)
{
myBitmap.Dispose();
}
myBitmap = null;

if (myAlphaBitmap != null)
{
myAlphaBitmap.Dispose();
}
myAlphaBitmap = null;



还有我自己修改的一个地方
protected override void OnMouseLeave(EventArgs e)
{
//found this code to find the current cursor location
//at http://www.syncfusion.com/FAQ/WinForms/FAQ_c50c.asp#q597q

Point ptCursor = Cursor.Position;

Form f = this.FindForm();
//下面这个地方会导致偶尔崩溃,f有时候是null,且怀疑这里每次调用都会 有内存侧漏
ptCursor = f.PointToClient(ptCursor);

if( !this.Bounds.Contains(ptCursor) ) 
base.OnMouseLeave (e);


被我修改为
Point tempPoint=new Point(100,100);
protected override void OnMouseLeave(EventArgs e)
{
Point ptCursor = Cursor.Position;

ptCursor =tempPoint;//改成这样 不崩溃了
if( !this.Bounds.Contains(ptCursor) ) 
base.OnMouseLeave (e);



现在 当光标落在textbox中时  内存侧漏 每秒 不到30k
--------------------编程问答-------------------- 侧漏?......

有时是GC还没回收 --------------------编程问答-------------------- 我找到地方了。。。。
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus (e);
myCaretUpToDate = false;
myUpToDate = false;
this.Invalidate();


myTimer1 = new System.Windows.Forms.Timer(this.components);
myTimer1.Interval = (int) win32.GetCaretBlinkTime(); //  usually around 500;

myTimer1.Tick +=new EventHandler(myTimer1_Tick);
myTimer1.Enabled = true;


这里每次new了一遍 但都没有释放掉呢。。。
dispose+null赋值后
终于不侧漏了

补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,