I'm currently using C++Builder to create an application that copies text to the user's clipboard. I've placed a TMemo
control and I want to contain that in a const char *
variable as seen in the code below:
const char* output = TMemo1->Text;
When I compile the program it throws the error
no viable conversion from 'Vcl::Controls::TCaption' (aka 'System::UnicodeString') to 'const char *'
Here's the code that copies text to the clipboard:
const char* output = TMemo1->Text; // Error here
const size_t len = strlen(output) + 1;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), output, len);
GlobalUnlock(hMem);
OpenClipboard(0);
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
CloseClipboard();
The Text
property returns a UnicodeString
object, not a const char*
pointer. And there is no implicit conversion from UnicodeString
to const char*
(nor do you want one). So you would have to convert the data manually, such as with WideCharToMultiByte()
(or equivalent), eg:
UnicodeString text = TMemo1->Text;
const size_t len = WideCharToMultiByte(CP_ACP, 0, text.c_str(), -1, NULL, 0, NULL, NULL);
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
if (hMem)
{
char *output = (char*) GlobalLock(hMem);
WideCharToMultiByte(CP_ACP, 0, text.c_str(), -1, output, len, NULL, NULL);
GlobalUnlock(hMem);
if (OpenClipboard(0))
{
EmptyClipboard();
if (SetClipboardData(CF_TEXT, hMem))
hMem = NULL;
CloseClipboard();
}
if (hMem)
GlobalFree(hMem);
}
Alternatively, you can save the TMemo
's text to an AnsiString
and let the RTL handle the conversion for you, eg:
AnsiString output = TMemo1->Text; // <-- automatic conversion from UTF-16 to ANSI
const size_t len = (output.Length() + 1) * sizeof(System::AnsiChar);
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
if (hMem)
{
memcpy(GlobalLock(hMem), output.c_str(), len);
GlobalUnlock(hMem);
if (OpenClipboard(0))
{
EmptyClipboard();
if (SetClipboardData(CF_TEXT, hMem))
hMem = NULL;
CloseClipboard();
}
if (hMem)
GlobalFree(hMem);
}
However, since you are dealing with Unicode text, you should be using the CF_UNICODETEXT
format instead of CF_TEXT
. That way, you don't need to convert the UnicodeString
data at all, you can just store it as-is (if anybody requests CF_TEXT
from the clipboard afterwards, the clipboard itself will convert the text for you), eg:
#include <System.SysUtils.hpp> // for ByteLength()
UnicodeString output = TMemo1->Text;
const size_t len = ByteLength(output) + sizeof(System::WideChar);
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
if (hMem)
{
memcpy(GlobalLock(hMem), output.c_str(), len);
GlobalUnlock(hMem);
if (OpenClipboard(0))
{
EmptyClipboard();
if (SetClipboardData(CF_UNICODETEXT, hMem))
hMem = NULL;
CloseClipboard();
}
if (hMem)
GlobalFree(hMem);
}
That being said, you are making things harder for yourself then you need to. The VCL has a TClipboard
class that handles all of these details for you, eg:
#include <Vcl.Clipbrd.hpp>
Clipboard()->AsText = TMemo1->Text;