Create data on clipboard through code

May 4, 2018 at 7:21am
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 May 4, 2018 at 7:25am
May 4, 2018 at 11:01am
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 May 4, 2018 at 11:02am
May 7, 2018 at 10:45am
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.

May 7, 2018 at 12:40pm
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);

}
May 7, 2018 at 2:33pm
I have the same problem!!
May 8, 2018 at 1:05pm
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.
May 8, 2018 at 1:54pm
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 May 8, 2018 at 2:00pm
May 22, 2018 at 5:10am
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.