As in title I want to add/remove items to a class derived from the WTL CListViewCtrl class from worker threads, but always get "Unhandled exception thrown: read access violation."
I tried Win32 API PostMessage and SendMessage but once the worker thread touches the HWND of CListViewCtrl I get the same exception.
// CListCtrl member function, calling from worker thread
HWND GetHwnd()
{
    return hwndListCtrl;       // exception here
}
I tried this SafeQueue but once worker thread touches the mutex or queue then exception again.
// SafeQueue is member variable in CListViewCtrl, created in GUI thread
SafeQueue<T> m_SafeQueue;
. . .
// member function in SafeQueue class, calling from worker thread
void enqueue(T t)
{
    std::lock_guard<std::mutex> lock(m);  // exception here
    q->push(t);
}
I tried to create the mutex and queue with new and HeapAlloc/LocalAlloc but same exception again.
I tried Win32 API CreateMutex but no luck, same exception when accessing mutex handle from worker thread.
It works fine when I add items from the GUI thread.
Only way it works from worker threads if I declare HWND or mutex and queue as static/global but I would avoid this since I want to use more than one instance from this listcontrol and I prefer any more elegant way than global variable.
I want to make this class reusable since I want to use it many times with a few modifications (more columns, different colors).
I appreciate any help and idea how I can make this work.
Environment: VS2015 Community, WTL/C++ and Win10 Pro 64bit
I found the problem that causes access violation exception: I declared ThreadProc callback function as static member function in CListViewCtrl class.
// DO NOT USE
// in CListViewCtrl
**static** DWORD WINAPI ThreadProc(LPVOID lp)
{
. . .
}
LRESULT OnStartWorkerThread(WORD /*wNotifyCode*/, WORD /*wID*/, HWND . ..)
{
    DWORD dw;
    ::CreateThread(NULL, 0, this->ThreadProc, NULL, 0, &dw);
}
A working solution:
class CListViewCtrl ...
{
    // thread-safe queue to store listctrl items to be added later in GUI thread
    SafeQueue<CListCtrlItem<nCols> > m_SafeQueue;  
    // thread ID of the thread in which listctrl was created, saved in OnCreate
    DWORD m_dwGuiTid;
    // . . .
Check if SafeAddItem function called from GUI or any other threads
    BOOL InvokeRequired()
    {
        if (m_GuiTid == ::GetCurrentThreadId())
            return false;
        return true;
    }
    // ...
SafeAddItem member function can be called from GUI and worker threads
    void SafeAddItem(CListCtrlItem<nCols> item)
    {
        if (!InvokeRequired())
        {
            // we are in GUI thread so just add listctrl item "normal" way
            AddItem(item);
            return;
        }
     // we are in other thread so enqueue listctrl item and post a message to GUI           
        m_SafeQueue.Enqueue(item);
        ::PostMessage(m_hWnd, WM_ADD_ITEM, 0, 0);
     }
    // . . .
Message handler of PostMessage, we are in GUI thread
    LRESULT OnAddItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
    {
        CListCtrlItem<nCols> item;
        while (!m_SafeQueue.Empty())
        {
            item = m_SafeQueue.Dequeue();
            // we are in GUI thread so we can add list ctrl items normal way
            AddItem(item);
        }
        return 1;
    }
    // ...
}
And now we can add listctrl items from any threads this way. I pass this pointer to ThreadProc in _beginthreadex
m_ListCtrl.SafeAddItem(item);
 
     
     
    