Tony Teveris
Tony Teveris

Reputation: 195

IWICImagingFactory::CreateDecoderFromFilename() keeps the file locked even after the decoder is destroyed

I'm using IWICImagingFactory::CreateDecoderFromFilename() for reading only. Is there a way I can pass something like the FILE_SHARE_READ flag? The file stays open from the function call above until the program terminates.

During another operation within the same program, I attempted to use CFile::Open(), but I got error 32 ("The process cannot access the file because it is being used by another process").

Upvotes: 2

Views: 927

Answers (3)

V.V.T
V.V.T

Reputation: 231

It does not help if you create the file handle while still use the method CreateDecoderFromFilename() to create a decoder: the file remains locked after CloseHandle(). To unlock the file, you should use the method CreateDecoderFromFileHandle(), see @isanae's answer.

IWICFormatConverter inherits from IWICBitmapSource. In this sense, it represents IWICBitmapSource, as the documentation states. And when WIC does create (IWICFormatConverter*) converter from (IWICBitmapFrameDecode*) source from (IWICBitmapDecoder*) decoder, it does not copy immediately the pixel data of the image file used in a CreateDecoderFromFilename()/CreateDecoderFromFileHandle() call. The data processing by the converter (prescribed by the parameters used in the converter->Initialize(...) call) is executed later, when the pixel data are used in the program, and this processing uses the data of the image file i/o buffer. With this delayed execution, the pipeline avoids unnecessary copying of data.

However, when you unlock the image file, you delete this io buffer. So, if you want to unlock the file and still keep the image pixel data, you have to copy this pixel data. For example, immediately, prior to the CloseHandle() call, using the call converter.Detach()->CopyPixels(nullptr, stride, imagesize, pixels), you can copy to memory the pixel data pointed by the converter.Detach() structure and then create (IWICBitmapSource*) wicBitmap using width/height and other parameters of the source image including this pixel data copied to memory: wicFactory->CreateBitmapFromMemory(width, height, wicguid, stride, imagesize, pixels, &wicBitmap);. The image file's io buffer does not own this copied pixel data, and you can safely close the file handle.

Upvotes: 0

anon
anon

Reputation:

I'm not sure what the IWICBitmapDecoder does with the file, but it seems to be keeping it opened past the Release() call on it. It might have a bug where the handle isn't closed, who knows. I couldn't find any information on that behaviour. Actually, apart from this question, nobody seems to have noticed (or nobody cares).

In any case, the solution, as hinted by Tony, is to open the file manually and use CreateDecoderFromFileHandle() instead of CreateDecoderFromFilename(). Note that "the file handle must remain alive during the lifetime of the decoder."

So this:

void f(IWICImagingFactory* factory, const wchar_t* path)
{
    IWICBitmapDecoder* decoder = nullptr;

    factory->CreateDecoderFromFilename(
        path, nullptr, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &decoder);

    // ...

    decoder->Release();
}

becomes this:

void f(IWICImagingFactory* factory, const wchar_t* path)
{
    auto h = CreateFileW(
        path, GENERIC_READ, FILE_SHARE_READ,
        nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

    IWICBitmapDecoder* decoder = nullptr;

    factory->CreateDecoderFromFileHandle(
        reinterpret_cast<ULONG_PTR>(h), nullptr,
        WICDecodeMetadataCacheOnLoad, &decoder);

    // ...

    decoder->Release();
    CloseHandle(h);
}

Upvotes: 1

Tony Teveris
Tony Teveris

Reputation: 195

What I ended up doing was using

pImagePoolEntry->hFileHandle = CreateFile(
    path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

before the call to CreateDecoderFromFilename().

Since I was already using an Image Pool keeping track of opened, shared images I just added the initial file handle and added code to use CloseHandle() when the image was not longer in use.

Upvotes: 1

Related Questions