Bonjour a tous,
je suis en train de realiser une classe de monitoring de fichier multi plateforme.
je l'ai realise sous BSD, Linux et la sous windows j'ai un petit probleme.

J'utilise la fonction ReadDirectoryChangesW pour lire les changements de maniere asynchrone avec les IOCompletionPorts.

Voici les grandes lignes de ma classe:

Ouverture du dossier:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
hndl = CreateFile(dir.toString().c_str(),
                    FILE_LIST_DIRECTORY, 
                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                    NULL,
                    OPEN_EXISTING,
                    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
                    NULL);
Association avec l'iocp:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
                HANDLE sub_iocp = CreateIoCompletionPort(hndl, this->_iocp, 0, 0);
                if (sub_iocp == NULL)
                {
                    delete o;
                    Debug(Debug::error) << "[Windir] Cannot create sub IOCP" << std::endl;
                    // XXX: Exception ?
                    return false;
                }
Fonction qui ajoute une operation de lecture:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
            bool startReadFor(Operation* o)
            {
                memset(&o->overlapped, 0, sizeof(o->overlapped));
                DWORD read = ReadDirectoryChangesW(o->dir,
                    o->changes, sizeof(o->changes),
                    FALSE,
                    FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME,
                    NULL,
                    &o->overlapped,
                    NULL);

                if (read == 0)
                {
                    Debug(Debug::error) << "[WinDir] Error in ReadDirectoryChangesW: " <<
                        GetLastError() << std::endl;
                    return false;
                }
                return true;
            }
dans ma methode run:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
            void run()
            {
                DWORD           nByte = 0;
                ULONG_PTR       key = 0;
                LPOVERLAPPED    overlapped = NULL;
                Operation   *op = NULL;

                Debug(Debug::info) << "[WinDir] Start Monitoring"
                    << std::endl;
                while (true)
                {
                    BOOL ret = GetQueuedCompletionStatus(this->_iocp, &nByte, &key, &overlapped, INFINITE);

                    if (key == ~(0))
                    { /* ...Stop...*/   }

                    if (overlapped == NULL)
                    { /* ..........*/   }

                    int error;
                    /* ..........*/
                    
                    op = CONTAINING_RECORD(overlapped, Operation, overlapped);

                    std::string filename;
                    std::wstring wfilename;
                    Operation::FileDatas::iterator it;

                    if (nByte == 0)
                    {/* ..........*/}

                    PFILE_NOTIFY_INFORMATION notify = reinterpret_cast< PFILE_NOTIFY_INFORMATION >(op->changes);

                    /* .....Get filename.....*/
                  

                    it = op->watchedFiles.find(filename);
                    if (it != op->watchedFiles.end())
                    {
                        Operation::FileData& data = it->second;
                        bool has_next = true;
                        do
                        {
                            switch (notify->Action)
                            {
                            case FILE_ACTION_MODIFIED:
                                if (data.mode & NOTIFY_WRITE)
                                    (*data.callable)();
                                break;

                            case FILE_ACTION_REMOVED:
                                if (data.mode & NOTIFY_DELETE)
                                    (*data.callable)();
                                break;

                            default:
                                Debug(Debug::error) << "[WinDir] Receive not supported notification: "
                                    << notify->Action
                                    << std::endl;
                            }

                            if(notify->NextEntryOffset)
                            {
                                Debug(Debug::info) << "[WinDir] There is another notification to read" << std::endl;
                                notify = (PFILE_NOTIFY_INFORMATION)(((DWORD) notify) + notify->NextEntryOffset);
                                has_next = true;
                            }
                            else
                            {
                                Debug(Debug::debug) << "[WinDir] All event are consumed" << std::endl;
                                has_next = false;
                            }
                        } while (has_next);
                    }
                    else
                    {
                        Debug(Debug::info) << "[WinDir] Notification for not watched file received: "
                            << filename << std::endl;
                    }

                    // restart a read with current Operation
                    if (!this->startReadFor(op))
                    {
                        Debug(Debug::error) << "[WinDir] Cannot restart a read: " << GetLastError()
                            << std::endl;
                        throw GetLastError();
                    }
                }
            }
Le probleme c'est que lorsque j'ajoute un fichier a monitorer, je recois DEUX notifications.

Lorsque j'enregistre un fichier j'ai donc deux notifications, par contre quand je le supprime je n'en ai qu'une.

Auriez vous des informations sur pourquoi ca reagis comme ca ?

Si vous avez besoin du code complet ...

Merci.

PS:
Voici le operation:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
            struct Operation
            {
                Operation()
                {}

                ~Operation()
                {}

                struct FileData
                {
                    FileData()
                    {}

                    FileData(shared_ptr< ICallable > d, int m) :
                        callable(d), mode(m)
                    {}

                    FileData(const FileData& f) :
                        callable(f.callable), mode(f.mode)
                    {}

                    shared_ptr< ICallable > callable;
                    int                     mode;
                };

                typedef std::map <Path, FileData> FileDatas;
                FileDatas                   watchedFiles;
                OVERLAPPED                  overlapped;
                CHAR                        changes[4096];
                HANDLE                      dir;
                Path                        path;
            };