2021-01-24

17: Windows Clipboard with C++: in Multi-Formats

<The previous article in this series | The table of contents of this series | The next article in this series>

The Win32 API is used. All the formats including 'Bitmap' and 'EnhancedMetafile' are supported.

Topics


About: C++

The table of contents of this article


Starting Context


  • The reader has a basic knowledge on C++.

Target Context


  • The reader will know how to get and set any composite of format-specific data from and to the Windows clipboard, in C++.

Orientation


All the formats are supported by this technique.

All the formats are supported by a technique in C++ for Linux, as will be introduced in a future article.

Many, but not all the, formats are supported by a technique in Python for Linux and Microsoft Windows.

Many, but not all the, formats are supported by a technique in C# for Microsoft Windows.


Main Body


1: Aim: to Implement Multiple Copy Buffers for a Word Processor


Hypothesizer 7
As I use Vim as a text editor, one of the benefits is that it has multiple copy buffers: I can copy a piece of text to the buffer 'a', another piece of text to the buffer 'b', etc.. That is huge help.

As I use LibreOffice Writer as a word processor, I want that functionality in it.

In fact, I tried to implement the functionality in Python, and it works partially, but not ideally.

The 2 dissatisfactions about the technique are 1) the possible datum formats have to be known a priori and 2) the supported datum formats are limited.

So, I tried to implement the functionality in C#, and it works better, but not ideally.

The dissatisfaction about the technique is that the supported datum formats are still limited.

After all, I seem to have to directly use the Win32 API, in order to fully handle the Windows clipboard.

If the Win32 API functionality is satisfactory, I can incorporate it into a global UNO service, which my Python macro will use.


2: The Basics of the Win32 API Clipboard Functionality


Hypothesizer 7
Each datum format is identified by a number, and the name of the format cannot be necessarily gotten, API-wise.

For example, the name of the format identified by '1' (which is the 'Text' format) cannot be gotten with the 'GetClipboardFormatNameA (UINT format, LPSTR lpszFormatName, int cchMaxCount)' function.

However, each of such formats has a fixed number, while the number of each of the other formats is ephemeral (which means that the format takes a number at a time and another number at another time).

The clipboard needs to be explicitly opened and closed with the functions, 'OpenClipboard (HWND hWndNewOwner)' and 'CloseClipboard ()'.

The format numbers in the clipboard can be enumerated with the 'EnumClipboardFormats' function.

The handle to the datum of each format can be gotten with the 'GetClipboardData (UINT uFormat)' function.

It is important to know that the datum of each format cannot necessarily be gotten in a straightforward way as a bytes array.

For example, the handle I get for the 'Bitmap' format is an 'HBITMAP' handle, and I have to use a specific function (like 'GetObject (HANDLE h, int c, LPVOID pv)') in order to retrieve the 'Bitmap' datum.

But, in fact, many formats allow the data to be gotten in a uniform way (via the 'GlobalLock (HGLOBAL hMem)' function) as bytes arrays.

It is likewise for setting the stashed data to the clipboard: many formats allow the data to be set in a uniform way ('GlobalLock (HGLOBAL hMem)' is used), but each of the others requires a specific handing.

For example, I use the 'CreateBitmapIndirect (const BITMAP *pbm)' function in order to set the 'Bitmap' datum.

Anyway, 'SetClipboardData (UINT uFormat, HANDLE hMem)' is used after all.


3: My Code


Hypothesizer 7
As my aim is to store a history of clipboard data, I have created some classes as the storage, like these.

theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDatum.hpp

