IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Discussion :

[ReadDirectoryChangesW et IoCompletionPort] Double notification


Sujet :

Windows

  1. #1
    Membre actif
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2004
    Messages
    230
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2004
    Messages : 230
    Points : 250
    Points
    250
    Par défaut [ReadDirectoryChangesW et IoCompletionPort] Double notification
    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;
                };

  2. #2
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par daedric Voir le message
    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.
    Quelles notifications reçois-tu, exactement, et dans les deux cas ?
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  3. #3
    Membre actif
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2004
    Messages
    230
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2004
    Messages : 230
    Points : 250
    Points
    250
    Par défaut
    La meme, voici un copier coller de la sortie de mon programme de test:

    [INFO] [WinDir] Start Monitoring
    [DEBUG] [WinDir] Byte read: 24
    [NOTICE] [WinDir] Dir(0000000000000028) have been updated: .
    [DEBUG] [Windir] Operation type = 3
    Notification recu pour: kikoo1
    [INFO] [WinDir] Stop Monitoring
    [DEBUG] [WinDir] All event are consumed
    [DEBUG] [WinDir] exit WinMonitor::run()
    [INFO] [WinDir] Start Monitoring
    [DEBUG] [WinDir] Byte read: 24
    [NOTICE] [WinDir] Dir(0000000000000028) have been updated: .
    [DEBUG] [Windir] Operation type = 3
    Notification recu pour: kikoo1
    [INFO] [WinDir] Stop Monitoring
    [DEBUG] [WinDir] All event are consumed
    [DEBUG] [WinDir] exit WinMonitor::run()
    Appuyez sur une touche pour continuer...
    On vois donc bien que le type de l'operation est donc FILE_ACTION_MODIFIED dans les deux cas.
    Voici mon programme de test:

    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
    # include "Bind.hpp"
    # include "FileMonitoring.hpp"
    
    DEBUG_INIT(Debug::debug);
    
    using namespace ztk::fs;
    
    FileMonitor monitor;
    
    void test(std::string test)
    {
        std::cout << "Notification recu pour: " << test << std::endl;
        monitor.stop();
    }
    
    
    int main(int, char**)
    {
        {
            Path p1("kikoo1");
            Path p2("kikoo2");
            Path p3("kikoo3");
    
            if (!p1.exists())
                p1.createFile();
            if (!p2.exists())
                p2.createFile();
            if (!p3.exists())
                p3.createFile();
        }
    
        monitor.addFile("kikoo1", FileMonitor::NOTIFY_WRITE | FileMonitor::NOTIFY_DELETE, ztk::bind(&test, "kikoo1"));
        monitor.addFile("kikoo2", FileMonitor::NOTIFY_WRITE | FileMonitor::NOTIFY_DELETE, ztk::bind(&test, "kikoo2"));
        monitor.addFile("kikoo3", FileMonitor::NOTIFY_WRITE | FileMonitor::NOTIFY_DELETE, ztk::bind(&test, "kikoo3"));
        monitor.run();
    
        monitor.rmFile("kikoo2");
        monitor.run();
        system("pause");
    
        return (0);
    }

Discussions similaires

  1. double notification ReadDirectoryChangesW
    Par antoine2641 dans le forum Débuter
    Réponses: 1
    Dernier message: 05/09/2012, 20h50
  2. Réponses: 3
    Dernier message: 01/07/2003, 16h04
  3. [CODE] Application dans la zone de notification
    Par Rodrigue dans le forum C++Builder
    Réponses: 4
    Dernier message: 29/05/2003, 19h06
  4. String -> long double (_strlold ?)
    Par haypo dans le forum C
    Réponses: 7
    Dernier message: 25/07/2002, 20h22
  5. Réponses: 3
    Dernier message: 12/06/2002, 21h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo