mhammond / pywin32

Python for Windows (pywin32) Extensions
5.01k stars 793 forks source link

Suggestion: Use the 'with' statement for managing system resources like 'bmp' #2105

Closed songyuc closed 1 year ago

songyuc commented 1 year ago

Hi, guys! I've noticed that currently, pywin32 uses an apply & release method to manage system resources like 'bmp'. While the 'with' statement is more elegant and Pythonic way to manage resources, would you please consider providing a 'with' statement implementation for system resources?

Your response and guidance would be greatly appreciated!

mhammond commented 1 year ago

Can you please be more specific about exactly what resources should be managed this way? Things like handles which come directly from win32 and don't have a python wrapper can't really have this done sanely.

songyuc commented 1 year ago

Hi, @mhammond, I'm referring to code that captures a window screenshot. Currently, the code might look like this:

hdc = win32api.GetDC(hwnd)
hbitmap = win32api.CreateCompatibleBitmap(hdc, width, height)
# ... (rest of the code)
win32api.DeleteObject(hbitmap)

I suggest that it could be more Pythonic and easier to manage resources using the with statement, like so:

with win32api.DC(hwnd) as hdc:
    with win32api.CreateCompatibleBitmap(hdc, width, height) as hbitmap:
        with win32api.CreateCompatibleDC(hdc) as dc:
            bitmap = win32api.SelectObject(dc, hbitmap)
            win32api.BitBlt(dc, 0, 0, width, height, hdc, 0, 0, win32con.SRCCOPY)
            image = ctypes.windll.gdi32.GetBitmapBits(hbitmap, width * height * 4)

This way, the resources would be automatically managed, making the code cleaner and less error-prone.

mhammond commented 1 year ago

The problem is that win32api.DC(hwnd) returns an integer.

songyuc commented 1 year ago

Hi @mhammond,

Thanks for your reply.

The above codes are just kind of pseudocode. To implement this feature in Python, we need to create a new class that implements the __enter__() and __exit__() methods.

The __enter__() method will be called when the with statement is entered, and the __exit__() method will be called when the with statement is exited. The __exit__() method will be responsible for releasing the resource.

mhammond commented 1 year ago

I understand how context managers work. But these methods already exist and already return ints. What you are suggesting would break backwards compatibility.

songyuc commented 1 year ago

Hi @mhammond,

Thank you for your response. I understand the concerns about backward compatibility. To address this, I suggest adding new APIs that implement the with statement for resource management, rather than altering the existing ones. This way, users can opt to use the new, more Pythonic way of managing resources without affecting the existing code that relies on the old APIs.

Here's a simple example to illustrate how the new API could work:

with win32api.NewDC(hwnd) as hdc:
    with win32api.NewCreateCompatibleBitmap(hdc, width, height) as hbitmap:
        # ... rest of the code

In this example, NewDC and NewCreateCompatibleBitmap are the new APIs that implement the with statement. They would handle the resource allocation and release automatically, making the code cleaner and less error-prone.

I believe this would be a valuable addition to the library and would love to hear your thoughts on this.

mhammond commented 1 year ago

I think duplicating every API which returns a handle would be a massive job for marginal benefit, but I'd welcome the chance to inspect a patch.