0

I got an error when I open the Clipboard,which says 'pywintypes.error: (5, 'OpenClipboard', 'Access is denied')'.I have seen some answers in SO but they can't meet my requirement,cause I copy some DIB-form picture into the clipboard but not only some string—like words that many answers mentioned. codes are as follows,which copied from Mr.martineau .Mr.martineau's great answer Hope for an answer THANKS!

import ctypes
from ctypes.wintypes import *
import win32clipboard
from win32con import *
import sys,win32api,win32con

#GRAB
win32api.keybd_event(win32con.VK_SNAPSHOT, 0)

class BITMAPFILEHEADER(ctypes.Structure):
    _pack_ = 1  # structure field byte alignment
    _fields_ = [
        ('bfType', WORD),  # file type ("BM")
        ('bfSize', DWORD),  # file size in bytes
        ('bfReserved1', WORD),  # must be zero
        ('bfReserved2', WORD),  # must be zero
        ('bfOffBits', DWORD),  # byte offset to the pixel array
    ]
SIZEOF_BITMAPFILEHEADER = ctypes.sizeof(BITMAPFILEHEADER)

class BITMAPINFOHEADER(ctypes.Structure):
    _pack_ = 1  # structure field byte alignment
    _fields_ = [
        ('biSize', DWORD),
        ('biWidth', LONG),
        ('biHeight', LONG),
        ('biPLanes', WORD),
        ('biBitCount', WORD),
        ('biCompression', DWORD),
        ('biSizeImage', DWORD),
        ('biXPelsPerMeter', LONG),
        ('biYPelsPerMeter', LONG),
        ('biClrUsed', DWORD),
        ('biClrImportant', DWORD)
    ]
SIZEOF_BITMAPINFOHEADER = ctypes.sizeof(BITMAPINFOHEADER)
***#GAIN AN ERROR FROM THIS LINE***  
win32clipboard.OpenClipboard()
try:
    if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_DIB):
        data = win32clipboard.GetClipboardData(win32clipboard.CF_DIB)
    else:
        print('clipboard does not contain an image in DIB format')
        sys.exit(1)
finally:
    win32clipboard.CloseClipboard()

bmih = BITMAPINFOHEADER()
ctypes.memmove(ctypes.pointer(bmih), data, SIZEOF_BITMAPINFOHEADER)

if bmih.biCompression != BI_BITFIELDS:  # RGBA?
    print('insupported compression type {}'.format(bmih.biCompression))
    sys.exit(1)

bmfh = BITMAPFILEHEADER()
ctypes.memset(ctypes.pointer(bmfh), 0, SIZEOF_BITMAPFILEHEADER)  # zero structure
bmfh.bfType = ord('B') | (ord('M') << 8)
bmfh.bfSize = SIZEOF_BITMAPFILEHEADER + len(data)  # file size
SIZEOF_COLORTABLE = 0
bmfh.bfOffBits = SIZEOF_BITMAPFILEHEADER + SIZEOF_BITMAPINFOHEADER + SIZEOF_COLORTABLE

bmp_filename = 'clipboard.bmp'
with open(bmp_filename, 'wb') as bmp_file:
    bmp_file.write(bmfh)
    bmp_file.write(data)

print('file "{}" created from clipboard image'.format(bmp_filename))
moqin
  • 64
  • 8
  • Are you using the clipboard because that is the desired functionality, or is it just an artifact because you don't know how else to take a screenshot? If it is the latter, stop using the clipboard and you'll see this issue disappear. There are numerous Q&A's the explain how to take a screenshot. Alternatively, if you can limit your code to Windows 10 1803 or later you can use the functionality built into the system to [take a screenshot](https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/screen-capture#take-a-screenshot). – IInspectable Mar 19 '20 at 06:08

1 Answers1

0

I think i found it. Looks like Windows doing the screenshot locks it. Adding a one second sleep after the keyboard event sending makes your script work on my machine.

Edit: just in case you do decide to go the "easy but evil" way, this is the simplest code to do the retries. And yes, i do agree, this is not the right way to do this, but it is a quick and dirty fix.

def OpenClipboardWithEvilRetries(retries=10, delay=0.1):
    while True:
        try:
            return win32clipboard.OpenClipboard()
        except pywintypes.error as e:
            if e.winerror!=5 or retries==0:
                raise
            retries = retries - 1
            time.sleep(delay)
Boris Lipschitz
  • 1,514
  • 8
  • 12
  • Adding arbitrary timeouts is fairly heavy-handed. A far better solution is to install a [clipboard format listener](https://learn.microsoft.com/en-us/windows/win32/dataxchg/using-the-clipboard#creating-a-clipboard-format-listener), and respond to the respective changes. – IInspectable Mar 19 '20 at 05:58
  • @IInspectable, i am not suggesting to actually add it, so, yea, this isn't a proper solution, but it DOES indicate whats going on and points in the right direction. – Boris Lipschitz Mar 19 '20 at 06:01
  • @IInspectable, BTW, how do you suggest to actually implement it? AddClipboardFormatListener requires a window, a running message pump... are you going to actually implement a full blown Win32 app here? Depending on the purpose, a retry mechanism with a short timeout may not be such an evil thing compared to implementing this stuff in python. – Boris Lipschitz Mar 19 '20 at 06:09
  • 1
    Indeed, I am proposing to write proper code, that works by virtue of being correct. If you need a window whose sole purpose is to receive messages, you can create a [message-only window](https://learn.microsoft.com/en-us/windows/win32/winmsg/window-features#message-only-windows). But, [as mentioned earlier](https://stackoverflow.com/questions/60751385/python-how-to-slove-the-problem-pywintypes-error-5-openclipboard-access#comment107486466_60751385) using the clipboard is probably not even needed. – IInspectable Mar 19 '20 at 06:17
  • @moq: This is not a solution. It's a workaround to make your proposed solution work, sometimes. And judging from your code, your proposed solution isn't even a solution. It looks like you don't even need to access (and abuse) the clipboard at all. If all you want is to take a screenshot, and save it to disk, there are [several solutions](https://stackoverflow.com/q/2846947/1889329) readily available as Python modules. – IInspectable Mar 19 '20 at 09:14
  • @IInspectable : Thank you for your guidance. But.it is the last method I want to use.Convinient as Python modles are ,I have no alternatives but to operate the clipboard causing the application which i want to capture limits all the capture-operations but the winapi one – moqin Mar 19 '20 at 12:45
  • @moq: You don't *have* to use any modules. You can [take a screenshot using the Windows API](https://stackoverflow.com/q/3291167/1889329) only. Abusing the clipboard for this is the worst you could do. It's not even a last-resort kind of thing to do. The clipboard belongs to the user. Your application has no business trashing the user's data. Which you are doing. – IInspectable Mar 19 '20 at 14:49
  • "Your application has no business trashing the user's data." - what if your application does automation testing? The web browser also belongs to the user, and using this logic no apps should ever touch it, yet tools like selenium webdriver exist. For a reason. Again, i am not saying this is the right thing to do in most cases. But it is use case dependent, and may not be such a big evil. – Boris Lipschitz Mar 19 '20 at 15:49
  • @IInspectable: Above all,thank you for your attention to my problem sincerely.Maybe you have misunderstood my intention. I must state that I'm not inclined to steal user's private information,but just uesd by myself.I shall make some explanation I want to make a screenshot to a software, but the software has taken measures to forbid all kinds of the simple operations of screen capturing. Consequently, only this method does work. And you are supposed to believe that I definitely not have any intention to intercept any private information. – moqin Mar 19 '20 at 16:15