0

I am trying to watch a folder changes and notify the added filename so here is my code

bool FileWatcher::NotifyChange()
{
    // Read the asynchronous result of the previous call to ReadDirectory
    DWORD dwNumberbytes;
    GetOverlappedResult(hDir, &overl, &dwNumberbytes, FALSE);

    // Browse the list of FILE_NOTIFY_INFORMATION entries

    FILE_NOTIFY_INFORMATION *pFileNotify = (FILE_NOTIFY_INFORMATION *)buffer[curBuffer];
    // Switch the 2 buffers
    curBuffer = (curBuffer + 1) % (sizeof(buffer)/(sizeof(buffer[0])));
    SecureZeroMemory(buffer[curBuffer], sizeof(buffer[curBuffer]));
    // start a new asynchronous call to ReadDirectory in the alternate buffer
    ReadDirectoryChangesW(
         hDir, /* handle to directory */
         &buffer[curBuffer], /* read results buffer */
         sizeof(buffer[curBuffer]), /* length of buffer */
         FALSE, /* monitoring option */
         FILE_NOTIFY_CHANGE_FILE_NAME  ,
         //FILE_NOTIFY_CHANGE_LAST_WRITE, /* filter conditions */
         NULL, /* bytes returned */
         &overl, /* overlapped buffer */
         NULL); /* completion routine */    

    for (;;) {
         (pFileNotify->Action == FILE_ACTION_ADDED)
        {
                qDebug()<<"in NotifyChange if ";
                char szAction[42];
                char szFilename[MAX_PATH] ;
                memset(szFilename,'\0',sizeof( szFilename));
                strcpy(szAction,"added");
                wcstombs( szFilename, pFileNotify->FileName, MAX_PATH);
                qDebug()<<"pFileNotify->FileName : "<<QString::fromWCharArray(pFileNotify->FileName)<<"\nszFilename : "<<QString(szFilename);                       

        }

        // step to the next entry if there is one
        if (!pFileNotify->NextEntryOffset)
            return false;
        pFileNotify = (FILE_NOTIFY_INFORMATION *)((PBYTE)pFileNotify + pFileNotify->NextEntryOffset);
    }
    pFileNotify=NULL;
    return true;
}

It works fine unless a file with Arabic name was added so I get

pFileNotify->FileName :  "???  ???????.txt" 
szFilename :  ""  

How can I support the UTF-8 code file name ??? any idea please.

Oumaya
  • 655
  • 4
  • 18
  • 43

1 Answers1

3

Apart from FILE_NOTIFY_INFORMATION::FileName not being null-terminated, there's nothing wrong with it.

FileName: A variable-length field that contains the file name relative to the directory handle. The file name is in the Unicode character format and is not null-terminated. If there is both a short and long name for the file, the function will return one of these names, but it is unspecified which one.

FileNameLength: The size of the file name portion of the record, in bytes. Note that this value does not include the terminating null character.

You'll have to use FILE_NOTIFY_INFORMATION::FileNameLength / sizeof(WCHAR) to get the length of the string in wchars pointed to by FileName. So in your case, the proper way would be:

size_t cchFileNameLength = pFileNotify->FileNameLength / sizeof(WCHAR);
QString::fromWCharArray( pFileNotify->FileName, cchFileNameLength );

If you need to use a function that expects the string to be null-terminated (like wcstombs) you'd have to allocate a temporary buffer with the size of FILE_NOTIFY_INFORMATION::FileNameLength + sizeof(WCHAR) and null-terminate it yourself.


As for the empty szFilename and question marks, that's just the result of converting an UTF16 (NTFS) filename that contains unconvertible characters to ANSI. If there's no conversion possible, wcstombs returns an error and QDebug converts any unconvertible character to ?.

If wcstombs encounters a wide character it cannot convert to a multibyte character, it returns –1 cast to type size_t and sets errno to EILSEQ.

So if you need to support unicode filenames, do not convert them to ANSI and exclusively handle them with functions that support unicode.

Anonymous Coward
  • 6,186
  • 1
  • 23
  • 29
  • thank you for this detailed answer I appreciate it, I fixed the not null-terminated issue, and I try this `size_t FileNameLength = pFileNotify->FileNameLength / sizeof(WCHAR); QByteArray encodedString = QString::fromWCharArray( pFileNotify->FileName, FileNameLength ).toLatin1(); QTextCodec *codec = QTextCodec::codecForName("UTF-8"); QString Fname = codec->toUnicode(encodedString);` but in vain, and what do you mean by _do not convert them to ANSI and exclusively handle them with functions that support unicode._ functions such as. – Oumaya Nov 07 '12 at 13:51
  • 1
    @oumaya What i mean is: leave the filename as unicode, don't convert it to ansi. If you need to open the file, use CreateFileW etc. Let QT handle the unicode string (don't convert it to latin1). I'm not using QT but i assume that you have to compile your application with _UNICODE defined if the GUI needs to display unicode strings possibly even for QString. Long story short: FILE_NOTIFY_INFORMATION isn't the problem. It's how you output the string. [How to print unicode characters using Qt?](http://stackoverflow.com/questions/9230610/how-to-print-unicode-characters-using-qt) – Anonymous Coward Nov 07 '12 at 14:28
  • OK but I need to output the name so I will try to use CreateFileW instead of fopen to open my file and see what can I do to get the name properly , thank you one more time. – Oumaya Nov 07 '12 at 14:47