我是C ++的新手。我想获取剪贴板的内容,其中可能包含Unicode字符,附加一个div标签,其中包含一些格式为HTML的内容并将其设置回剪贴板。
我已成功获取内容并附加内容。但无法将其作为HTML文本重新设置回剪贴板。我已经设置了简单的文本。这是我的代码:
#include <shlwapi.h>
#include <iostream>
#include <conio.h>
#include <stdio.h>
using namespace std;
wstring getClipboard(){
if (OpenClipboard(NULL)){
HANDLE clip = GetClipboardData(CF_UNICODETEXT);
WCHAR * c;
c = (WCHAR *)clip;
CloseClipboard();
return (WCHAR *)clip;
}
return L"";
}
bool setClipboard(wstring textToclipboard)
{
if (OpenClipboard(NULL)){
EmptyClipboard();
HGLOBAL hClipboardData;
size_t size = (textToclipboard.length()+1) * sizeof(WCHAR);
hClipboardData = GlobalAlloc(NULL, size);
WCHAR* pchData = (WCHAR*)GlobalLock(hClipboardData);
memcpy(pchData, textToclipboard.c_str(), size);
SetClipboardData(CF_UNICODETEXT, hClipboardData);
GlobalUnlock(hClipboardData);
CloseClipboard();
return true;
}
return false;
}
int main (int argc, char * argv[])
{
wstring s = getClipboard();
s += std::wstring(L"some extra text <b>hello</b>");
setClipboard(s);
getch();
return 0;
}
我确实尝试使用here描述的代码并阅读文档here。但我无法使其发挥作用。我尝试的可能是偏离轨道或完全错误。
更新:以下代码是我在Cody Gray对原始代码here建议修改后尝试的代码:
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;
}
此代码编译成功,但我在SetClipboardData上收到以下错误:HEAP[Project1.exe]: Heap block at 007A8530 modified at 007A860A past requested size of d2
Project1.exe has triggered a breakpoint.
请指导我如何继续。我在Windows 8上使用Visual Studio Express 2012.谢谢。
答案 0 :(得分:1)
您的ANSI(窄)和Unicode(宽)字符串不匹配。
与wcscpy
函数不同,w
函数中的wsprintf
不代表“宽”,它代表“Windows”。它是Win32 API的一部分,而不是C运行时库。所有使用字符串的Win32 API函数都有两个版本,一个后缀为A
,后者处理ANSI字符串,另一个后缀为W
,处理宽字符串。标头用宏隐藏了所有这些内容。我将更详细地解释所有这些here - 推荐阅读。
无论如何,这里的简单修复是显式调用该函数的宽变量,因为你在其他地方正确使用宽字符串。拨打wsprintf
的所有电话都是这样的:
wchar_t *ptr = wcsstr(buf, L"StartHTML");
wsprintfW(ptr+10, L"%08u", wcsstr(buf, L"<html>") - buf);
*(ptr+10+8) = L'\r';
或者,您可以使用C运行时库提供的swprintf
函数而不是Win32版本。这个功能就像您在其他地方使用的wcsstr
和wcscpy
功能一样。名称中的w
表示“宽”。这一系列功能的文档是here。
另请注意,使用字符或字符串文字时,它们也需要是宽字符。您可以通过在L
前添加它们来实现这一目标。你在某些地方这样做,但却错过了其他地方。确保你做到一致。
但编译器应该警告你所有这些。您只需要确保提高警告级别,不要忽略任何警告。还要确保为项目全局定义UNICODE
和_UNICODE
预处理器符号。这将确保您始终调用Unicode / wide版本的函数。虽然这应该是所有新项目的默认值。
答案 1 :(得分:0)
这是我在Jochen Arndt at codeproject.com的帮助下提出的功能。希望这有助于某人。 Here is a complete working code,如果您有兴趣查看此内容。
它还有一个问题。这就是当单独粘贴到onenote时,它会在锚标记之后粘贴乱码。 Word,PowerPoint或Excel不会发生这种情况。它对于普通的英语语言文本没有这个问题。如果您有解决方案,请告诉我。问题似乎与OneNote有关。没有代码。
bool setClipboard(LPCWSTR lpszWide){
int nUtf8Size = ::WideCharToMultiByte(CP_UTF8, 0, lpszWide, -1, NULL, 0, NULL, NULL);
if (nUtf8Size < 1) return false;
const int nDescLen = 105;
HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE, nDescLen + nUtf8Size);
if (NULL != hGlobal)
{
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)
{
bErr = true;
}
else
{
LPCSTR lpszStartFrag = strstr(lpszUtf8, "<!--StartFragment-->");
LPCSTR lpszEndFrag = strstr(lpszUtf8, "<!--EndFragment-->");
lpszStartFrag += strlen("<!--StartFragment-->") + 2;
int i = _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;
}
// Get clipboard id for HTML format...
static int cfid = 0;
cfid = RegisterClipboardFormat("HTML Format");
// Open the clipboard...
if(OpenClipboard(0)) {
EmptyClipboard();
HGLOBAL hText = GlobalAlloc(GMEM_MOVEABLE |GMEM_DDESHARE, strlen(lpszBuf)+4);
char *ptr = (char *)GlobalLock(hText);
strcpy(ptr, lpszBuf);
GlobalUnlock(hText);
::SetClipboardData(cfid, hText);
CloseClipboard();
GlobalFree(hText);
}
}
return NULL != hGlobal;
}
答案 2 :(得分:0)
您的问题出在所引用示例中的使用 wchar_t 而不是 char ,这使您在偏移量计算上出错。
但是,我建议您避免使用 wchar_t 将 UNICODE 文本传输到剪贴板。实际上, UTF-8 char可以使用1到4个字节的字节序列进行编码,而Windows上的 wchar_t 是固定的2字节类型。
如您的电子邮件中引用的Microsoft文档中所述,剪贴板的内容应为UNICODE,它与剪贴板内存头中包含的字符的ASCII相同。
要在剪贴板中传输UNICODE,可以使用标准的 char C ++函数来准备发送到剪贴板的内容(例如, std :: string )。
虽然引用的示例有效,但是请在这里找到另一个使用C ++框架的代码示例,该示例实际上可以将HTML格式的UTF-8字符复制到剪贴板:
void copyHTMLtoClipboard(const std::string& html) {
std::string contextStart("Version:0.9\r\nStartHTML:0000000000\r\nEndHTML:0000000000\r\nStartFragment:0000000000\r\nEndFragment:0000000000\r\n<html><body>\r\n<!--StartFragment -->\r\n");
std::string contextEnd("\r\n<!--EndFragment -->\r\n</body></html>");
std::stringstream aux;
aux << contextStart << html << contextEnd;
std::string res = aux.str();
size_t htmlStart = 105 * sizeof(char);
size_t fragmentStart = 119 * sizeof(char);
size_t htmlEnd = res.size() * sizeof(char);
size_t fragmentEnd = htmlEnd - 35 * sizeof(char);
aux.fill('0');
aux.width(10);
aux.seekp(23);
aux << htmlStart;
aux.seekp(43);
aux.fill('0');
aux.width(10);
aux << htmlEnd;
aux.seekp(69);
aux.fill('0');
aux.width(10);
aux << fragmentStart;
aux.seekp(93);
aux.fill('0');
aux.width(10);
aux << fragmentEnd;
res = aux.str();
HGLOBAL hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, htmlEnd + sizeof(char));
LPSTR dst = (LPSTR)GlobalLock(hdst);
memcpy(dst, res.c_str(), htmlEnd);
dst[htmlEnd] = 0;
GlobalUnlock(hdst);
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(RegisterClipboardFormat(L"HTML Format"), hdst);
CloseClipboard();
GlobalFree(hdst);
}
请注意,此代码是编译后定义的宏 _UNICODE 和 UNICODE 。