@C++ Source Code
#ifndef __theBiasPlanet_coreUtilities_clipboardHandling_ClipboardFormatSpecificDatum_hpp__
	#define __theBiasPlanet_coreUtilities_clipboardHandling_ClipboardFormatSpecificDatum_hpp__
	
	#include <string>
	#include "theBiasPlanet/coreUtilities/visualCplusplusSpecificHeaders/VisualCplusplusSpecificDefinitions.hpp"
	
	namespace theBiasPlanet {
		namespace coreUtilities {
			namespace clipboardHandling {
				class __theBiasPlanet_coreUtilities_symbolExportingOrImportingForVisualCplusplus__ ClipboardFormatSpecificDatum {
					private:
						::std::string i_formatName;
						unsigned int i_formatNumber;
						bool i_datumIsArray;
						int i_datumSize;
						void * i_datum;
					public:
						ClipboardFormatSpecificDatum ();
						ClipboardFormatSpecificDatum (::std::string const & a_formatName, unsigned int const & a_formatNumber, bool const & a_datumIsArray, int const & a_datumSize, void * const a_datum);
						virtual ~ClipboardFormatSpecificDatum ();
						ClipboardFormatSpecificDatum (ClipboardFormatSpecificDatum const & a_copiedObject) = delete; // because the datum is not meant to be shared by multiple instances
						virtual ClipboardFormatSpecificDatum & operator = (ClipboardFormatSpecificDatum const & a_assignedFromObject) = delete; // because the datum is not meant to be shared by multiple instances
						virtual ::std::string const & getFormatName () const;
						virtual unsigned int const & getFormatNumber () const;
						virtual int const & getDatumSize () const;
						virtual void * const getDatum () const;
				};
			}
		}
	}
#endif

theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDatum.cpp

@C++ Source Code
#include "theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDatum.hpp"

namespace theBiasPlanet {
	namespace coreUtilities {
		namespace clipboardHandling {
			ClipboardFormatSpecificDatum::ClipboardFormatSpecificDatum () {
			}
			
			ClipboardFormatSpecificDatum::ClipboardFormatSpecificDatum (::std::string const & a_formatName, unsigned int const & a_formatNumber, bool const & a_datumIsArray, int const & a_datumSize, void * const a_datum): i_formatName (a_formatName), i_formatNumber (a_formatNumber), i_datumIsArray (a_datumIsArray), i_datumSize (a_datumSize), i_datum (a_datum) {
			}
			
			ClipboardFormatSpecificDatum::~ClipboardFormatSpecificDatum () {
				if (i_datumIsArray) {
					delete [] i_datum;
				}
				else {
					delete i_datum;
				}
			}
			
			::std::string const & ClipboardFormatSpecificDatum::getFormatName () const {
				return i_formatName;
			}
			
			unsigned int const & ClipboardFormatSpecificDatum::getFormatNumber () const {
				return static_cast <unsigned int const> (i_formatNumber);
			}
			
			int const & ClipboardFormatSpecificDatum::getDatumSize () const {
				return i_datumSize;
			}
			
			void * const ClipboardFormatSpecificDatum::getDatum () const {
				return i_datum;
			}
		}
	}
}

theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataComposite.hpp

@C++ Source Code
#ifndef __theBiasPlanet_coreUtilities_clipboardHandling_ClipboardFormatSpecificDataComposite_hpp__
	#define __theBiasPlanet_coreUtilities_clipboardHandling_ClipboardFormatSpecificDataComposite_hpp__
	
	#include <list>
	#include <string>
	#include "theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDatum.hpp"
	#include "theBiasPlanet/coreUtilities/collections/NavigableLinkedMap.hpp"
	#include "theBiasPlanet/coreUtilities/visualCplusplusSpecificHeaders/VisualCplusplusSpecificDefinitions.hpp"
	
	using namespace ::theBiasPlanet::coreUtilities::collections;
	
	namespace theBiasPlanet {
		namespace coreUtilities {
			namespace clipboardHandling {
				class __theBiasPlanet_coreUtilities_symbolExportingOrImportingForVisualCplusplus__ ClipboardFormatSpecificDataComposite {
					private:
						NavigableLinkedMap <::std::string const, ClipboardFormatSpecificDatum const *> i_formatNameToDatumMap;
					public:
						ClipboardFormatSpecificDataComposite ();
						virtual ~ClipboardFormatSpecificDataComposite ();
						ClipboardFormatSpecificDataComposite (ClipboardFormatSpecificDataComposite const & a_copiedObject) = delete; // because the data are not meant to be shared by multiple instances
						virtual ClipboardFormatSpecificDataComposite & operator = (ClipboardFormatSpecificDataComposite const & a_assignedFromObject) = delete; // because the data are not meant to be shared by multiple instances
						virtual bool addFormatSpecificDatum (ClipboardFormatSpecificDatum const * const a_formatSpecificDatum);
						virtual ::std::list <::std::string> getFormatNames () const;
						virtual ClipboardFormatSpecificDatum const * const getFormatSpecificDatum (::std::string const & a_formatName) const;
				};
			}
		}
	}
