使用WinDbg可以很好地运行代码,但没有它就很奇怪

时间:2017-06-27 22:09:04

标签: c++ mfc windbg

我正在调试WinDbg的问题,我可以持续生成。问题是当我用WinDbg运行可执行文件来调试它时,问题无法再现。可能是什么原因?

以下代码行为不同:

CWnd* pWnd = GetDlgItem(IDOKCANCEL);
if(pWnd)
{
    CString sOK;
    sOK.LoadString(IDS_OK);
    pWnd->SetWindowText(sOK);
}

当我使用WinDbg运行时,按钮文本会正确更新,但是当我正常运行它时它没有更新(这是错误)。

更新

正如我在评论中所说,问题不在于上面的代码,因为它甚至没有被调用。该操作在工作线程中完成,该线程将更新消息发送到此对话框。执行上述代码的最终消息永远不会发送,因此上述代码永远不会被执行。

为什么工作线程没有发送此消息很有意思。它在打开数据库时锁定在关键部分。 WinDbg告诉我,主线程是该关键部分的所有者,但我无法从调用堆栈或任何其他方式看到它无法解锁关键部分。

问题的复杂之处在于,如果我使用调试器运行它会正常工作。我添加了日志输出,但它也可以通过此更改开始正常工作。

我可以用调试器捕获它的唯一方法是当我运行它正常模式,产生问题,然后附加调试器,它显示我锁定在临界区。它显示主线程是该关键部分的所有者,但不清楚它为什么处于锁定状态。关键部分只需在一个函数中锁定和解锁即可。

更新2

我只在我的整个项目中的一个文件中使用临界区,并且只有两个函数(当它打开数据库和记录集时)。

BOOL CADODatabase::Open(LPCTSTR lpstrConnection, LPCTSTR lpstrUserID, LPCTSTR lpstrPassword)
{
    CString database = GetSourceDatabase( lpstrConnection, NULL );

    // get the appropriate critical section based on database
    g_dbCriticalSection = GetDbCriticalSection( database );

    if( g_dbCriticalSection) 
        g_dbCriticalSection->Lock();

    HRESULT hr = S_OK;

    if(IsOpen())
        Close();

    if(wcscmp(lpstrConnection, _T("")) != 0)
        m_strConnection = lpstrConnection;

    ASSERT(!m_strConnection.IsEmpty());

    try
    {
        if(m_nConnectionTimeout != 0)
            m_pConnection->PutConnectionTimeout(m_nConnectionTimeout);
        hr = m_pConnection->Open(_bstr_t(m_strConnection), _bstr_t(lpstrUserID), _bstr_t(lpstrPassword), NULL);

        if( g_dbCriticalSection) 
            g_dbCriticalSection->Unlock();

        return hr == S_OK;
    }
    catch(_com_error &e)    
    {
        dump_com_error(e);

        if( g_dbCriticalSection) 
            g_dbCriticalSection->Unlock();

        return FALSE;
    }
}

第二个功能有其他明显的缺陷,但请忽略它的遗留代码。

