Friday, March 4, 2011

How to use ReadDirectoryChangesW() method with completion routine?

I want to use function ReadDirectoryChangesW() in asynchronous mode with I/O completion routine supplied. The question is I don't know how to retrieve the exact information about the change in the completion routine (a CALLBACK function). Completion routine is defined like this:

VOID CALLBACK FileIOCompletionRoutine(
  [in]                 DWORD dwErrorCode,
  [in]                 DWORD dwNumberOfBytesTransfered,
  [in]                 LPOVERLAPPED lpOverlapped
);

I wonder the information is included in the LPOVERLAPPED structure. But I don't know how to get it. Can you teach me how to retrieve data from completion routine. Thank you very much!

From stackoverflow
  • ReadDirectoryChangesW has an lpBuffer argument which receives the output data. The completion routine's dwNumberOfBytesTransfered parameter only tells you about how much information has been written into this buffer. The actual structure of the data, as indicated by the ReadDirectoryChangesW documentation, is in the form of FILE_NOTIFY_INFORMATION records.

    So, you allocate a buffer, pass it off to ReadDirectoryChangesW, and scan the data out of that buffer when you get called back, interpreting the data of the buffer as a series of FILE_NOTIFY_INFORMATION structs.

    I'd advise you to get that working without asynchronous I/O first though, rather than trying to tackle two problems at once.

    Once you have it working synchronously, there's a trick to accessing user data from the async callback routine: over-allocate the OVERLAPPED structure and put extra data (such as the address of the buffer) past the end.

    Update: you seem not to have much of a clue about programming in C or for the Windows platform, so let me break it down a little more simply:

    From documentation for ReadDirectoryChangesW:

    lpOverlapped [in, out, optional]

    A pointer to an OVERLAPPED structure that supplies data to be used during asynchronous operation.

    It's an "in" parameter. That means you get to fill in at least some of the values inside the buffer; it also means that you get to allocate the buffer, and it also means that you get to decide how much memory you are going to allocate. You can decide to allocate more than sizeof(OVERLAPPED) in order to pass data to the routine, something along these lines:

    typedef struct MyOVERLAPPED {
        OVERLAPPED overlapped;
        MyData *data;
    } MyOVERLAPPED;
    

    Here is the documentation for OVERLAPPED.

    Here is how you might use above:

    MyOVERLAPPED *overlapped = malloc(sizeof(*overlapped));
    memset(overlapped, 0, sizeof(*overlapped));
    overlapped->data = // my data here
    ReadDirectoryChangesW(/* ... */, &overlapped->overlapped, MyCallback);
    

    And later:

    static void CALLBACK MyCallback(DWORD errorCode, DWORD tferred, LPOVERLAPPED over)
    {
        MyOVERLAPPED *overlapped = (MyOVERLAPPED *) over;
        MyData *data = overlapped->data;
        free(over);
        // etc.
    }
    

    It's not like this stuff is difficult. Here's an extensive worked example from MSDN. Note well the use of the PIPEINST struct.

    : I know what you mean. But how can I achieve this if the completion routine is a global function, or even belongs to another class, which can not get the lpBuffer which resides in some other place.
    Barry Kelly : The way you smuggle data from the initiation of the async I/O to the completion callback is by overallocating the `OVERLAPPED` structure and putting the extra data (such as the address of the buffer) in there.
    : How can I do this? I don't know at what point to insert the data into OVERLAPPED structure, because the completion callback is invoked automatically.
    Barry Kelly : You don't insert data *into* the overlapped structure; you allocate a buffer that is sizeof(OVERLAPPED)+sizeof(YOURDATA), and store your data past the end of the OVERLAPPED data. Then hand the address of the start of the data as the lpOverlapped argument.
    : sorry, I think the lpOverlapped argument is set by ReadDirectoryChangesW() function, and can't be self-defined.
    Barry Kelly : It is an argument. YOU pass it. It is something YOU create in order to pass to ReadDirectoryChangesW. Perhaps you have difficulty reading English, or is the MSDN documentation not sufficient to convince you of this case?
    : Thank you! It helped me a lot! I should read the documentation more throughly before asking a question next time.

0 comments:

Post a Comment