#endif

theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataComposite.cpp

@C++ Source Code
#include "theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataComposite.hpp"

namespace theBiasPlanet {
	namespace coreUtilities {
		namespace clipboardHandling {
			ClipboardFormatSpecificDataComposite::ClipboardFormatSpecificDataComposite () {
			}
			
			ClipboardFormatSpecificDataComposite::~ClipboardFormatSpecificDataComposite () {
				for (::std::pair <::std::string const, ClipboardFormatSpecificDatum const *> const & l_formatNameToDatumMapEntry: i_formatNameToDatumMap) {
					delete l_formatNameToDatumMapEntry.second;
				}
			}
			
			bool ClipboardFormatSpecificDataComposite::addFormatSpecificDatum (ClipboardFormatSpecificDatum const * const a_formatSpecificDatum) {
				i_formatNameToDatumMap [a_formatSpecificDatum->getFormatName ()] = a_formatSpecificDatum;
				return true;
			}
			
			::std::list <::std::string> ClipboardFormatSpecificDataComposite::getFormatNames () const {
				::std::list <::std::string> l_formatNames;
				for (::std::pair <::std::string const, ClipboardFormatSpecificDatum const *> const & l_formatNameToDatumMapEntry: i_formatNameToDatumMap) {
					l_formatNames.push_back (l_formatNameToDatumMapEntry.first);
				}
				return l_formatNames;
			}
			
			ClipboardFormatSpecificDatum const * const ClipboardFormatSpecificDataComposite::getFormatSpecificDatum (::std::string const & a_formatName) const {
				return i_formatNameToDatumMap.at (a_formatName);
			}
		}
	}
}

theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataCompositesHistory.hpp

@C++ Source Code
#ifndef __theBiasPlanet_coreUtilities_clipboardHandling_ClipboardFormatSpecificDataCompositesHistory_hpp__
	#define __theBiasPlanet_coreUtilities_clipboardHandling_ClipboardFormatSpecificDataCompositesHistory_hpp__
	
	#include "theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataComposite.hpp"
	#include "theBiasPlanet/coreUtilities/collections/NavigableLinkedMap.hpp"
	#include "theBiasPlanet/coreUtilities/visualCplusplusSpecificHeaders/VisualCplusplusSpecificDefinitions.hpp"
	
	using namespace ::theBiasPlanet::coreUtilities::collections;
	
	namespace theBiasPlanet {
		namespace coreUtilities {
			namespace clipboardHandling {
				class __theBiasPlanet_coreUtilities_symbolExportingOrImportingForVisualCplusplus__ ClipboardFormatSpecificDataCompositesHistory {
					private:
						NavigableLinkedMap <string const, ClipboardFormatSpecificDataComposite const *> i_dataCompositeKeyToDataCompositeMap;
					public:
						ClipboardFormatSpecificDataCompositesHistory ();
						virtual ~ClipboardFormatSpecificDataCompositesHistory ();
						ClipboardFormatSpecificDataCompositesHistory (ClipboardFormatSpecificDataCompositesHistory const & a_copiedObject) = delete; // because the data are not meant to be shared by multiple instances
						virtual ClipboardFormatSpecificDataCompositesHistory & operator = (ClipboardFormatSpecificDataCompositesHistory const & a_assignedFromObject) = delete; // because the data are not meant to be shared by multiple instances
						virtual bool addDataComposite (string const & a_dataCompositeKey, ClipboardFormatSpecificDataComposite const * const a_dataComposite);
						virtual bool removeDataComposite (string const & a_dataCompositeKey);
						virtual ClipboardFormatSpecificDataComposite const * const getDataComposite (string const & a_dataCompositeKey);
				};
			}
		}
	}
