Issue
I have this structure in my C++ code:
struct sData
{
DWORD Number;
int CurrentNumber;
bool GameOver;
};
I need to save it to Clipboard as a structure from one process. And from other process I need to load it again as the structure. I can do it easy with Cstrings/strings but not with structures. What do you suggest to me?
This is my method for setting Cstring to Clipboard:
bool SetText(CString text)
{
CString source;
source = text;
//put your text in source
if (OpenClipboard(NULL))
{
HGLOBAL clipbuffer;
char * buffer;
EmptyClipboard();
clipbuffer = GlobalAlloc(GMEM_DDESHARE, source.GetLength() + 1);
buffer = (char*)GlobalLock(clipbuffer);
strcpy(buffer, LPCSTR(source));
GlobalUnlock(clipbuffer);
SetClipboardData(CF_TEXT, clipbuffer);
CloseClipboard();
return true;
}
else
{
return false;
}
}
And this is getter:
std::string GetText(void) const
{
return (const char*)GetClipboardData(CF_TEXT);
}
Solution
You need to register your own clipboard format, then you can store the struct
data as-is.
static UINT CF_MYSTRUCTDATA = RegisterClipboardFormat(TEXT("MyStructData"));
#pragma pack(push, 1)
struct sData
{
DWORD Number;
int CurrentNumber;
bool GameOver;
};
#pragma pack(pop)
bool SetData(const sData &data)
{
if (CF_MYSTRUCTDATA == 0)
return false;
bool bOK = false;
if (OpenClipboard(NULL))
{
if (EmptyClipboard())
{
HGLOBAL clipbuffer = GlobalAlloc(GMEM_MOVEABLE, sizeof(sData));
if (clipbuffer)
{
sData *buffer = (sData*) GlobalLock(clipbuffer);
if (buffer)
{
*buffer = data;
GlobalUnlock(clipbuffer);
bOK = SetClipboardData(CF_MYSTRUCTDATA, clipbuffer);
}
if (!bOK)
GlobalFree(clipbuffer);
}
}
CloseClipboard();
}
return bOK;
}
bool GetData(sData &data) const
{
if (CF_MYSTRUCTDATA == 0)
return false;
bool bOk = false;
if (OpenClipboard(NULL))
{
HANDLE clipbuffer = GetClipboardData(CF_MYSTRUCTDATA);
if (clipbuffer)
{
sData *buffer = (sData*) GlobalLock(clipbuffer);
if (buffer)
{
data = *buffer;
GlobalUnlock(clipbuffer);
bOK = true;
}
}
CloseClipboard();
}
return bOK;
}
Alternatively, using some C++ RAII wrappers:
struct Clipboard
{
Clipboard(HWND hWnd = NULL)
{
if (!OpenClipboard(hWnd))
throw std::runtime_error("Error opening clipboard");
}
~Clipboard()
{
CloseClipboard();
}
void Empty()
{
if (!EmptyClipboard())
throw std::runtime_error("Error emptying clipboard");
}
template<typename T>
struct DataBuffer
{
HGLOBAL _hmem;
bool _free;
struct Lock
{
DataBuffer& _buffer;
T* _data;
Lock(DataBuffer &buffer)
: _buffer(buffer), _locked(false)
{
_data = (T*) GlobalLock(_buffer.Get());
if (!_data)
throw std::runtime_error("Error locking memory");
}
~Lock()
{
GlobalUnlock(_buffer.Get());
}
T& Data() { return *_data; }
};
DataBuffer(const T &data)
: _hmem(NULL), _free(true)
{
_hmem = GlobalAlloc(GMEM_MOVEABLE, sizeof(T));
if (!_hmem)
throw std::runtime_error("Error allocating memory");
Lock(*this).Data() = data;
}
DataBuffer(HGLOBAL hmem)
: _hmem(mem), _free(false)
{
if (GlobalSize(_hmem)) < sizeof(T))
throw std::runtime_error("Bad memory size");
}
~DataBuffer()
{
if ((_hmem) && (_free))
GlobalFree(_hmem);
}
HGLOBAL Release()
{
HGLOBAL tmp = _hmem;
_hmem = NULL;
return tmp;
}
HGLOBAL Get()
{
return _hmem;
}
void Copy(T &data)
{
data = Lock(*this).Data();
}
};
template<typename T>
void SetData(UINT format, const T &data)
{
DataBuffer<T> buffer(data);
if (!SetClipboardData(format, buffer.Get()))
throw std::runtime_error("Error setting clipboard data");
buffer.Release();
}
template<typename T>
void GetData(UINT format, T &data)
{
DataBuffer<T> buffer(GetClipboardData(format));
if (!buffer.Get())
throw std::runtime_error("Error getting clipboard data");
buffer.Copy(data);
}
};
bool SetData(const sData &data)
{
if (CF_MYSTRUCTDATA != 0)
{
try
{
Clipboard clipbrd;
clipbrd.Empty();
clipbrd.SetData(CF_MYSTRUCTDATA, data);
return true;
}
catch (const std::runtime_error&)
{
}
}
return false;
}
bool GetData(sData &data) const
{
if (CF_MYSTRUCTDATA != 0)
{
try
{
Clipboard clipbrd;
clipbrd.GetData(CF_MYSTRUCTDATA, data);
return true;
}
catch (const std::runtime_error&)
{
}
}
return false;
}
Answered By – Remy Lebeau
Answer Checked By – Willingham (BugsFixing Volunteer)