Search code examples
pythonclipboardctypespython-3.6

Read text from clipboard in Windows using ctypes


I'm trying to get the text stored in the clipboard by just using ctypes in Python 3.6. I tested a lot of solutions I found on Stack and GitHub, but they only work for Python 2 to Python 3.4.

This is the code you'll find almost everywhere:

from ctypes import *

def get_clipboard_text():
    text = ""
    if windll.user32.OpenClipboard(c_int(0)):
        h_clip_mem = windll.user32.GetClipboardData(1)
        windll.kernel32.GlobalLock.restype = c_char_p
        text = windll.kernel32.GlobalLock(c_int(h_clip_mem))
        windll.kernel32.GlobalUnlock(c_int(h_clip_mem))
        windll.user32.CloseClipboard()
    return text

I tested it in Python 3.4. It worked fine and returned the text in the clipboard. But running the same script on Python 3.6 always returns None. I could not find a solution for Python 3.6 so far.

I'm wondering if anybody could help me out since I don't know much about ctypes and C programming at all.


Solution

  • My guess is you are using 64-bit Python 3.6 so handles are 64-bit, and you are passing them as c_int (32-bit).

    With ctypes, it is best to be explicit about all the arguments and return types. the following code should work on 32- and 64-bit Python 2 and 3.

    Also, CF_UNICODETEXT will be able to handle any text you copy.

    from __future__ import print_function
    import ctypes
    import ctypes.wintypes as w
    
    CF_UNICODETEXT = 13
    
    u32 = ctypes.WinDLL('user32')
    k32 = ctypes.WinDLL('kernel32')
    
    OpenClipboard = u32.OpenClipboard
    OpenClipboard.argtypes = w.HWND,
    OpenClipboard.restype = w.BOOL
    GetClipboardData = u32.GetClipboardData
    GetClipboardData.argtypes = w.UINT,
    GetClipboardData.restype = w.HANDLE
    GlobalLock = k32.GlobalLock
    GlobalLock.argtypes = w.HGLOBAL,
    GlobalLock.restype = w.LPVOID
    GlobalUnlock = k32.GlobalUnlock
    GlobalUnlock.argtypes = w.HGLOBAL,
    GlobalUnlock.restype = w.BOOL
    CloseClipboard = u32.CloseClipboard
    CloseClipboard.argtypes = None
    CloseClipboard.restype = w.BOOL
    
    def get_clipboard_text():
        text = ""
        if OpenClipboard(None):
            h_clip_mem = GetClipboardData(CF_UNICODETEXT)
            text = ctypes.wstring_at(GlobalLock(h_clip_mem))
            GlobalUnlock(h_clip_mem)
            CloseClipboard()
        return text
    
    print(get_clipboard_text())