#endif

theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataCompositesHistory.cpp

@C++ Source Code
#include "theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataCompositesHistory.hpp"

namespace theBiasPlanet {
	namespace coreUtilities {
		namespace clipboardHandling {
			ClipboardFormatSpecificDataCompositesHistory::ClipboardFormatSpecificDataCompositesHistory () {
			}
			
			ClipboardFormatSpecificDataCompositesHistory::~ClipboardFormatSpecificDataCompositesHistory () {
				for (::std::pair <string const, ClipboardFormatSpecificDataComposite const *> const & l_dataCompositeKeyToDataCompositeMapEntry: i_dataCompositeKeyToDataCompositeMap) {
					delete l_dataCompositeKeyToDataCompositeMapEntry.second;
				}
			}
			
			bool ClipboardFormatSpecificDataCompositesHistory::addDataComposite (string const & a_dataCompositeKey, ClipboardFormatSpecificDataComposite const * const a_dataComposite) {
				i_dataCompositeKeyToDataCompositeMap [a_dataCompositeKey] = a_dataComposite;
				return true;
			}
			
			bool ClipboardFormatSpecificDataCompositesHistory::removeDataComposite (string const & a_dataCompositeKey) {
				delete i_dataCompositeKeyToDataCompositeMap.at (a_dataCompositeKey);
				i_dataCompositeKeyToDataCompositeMap.erase (i_dataCompositeKeyToDataCompositeMap.find (a_dataCompositeKey));
				return true;
			}
			
			ClipboardFormatSpecificDataComposite const * const ClipboardFormatSpecificDataCompositesHistory::getDataComposite (string const & a_dataCompositeKey) {
				return i_dataCompositeKeyToDataCompositeMap.at (a_dataCompositeKey);
			}
		}
	}
}

The clipboard handling class is this.

theBiasPlanet/coreUtilities/clipboardHandling/MicrosoftWindowsClipboard.hpp

@C++ Source Code
#ifndef GCC
	#ifndef __theBiasPlanet_coreUtilities_clipboardHandling_MicrosoftWindowsClipboard_hpp__
		#define __theBiasPlanet_coreUtilities_clipboardHandling_MicrosoftWindowsClipboard_hpp__
		
		#include "theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataComposite.hpp"
		#include "theBiasPlanet/coreUtilities/visualCplusplusSpecificHeaders/VisualCplusplusSpecificDefinitions.hpp"
		
		namespace theBiasPlanet {
			namespace coreUtilities {
				namespace clipboardHandling {
					class __theBiasPlanet_coreUtilities_symbolExportingOrImportingForVisualCplusplus__ MicrosoftWindowsClipboard {
						private:
						public:
							static bool openClipboard ();
							static bool closeClipboard ();
							static bool clearClipboard ();
							static ClipboardFormatSpecificDataComposite * const getFormatSpecificDataComposite ();
							static bool setFormatSpecificDataComposite (ClipboardFormatSpecificDataComposite const * const a_formatSpecificDataComposite);
					};
				}
			}
		}
	#endif
#endif

theBiasPlanet/coreUtilities/clipboardHandling/MicrosoftWindowsClipboard.cpp

