有没有办法取消并重新启动COM对象中的函数?

时间:2015-08-27 17:01:02

标签: com callback vb6 activex

我的软件现在如何运作:

我有一个C ++ ATL对象和一个VB6客户端应用程序。 COM对象有一个函数Find,它搜索数据库并通过回调函数报告匹配。当用户使用其Change事件将文本输入TextBox,传递文本和回调函数的地址时,我从VB6调用Find函数。回调函数输出与ListBox的匹配,进行DoEvents调用,并返回一个值,指示搜索是否应该继续。

我想要完成的任务:

当用户在搜索已经运行时更改搜索字段中的文本时,我想取消正在运行的搜索,清空ListBox,然后使用更新后的文本启动一个新文件。

我遇到的问题:

因为在回调函数的DoEvents调用期间触发了TextBox的Change事件,所以在回调可以返回“取消”代码之前,新搜索会堆叠在第一个上面。当这个新搜索匹配时,它会调用回调,取回取消代码,然后结束,此时将恢复先前的搜索。

如何在自动开始新搜索之前取消旧搜索?

代码:

Private Sub txtFind_Change()
    lvResults.ListItems.Clear
    m_customer.CancelFind #' Not useful
    frmMain.appData.Licfile.Find(txtFind.Text, AddressOf FindCallback, ObjPtr(m_customer))
End Sub

Public Function CancelFind()
    If m_bFindRunning Then: m_bCancelFind = True
End Function

Public Function FindCallback(ByVal foundItem As Boolean, _
                             ByVal finished As Boolean, _
                             ByVal index As Long) As Long
Dim record As zLicFileRecord
Dim resultstr As String
Dim error As Long
    If foundItem Then
        frmMain.appData.Licfile.Read(index, record)
        RaiseEvent SearchResult(index, record)
        DoEvents
    Else
        If Not finished Then
            RaiseEvent SearchProgress(index, frmMain.appData.Licfile.RecordCount)
            DoEvents
        Else
            RaiseEvent SearchFinished
        End If
    End If
    If m_bCancelFind Then
        FindCallback = 1
        m_bCancelFind = False
    End If
End Function


STDMETHODIMP CzLicenseFile::Find(BSTR  find, 
                                 LONG  callbackFunction /* fnFindCallback */,
                                 LONG  context,
                                 LONG* win32Error)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    CHECK_PTR(win32Error);

    if (!callbackFunction)
    {
        *win32Error = ERROR_NO_CALLBACK_ACTIVE;
        RETURN_OK;
    }

    fnFindCallback pfnCallback = reinterpret_cast<fnFindCallback>(callbackFunction);

    try 
    {
        DWORD recordCount;
        get_RecordCount(reinterpret_cast<LONG*>(&recordCount));
        if (recordCount == static_cast<DWORD>(-1))
        {
            *win32Error = ERROR_READ_FAULT;
            RETURN_OK;
        }

        QuickMatcher matcher(std::wstring(find, ::SysStringLen(find)));

        for (size_t i = static_cast<size_t>(startIndex); i < recordCount; ++i)
        {
            LicenseFileRecord const& item = m_fileBuf.Get(i);  

            bool match = matcher.match(item);

            if (match)
            {
                if (pfnCallback)
                {
                    LONG result = pfnCallback(VTRUE, VFALSE, i, context);
                    if (result != 0)
                    {
                        break;
                    }
                }
            }
            else if (i % 1000 == 0)
            {
                if (pfnCallback)
                {
                    LONG result = pfnCallback(VFALSE, VFALSE, i, context);
                    if (result != 0)
                    {
                        break;
                    }
                }
            }
        }    
    }
    catch (AutoWinError const& e)
    {
        *win32Error = e.error();
        RETURN_OK;
    }

    if (pfnCallback)
    {
        pfnCallback(VFALSE, VTRUE, -1, context);
    }

    *win32Error = ERROR_SUCCESS;
    RETURN_OK;
}

1 个答案:

答案 0 :(得分:1)

我用函数和Timer对象解决了这个问题。 txtFind_Change现在调用此函数:

Public Sub StartSearch()
Dim error As Long
    lvResults.ListItems.Clear
    If Not m_customer Is Nothing Then
        If Not m_customer.FindRunning Then
            error = frmMain.appData.Licfile.Find(txtFind.Text, AddressOf FindCallback, ObjPtr(m_customer))
        Else
            m_customer.CancelFind
            TimerSearchRestart.Interval = 50
            TimerSearchRestart.enabled = True
        End If
    End If
End Sub