Create data on clipboard through code

Hey,

I'm currently trying to add data (virtual, files, string etc) to a clipboard which is created through code.

I've tried to do this by implementing my own IDataObject (FileDataObject) and create it with an IStream obejct:


1
2
3
4
5
6
7
8
9
10
11
12
			
auto m_dataObject = std::make_unique<FileDataObject>();
					

const char* abc = "Hello Ogden!";
auto stream = SHCreateMemStream((BYTE*)&abc, strlen(abc));
STGMEDIUM med;
med.pstm = stream;
med.lpszFileName = L"TEMP";

auto att = FileTransferUtils::GetFormatAttachments();
m_dataObject->SetData(&att, &med, false);



And then Clear the current clipboard:

OleSetClipboard(nullptr);

and then set the new IDataObject which I've created:

 
HRESULT hr = OleSetClipboard(m_dataObject.get());


But when i try to retrieve the IDataObject from the clipboard again through

1
2
IDataObject* pcb = 0;
OleGetClipboard(&pcb);


I get a different Object called CClipDataObject.


Does anyone know how to set data on the clipboard or if there is an easier way?

Last edited on
You set data with SetClipboardData(). You don't need OLE, COM, .Net .. just the old Platform SDK.

There's an example here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms649016(v=vs.85).aspx#_win32_Copying_Information_to_the_Clipboard
Last edited on
hmm ok, but i think i were able to create an IStream with a buffer on the clipboard.
Currently I'm not sure how to this should work together with the CRTL+V paste functionallity from Windows.

Currently when i use CRTL+V nothing happens. Probably my IStream data isn't set correctly so windows sees it as a file or text to be pasted.

I couldn't find anything related to this in your link @kbw.

function copiarAlPortapapeles(id_elemento) {

// Crea un campo de texto "oculto"
var aux = document.createElement("input");

// Asigna el contenido del elemento especificado al valor del campo
aux.setAttribute("value", document.getElementById(id_elemento).innerHTML);

// Añade el campo a la página
document.body.appendChild(aux);

// Selecciona el contenido del campo
aux.select();

// Copia el texto seleccionado
document.execCommand("copy");

// Elimina el campo de la página
document.body.removeChild(aux);

}
I have the same problem!!
I were able to get CRTL + V working for text only, by using the HGlobal isntead of the istream, which is still not really what i want, it might be possible that its not possible for text to work with the past functionality through streams.

But it should be possible for files at least, since i don't want to allocate the whole file content on memory before pasting it somewhere, this has to work with istreams.

I only need to know how to create a file representation with a istream on the clipboard.
ok possible solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
        HGLOBAL clipbuffer;
	clipbuffer = GlobalAlloc(GMEM_DDESHARE, sizeof(FILEGROUPDESCRIPTOR));
	FILEGROUPDESCRIPTOR* buffer = (FILEGROUPDESCRIPTOR*)GlobalLock(clipbuffer);
	GlobalUnlock(clipbuffer);

	buffer->cItems = 1;
	lstrcpy(buffer->fgd[0].cFileName, L"TESTO.ogden");

HRESULT hr = OleInitialize(NULL);
	if (SUCCEEDED(hr))
	{
		IDataObject* pDataObject;
		hr = SHCreateDataObject(NULL, 0, NULL, NULL, IID_PPV_ARGS(&pDataObject));
		if (SUCCEEDED(hr))
		{
			

			IStream* pstm;
			
			{

				CHAR* data = "The big brown fox jumps over the lazy dog";
pstm = SHCreateMemStream((BYTE*)data, strlen(data) * sizeof(CHAR));

FORMATETC fmte = FileTransferUtils::GetFormatDescriptor();//{ (CLIPFORMAT)CF_TEXT , NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM };
				STGMEDIUM medium = { 0 };
				medium.tymed = TYMED_HGLOBAL;
				medium.hGlobal = clipbuffer;

				hr = pDataObject->SetData(&fmte, &medium, TRUE);



				fmte = FileTransferUtils::GetFormatContents();//{ (CLIPFORMAT)CF_TEXT , NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM };
				medium = { 0 };
				medium.tymed = TYMED_ISTREAM;
				medium.pstm = pstm;

				hr = pDataObject->SetData(&fmte, &medium, TRUE);

				
				if (SUCCEEDED(hr))
				{
					hr = OleSetClipboard(pDataObject);
					// hr = OleFlushClipboard();
				}



				// pstm->Release();
			}
			pDataObject->Release();
		}
Last edited on
ok i've found the solution myself.

You have to implement your own custom IDataObject. The default one from SHCreateDataObject only supports one IStream.
Topic archived. No new replies allowed.