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:
Association avec l'iocp:
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);
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 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; }
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 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; }
Le probleme c'est que lorsque j'ajoute un fichier a monitorer, je recois DEUX notifications.
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(); } } }
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; };
Partager