.NET text box blank/empty/invisible/hidden when text reaches certain length

It seems, that .NET 2.0 have bug when text box (TextBox control) appears blank / empty / invisible / hidden — not showing text when text length reaches certain size. My quick tests shows, that the length of the text that causes this bug to appear depends on something and are changing from program to program or from computer to computer. Unfortunately I do not have resources to test this bug in full right now.

How to repeat this bug in C# .NET 2.0.

Open Visual Studio and create New Project – Windows Forms Project.

Create a new .NET 2.0 project

Add one TextBox and two Buttons to the project.

Form with 2 Buttons and TextBox

Add click handlers for two buttons and one helper function. Here is a code.

      private void button1k_Click(object sender, EventArgs e)
      {
         textBox.Text = GenerateString(1000);
      }
 
      private void button10k_Click(object sender, EventArgs e)
      {
         textBox.Text = GenerateString(10000);
      }
 
      private string GenerateString(int lenght)
      {
         string text = "";
         for (int i = 0; i < lenght; ++i)             text += Convert.ToChar('0' + i % 10);          return text;       }

Now run the code! Clicking on the first button, TextBox shows some random numbers as expected.

Correct result, text is shown

Now click on the second button. Text disappears, and only blinking cursor is shown. Also note, that TextBox is functioning -- you can still delete / add characters, select all, use copy / paste, you just do not see the results on the screen.

Incorrect result, only cursor blinks

Workarounds? Currently none. Submitted this bug to Connect: .NET 2.0 TextBox fails to display long texts.

Tested on Windows 7 Pro 64-bit and Windows 7 Ultimate 64-bit with latest updates on 12/2/2011. Compiled with latest Visual Studio 2010 Pro 10.0.40219.1 SP1Rel w/ Microsoft .NET Framework Version 4.0.30319 SP1Rel.

P.S. One similar bug is reported on Microsoft Connect, however it seems like separate issue: Vanishing text bug.

P.S.S. My source code can be downloaded from MS Connect.

Static code analysis for C++ for free and for Pro

Up and until Visual Studio 2010 Microsoft decided that Code Analysis tool was available only for Visual Studio Premium and Ultimate editions. I have Visual Studio 2010 Pro w/MSDN subscriptions (actually 2 of them), but can not use Code Analysis tool.

VS Pro w/o code analysis tool

This however will change with upcoming Visual Studio 11. See the SDL blog: Code Analysis for All.

This is the first time that Code Analysis has been made available in an Express edition of Visual Studio…

COM, BSTR or _bstr_t is leaking memory

COM, BSTR or _bstr_t is leaking memory. That was my first thought when I saw increasing number in Task Manager under memory colon for the process I am developing.

Searching Google for quick answer I found famous Microsoft employee and blogger Larry Osterman’s blog post about Hey, why am I leaking all my BSTR’s? He describes OLE caching of BSTR objects and tool called UMDH. OLE caching is not my case, however UMDH may be useful is you are able to figure out what to do.

Another link I found is from 1999 (VS6) Implementing a Simple MFC Client for an ATL Server. They have notes about memory leaks all over the place. Particularly interesting are two examples I have copied below.

Without leak:
//Update static text with new value
BSTR tmpBStr;
 
m_pObject1->get_ObjectString(&tmpBStr);
_bstr_t tmpbstr(tmpBStr, FALSE); //necessary to avoid a memory leak
 
SetDlgItemText(IDC_CURPROPVAL, tmpbstr);

With leak:
//Update static text with new value
BSTR tmpBStr;
 
m_pObject1->get_ObjectString(&tmpBStr);
_bstr_t tmpbstr;
 
tmpbstr= tmpBStr; //Caution: Memory leak occurs
SetDlgItemText(IDC_CURPROPVAL, tmpbstr);

And explanation:

The leak occurs when the tmpbstr variable is initialized. A call to SysAllocString (reference available in the Component Services section of the Platform SDK) is automatically made when creating the tmpbstr variable. This new allocation is never freed later, resulting in a memory leak. Using this version of the _bstr_t constructor avoids the issue by attaching the BSTR object to tmpbstr without a call to SysAllocString. For more information on this issue, see _bstr_t::_bstr_t (reference available in the C++ Language Reference section of the Visual C++ Documentation).

The problem is that explanation is wrong. My speculation: Most probably one person (senior programmer?) found memory leak in documentation, fixed it and told another person (junior programmer?) to update documentation. And that second person got it wrong. First: _bstr_t constructor _bstr_t::_bstr_t() does not allocate memory. Second: if it were allocating, then it would be freed, see the code below:
_bstr_t& _bstr_t::operator=(const wchar_t* s)
{
    if (s == NULL || ...)
    {
        _Free();
        m_Data = new Data_t(s);

And yes, _Free does exactly that. It frees m_Data if it contains something, in our case as I noted above, it points to 0x00000000;

operator=(const wchar_t* s) is exactly what is called in my case – Unicode compile.

Again, the code in Microsoft article leaks memory as comment says, but it does not leak as it is described. It leaks because memory allocated by m_pObject1->get_ObjectString is not freed.

In the end I found my memory leak. It was similar problem, I needed to call _bstr_t constructor with FALSE as second argument. From MSDN: If false, the bstr argument is attached to the new object without making a copy by calling SysAllocString.

So be careful playing with BSTRs.