@C++ Source Code
#ifndef GCC
	#include <windows.h> // This has to be before the primary header file in order to avoid the conflict of the '::std::' namespace and the Win32 API namespace.
	#include "theBiasPlanet/coreUtilities/clipboardHandling/MicrosoftWindowsClipboard.hpp"
	#include "theBiasPlanet/coreUtilities/messagingHandling/Publisher.hpp"
	#include "theBiasPlanet/coreUtilities/stringsHandling/StringHandler.hpp"
	
	using namespace ::theBiasPlanet::coreUtilities::messagingHandling;
	using namespace ::theBiasPlanet::coreUtilities::stringsHandling;
	
	namespace theBiasPlanet {
		namespace coreUtilities {
			namespace clipboardHandling {
				bool MicrosoftWindowsClipboard::openClipboard () {
					return OpenClipboard (nullptr);
				}
				
				bool MicrosoftWindowsClipboard::closeClipboard () {
					return CloseClipboard ();
				}
				
				bool MicrosoftWindowsClipboard::clearClipboard () {
					return EmptyClipboard ();
				}
				
				ClipboardFormatSpecificDataComposite * const MicrosoftWindowsClipboard::getFormatSpecificDataComposite () {
					UINT l_datumFormatNumber = 0;
					int l_datumFormatNameMaximumSize = 100;
					HGLOBAL l_datumFormatNameGlobalMemoryArea = GlobalAlloc (GMEM_MOVEABLE, l_datumFormatNameMaximumSize);
					LPSTR l_datumFormatName = (LPSTR) GlobalLock (l_datumFormatNameGlobalMemoryArea);
					ClipboardFormatSpecificDataComposite * const l_formatSpecificDataComposite = new ClipboardFormatSpecificDataComposite ();
					while (true) {
						l_datumFormatNumber = EnumClipboardFormats (l_datumFormatNumber);
						if (l_datumFormatNumber == 0) {
							break;
						}
						if (l_datumFormatNumber == 1) {
							strcpy (l_datumFormatName, "Text");
						}
						else if (l_datumFormatNumber == 2) {
							strcpy (l_datumFormatName, "Bitmap");
						}
						else if (l_datumFormatNumber == 3) {
							strcpy (l_datumFormatName, "MetaFilePict");
						}
						else if (l_datumFormatNumber == 4) {
							strcpy (l_datumFormatName, "SymbolicLink");
						}
						else if (l_datumFormatNumber == 5) {
							strcpy (l_datumFormatName, "DataInterchangeFormat");
						}
						else if (l_datumFormatNumber == 7) {
							strcpy (l_datumFormatName, "OEMText");
						}
						else if (l_datumFormatNumber == 8) {
							strcpy (l_datumFormatName, "DeviceIndependentBitmap");
						}
						else if (l_datumFormatNumber == 13) {
							strcpy (l_datumFormatName, "UnicodeText");
						}
						else if (l_datumFormatNumber == 14) {
							strcpy (l_datumFormatName, "EnhancedMetafile");
						}
						else if (l_datumFormatNumber == 16) {
							strcpy (l_datumFormatName, "Locale");
						}
						else if (l_datumFormatNumber == 17) {
							strcpy (l_datumFormatName, "Format17");
						}
						else {
							strcpy (l_datumFormatName, "???");
							GetClipboardFormatNameA (l_datumFormatNumber, l_datumFormatName, l_datumFormatNameMaximumSize);
						}
						HANDLE l_formatSpecificDatumHandle = GetClipboardData (l_datumFormatNumber);
						if (l_formatSpecificDatumHandle != nullptr) {
							if (l_datumFormatNumber == 2) {
								HBITMAP l_formatSpecificDatumHandleForBitmap = (HBITMAP) l_formatSpecificDatumHandle;
								BITMAP * const l_copiedFormatSpecificDatumForBitmap = new BITMAP ();
								GetObject (l_formatSpecificDatumHandleForBitmap, sizeof (BITMAP), l_copiedFormatSpecificDatumForBitmap);
								l_formatSpecificDataComposite->addFormatSpecificDatum (new ClipboardFormatSpecificDatum (l_datumFormatName, l_datumFormatNumber, false, sizeof (BITMAP), l_copiedFormatSpecificDatumForBitmap));
							}
							else if (l_datumFormatNumber == 14) {
								HENHMETAFILE l_formatSpecificDatumHandleForEnhancedMetafile = (HENHMETAFILE) l_formatSpecificDatumHandle;
								int const l_formatSpecificDatumForEnhancedMetafileMaximumSize = 10000;
								::std::byte * const l_copiedFormatSpecificDatumForEnhancedMetafile = new ::std::byte [l_formatSpecificDatumForEnhancedMetafileMaximumSize];
								int const l_formatSpecificDatumForEnhancedMetafileSize (GetEnhMetaFileBits (l_formatSpecificDatumHandleForEnhancedMetafile, l_formatSpecificDatumForEnhancedMetafileMaximumSize, (LPBYTE) l_copiedFormatSpecificDatumForEnhancedMetafile));
								l_formatSpecificDataComposite->addFormatSpecificDatum (new ClipboardFormatSpecificDatum (l_datumFormatName, l_datumFormatNumber, true, l_formatSpecificDatumForEnhancedMetafileSize, l_copiedFormatSpecificDatumForEnhancedMetafile));
							}
							else {
								LPVOID l_formatSpecificDatumForUsualFormats = GlobalLock (l_formatSpecificDatumHandle);
								if (l_formatSpecificDatumForUsualFormats != nullptr) {
									SIZE_T l_formatSpecificDatumSizeForUsualFormats = GlobalSize (l_formatSpecificDatumHandle);
									::std::byte * const l_copiedFormatSpecificDatumForUsualFormats = new ::std::byte [l_formatSpecificDatumSizeForUsualFormats];
									::std::memcpy (l_copiedFormatSpecificDatumForUsualFormats, l_formatSpecificDatumForUsualFormats, l_formatSpecificDatumSizeForUsualFormats);
									l_formatSpecificDataComposite->addFormatSpecificDatum (new ClipboardFormatSpecificDatum (l_datumFormatName, l_datumFormatNumber, true, l_formatSpecificDatumSizeForUsualFormats, l_copiedFormatSpecificDatumForUsualFormats));
									GlobalUnlock (l_formatSpecificDatumHandle);
								}
								else {
									Publisher::logWarningInformation (StringHandler::format (::std::string ("The clipboard datum for the '%d' format could not be gotten."), (int) l_datumFormatNumber));
								}
							}
						}
						else {
							return false;
						}
					}
					GlobalUnlock (l_datumFormatNameGlobalMemoryArea);
					GlobalFree (l_datumFormatNameGlobalMemoryArea);
					return l_formatSpecificDataComposite;
				}
				
				bool MicrosoftWindowsClipboard::setFormatSpecificDataComposite (ClipboardFormatSpecificDataComposite const * const a_formatSpecificDataComposite) {
					for (::std::string const & l_datumFormatName: a_formatSpecificDataComposite->getFormatNames ()) {
						ClipboardFormatSpecificDatum const * const l_formatSpecificDatum (a_formatSpecificDataComposite->getFormatSpecificDatum (l_datumFormatName));
						if (l_datumFormatName == "Bitmap") {
							BITMAP const * const l_copiedFormatSpecificDatumForBitmap = (BITMAP const * const) (l_formatSpecificDatum->getDatum ());
							HBITMAP l_formatSpecificDatumHandleForBitmap = CreateBitmapIndirect (l_copiedFormatSpecificDatumForBitmap);
							HANDLE l_formatSpecificDatumHandle = SetClipboardData (l_formatSpecificDatum->getFormatNumber (), l_formatSpecificDatumHandleForBitmap);
						}
						else if (l_datumFormatName == "EnhancedMetafile") {
							LPBYTE const l_copiedFormatSpecificDatumForEnhancedMetafile = (LPBYTE const) (l_formatSpecificDatum->getDatum ());
							HENHMETAFILE l_formatSpecificDatumHandleForEnhancedMetafile = SetEnhMetaFileBits (l_formatSpecificDatum->getDatumSize (), l_copiedFormatSpecificDatumForEnhancedMetafile);
							HANDLE l_formatSpecificDatumHandle = SetClipboardData (l_formatSpecificDatum->getFormatNumber (), l_formatSpecificDatumHandleForEnhancedMetafile);
						}
						else {
							::std::byte const * const l_copiedFormatSpecificDatumForUsualFormats = (::std::byte const * const) (l_formatSpecificDatum->getDatum ());
							HGLOBAL l_formatSpecificDatumForUsualFormatsGlobalMemoryArea = GlobalAlloc (GMEM_MOVEABLE, l_formatSpecificDatum->getDatumSize ());
							LPBYTE l_formatSpecificDatumForUsualFormats = (LPBYTE) GlobalLock (l_formatSpecificDatumForUsualFormatsGlobalMemoryArea);
							::std::memcpy (l_formatSpecificDatumForUsualFormats, l_copiedFormatSpecificDatumForUsualFormats, l_formatSpecificDatum->getDatumSize ());
							GlobalUnlock (l_formatSpecificDatumForUsualFormatsGlobalMemoryArea);
							HANDLE l_formatSpecificDatumHandle = SetClipboardData (l_formatSpecificDatum->getFormatNumber (), l_formatSpecificDatumForUsualFormatsGlobalMemoryArea);
						}
					}
					return true;
				}
			}
		}
	}
