C++ Copy a string to Clipboard

:D Hello everyone,

I am making a program where the user types in a string and then the string is saved to the clipboard, but I am not quite sure how. I have had a look at http://www.cplusplus.com/forum/beginner/33250/ but I am not quite sure how to implement this.

I would greatly appreciate any help offered because I am a beginner.

Thanks,
Muhasaresa
Last edited on
@Muhasaresa

The post you mention (beginner/33250) incorrectly uses GMEM_FIXED rather than GMEM_MOVEABLE.

helios' code is correct in this respect, but note that there is a small error: the memory allocated should be s.size() + 1, to provide space for the string's null terminator.

Andy

P.S. And I would probably check to see that the string isn't empty before beginning the clipboard operation.
Last edited on
The null terminator is unnecessary because the clipboard uses sized strings.
I disagree!

1. It makes the corresponding paste operation that bit safer.

2. Calling c_str() on a standard string returns a pointer to a null term string, and the terminating null is part of the string. If I copy a string with memcpy (as opposed to moving chunks of string to build a new strings) I always copy the whole of the string.

Andy

P.S. I have also just had a quick check of Petzold (who draws attention to the need for room for the terminating null) and a couple of the Windows SDK samples. These are also allocating space for the terminating null.
Last edited on
If MS says so, then it must be true.

PS: Though it may seem so, I'm not being ironic.
@andywestken

Thanks for your help. In the link http://www.cplusplus.com/forum/beginner/33250/ , I was wondering what I would need to change in order for it to apply to my specific string, for example string "AAA". I'm using windows Vista and Dev C++.

Muhasaresa
Last edited on
As you should be getting the length of the string from a call to string::length (or strlen) the exact string used is irrelevent. And as the basic clipboard functionality has not changed for years, the Windows version should not matter.

The version of the source you linked to has other problems, as already mentioned. The version helios points to above is pretty much what I'd do, formatting aside, except for the change from s.size() to s.size()+1 and the OpenClipboard() call's parameter.

I usually call OpenClipboard(hwnd); -- with the call of my app's main window. I have now checked this on MSDN and while NULL (or 0) is an acceptable parameter value, the comments for this call state:

If an application calls OpenClipboard with hwnd set to NULL, EmptyClipboard sets the clipboard owner to NULL; this causes SetClipboardData to fail.


As EmptyClipboard() is being called here, you should avoid the use of a NULL window handle.

Depending on how defensive you want to be, you could check that the call to OpenClipboad succeeds. This would only fail if another application didn't successfully close the clipboard after use, leaving it locked.

Andy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void toClipboard(HWND hwnd, const std::string &s){
	OpenClipboard(hwnd);
	EmptyClipboard();	
	HGLOBAL hg=GlobalAlloc(GMEM_MOVEABLE,s.size()+1);
	if (!hg){
		CloseClipboard();
		return;
	}
	memcpy(GlobalLock(hg),s.c_str(),s.size()+1);
	GlobalUnlock(hg);
	SetClipboardData(CF_TEXT,hg);
	CloseClipboard();
	GlobalFree(hg);
}


P.S. There are other minor details you might see in similar code:
- OpenClipboard(NULL); -- the same, as NULL == 0
- GHND rather than GMEM_MOVEABLE -- GHND == GMEM_MOVEABLE | GMEM_ZEROINIT (I wouldn't use GHND here as the allocated buffer is being completely filled by memset
- some form of string copy rather than memcpy (here you know the length of the string, so memcpy makes more sense)
Last edited on
Thanks for the help but I'm still not sure what I'm doing wrong here:
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
 #include <conio.h>
#include <stdio.h>
#include <cstdlib>
#include "Windows.h"
#include "winuser.h"
#include <cmath>
#include <iostream>
#include <iomanip>
#include <complex>
#include <string>

int main (){

using namespace std;

string AAA;

cout <<"Please enter sentence: "; cin >> AAA;
cout << endl;
cout << endl;
cout << "This has been copied to the clipboard: ";
cout << AAA;
strlen(AAA);
void toClipboard(HWND hwnd, const std::string &s){
	OpenClipboard(hwnd);
	EmptyClipboard();	
	HGLOBAL hg=GlobalAlloc(GMEM_MOVEABLE,s.size()+1);
	if (!hg){
		CloseClipboard();
		return;
	}
	memcpy(GlobalLock(hg),s.c_str(),s.size()+1);
	GlobalUnlock(hg);
	SetClipboardData(CF_TEXT,hg);
	CloseClipboard();
	GlobalFree(hg);
}


cin.clear();
cin.ignore(255, '\n');
cin.get();

return 0; 
}


Thanks, Muhasaresa
I assume you have problems compiling your code? Remember to include the details of what it wrong next time, or your post might be ignored due to a lack of info.

C++ does not support nested functions: toClipboard() must be defined outside of main(). If afterwards you'll also need a forward definition.

Also, I did not realized you were using a console app. I have not used it, but you should be able to pass the handle obtained by a call to GetConsoleWindow();
Last edited on
Yes, I'm making a console app in Dev C++ and I get 2 errors.

1: for strlen(AAA); it says
no matching function for call to `strlen(std::string&)'


2: and at line 24 it says
a function-definition is not allowed here before '{' token
and
expected `,' or `;' before '{' token


I hope this problem can be fixed :D Sorry this thread is so long; I'm new to C++.

Muhasaresa

P.S. Where should I put the piece of code you gave me so that it knows which string its referring to.
Last edited on
It was just a matter of using c_str() and moving the function out of main(), as I said in my last post.

See comments in code. (It worked for me on Windows XP -- I tested by pasting into Notepad)

Andy

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
54
#include <conio.h>
#include <stdio.h>
#include <cstdlib>
#include <Windows.h> // use < > for all system and library headers
#include <winuser.h>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <complex>
#include <string>

// 2. forward declaration (also see later)
void toClipboard(HWND hwnd, const std::string &s);

int main (){

	using namespace std;

	string AAA;

	cout <<"Please enter sentence: "; cin >> AAA;
	cout << endl;
	cout << endl;
	cout << "This has been copied to the clipboard: ";
	cout << AAA << endl;
	// 1. strlen takes a const char*, so have to call the strings c_str() method
	// (but it would be better to use len = AAA.length() instead)
	size_t len = strlen(AAA.c_str());
	cout << len << " char(s)" << endl;
	// get desktop windows and the call toClipboard
	HWND hwnd = GetDesktopWindow();
	toClipboard(hwnd, AAA);
	cin.clear();
	cin.ignore(255, '\n');
	cin.get();

	return 0; 
}

// 2. declare functions at file scope 
void toClipboard(HWND hwnd, const std::string &s){
	OpenClipboard(hwnd);
	EmptyClipboard();
	HGLOBAL hg=GlobalAlloc(GMEM_MOVEABLE,s.size()+1);
	if (!hg){
		CloseClipboard();
		return;
	}
	memcpy(GlobalLock(hg),s.c_str(),s.size()+1);
	GlobalUnlock(hg);
	SetClipboardData(CF_TEXT,hg);
	CloseClipboard();
	GlobalFree(hg);
}
Thank you so much for all your great help and effort :D The code works perfectly !

Muhasaresa
Topic archived. No new replies allowed.