如何在C语言中将字符串复制到剪贴板?

39

SetClipboardData 函数需要一个 HANDLE 引用; 我在将字符串转换为可用于该函数的格式时遇到了麻烦。

这是我的代码:

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();

我在这里做错了什么,正确的方法是什么?

谢谢。

3个回答

67

阅读 SetClipboardData 函数的 MSDN 文档。看起来你漏了一些步骤并且提前释放了内存。首先,你必须在使用 SetClipboardData 前调用 OpenClipboard。其次,系统会接管发送到剪贴板的内存,因此必须将其解锁。此外,该内存必须是可移动的,这需要使用 GlobalAlloc 的 GMEM_MOVEABLE 标记(而非 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();

1
为什么也要复制空字节终止符? - Jack
4
由于 SetClipboardData 函数在使用 CF_TEXT 格式时不接受长度参数,因此它必须确定字符串的结尾位置。有关更多信息,请参阅 http://msdn.microsoft.com/en-us/library/windows/desktop/ff729168(v=vs.85).aspx。 - Elkvis
1
我理解的是否正确,如果调用 SetClipboardData 成功,则系统会为您调用 free(hMem)? - Pyjong
1
@Pyjong:是的,除了它是“GlobalFree”。 - Yakov Galka
2
根据文档,这个答案是错误的。您必须传递一个有效的HWNDOpenClipboard。引用:“_如果应用程序使用hwnd设置为NULL调用OpenClipboard,则EmptyClipboard将剪贴板所有者设置为NULL;这会导致SetClipboardData失败_”。 - GetFree
显示剩余3条评论

18

我写了一个开源的命令行工具用于在Windows中实现此功能:

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

ccwd.exe可以将当前工作目录复制到剪贴板。当我进入源代码库的多个层级时需要复制路径时,这将非常方便。

以下是完整的源代码:

#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;
}

+1 是的,它很容易阅读、复制并且可以直接运行,正是我所需要的。而 CF_UNICODETEXT 真是让人头疼。CF_TEXT 只能处理普通的美国 ASCII 字符。DWORD 长度应该改为 size_t 长度(这样编译器就不会报错了)。 - Jan Bergström
1
你的回答使用了 GMEM_DDESHARE。我理解你的回答是11年前写的(!)。现代文档说:以下值已过时,但为了与16位Windows兼容而提供。它们被忽略。GMEM_DDESHARE... 来自这里:https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalalloc - kevinarpe
如果发生错误,此代码会泄漏hdstcwdBuffer - Alexey Ivanov

-2

请查看Microsoft有关使用剪贴板的文档。这需要使用WinAPI,但由于您在Windows上,所以这不应该是问题。请注意,编程Windows API从来都不简单,除非您使用非常高级的语言。


1
嗯,我已经看过了,写了一段代码但是不起作用。 - unknown
你可以尝试复制完全相同的代码,看看是否有效。然后你可以从那里开始。 - Kredns

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接