Search code examples
c++stringwinapistructclipboard

Saving struct to clipboard in C++


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;
    }