Click here to Skip to main content
15,886,766 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am a newbie to C++. I was trying to convert the function here to set html unicode text to clipboard. This is what I have done so far:

C++
bool CopyHTML2(WCHAR *html ){
    wchar_t *buf = new wchar_t [400 + wcslen(html)];
    if(!buf) return false;

	static int cfid = 0;
    if(!cfid) cfid = RegisterClipboardFormat("HTML Format");

	    // Create a template string for the HTML header...
    wcscpy(buf,
        L"Version:0.9\r\n"
        L"StartHTML:00000000\r\n"
        L"EndHTML:00000000\r\n"
        L"StartFragment:00000000\r\n"
        L"EndFragment:00000000\r\n"
        L"<html><body>\r\n"
        L"<!--StartFragment -->\r\n");

    // Append the HTML...
    wcscat (buf, html);
    wcscat (buf, L"\r\n");
    // Finish up the HTML format...
    wcscat (buf,
        L"<!--EndFragment-->\r\n"
        L"</body>\r\n"
        L"</html>");

	wchar_t *ptr = wcsstr(buf, L"StartHTML");
	wsprintfW(ptr+10, L"%08u", wcsstr(buf, L"<html>") - buf);
	*(ptr+10+8) = L'\r';

    ptr = wcsstr(buf, L"EndHTML");
    wsprintfW(ptr+8, L"%08u", wcslen(buf));
    *(ptr+8+8) = '\r';

    ptr = wcsstr(buf, L"StartFragment");
    wsprintfW(ptr+14, L"%08u", wcsstr(buf, L"<!--StartFrag") - buf);
    *(ptr+14+8) = '\r';

    ptr = wcsstr(buf, L"EndFragment");
    wsprintfW(ptr+12, L"%08u", wcsstr(buf, L"<!--EndFrag") - buf);
    *(ptr+12+8) = '\r';

	// Open the clipboard...
    if(OpenClipboard(0)) {
        EmptyClipboard();
        HGLOBAL hText = GlobalAlloc(GMEM_MOVEABLE |GMEM_DDESHARE, wcslen(buf)+4);
        wchar_t *ptr = (wchar_t *)GlobalLock(hText);
        wcscpy(ptr, buf);
        GlobalUnlock(hText);
        SetClipboardData(cfid, hText);
        CloseClipboard();
        GlobalFree(hText);
    }

    // Clean up...
    //delete [] buf;
	return true;
}


I get the following error at SetClipboardData function:

HEAP[Project1.exe]: Heap block at 00378038 modified at 0037813E past requested size of fe
Project1.exe has triggered a breakpoint.

Any idea on how to solve this? Also is it the right way to do this? Or is there a simpler way to do it?

Thanks in advance for all your help.
Posted
Comments
Richard MacCutchan 13-Apr-13 4:36am    
All the code from the line wsprintfW(ptr+8, L"%08u", wcslen(buf)); is impossible to understand, but looks very likely to cause corruption. Start again in building your buffer but make sure that at every point you do not overflow it.

1 solution

I did not see the source for the heap error but you also asked for the right or simpler way. At first you should know that the HTML clipboard format must contain UTF-8 encoded text. So the input text must be converted to UTF-8 and prefixed with the HTML format header. A snippet from one of my projects (lpszWide is the HTML text as wide string including the HTML and fragment start and end markers):

