c++ - 代码在 WinDbg 上运行良好,但没有它就很奇怪

标签 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

最佳答案

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

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

关于c++ - 代码在 WinDbg 上运行良好,但没有它就很奇怪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44790735/

相关文章:

c++ - 在 Windows 窗体上获取文本的方法(非托管 C++ 项目)

c++ - 使用 `.reload` 强制 WinDbg 加载 pdb 不起作用

qt - CDB 在 Qt Creator 中加载变量的速度非常慢

c++ - 类构造函数打印有问题

c++ - 用于 URL 验证的正则表达式

winapi - Windows 浏览器控件与 CDHtmlDialog 和 CHtmlView

.net - 如何判断是托管内存泄漏还是 native 内存泄漏?

c++ - 将 Platform::Array<byte> 转换为字符串

android - 如何使用 opencv c++ 和 android studio ndk 将图像读入 Mat 对象?

c++ - 更改 CMFCRibbonStatusBar 的文本,但显示第一个字符和三个点(如 "C...")