BOOL CADORecordset::Open(_ConnectionPtr mpdb, LPCTSTR lpstrExec, int nOption)
{   
    BSTR bstrConnString;
    m_pConnection->get_ConnectionString(&bstrConnString);
    CString database = GetSourceDatabase( bstrConnString, m_pConnection );

    g_dbCriticalSection = GetDbCriticalSection( database );

    if( g_dbCriticalSection) 
        g_dbCriticalSection->Lock();

    Close();

    if(wcscmp(lpstrExec, _T("")) != 0)
        m_strQuery = lpstrExec;

    ASSERT(!m_strQuery.IsEmpty());

    if(m_pConnection == NULL)
        m_pConnection = mpdb;

    m_strQuery.TrimLeft();
    BOOL bIsSelect = m_strQuery.Mid(0, _tcslen(_T("Select "))).CompareNoCase(_T("select ")) == 0 && nOption == openUnknown;

    int maxRetries = 10;
    bool bContinue = true;

    CursorTypeEnum adCursorType = adOpenStatic;
    if (!m_bSQLEngine)
    {
        // MDB Engine
        adCursorType = adOpenStatic;
        m_pConnection->CursorLocation = adUseClient;
    }
    else
    {
        // SQL Engine
        adCursorType = adOpenDynamic;
        m_pConnection->CursorLocation = adUseServer;
    }

    int currentCommandTimeout = m_pConnection->CommandTimeout;

    if( g_dbCriticalSection) 
        g_dbCriticalSection->Unlock();

    for (int iRetry = 0; (iRetry < maxRetries) && bContinue; iRetry++)
    {
        try
        {
            // we just use an auto lock object so it is unlocked automatically, it uses same 
            // critical section object.
            if( g_dbCriticalSection) 
                g_dbCriticalSection->Lock();

            int newCommandTimeout = currentCommandTimeout + 15 * iRetry;
            m_pConnection->CommandTimeout = newCommandTimeout;


            if(bIsSelect || nOption == openQuery || nOption == openUnknown)
            {

                m_pRecordset->Open((LPCTSTR)m_strQuery, _variant_t((IDispatch*)mpdb, TRUE), 
                                adCursorType, adLockOptimistic, adCmdUnknown);
            }
            else if(nOption == openTable)
            {
                m_pRecordset->Open((LPCTSTR)m_strQuery, _variant_t((IDispatch*)mpdb, TRUE), 
                            adOpenDynamic, adLockOptimistic, adCmdTable);
            }
            else if(nOption == openStoredProc)
            {
                m_pCmd->ActiveConnection = mpdb;
                m_pCmd->CommandText = _bstr_t(m_strQuery);
                m_pCmd->CommandType = adCmdStoredProc;

                m_pRecordset = m_pCmd->Execute(NULL, NULL, adCmdText);
            }
            else
            {
                TRACE( _T("Unknown parameter. %d"), nOption);

                if( g_dbCriticalSection) 
                    g_dbCriticalSection->Unlock();

                return FALSE;
            }

            if( g_dbCriticalSection) 
                g_dbCriticalSection->Unlock();

            bContinue = false;
        }
        catch(_com_error &e)
        {
            if( g_dbCriticalSection) 
                g_dbCriticalSection->Unlock();

            dump_com_error_without_exception(e, _T("Open"));

            // retry Query timeout

            CString szDescription;
            _bstr_t bstrDescription(e.Description());
            szDescription.Format( _T("%s"), (LPCTSTR)bstrDescription);

            if ((szDescription.Find(_T("Query timeout expired")) == -1) || (iRetry == maxRetries - 1))
            {
                m_pConnection->CommandTimeout = currentCommandTimeout;
                throw CADOException(e.Error(), e.Description());
            }
            Sleep (1000);
            bContinue = true;
        }

    }

    m_pConnection->CommandTimeout = currentCommandTimeout;

    return m_pRecordset != NULL && m_pRecordset->GetState()!= adStateClosed;
}

为了完整起见,上面调用了这个函数:

static CCriticalSection* GetDbCriticalSection(const CString& database)
{
  // For now we only care about one database and its corresponding critical section
    if (database.CompareNoCase( _T("Alr") ) == 0)
        return &g_csAlrDb; // g_csAlrDb is defined static global in this file
    else
        return 0;

}

为各种数据库调用Open()函数,我只锁定对一个数据库的访问权限。正如您所看到的那样,存在相应的锁定/解锁,因此不确定这些函数的代码是如何在关键部分锁定的情况下实现的。可能是因为MFC issue

1 个答案:

答案 0 :(得分:-1)

就我而言,大多数情况下,当C ++软件在调试和发布版本之间表现不同时,这是因为未初始化的变量,不同的库链接或编译器优化的回火。

要跟踪错误,请尝试评估变量和函数返回值,例如LoadString,例如AfxMessageBox()