#endif

Although I have noticed only 'Bitmap' and 'EnhancedMetafile' as datum formats that require special treatments, if I notice more, I will have to deal with them too.


4: Testing


Hypothesizer 7
My test code is this.

theBiasPlanet/coreUtilitiesTests/clipboardHandlingTest1/Test1Test.hpp

@C++ Source Code
#include <string>

using namespace ::std;

namespace theBiasPlanet {
	namespace coreUtilitiesTests {
		namespace clipboardHandlingTest1 {
			class Test1Test {
				public:
					static int main (int const & a_argumentsNumber, char const * const a_argumentsArray []);
					static void test ();
			};
		}
	}
}

theBiasPlanet/coreUtilitiesTests/clipboardHandlingTest1/Test1Test.cpp

@C++ Source Code
#include "theBiasPlanet/coreUtilitiesTests/clipboardHandlingTest1/Test1Test.hpp"
#include <iostream>
#include <list>
#include "theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataComposite.hpp"
#include "theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataCompositesHistory.hpp"
#include "theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDatum.hpp"
#include "theBiasPlanet/coreUtilities/clipboardHandling/MicrosoftWindowsClipboard.hpp"
#include "theBiasPlanet/coreUtilities/messagingHandling/Publisher.hpp"
#include "theBiasPlanet/coreUtilities/stringsHandling/StringHandler.hpp"

