Home > Software design >  How to get and set non-standard formats to clipboard, using python win32clipboard?
How to get and set non-standard formats to clipboard, using python win32clipboard?

Time:12-20

Want to copy and save multiple non-text elements from an obscure software, and later set them back in clipboard. (for context, it's a PLC programming environment - UniLogic, and elements in question are ladder rungs).

Copying the elements and using function win32clipboard.EnumClipboardFormats(0)
Returns 49161 or C009 in hex

Using win32clipboard.GetClipboardFormatName(49161)
Returns DataObject

Then

data = win32clipboard.GetClipboardData(49161)
print(data)

Shows b'\x00\x00\x00\x00\x00\x00\x00\x00'

I can then set this data to clipboard, without errors, but the paste function doesn't do anything anymore.

win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(49161,data)
win32clipboard.CloseClipboard()

Seems that I can't access the full data from clipboard.
From what I read, some programs just give the clipboard the pointer to data, not data itself. But why can't I reuse this pointer, with the said program still open? Is there any way around this?

Any help appreciated, thank you.

CodePudding user response:

[MS.Docs]: Clipboard is MS's root reference for clipboard documentation.

For PyWin32 documentation, check [ME.TimGolden]: Python for Win32 Extensions Help ((officially) referenced by [GitHub]: mhammond/pywin32 - pywin32).

GetClipboardData returns a handle (pointer) to the clipboard data. Depending on its format, the memory contents should be interpreted and handled. It's impossible to handle all possible formats, because virtually anyone can register their own format (having its data particularities).

The PyWin32 wrapper (win32clipboard.GetClipboardData) "decodes" data for a few basic formats (that mainly work with text). Check sources (win32clipboardmodule.cpp) for more details.
For the other formats (including registered ones), it offers:

  1. GetClipboardDataHandle - returns the raw handle (from WinAPI)

  2. GetGlobalMemory - "decodes" handle data

Now, even if after #2. for some formats (CF_DIB) data would be available, for many, it won't. I assume that your format is in the latter category (an object is composed of other objects, which in turn are composed of others and so on, and each object aggregates sub-objects via pointers (references)), so I don't think you'd be able to achieve your goal OOTB, probably you should use some API (if) provided by that program to serialize / deserialize objects.

I prepared a dummy example.

code00.py:

#!/usr/bin/env python

import sys
from pprint import pprint as pp

import win32gui as wgui
import win32clipboard as wcb
import win32con as wcon


def clipboard_formats():
    l = [wcb.EnumClipboardFormats(0)]
    while l[-1]:
        l.append(wcb.EnumClipboardFormats(l[-1]))
    l.pop()
    ret = {}
    for e in l:
        try:
            name = wcb.GetClipboardFormatName(e)
        except:
            name = ""
        ret[e] = name
    return ret


def is_simple_format(fmt):  # @TODO: dummy!!!
    return fmt in (
        wcon.CF_TEXT,
        wcon.CF_OEMTEXT,
        wcon.CF_UNICODETEXT,
        wcon.CF_LOCALE
    )


def main(*argv):
    try:
        hwnd = int(argv[0])
    except (IndexError, ValueError):
        hwnd = None
    print("Handling clipboard for window: {:} ({:s})".format(hwnd, wgui.GetWindowText(hwnd or wgui.GetActiveWindow())))
    clip = wcb.OpenClipboard(hwnd)
    fmts_dict = clipboard_formats()
    print("Available formats:")
    pp(fmts_dict, sort_dicts=0)
    try:
        fmt = int(argv[1])
        fmts_dict[fmt]
    except (IndexError, ValueError, KeyError):
        fmt = tuple(fmts_dict.keys())[0]  # 1st one
    print("Using format {:d} ({:s})".format(fmt, fmts_dict[fmt]))

    if is_simple_format(fmt):
        print("Handling simple (text) format data")
        data = wcb.GetClipboardData(fmt)
        print("--- Data ---\n{:}\n--- Data end ---".format(data))
    else:
        print("Handling custom format data")
        hg = wcb.GetClipboardDataHandle(fmt)
        print("HGLOBAL: {:}".format(hg))
        data = wcb.GetGlobalMemory(hg)
        data_len = getattr(data, "__len__", lambda: -1)()
        print("Data length: {:d}".format(data_len))
        if data_len < 0x100:
            print("--- Data ---\n{:}\n--- Data end ---".format(data))

    wcb.EmptyClipboard()
    wcb.SetClipboardData(fmt, data)

    wcb.CloseClipboard()


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.\n")
    sys.exit(rc)

Output:

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q074838210]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[prompt]> :: Run the script for an LibreOffice sheet with a couple of dummy cells copied in the clipboard
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" ./code00.py 42211480
Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32

Handling clipboard for window: 42211480 (Untitled 1 - LibreOffice Calc)
Available formats:
{49161: 'DataObject',
 50348: 'Star Embed Source (XML)',
 50368: 'Star Object Descriptor (XML)',
 49897: 'GDIMetaFile',
 14: '',
 3: '',
 49513: 'PNG',
 8: '',
 50286: 'Windows Bitmap',
 50377: 'HTML (HyperText Markup Language)',
 49435: 'HTML Format',
 4: '',
 50375: 'Link',
 5: '',
 13: '',
 1: '',
 49274: 'Rich Text Format',
 50127: 'Richtext Format',
 49171: 'Ole Private Data',
 16: '',
 7: '',
 2: '',
 17: ''}
Using format 49161 (DataObject)
Handling custom format data
HGLOBAL: 2484318176448
Data length: 8
--- Data ---
b'\x84\r`\x04\x00\x00\x00\x00'
--- Data end ---

Done.


[prompt]> :: Copy some text from above lines and run the script for "current" window
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" ./code00.py
Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32

Handling clipboard for window: None ()
Available formats:
{13: '', 16: '', 1: '', 7: ''}
Using format 13 ()
Handling simple (text) format data
--- Data ---
sing format 49161 (
andling custom form
GLOBAL: 24843181764
ata length: 8
-- Data ---
'\x84\r`\x04\x00\x0
--- Data end ---

Done.

More details on the following tasks:

  • Related