39

The SetClipboardData function requires a HANDLE reference; I'm having trouble converting my string for use in the function.

Here is my code:

char* output = "Test";
HLOCAL hMem =  LocalAlloc( LHND,1024);
char* cptr = (char*) LocalLock(hMem);
memcpy( cptr, output, 500 );
SetClipboardData(CF_TEXT, hMem);
LocalUnlock( hMem );
LocalFree( hMem );
CloseClipboard();

What am I doing wrong here and what's the proper way to do it?

Thanks.

Asesh
  • 3,186
  • 2
  • 21
  • 31

3 Answers3

67

Read the MSDN documentation for the SetClipboardData function. It appears you are missing a few steps and releasing the memory prematurely. First of all, you must call OpenClipboard before you can use SetClipboardData. Secondly, the system takes ownership of the memory passed to the clipboard and it must be unlocked. Also, the memory must be movable, which requires the GMEM_MOVEABLE flag as used with GlobalAlloc (instead of LocalAlloc).

const char* output = "Test";
const size_t len = strlen(output) + 1;
HGLOBAL hMem =  GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), output, len);
GlobalUnlock(hMem);
OpenClipboard(0);
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
CloseClipboard();
Judge Maygarden
  • 26,961
  • 9
  • 82
  • 99
  • Works for me too... with two corrections: GMEM_MOVEABLE and no parameter passed in OpenClipboard(); – Harvey Jun 21 '12 at 18:40
  • 1
    Why copy the null-byte-terminattor too? – Jack Jun 13 '14 at 20:30
  • 4
    because SetClipboardData doesn't accept a length parameter, so it has to figure out where the end of the string is, when you use CF_TEXT. See http://msdn.microsoft.com/en-us/library/windows/desktop/ff729168(v=vs.85).aspx for more info – Elkvis Sep 03 '14 at 20:33
  • 1
    Do I understand correctly, if the call to SetClipboardData succeeds system calls free(hMem) for you? – Pyjong May 13 '15 at 12:37
  • 1
    @Pyjong: Yes, except that it's `GlobalFree`. – Yakov Galka Nov 17 '16 at 15:52
  • 1
    Note that if you are copying a `wchar_t*` instead of a `char*`, use `CF_UNICODETEXT` instead of `CF_TEXT`. – MultiplyByZer0 Oct 21 '18 at 07:44
  • 2
    Accoring to the [documentation](https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setclipboarddata), this answer is wrong. You must pass a valid `HWND` to `OpenClipboard`. Quote: "_If an application calls OpenClipboard with hwnd set to NULL, EmptyClipboard sets the clipboard owner to NULL; this causes SetClipboardData to fail_" – GetFree Dec 26 '18 at 23:24
  • This doesn't work as @GetFree said. – Y K Jun 18 '22 at 14:07
18

I wrote an open source command line tool to do this in Windows:

http://coffeeghost.net/2008/07/25/ccwdexe-copy-current-working-directory-command/

ccwd.exe copies the current working directory to the clipboard. It's handy when I'm several levels deep into a source repo and need to copy the path.

Here's the complete source:

#include "stdafx.h"
#include "windows.h"
#include "string.h"
#include <direct.h>

int main()
{
    LPWSTR cwdBuffer;

    // Get the current working directory:
    if( (cwdBuffer = _wgetcwd( NULL, 0 )) == NULL )
        return 1;

    DWORD len = wcslen(cwdBuffer);
    HGLOBAL hdst;
    LPWSTR dst;

    // Allocate string for cwd
    hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (len + 1) * sizeof(WCHAR));
    dst = (LPWSTR)GlobalLock(hdst);
    memcpy(dst, cwdBuffer, len * sizeof(WCHAR));
    dst[len] = 0;
    GlobalUnlock(hdst);

    // Set clipboard data
    if (!OpenClipboard(NULL)) return GetLastError();
    EmptyClipboard();
    if (!SetClipboardData(CF_UNICODETEXT, hdst)) return GetLastError();
    CloseClipboard();

    free(cwdBuffer);
    return 0;
}
Al S.
  • 361
  • 3
  • 4
  • +1 Yes, it is simple to read, copy and it works right on, just what I was looking for. And the CF_UNICODETEXT is a horror not getting. CF_TEXT makes only one letter in normal US ASCII. The DWORD len should be a size_t len (not getting compiler complaints). – Jan Bergström Mar 18 '19 at 05:46
  • 1
    Your answer uses `GMEM_DDESHARE`. I understand that your answer was written 11 years ago(!). Modern docs say: `The following values are obsolete, but are provided for compatibility with 16-bit Windows. They are ignored. GMEM_DDESHARE...` from here: https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalalloc – kevinarpe Dec 19 '22 at 15:36
  • In case an error occurs, this code leaks both `hdst` and `cwdBuffer`. – Alexey Ivanov Mar 20 '23 at 19:23
-2

Take a look at Microsoft's Documentation on using the clipboard. This requires that your using the WinAPI, but this shouldn't be a problem since your on Windows. Note that programming the Windows API is never simple unless you use a very high-level language.

Kredns
  • 36,461
  • 52
  • 152
  • 203
  • 1
    Well, I've already looked at that, and came up with the code which doesn't work. –  Aug 12 '09 at 04:07
  • You might just try copying the exact code and see if it works. Then you can go from there. – Kredns Aug 12 '09 at 04:10