2

私はC++の初心者です。Unicode 文字が含まれている可能性があるクリップボードのコンテンツを取得し、HTML でフォーマットされたコンテンツを含む div タグを追加して、それをクリップボードに戻したいと考えています。

コンテンツを取得して追加することに成功しました。しかし、それを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 によって提案された変更をここに示されている元のコードに加えた後に試したものです。

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 を使用しています。ありがとうございます。

4

3 に答える 3

0

これは、 codeproject.comの Jochen Arndt の助けを借りて思いついた関数です。これが誰かに役立つことを願っています。これをチェックすることに興味がある場合は、ここに完全な作業コードがあります。

これにはまだ 1 つの問題があります。それは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;
}
于 2013-05-05T10:21:03.837 に答える
0

あなたの問題は、引用された例でcharの代わりにwchar_tを使用しているため、オフセットの計算が間違っています。

ただし、 UNICODEテキストをクリップボードに転送するためにwchar_tを使用しないことをお勧めします。実際、UTF-8 char は 1 ~ 4 バイトのバイト シーケンスでコーディングできますが、Windows のwchar_tは固定の 2 バイト タイプです。

電子メールで参照されている Microsoft ドキュメントで説明されているように、クリップボードの内容は UNICODE である必要があります。これは、たまたまクリップボード メモリのヘッダーに含まれる文字の ASCII と同じです。

UNICODE をクリップボードに転送するには、標準のchar C++ 関数を使用して、クリップボードに送信されるコンテンツを準備します ( std::stringなど)。

引用された例は機能しますが、実際にUTF-8文字をHTML形式でクリップボードにコピーできるC++フレームワークを使用した別のコードサンプルを見つけてください:

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を定義してコンパイルされていることに注意してください。

于 2020-03-10T15:26:43.917 に答える