// Get length of UTF-8 string including terminating NULL char.
// The MSDN does not mention if the string should be NULL terminated or not.
// Providing the NULL terminator is safe and always better.
int nUtf8Size = ::WideCharToMultiByte(CP_UTF8, 0, lpszWide, -1, NULL, 0, NULL, NULL);
if (nUtf8Size < 1)
{
    TRACE0("CHtmlFormat::SetHtml: UTF-8 conversion failed\n");
    ASSERT(0);
    return false;
}
// Allocate buffer for HTML format descriptor and UTF-8 content. 
// NOTE: Adjust length definition when changing the descriptor!
const int nDescLen = 105;
hGlobal = ::GlobalAlloc(GMEM_MOVEABLE, nDescLen + nUtf8Size);
if (NULL != hGlobal)
{
    // Convert to UTF-8
    bool bErr = false;
    LPSTR lpszBuf = static_cast<LPSTR>(::GlobalLock(hGlobal));
    LPSTR lpszUtf8 = lpszBuf + nDescLen;
    if (::WideCharToMultiByte(CP_UTF8, 0, lpszWide, -1, lpszUtf8, nUtf8Size, NULL, NULL) <= 0)
    {
        TRACE0("CHtmlFormat::SetHtml: UTF-8 conversion failed\n");
        bErr = true;
    }
    else
    {
        // Get the fragment marker positions
        LPCSTR lpszStartFrag = strstr(lpszUtf8, "<!--StartFragment-->");
        LPCSTR lpszEndFrag = strstr(lpszUtf8, "<!--EndFragment-->");
        ASSERT(lpszStartFrag);
        ASSERT(lpszEndFrag);
        // Adjust pointer to be behind inserted string followed by CR-LF
        lpszStartFrag += strlen("<!--StartFragment-->") + 2;
        // Create descriptor and prepend it to the string.
        // Use only ASCII chars here!
        // Using leading zeroes with the offsets here to avoid iterative calculations.
        // With valid nDescLen, _snprintf() will not append the NULL terminator here.
        VERIFY(nDescLen == _snprintf(
            lpszBuf, nDescLen,
            "Version:1.0\r\nStartHTML:%010d\r\nEndHTML:%010d\r\nStartFragment:%010d\r\nEndFragment:%010d\r\n",
            nDescLen, 
            nDescLen + nUtf8Size - 1,		// offset to next char behind string
            nDescLen + static_cast<int>(lpszStartFrag - lpszUtf8), 
            nDescLen + static_cast<int>(lpszEndFrag - lpszUtf8)));
    }
    ::GlobalUnlock(hGlobal);
    if (bErr)
    {
        ::GlobalFree(hGlobal);
        hGlobal = NULL;
    }
}
return NULL != hGlobal;
 
Share this answer
 
Comments
madharasan1 13-Apr-13 8:45am    
To @Jochen A: I did make it work thanks a lot. Can you please explain what these lines do:
>>nDescLen = 105;
What does 105 stand for? and
>>VERIFY(nDescLen == _snprintf(...
What does his statement do? I mean what is the effect of this comparison?

Since I have only expression edition of Visual Studio Expression Edition, Can I remove all the macros? I mean like TRACE0, ASSERT and VERIFY? Will there be any side effects?
Jochen Arndt 13-Apr-13 9:05am    
105 is the length of the formatted HTML descriptor string.

The macros are only effective with debug builds. The VERIFY macro just checks if the length is 105. If the format string is not changed in the future, it can be removed. The TRACE macros can be removed or replaced by error messages. The ASSERT macros can be removed or replaced by code that returns from the function when the condition fails.

There will be no side effects for release builds. But the macros should be also present with the Express Edition.
madharasan1 13-Apr-13 10:43am    
Thanks a lot for that explanation.. :)
madharasan1 5-May-13 6:13am    
Hi Jochen Arndt, Here is my full code: http://pastebin.com/wEFFCSNf When even I try to paste in Office Word, PowerPoint, Excel it works perfectly, but when I paste in OneNote, it pastes some gibberish values after the anchor tag. It happens only with the anchor tag and only to a unicode text. Is there any specific reason for this? Is this a bug in MS Office OneNote? or Is something wrong with my implementation? Any ideas?
Jochen Arndt 6-May-13 3:28am    
I don't use OneNote. so I can't help much. You may write the generated clipboard data to a file and check it with a Hex editor and an UTF-8 capable text editor.
If your data contain a HTML header (head tags), it may help to add a charset definition:
<meta http-equiv="content-type" content="text/html; charset=utf-8">

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900