From: Barnabé on
Hello,

I am trying to use the clipboard in Unicode with richedit control , I
can't get rid of a memory leak.
My project is ATL with Mfc support

Here is the clipboard function:

HGLOBAL hBuf;
_TCHAR* pBuf;
CString oDataConverted = CStringSelectedinRichEdit();
oDataConverted.FreeExtra();

int iLength = (oDataConverted.GetAllocLength()+1)*sizeof(_TCHAR);

// open clipboard
if ( OpenClipboard() )
{
hBuf = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, iLength);
pBuf = (_TCHAR*)GlobalLock(hBuf);
//copy data to clipboard
memcpy(pBuf,(LPCTSTR)oDataConverted,iLength);
GlobalUnlock(hBuf);

// remove the current clipboard contents
EmptyClipboard();
SetClipboardData(CF_UNICODETEXT,hBuf);
CloseClipboard();
}

I check in google group for quite a while and I couldn't find the
answer.
The leak seem to be related to the pBuf release.
The memory should be released automaticaly but somehow it's not the
case.

Thanks.

From: Joseph M. Newcomer on
See below...
On 12 Dec 2006 03:20:07 -0800, "Barnab�" <eric.franc(a)gmail.com> wrote:

>Hello,
>
>I am trying to use the clipboard in Unicode with richedit control , I
>can't get rid of a memory leak.
>My project is ATL with Mfc support
>
>Here is the clipboard function:
>
> HGLOBAL hBuf;
> _TCHAR* pBuf;
> CString oDataConverted = CStringSelectedinRichEdit();
> oDataConverted.FreeExtra();
****
I see no need for FreeExtra
****
>
> int iLength = (oDataConverted.GetAllocLength()+1)*sizeof(_TCHAR);
****
Why GetAllocLength()? Why not just GetLength()? What does allocated space have to do
with the problem?
****
>
> // open clipboard
> if ( OpenClipboard() )
> {
> hBuf = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, iLength);
> pBuf = (_TCHAR*)GlobalLock(hBuf);
> //copy data to clipboard
> memcpy(pBuf,(LPCTSTR)oDataConverted,iLength);
> GlobalUnlock(hBuf);
>
> // remove the current clipboard contents
> EmptyClipboard();
> SetClipboardData(CF_UNICODETEXT,hBuf);
> CloseClipboard();
> }
>
>I check in google group for quite a while and I couldn't find the
>answer.
>The leak seem to be related to the pBuf release.
>The memory should be released automaticaly but somehow it's not the
>case.
>
****
There had better not be any release of that storage! It is now owned by the clipboard,
and you must not touch it.

What is reporting this as a leak? Note that a lot of tools notice you did not call
GlobalFree, and therefore would erroneously report that this storage had "leaked", when in
fact the program is absolutely correct. A tool that reports a leak of storage that has
been set in the clipboard is reporting a nonexistent leak and can be construed as being
erroneous. It should be handling the SetClipboard call and treat this (logically, from
its viewpoint) as a proxy for the GlobalFree operation.
****
>Thanks.
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Barnabé on
Thanks for the help,

I have checked more in details what was wrong with my code and it
appeared that it's not the clipboard whose making the leak
but the rich editGetSelText function.

Here is the code I use:

CString CTest::GetSelText()
{
CHARRANGE cr;
cr.cpMin = cr.cpMax = 0;
::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);
LPSTR lpsz = (char*)_alloca((cr.cpMax - cr.cpMin + 1)*2);
lpsz[0] = NULL;
::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpsz);
return CString(lpsz);
}

I have also tried the following one, I think this one would be more
logical as I use unicode.
but for some reason it does not work at all.

CString CTest::GetSelection()
{
CHARRANGE cr;
GetRichEditCtrl().GetSel(cr);

// Allocate memory for the buffer
LPTSTR lptbuf = new TCHAR[cr.cpMax - cr.cpMin + 1];

// Get the selected text from the Rich Edit
GetRichEditCtrl().SendMessage(EM_GETSELTEXT, 0, (LPARAM) lptbuf);

CString strSelect(lptbuf);

// Release allocated memory
delete [] lptbuf;

return strSelect;
}

From: Joseph M. Newcomer on
See below...
On 12 Dec 2006 23:08:28 -0800, "Barnab�" <eric.franc(a)gmail.com> wrote:

>Thanks for the help,
>
>I have checked more in details what was wrong with my code and it
>appeared that it's not the clipboard whose making the leak
>but the rich editGetSelText function.
>
>Here is the code I use:
>
>CString CTest::GetSelText()
>{
> CHARRANGE cr;
> cr.cpMin = cr.cpMax = 0;
> ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);
****
And why doesn't
GetSel(cr);
do the job? This seems a clumsy way to implement what is already in MFC.
****
> LPSTR lpsz = (char*)_alloca((cr.cpMax - cr.cpMin + 1)*2);
****
This is unbelievably clumsy! Why do something this complex? What's the *2 doing there?
Did you mean sizeof(TCHAR)? Why are you using an LPSTR buffer (which is for ASCII
characters) and casting to char* if you are in Unicode? Why not
LPTSTR lpsz = (LPTSTR)_alloca((cr.cpMax - cpMin + 1) * sizeof(TCHAR));
but that's still an awfully complicated way to solve a simple problem. But the REAL
solution, if you have to do this (you haven't said if you are working in VS6 or VS.NET,
and to do this in VS6 you need to implement it yourself) is