using namespace ::std;
using namespace  ::theBiasPlanet::coreUtilities::clipboardHandling;
using namespace  ::theBiasPlanet::coreUtilities::messagingHandling;
using namespace  ::theBiasPlanet::coreUtilities::stringsHandling;

namespace theBiasPlanet {
	namespace coreUtilitiesTests {
		namespace clipboardHandlingTest1 {
			int Test1Test::main (int const & a_argumentsNumber, char const * const a_argumentsArray []) {
				Publisher::setLoggingLevel (3);
				test ();
				return 0;
			}
			
			void Test1Test::test () {
				ClipboardFormatSpecificDataCompositesHistory l_clipbardFormatSpecificDataCompositesHistory;
				while (true) {
					cout << "### Input 'S' (Set), 'G' (Get), 'D (Display)', or 'Q' (Quit):" << endl << flush;
					string l_userInput;
					getline (cin, l_userInput);
					string l_clipboardFormatSpecificDataCompositeKey;
					if (l_userInput == string ("S") || l_userInput == string ("G") || l_userInput == string ("D")) {
						cout << "### Input the key:" << endl << flush;
						getline (cin, l_clipboardFormatSpecificDataCompositeKey);
						if (l_userInput == string ("S")) {
#ifndef GCC
							MicrosoftWindowsClipboard::openClipboard ();
							MicrosoftWindowsClipboard::clearClipboard ();
							MicrosoftWindowsClipboard::setFormatSpecificDataComposite (l_clipbardFormatSpecificDataCompositesHistory.getDataComposite (l_clipboardFormatSpecificDataCompositeKey));
							MicrosoftWindowsClipboard::closeClipboard ();
#endif
						}
						else if (l_userInput == string ("G")) {
#ifndef GCC
							MicrosoftWindowsClipboard::openClipboard ();
							l_clipbardFormatSpecificDataCompositesHistory.addDataComposite (l_clipboardFormatSpecificDataCompositeKey, MicrosoftWindowsClipboard::getFormatSpecificDataComposite ());
							MicrosoftWindowsClipboard::closeClipboard ();
#endif
						}
						else if (l_userInput == string ("D")) {
							ClipboardFormatSpecificDataComposite const * const l_clipboardFormatSpecificDataComposite = l_clipbardFormatSpecificDataCompositesHistory.getDataComposite (l_clipboardFormatSpecificDataCompositeKey);
							list <string> l_clipboardDatumFormatNames = l_clipboardFormatSpecificDataComposite->getFormatNames ();
							for (string const & l_clipboardDatumFormatName: l_clipboardDatumFormatNames) {
								ClipboardFormatSpecificDatum const * const l_clipboardFormatSpecificDatum = l_clipboardFormatSpecificDataComposite->getFormatSpecificDatum (l_clipboardDatumFormatName);
								cout <<  StringHandler::format (string ("### clipboard datum format number, format name, size: %d, %s, %d"), (int) l_clipboardFormatSpecificDatum->getFormatNumber (), l_clipboardDatumFormatName, l_clipboardFormatSpecificDatum->getDatumSize ()) << endl << flush;
							}
						}
					}
					else {
						break;
					}
				}
			}
		}
	}
}

