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:
GetClipboardDataHandle - returns the raw handle (from WinAPI)
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:
Working with clipboard: [MS.Docs]: Using the Clipboard
Getting a window handle: use Spy application or check [SO]: Get the title of a window of another program using the process name (@CristiFati's answer) (a process name can be easily retrieved from tools like Task Manager)