Getclipboarddata(Cf_Text)

GetClipboardData(CF_TEXT)

GetClipboardData() is a Win32 API function.

The handle returned by GetClipboardData() must be first locked with GlobalLock(), then you can retrieve the char* pointer of the ANSI text in the clipboard (note that if you want to retrieve Unicode text, you should use the CF_UNICODETEXT format).

A sample code to retrieve the text from the clipboard and store it in a convenient std::string class instance follows (error management omitted for simplicity):

std::string GetClipboardText()
{
// Try opening the clipboard
if (! OpenClipboard(nullptr))
... // error

// Get handle of clipboard object for ANSI text
HANDLE hData = GetClipboardData(CF_TEXT);
if (hData == nullptr)
... // error

// Lock the handle to get the actual text pointer
char * pszText = static_cast<char*>( GlobalLock(hData) );
if (pszText == nullptr)
... // error

// Save text in a string class instance
std::string text( pszText );

// Release the lock
GlobalUnlock( hData );

// Release the clipboard
CloseClipboard();

return text;
}

You can use C++ RAII pattern and manage error conditions using exceptions, something like this:

#include <exception>
#include <iostream>
#include <ostream>
#include <stdexcept>
#include <string>
#include <windows.h>
using namespace std;

class RaiiClipboard
{
public:
RaiiClipboard()
{
if (! OpenClipboard(nullptr))
throw runtime_error("Can't open clipboard.");
// ... or define some custom exception class for clipboard errors.
}

~RaiiClipboard()
{
CloseClipboard();
}

// Ban copy
private:
RaiiClipboard(const RaiiClipboard&);
RaiiClipboard& operator=(const RaiiClipboard&);
};

class RaiiTextGlobalLock
{
public:
explicit RaiiTextGlobalLock(HANDLE hData)
: m_hData(hData)
{
m_psz = static_cast<const char*>(GlobalLock(m_hData));
if (! m_psz)
throw runtime_error("Can't acquire lock on clipboard text.");
}

~RaiiTextGlobalLock()
{
GlobalUnlock(m_hData);
}

const char* Get() const
{
return m_psz;
}

private:
HANDLE m_hData;
const char* m_psz;

// Ban copy
RaiiTextGlobalLock(const RaiiTextGlobalLock&);
RaiiTextGlobalLock& operator=(const RaiiTextGlobalLock&);
};

string GetClipboardText()
{
RaiiClipboard clipboard;

HANDLE hData = GetClipboardData(CF_TEXT);
if (hData == nullptr)
throw runtime_error("Can't get clipboard text.");

RaiiTextGlobalLock textGlobalLock(hData);
string text( textGlobalLock.Get() );

return text;
}

int main()
{
static const int kExitOk = 0;
static const int kExitError = 1;
try
{
cout << GetClipboardText() << endl;
return kExitOk;
}
catch(const exception& e)
{
cerr << "*** ERROR: " << e.what() << endl;
return kExitError;
}
}

In what circumstances will GetClipboardData(CF_TEXT) return NULL?

I did a Google search and found someone else with a similar problem (scroll down to find the particular response) that turned out to be due to re-entrancy. Do you call EmptyClipboard() anywhere and then react to changes? Perhaps you have a re-entrancy problem.

Update after code snippet provided
In the code you posted, the condition is wrong before calling GetLastError. You're only calling it when you get a non-NULL result, rather than when you get a NULL result. If you fix that, you should get a better answer from GetLastError. This MSDN article should help in deciphering what the result of GetLastError actually means.

Update after corrected code snippet
My guess is that you're facing a race condition with some other application accessing the clipboard. I would recommend checking to see if you have any other tools running that might do this.

C++ (VC): How to detect whether Windows clipboard contains CF_TEXT data?

Before you get data from the clipboard using the GetClipboardData function, you have to check that the clipboard contains data in the format that you expect. This can be done using the IsClipboardFormatAvailable function as follows:

if(IsClipboardFormatAvailable(CF_TEXT))
{
// The clipboard contains null-terminated ANSI string.
}
else if (IsClipboardFormatAvailable(CF_UNICODETEXT))
{
// The clipboard contains null-terminated Unicode string.
}

Then you have to open the clipboard and obtain a handle to the clipboard buffer as follows (assuming the clipboard contains ANSI string):

if(!OpenClipboard(NULL)) return;
HGLOBAL hglb = GetClipboardData(CF_TEXT);

Then you have to obtain exclusive access to the data using the GlobalLock function . Only on success you can safely access the data

if (hglb != NULL)
{
LPTSTR lptstr = GlobalLock(hglb);
if (lptstr != NULL)
{
// Read the contents of lptstr which just a pointer to the string.

// Don't forget to release the lock after you are done.
GlobalUnlock(hglb);
}
}
CloseClipboard();