After I have copied a text piece on a 'cmd' terminal, I get an output like this for the 'G' -> 'A' -> 'D' -> 'A' inputs.

@Output
### clipboard datum format number, format name, size: 13, UnicodeText, 12
### clipboard datum format number, format name, size: 16, Locale, 4
### clipboard datum format number, format name, size: 1, Text, 6
### clipboard datum format number, format name, size: 7, OEMText, 6

Compared with the result of the C# version, I see the basically same result.

After I have copied a text piece on a LibreOffice Writer instance, I get an output like this for the 'G' -> 'A' -> 'D' -> 'A' inputs.

@Output
### clipboard datum format number, format name, size: 49161, DataObject, 8
### clipboard datum format number, format name, size: 49937, Star Embed Source (XML), 5946
### clipboard datum format number, format name, size: 49306, Rich Text Format, 2192
### clipboard datum format number, format name, size: 49946, Richtext Format, 2192
### clipboard datum format number, format name, size: 49948, HTML (HyperText Markup Language), 641
### clipboard datum format number, format name, size: 49412, HTML Format, 900
### clipboard datum format number, format name, size: 13, UnicodeText, 8
### clipboard datum format number, format name, size: 1, Text, 4
### clipboard datum format number, format name, size: 49949, Link, 44
### clipboard datum format number, format name, size: 49950, Star Object Descriptor (XML), 81
### clipboard datum format number, format name, size: 49171, Ole Private Data, 552
### clipboard datum format number, format name, size: 16, Locale, 4
### clipboard datum format number, format name, size: 7, OEMText, 4

Compared with the result of the C# version, I see more datum formats ("DataObject", "Ole Private Data", "Locale", and "OEMText") there.


References


<The previous article in this series | The table of contents of this series | The next article in this series>