[Qt-interest] QFile::copy() fails on Windows Vista if the source is in resources (Was Re: QFile::remove() fails on Windows Vista)

Constantin Makshin dinosaur-rus at users.sourceforge.net
Tue Jun 23 19:50:06 CEST 2009


I guess I've found the source of this problem -- QFile::copy() uses  
temporary file when native API can't do the work (and that happens because  
native APIs don't know about Qt reources), and since QTemporaryFile object  
doesn't close its file until it (object) is destroyed, any attempt to  
delete it (file) fails.

As a workaround, you can use something like this:

QFile file(":/deltest.pro"),
       destFile("copycopy.txt");
if (srcFile.open(QIODevice::ReadOnly) &&
     destFile.open(QIODevice::WriteOnly))
{
     QByteArray data = file.readAll();
     destFile.write(data);
}
file.close();
destFile.close();

On Tue, 23 Jun 2009 08:05:14 +0400, Yevgen Muntyan <muntyan at fastmail.fm>  
wrote:
> Hey,
>
> I tried simple QFile::rename(), it works fine for regular files. My  
> program copies a file from
> resources and apparently that hits an unlucky code path.
>
> DeleteFile fails because the file is held by someone else. I can't  
> delete the file while the application
> is sitting in debugger right before DeleteFile call. DeleteFile returns  
> 0, and GetLastError is 32.
> Trying to delete file in cmd.exe I get "The process cannot access the  
> file because it is being used
> by another process." After I let the program run further (and after  
> QFile::rename() fails), I can
> delete the file without problems, with or without "\\?\" prefix. What I  
> said earlier about the prefix
> was wrong, I simply tried to delete the file while the program was  
> stopped.
>
> The following is a complete test case which reproduces my problem (you  
> need to add a resource
> file which includes some file, deltest.pro in this code):
>
> #include <QtGui>
>
> int main(int argc, char *argv[])
> {
>     QApplication app(argc, argv);
>     QFile file(":/deltest.pro");
>     if (file.copy("copycopy.txt"))
>         QMessageBox::information(0, "yay!", "yay!");
>     else
>         QMessageBox::critical(0, "oops!", file.errorString());
>     return 0;
> }
>
> It gives me "Cannot create copycopy.txt for output" (it's lying, the  
> error message is overwritten inside
> QFile::copy).
>
> Best regards,
> Yevgen
>
> Constantin Makshin wrote:
>> "\\?\" prefix is used to extend the maximum path length from 259 to  
>> ~32000  characters. Could you call DeleteFileW(L"\\?\<path>"), where  
>> <path> is the  absolute path to your temporary file with backslashes as  
>> path delimiters,  directly and see what it returns?
>>
>> On Mon, 22 Jun 2009 21:00:48 +0400, Yevgen Muntyan  
>> <muntyan at fastmail.fm>  wrote:
>>
>>> Yevgen Muntyan wrote:
>>>
>>>> Hey,
>>>>
>>>> I have a problem with QFile::rename: it fails when it tries to  
>>>> remove  the
>>>> temporary file it uses, because DeleteFileW() fails inside
>>>> QFSFileEngine::remove(). My code is roughly the following:
>>>>
>>>> QFile source(":/gap/ggap.g");
>>>> source.copy("C:/Users/muntyan/AppData/Local/Temp/ggap-000025cb/ggap.g")
>>>>
>>>> The copy() call here fails.
>>>> "C:/Users/muntyan/AppData/Local/Temp/ggap-000025cb" directory is  
>>>> created
>>>> with QDir::mkdir(), and I do have permissions to delete files from  
>>>> it,  and I
>>>> can delete files from it in explorer. The temporary files   
>>>> qt_temp.XXXXXX are
>>>> not read-only, so DeleteFile() isn't supposed to fail. But it does!
>>>>
>>>>
>>> I found out that Qt calls DeleteFile() on some funny long version of  
>>> the
>>> filename, namely it passes
>>> the following string to DeleteFile:
>>>
>>> \\?\c:\Users\muntyan\AppData\Local\Temp\ggap-00002d22\qt_temp.Za5308
>>>
>>> it prepends \\?\ in QFSFileEnginePrivate::longFileName(). DeleteFile()
>>> doesn't fail if I call it on
>>> the filename without that prefix. Ideas?
>>>
>>> Thanks,
>>> Yevgen

-- 
Constantin "Dinosaur" Makshin



More information about the Qt-interest-old mailing list