CString s;
LPTSTR p = s.GetBuffer(cr.cpMax - cr.cpMin + 1);
::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)p);
s.ReleaseBuffer();
return s;
and no ugly obsolete _alloca calls are required! No sizeof(TCHAR)! It is about as
trivial as you can get. And it works correctly in both Unicode and ANSI versions.
****
> lpsz[0] = NULL;
****
NULL is a pointer value. _T('\0') is a character value. Why are you writing a pointer
into a character value in a buffer that is about to be overwritten anyway?
****
> ::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpsz);
****
Again, a remarkably clumsy way to handle this! If you're using anything beyond VS6, you
can just write
return GetSelText();
****
> return CString(lpsz);
>}
****
In anything beyond VS6 this whole piece of code could be replaced simply by the GetSelText
call on the CRichEditCtrl!
****
>
>I have also tried the following one, I think this one would be more
>logical as I use unicode.
>but for some reason it does not work at all.
>
>CString CTest::GetSelection()
>{
> CHARRANGE cr;
> GetRichEditCtrl().GetSel(cr);
>
> // Allocate memory for the buffer
> LPTSTR lptbuf = new TCHAR[cr.cpMax - cr.cpMin + 1];
>
> // Get the selected text from the Rich Edit
> GetRichEditCtrl().SendMessage(EM_GETSELTEXT, 0, (LPARAM) lptbuf);
>
> CString strSelect(lptbuf);
>
> // Release allocated memory
> delete [] lptbuf;
>
> return strSelect;
>}
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Barnabé on
I tried that function GetSeltext without any success
I found the solution , in atl there is no CString GetSelText() but BOOL
GetSelTextBSTR(BSTR& bstrText) const

Here is the GetSelTextBSTR code

BOOL GetSelTextBSTR(BSTR& bstrText) const
{
ATLENSURE(::IsWindow(m_hWnd));
ATLENSURE(bstrText == NULL);

CHARRANGE cr;
cr.cpMin = cr.cpMax = 0;
::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);
LPSTR lpstrText = (char*)_alloca((cr.cpMax - cr.cpMin + 1) * 2);
lpstrText[0] = 0;
if(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0)
return FALSE;

bstrText = ::SysAllocString(CA2W(lpstrText));
return (bstrText != NULL) ? TRUE : FALSE;
}

They have done almost the same as me. about the "2", I agree that
sizeof(TCHAR) is way more better.

about the following code you gave, I have tried similar and it failed:

CString s;
LPTSTR p = s.GetBuffer(cr.cpMax - cr.cpMin + 1);
::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)p);
s.ReleaseBuffer();
return s;

EM_GETSELTEXT return incorrect characters. LPARAM return LPSTR not
LPTSTR.

Thanks for your precision.

On Dec 13, 11:23 pm, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
> See below...
> On 12 Dec 2006 23:08:28 -0800, "Barnabé" <eric.fr...(a)gmail.com> wrote:
>
> >Thanks for the help,
>
> >I have checked more in details what was wrong with my code and it
> >appeared that it's not the clipboard whose making the leak
> >but the rich editGetSelText function.
>
> >Here is the code I use:
>
> >CString CTest::GetSelText()
> >{
> > CHARRANGE cr;
> > cr.cpMin = cr.cpMax = 0;
> > ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);****
> And why doesn't
> GetSel(cr);
> do the job? This seems a clumsy way to implement what is already in MFC.
> ****> LPSTR lpsz = (char*)_alloca((cr.cpMax - cr.cpMin + 1)*2);****
> This is unbelievably clumsy! Why do something this complex? What's the *2 doing there?
> Did you mean sizeof(TCHAR)? Why are you using an LPSTR buffer (which is for ASCII
> characters) and casting to char* if you are in Unicode? Why not
> LPTSTR lpsz = (LPTSTR)_alloca((cr.cpMax - cpMin + 1) * sizeof(TCHAR));
> but that's still an awfully complicated way to solve a simple problem. But the REAL
> solution, if you have to do this (you haven't said if you are working in VS6 or VS.NET,
> and to do this in VS6 you need to implement it yourself) is
>
> CString s;
> LPTSTR p = s.GetBuffer(cr.cpMax - cr.cpMin + 1);
> ::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)p);
> s.ReleaseBuffer();
> return s;
> and no ugly obsolete _alloca calls are required! No sizeof(TCHAR)! It is about as
> trivial as you can get. And it works correctly in both Unicode and ANSI versions.
> ****> lpsz[0] = NULL;****
> NULL is a pointer value. _T('\0') is a character value. Why are you writing a pointer
> into a character value in a buffer that is about to be overwritten anyway?
> ****> ::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpsz);****
> Again, a remarkably clumsy way to handle this! If you're using anything beyond VS6, you
> can just write
> return GetSelText();
> **** > return CString(lpsz);
> >}****
> In anything beyond VS6 this whole piece of code could be replaced simply by the GetSelText
> call on the CRichEditCtrl!
> ****
>
>
>
> >I have also tried the following one, I think this one would be more
> >logical as I use unicode.
> >but for some reason it does not work at all.
>
> >CString CTest::GetSelection()
> >{
> > CHARRANGE cr;
> > GetRichEditCtrl().GetSel(cr);
>
> > // Allocate memory for the buffer
> > LPTSTR lptbuf = new TCHAR[cr.cpMax - cr.cpMin + 1];
>
> > // Get the selected text from the Rich Edit
> > GetRichEditCtrl().SendMessage(EM_GETSELTEXT, 0, (LPARAM) lptbuf);
>
> > CString strSelect(lptbuf);
>
> > // Release allocated memory
> > delete [] lptbuf;
>
> > return strSelect;
> >}Joseph M. Newcomer [MVP]
> email: newco...(a)flounder.com
> Web:http://www.flounder.com
> MVP Tips:http://www.flounder.com/mvp_tips.htm