The return type of GlobalLock is a void pointer. So depending on the data format which you have already determined using IsClipboardFormatAvailable, you have to cast it to the corresponding type. Windows data types are documented here.

GetClipboardData (CF_UNICODETEXT);

CF_UNICODETEXT uses UTF-16. On Windows, wchar_t data elements are used for UTF-16, but your code is using char instead. CStringA is not compatible with UTF-16. You are mismatching the data in both functions, that is why you do not get the results you are expecting.

One solution is to use CStringW instead of CStringA:

CStringW getClipboard()
{
CStringW strData;

if (OpenClipboard(NULL))
{
HANDLE hClipboardData = GetClipboardData(CF_UNICODETEXT);
if (hClipboardData)
{
WCHAR *pchData = (WCHAR*) GlobalLock(hClipboardData);
if (pchData)
{
strData = pchData;
GlobalUnlock(hClipboardData);
}
}
CloseClipboard();
}
return strData;
}

bool setClipboard(CStringW textToclipboard)
{
bool success = true;

if (OpenClipboard(NULL))
{
EmptyClipboard();
size_t size = (textToclipboard.GetLength()+1) * sizeof(WCHAR);
HGLOBAL hClipboardData = GlobalAlloc(NULL, size);
if (hClipboardData)
{
WCHAR* pchData = (WCHAR*) GlobalLock(hClipboardData);
if (pchData)
{
memcpy(pchData, (WCHAR*) textToclipboard.GetString(), size);
GlobalUnlock(hClipboardData);
SetClipboardData(CF_UNICODETEXT, hClipboardData);
}
}
CloseClipboard();
}
return success;
}

If you need to stick with CStringA, then either:

  1. use CF_TEXT instead of CF_UNICODETEXT and let the clipboard handle conversions between Ansi and Unicode for you:

    CStringA getClipboard()
    {
    CStringA strData;

    if (OpenClipboard(NULL))
    {
    HANDLE hClipboardData = GetClipboardData(CF_TEXT);
    if (hClipboardData)
    {
    CHAR *pchData = (CHAR*) GlobalLock(hClipboardData);
    if (pchData)
    {
    strData = pchData;
    GlobalUnlock(hClipboardData);
    }
    }
    CloseClipboard();
    }
    return strData;
    }

    bool setClipboard(CStringA textToclipboard)
    {
    bool success = true;

    if (OpenClipboard(NULL))
    {
    EmptyClipboard();
    size_t size = (textToclipboard.GetLength()+1) * sizeof(CHAR);
    HGLOBAL hClipboardData = GlobalAlloc(NULL, size);
    if (hClipboardData)
    {
    CHAR* pchData = (CHAR*) GlobalLock(hClipboardData);
    if (pchData)
    {
    memcpy(pchData, (CHAR*) textToclipboard.GetString(), size);
    GlobalUnlock(hClipboardData);
    SetClipboardData(CF_TEXT, hClipboardData);
    }
    }
    CloseClipboard();
    }
    return success;
    }
  2. convert to/from UTF-16 manually when using CF_UNICODETEXT:

    CStringA getClipboard()
    {
    CStringW strData;

    if (OpenClipboard(NULL))
    {
    HANDLE hClipboardData = GetClipboardData(CF_UNICODETEXT);
    if (hClipboardData)
    {
    WCHAR *pchData = (WCHAR*) GlobalLock(hClipboardData);
    if (pchData)
    {
    strData = pchData;
    GlobalUnlock(hClipboardData);
    }
    }
    CloseClipboard();
    }

    return CStringA((WCHAR*)strData.GetString());
    }

    bool setClipboard(CStringA strData)
    {
    CStringW textToclipboard((CHAR*)strData.GetString());
    bool success = true;

    if (OpenClipboard(NULL))
    {
    EmptyClipboard();
    size_t size = (textToclipboard.GetLength()+1) * sizeof(WCHAR);
    HGLOBAL hClipboardData = GlobalAlloc(NULL, size);
    if (hClipboardData)
    {
    WCHAR* pchData = (WCHAR*) GlobalLock(hClipboardData);
    if (pchData)
    {
    memcpy(pchData, (WCHAR*) textToclipboard.GetString(), size);
    GlobalUnlock(hClipboardData);
    SetClipboardData(CF_UNICODETEXT, hClipboardData);
    }
    }
    CloseClipboard();
    }
    return success;
    }

Another solution is to use CString instead of either CStringA or CStringW, and then use CF_TEXT or CF_UNICODETEXT depending on whether TCHAR is Ansi or Unicode:

#ifdef UNICODE
#define CF_TEXT_T CF_UNICODETEXT
#else
#define CF_TEXT_T CF_TEXT
#endif

