C++ GDI+ loading an image from a file then deleting the file *before* unloading the image

5.6k views Asked by At

Simply what it says on the tin I'm loading a bitmap from a file using Bitmap::FromFile but afterwards I want to delete it from the disk.
The problem is, Bitmap::FromFile absolutely locks the file from any changes/deletion until the loaded image is unloaded

This is because I'm storing the bitmaps in a binary file, so I want to do it in this order:
1. extract the image from binary file
2. load the image
3. delete the file extracted in #1
(just some basic protection for my image resources, I just don't want them sitting in my program directory)

Bitmap::FromFile still locks the file from deletion even when cloning the loaded image from the file like in my attempt:

    Bitmap* tempbmp = Bitmap::FromFile(fileanddir.c_str(),false);
    Rect temprect( 0, 0, tempbmp->GetWidth(), tempbmp->GetHeight() );

    // make the image to be used as a clone to the temporary
    // bitmap to avoid file locking
    image_to_be_used = tempbmp->Clone(temprect, PixelFormatDontCare);

    // delete temporary loaded bitmap since it shouldn't be needed
    delete tempbmp;

    // delete the file itself, too bad the file is locked
    int theresult = remove(tocharptr(fileanddir)); 
    // returns -1, also: manually deleting at this point gives the error
    // that the file is being used by another person/program

Any idea how I can load a bitmap or somehow copy it to memory so the file itself wouldn't be locked ?
(So i can delete it a moment after loading it)

3

There are 3 answers

0
ak. On BEST ANSWER

Take a look at Bitmap::FromStream. You should be able to use SHCreateStreamOnFileEx to open an IStream on the file. After loading your bitmap you can safely delete the stream and then the temporary file.

If the binary file is only compressed with a supported algorithm, then pass the corresponding flag to SHCreateStreamOnFileEx and have it read the archive, bypassing the extraction of the image into a temp file. Otherwise can implement the IStream interface to read the binary file and extract your image data directly.

1
Sergey S On

You can do it this way

Gdiplus::Bitmap* LoadImageFromFileWithoutLocking(const WCHAR* fileName) {
    using namespace Gdiplus;
    Bitmap src( fileName );
    if ( src.GetLastStatus() != Ok ) {
        return 0;
    }
    Bitmap *dst = new Bitmap(src.GetWidth(), src.GetHeight(), PixelFormat32bppARGB);

    BitmapData srcData;
    BitmapData dstData;
    Rect rc(0, 0, src.GetWidth(), src.GetHeight());

    if (src.LockBits(& rc, ImageLockModeRead, PixelFormat32bppARGB, & srcData) == Ok)
    {
        if ( dst->LockBits(& rc, ImageLockModeWrite, PixelFormat32bppARGB, & dstData) == Ok ) {
            uint8_t * srcBits = (uint8_t *) srcData.Scan0;
            uint8_t * dstBits = (uint8_t *) dstData.Scan0;
            unsigned int stride;
            if (srcData.Stride > 0) { 
                stride = srcData.Stride;
            } else {
                stride = - srcData.Stride;
            }
            memcpy(dstBits, srcBits, src.GetHeight() * stride);

            dst->UnlockBits(&dstData);
        }
        src.UnlockBits(&srcData);
    }
    return dst;
}
0
Danil On

if you interested in MFC-OLE sample:

CFile file;
CFileException fe;
CString strFileName = "C:\\yours.bmp";

if (!file.Open(strFileName, CFile::modeRead | CFile::shareDenyNone , &fe))
{
    return;
}
COleStreamFile stream;
if(!stream.CreateMemoryStream(NULL))
{
    return;
}
BYTE buf[1024];
int readed = 0;
do
{
    readed = file.Read(buf,1024);
    stream.Write(buf,readed);
}
while(readed > 0);

file.Close();
stream.SeekToBegin();
USES_CONVERSION;
m_pImage = new Gdiplus::Bitmap(stream.GetStream( ));