Share via

Legacy code with atldbcli and OLEDB does behave differently with C++20

2024-01-18T10:53:01.5+00:00

I have a legacy code base where I connect with OLEDB to a MSSQL server.

Now here is the code:

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0A00
#endif

#include <afx.h>
#include <atlbase.h>
#include <atldbcli.h>

// -------------------------------------------------------------------
// OpenWithUDL - connect and open database using an udl file
// -------------------------------------------------------------------
HRESULT OpenWithUDL(CSession& m_session, const CString& pathToUdl)
{
	CDataSource db;
	USES_CONVERSION;

	HRESULT hr = db.OpenFromFileName(T2COLE(pathToUdl));
	if (FAILED(hr)) { return hr; }
	
	CDBPropSet dbinit(DBPROPSET_DBINIT);
	dbinit.AddProperty(DBPROP_INIT_OLEDBSERVICES, (short)DBPROPVAL_OS_ENABLEALL);

	return m_session.Open(db);
}
// -------------------------------------------------------------------
// Connect to database
//
// SetConnStr() or SetUdlStr() must be called first to define the db
// to open - when not set use hardcoded db details for connection
// -------------------------------------------------------------------
HRESULT Open(CSession& m_session, const CString& pathToUdl)
{
	HRESULT hr = CoInitialize(NULL);
	if (FAILED(hr)) { return E_FAIL; }

	return OpenWithUDL(m_session, pathToUdl);
}
// -------------------------------------------------------------------
// Return:	true  db connection ok - session param not NULL
//					false db connection failed
// -------------------------------------------------------------------
bool GetDBCon(const CSession& p_session)
{
	if (p_session.m_spOpenRowset == NULL) { return false; }

	HRESULT hr;
	XACTTRANSINFO pInfo;
	try
	{
		hr = p_session.GetTransactionInfo(&pInfo);
	}
	catch (...)
	{
		return false;
	}
 	return hr == S_OK || hr == XACT_E_NOTRANSACTION;
}

int main()
{
	CSession session;
	CString pathToUdl = "SomePathToUDL";
 	
	HRESULT hr = Open(session, pathToUdl);
	if (FAILED(hr)) { return -1; }

 	try
	{
		if (!GetDBCon(session)) { return -2; }
	}
 	catch (...)
	{
		return -3;
	}
 	
	CString sqlStatement = "SELECT GETDATE();"; // Some select statement

 	CCommand<CDynamicAccessor> d_tab; // <<-- Here is the Problem
	hr = d_tab.Open(session, sqlStatement);
	if (FAILED(hr))
	{
		d_tab.Close();
		return -4;
	}
 	hr = d_tab.MoveFirst(); // <<-- throws exception because ATLASSUME(m_pAccessor != NULL) fails
}

Now the interesting part is, at the process of instantiation of d_tab, CAccessorRowset gets its ctor called. There it registers itself as accessor (see code listing).

///////////////////////////////////////////////////////////////////////////
// CAccessorRowset
template <class TAccessor = CNoAccessor, template <typename T> class TRowset = CRowset>
class CAccessorRowset :
	public TAccessor,
	public TRowset<TAccessor>
{
public:
	template <class _Self = CAccessorRowset>
	CAccessorRowset()
	{
		// Give the rowset a pointer to the accessor
#ifdef _ATL_MODULES
		if constexpr(_Has_m_nAccessors<_Self>::value)
#else // ^^ _ATL_MODULES / !_ATL_MODULES vv
		__if_exists(m_nAccessors)
#endif // _ATL_MODULES
		{
			static_cast<_Self*>(this)->SetAccessor(this); // <<--- register as accessor
		}
	}
//...
};

The provided code at the top throws the exception regardless of the C++ version. But in my legacy code the access to the DB is compiled to a .lib with C++17. Excecuting the calls in main results in registering as accessor, but not so, when it was compiled in C++20. Which to me makes no sense. Does anyone know a solution to that?

Developer technologies | C++
Developer technologies | C++

A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.

SQL Server | Other
SQL Server | Other

Additional SQL Server features and topics not covered by specific categories


Answer accepted by question author

Minxin Yu 13,516 Reputation points Microsoft External Staff
2024-01-19T03:26:52.2933333+00:00

Hi, @Schmidiger Kevin Patrick, SPS52-11

From the bug report, Crash in ATL CEnumerator::MoveNext after upgrading to 17.3 toolset with conformance mode.
Please define _ATL_MODULES in preprocessor definition.

Best regards,

Minxin Yu


If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

Was this answer helpful?

1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.