CString getClipboard()
{
CString strData;

if (OpenClipboard(NULL))
{
HANDLE hClipboardData = GetClipboardData(CF_TEXT_T);
if (hClipboardData)
{
TCHAR *pchData = (TCHAR*) GlobalLock(hClipboardData);
if (pchData)
{
strData = pchData;
GlobalUnlock(hClipboardData);
}
}
CloseClipboard();
}
return strData;
}

bool setClipboard(CString textToclipboard)
{
bool success = true;

if (OpenClipboard(NULL))
{
EmptyClipboard();
size_t size = (textToclipboard.GetLength()+1) * sizeof(TCHAR);
HGLOBAL hClipboardData = GlobalAlloc(NULL, size);
if (hClipboardData)
{
TCHAR* pchData = (TCHAR*) GlobalLock(hClipboardData);
if (pchData)
{
memcpy(pchData, (TCHAR*) textToclipboard.GetString(), size);
GlobalUnlock(hClipboardData);
SetClipboardData(CF_TEXT_T, hClipboardData);
}
}
CloseClipboard();
}
return success;
}

Getting data from clipboard

The comments have given enough information to fix this problem.

In the Start() function, you need some API calls, such as OpenClipboard, SetClipboardData.

And you did not set isopen to true, so when debugging, you will find that the breakpoint cannot reach GetClipboardData ().

Add the following code to test:

Start(void)
{
const char* output = "Hello World";
const size_t len = strlen(output) + 1;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), output, len);
GlobalUnlock(hMem);
if (!OpenClipboard(NULL))
{
return;
}
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
this->isopen = TRUE;
}

Note: The above code uses SetClipboardData to copy the text to the clipboard, and then uses GetClipboardData to get the text.

You can also use the clipboard to copy text yourself. Run the code and check whether the return value of the GetClipboardSequenceNumber function has changed. If it changes, it means that the clipboard contents have changed or the clipboard has been emptied.

Code Sample:

#include <iostream>
#include <windows.h>
#include <cstring>

namespace Diall_ClipBoard_catch
{
class ClipBoard
{
private:
::HANDLE dHDat;
::std::string tmpstringsign;
bool isopen;
char* dHbuffer;
char* dHbuffertemp;
char* dNtoken;
public:
ClipBoard(void)
{
this->dHbuffer = const_cast <char*>("");
this->dHbuffertemp = const_cast <char*>("");
this->tmpstringsign = "dnb_4554_2102";
this->isopen = false;
};
~ClipBoard(void)
{

}
void GetData(void)
{
this->Start();
if (this->isopen)
{
this->dHDat = ::GetClipboardData(CF_TEXT);

if (this->dHDat)
{
this->dHbuffer = (char*)::GlobalLock(this->dHDat);

if (::std::strcmp(this->dHbuffertemp, this->dHbuffer) != 0 && this->dHbuffer != "" && this->dHbuffer != NULL)
{
this->dHbuffertemp = this->dHbuffer;
::std::cout << this->dHbuffer << "\n";
}

::GlobalUnlock(this->dHDat);
}
EmptyClipboard();
CloseClipboard();
this->isopen = FALSE;
::Sleep(1000);
}
}
private:
void Start(void)
{
if (!OpenClipboard(NULL))
{
return;
}
this->isopen = TRUE;
}
};
}

int main()
{
::Diall_ClipBoard_catch::ClipBoard* clipboard = new Diall_ClipBoard_catch::ClipBoard();
int temp1 = 0, temp2 = 0;
EmptyClipboard();
while (1)
{
temp1 = GetClipboardSequenceNumber();
if (temp1!= temp2)
{
clipboard->GetData();
}

temp2 = temp1;
}
return 0;
}

Debug:

1

Pasting after SetClipboardData() in C++ does not include newlines for Notepad

The excel_str must have the CRLF line endings. Here is example code to convert string to the good format:

string replaceAll(string in, string replaceIn, string replaceOut)
{
size_t pos = 0;
while(pos < in.size())
{
size_t pos2 = in.find(replaceIn, pos);
if(pos2 != string::npos)
{
in.replace(in.begin() + pos2, in.begin() + pos2 + replaceIn.size(), replaceOut);
pos = pos2 + replaceOut.size();
}
else
break;
}
return in;
}

Clipboard data set as CF_TEXT can't be retrieved correctly as CF_UNICODETEXT

You're probably missing the CF_LOCALE for Russian? CF_TEXT is interpreted using the system locale, unless specified otherwise. If your system locale charset is CP1252, but your app locale is CP1251, windows will mis-guess when it converts your 8 bits text to Unicode.

Local copy of clipboard memory?

  1. You get access to a shared memory.
  2. Clipboard memory is allocated as GMEM_MOVEABLE! So to receive the actual pointer you need GlobalLock
  3. The Clipboard Memory (even the copy in your process) is owned by the Clipboard and freed by the Clipboard handler. You are never allowed to free the memory. The memory may be freed when calling CloseClipboard

For more internals about the clipboard please read this.



Related Topics



Leave a reply



Submit