John Smith
John Smith

Reputation: 89

Unhandled CDBException while having an appropriate "catch"

I'm trying to handle DB connection error. If the CDatabase::Open (or the CDatabase::OpenEx) fails, the CDBException is normally thrown. But there's the thing. I can't handle it!

Here's my code:

try
{
    CDatabase db;
    db.OpenEx(L"DSN=INVALID_DSN;UID=noname", CDatabase::noOdbcDialog);
    wprintf(L"Connection established.\n"
            L"DSN used: %s\n"
            L"DB name:  %s\n",
            db.GetConnect().GetBuffer(),
            db.GetDatabaseName().GetBuffer());
    db.Close();
    puts("Connection closed.");
}
catch (CDBException& e)
{
    e.GetErrorMessage(buf, BUF_SIZE);
    wprintf(L"CDBException: %s\n", buf);
}
catch (CException& e)
{
    e.GetErrorMessage(buf, BUF_SIZE);
    wprintf(L"CException: %s\n", buf);
}
catch (std::exception& e)
{
    printf("STD exception: %s\n", e.what());
}
// this section is the only way to handle exception thrown by the CDatabase::OpenEx
//catch (...)
//{
//    puts("Unknown exception");
//}

If the last catch is commented, I get error notification:

**Unhandled exception at 0x76EAB727 in test-odbc.exe: Microsoft C++ exception: CDBException at memory location 0x004DF40C.**

I use Visual Studio 2013 (Version 12.0.40629.00 Update 5)

Upvotes: 2

Views: 1330

Answers (3)

IInspectable
IInspectable

Reputation: 51413

MFC 1.0 was released in 1992, 6 years before the official ISO/IEC language specification for the C++ Programming Language was ratified. With exception handling being one of the features that solidified late in the process, MFC based its framework on the (then current) implementation for exceptions. Exception Handling in MFC differs from today's exception handling in the following ways:

  • MFC exceptions can only be caught by pointer. The paradigm "throw by value, catch by (const) reference" hadn't been established.
  • The final exception handler must perform cleanup of MFC exceptions.

MFC provides macros to implement its exception handling (TRY, CATCH, AND_CATCH, END_CATCH, THROW, THROW_LAST) which you will find in existing code, but there is no requirement to use them in new code. The same functionality can be implemented using Standard C++ exception handling keywords (see Exceptions: Converting from MFC Exception Macros for instructions).

Applying this to your code:

try {
    CDatabase db;
    db.OpenEx(L"DSN=INVALID_DSN;UID=noname", CDatabase::noOdbcDialog);
    wprintf(L"Connection established.\n"
            L"DSN used: %s\n"
            L"DB name:  %s\n",
            db.GetConnect().GetBuffer(),
            db.GetDatabaseName().GetBuffer());
    db.Close();
    puts("Connection closed.");
}
catch (CDBException* e) {  // Catch by pointer
    e->GetErrorMessage(buf, BUF_SIZE);
    wprintf(L"CDBException: %s\n", buf);
    // Dispose exception object; Do not use the delete keyword, because it can fail if
    // the exception is not on the heap.
    // Do not call Delete() in case you want to rethrow the exception.
    e->Delete();
}
catch (CException* e) {
    e->GetErrorMessage(buf, BUF_SIZE);
    wprintf(L"CException: %s\n", buf);
    e->Delete();
}
catch (const std::exception& e) {  // Catch by const reference
    printf("STD exception: %s\n", e.what());
}
catch (...) {
    // Only use after a 'catch(CException*)' clause to not leak MFC exception objects
}

Upvotes: 2

Joey Yandle
Joey Yandle

Reputation: 141

Looking at the MSDN docs, they (strangely) say to catch a pointer to the exception, not a reference:

https://msdn.microsoft.com/en-us/library/19b8k939.aspx

try
{
}
catch(CDBException* e)
{
}

Upvotes: 1

Ajay
Ajay

Reputation: 18431

You will need to use MFC specific exception handling macros: TRY, CATCH, and END_CATCH. MFC exceptions are pointer-only, and are deleted by special macros only.

See example here

EDIT: Inline example:

TRY
{
   // Do something to throw an exception.
   AfxThrowUserException();
}
CATCH(CException, e)
{
   if (m_bPassExceptionsUp)
      THROW_LAST();

   if (m_bReturnFromThisFunction)
      return;

   // Not necessary to delete the exception e.
}
END_CATCH

Upvotes: 1

Related Questions