How to close Windows Portable Device IStream opened in Python / pythoncom / comtypes

251 Views Asked by At

I'm using Windows Portable Device in python with pythoncom and comtypes.

I'm in trouble because when I request for WPD_RESOURCE_THUMBNAIL resource, some android devices returns a "square" thumbnail while the raw image has 16:9 format (or 4:3...).

Then I tried to request for WPD_RESOURCE_DEFAULT resource in order to get the thumbnail from the EXIF data: so no need to read the whole file, once I get the EXIF tag for the thumbnail I can stop the read and skip to next file.

I'm able to get the thumbnail from the EXIF for the very first file. On the second file I get stuck on the GetStream() method. It simply hang. I suppose because the IStream from the previous call was not closed/disposed.

Have you any idea on how to force the Dispose / Close of this IStream?

This is what I do in code:

optimalTransferSizeBytes, fileStream = resources.GetStream(
                    self.objectID,
                    WPD_RESOURCE_DEFAULT,
                    ctypes.c_ulong(0),
                    optimalTransferSizeBytes,
                    pFileStream
                )

Thank you in advance for any suggestion on this.

EDIT: Since I found no other ways to interrupt the stream and release all the resources, I ended up reading the whole stream for WPD_RESOURCE_DEFAULT. It's a bit slower but it's safer because the application runs on big screens also and using the EXIF's thumbnail can lead to poor quality images on screen. So I decided to read the whole stream for WPD_RESOURCE_DEFAULT for this purpose and speed up code somewhere outside this point. Thank you @ShadowRanger for support.

1

There are 1 best solutions below

4
On

The UnmanagedMemoryStream type has a Dispose method, if your library exposes all the methods for you, a simple fileStream.Dispose() should work. To be safe, you'd want to either implement a context manager wrapper to allow the use of the with statement, or less Pythonically, but more simply, use a try/finally, e.g.:

optimalTransferSizeBytes, fileStream = resources.GetStream(
                    self.objectID,
                    WPD_RESOURCE_DEFAULT,
                    ctypes.c_ulong(0),
                    optimalTransferSizeBytes,
                    pFileStream
                )
try:
    ... do stuff with fileStream ...
finally:
    fileStream.Dispose()

Alternatively, you can make your own context manager to perform disposal:

from contextlib import contextmanager

@contextmanager
def disposing(disposable):
    try:
        yield disposable
    finally:
        disposable.Dispose()

which would allow the slightly nicer code:

optimalTransferSizeBytes, fileStream = resources.GetStream(
                    self.objectID,
                    WPD_RESOURCE_DEFAULT,
                    ctypes.c_ulong(0),
                    optimalTransferSizeBytes,
                    pFileStream
                )
with disposing(fileStream):
    ... do stuff with fileStream ...