0

TLDR - GetQueuedCompletionStatus does not return if I provide a class object as the completion key, it returns only if structure object is passed instead.


I created a IOCP in main thread using CreateIoCompletionPort

ShareInfo* l_poShareInfo = new ShareInfo(hDir, p_sSharePath, p_oChangeHandler, dwChangesToMonitor, true);

m_hCompPort = CreateIoCompletionPort(hDir, m_hCompPort, (ULONG_PTR)&l_poShareInfo, 0);

and then I wait for data in a worker thread using GetQueuedCompletionStatus

ShareInfo* l_ShareInfo;
GetQueuedCompletionStatus((HANDLE)l_pThis->m_hCompPort, &nBytes, (PULONG_PTR)&l_ShareInfo, &lpOverlapped, INFINITE);

ShareInfo is a class as follows, whose object I am using as a completion key.

class ShareInfo
{
public:
    ShareInfo();
    ShareInfo(HANDLE p_hDir, const std::wstring & p_sSharePath, FileChangeHandlerBase * p_poChangeHandler, DWORD p_dwChangeFilter, bool p_bWatchSubDir);
    ~ShareInfo();


    OVERLAPPED  m_Overlapped;
    HANDLE      m_hDir;
    TCHAR       m_sSharePath[MAX_PATH];
    CHAR        m_Buffer[4096];
    DWORD       m_dwBufLength;
    DWORD       m_dwChangeFilter;
    FileChangeHandlerBase* m_poChangeHandler;

    BOOL        m_bWatchSubDir;
};

However, GetQueuedCompletionStatus doesn't return. If I provide a structure object instead of a class object, it works as expected. So I had to transform my class as follows and use an object of ShareInfo::ShareInfoData as completion key.

class ShareInfo
{
public:
    .
    .
    typedef struct 
    {
        OVERLAPPED  m_Overlapped;
        HANDLE      m_hDir;
        TCHAR       m_sSharePath[MAX_PATH];
        CHAR        m_Buffer[4096];
        DWORD       m_dwBufLength;
        DWORD       m_dwChangeFilter;
        FileChangeHandlerBase* m_poChangeHandler;

    }ShareInfoData;

    ShareInfoData   m_shareInfoData;
    BOOL            m_bWatchSubDir;
};

I suspect Completion keys cannot to be classes, but I don't find anything mentioned in the official docs. Am I missing something fundamental here?

Praveen
  • 73
  • 2
  • 5
  • Just to add, there are 2 or 3 getter methods in this class. – Praveen Oct 10 '18 at 13:05
  • at first `GetQueuedCompletionStatus` dont understand what is *class*, *struct* etc. it return exactly pointer value passed by `PostQueuedCompletionStatus` direct or via file handle completion key. at second for what you use `GetQueuedCompletionStatus` at all instead `BindIoCompletionCallback` to `m_hDir` – RbMm Oct 10 '18 at 13:12
  • 3
    `(ULONG_PTR)&l_poShareInfo` - this is your error. must be `(ULONG_PTR)l_poShareInfo`. as result you got `&l_poShareInfo` - address of local variable which hold pointer to your data. but you need address intself (`l_poShareInfo`) – RbMm Oct 10 '18 at 13:19
  • 1
    It can be anything you want, it is just a pointer. The only requirement is that it is still valid by the time the I/O completes. So never pass a pointer to a local variable, you meant to use l_poShareInfo, not &l_poShareInfo. – Hans Passant Oct 10 '18 at 13:19
  • 2
    It's not actually even a pointer, it's just a value that is guaranteed to be the same size as a normal data pointer. – SoronelHaetir Oct 10 '18 at 19:08
  • Thank you very much, It was silly of me not to pass the local variable. Issue resolved. – Praveen Oct 11 '18 at 03:44
  • can advice also instead create iocp yourself and working thread pool which will be listen on it - much simply call `BindIoCompletionCallback` on `m_hDir` as result your callback with be called when io complete. and use reference count on `ShareInfo` – RbMm Oct 11 '18 at 15:14

0 Answers0