上一篇http://blog.csdn.net/liminlu0314/article/details/53433014博文中說到,可以通過配置項來解決mdb文件打開失敗的問題。該問題主要是在64位的程序中會出現。仔細查看gdal的代碼,發現在源碼中已經針對這個問題進行了修改,但是測試發現修改的不徹底。
具體的bug信息參考http://trac.osgeo.org/gdal/ticket/5594。GDAL庫中源碼片段如下,詳見文件ogrodbcdatasource.cpp中的132行左右,位於函數OGRODBCDataSource::OpenMDB中。
/* -------------------------------------------------------------------- */
/* Initialize based on the DSN. */
/* -------------------------------------------------------------------- */
CPLDebug( "ODBC", "EstablishSession(%s)", pszDSN );
if( !oSession.EstablishSession( pszDSN, NULL, NULL ) )
{
int bError = TRUE;
if( EQUAL(pszDSN, "") )//註釋掉這句話即可
{
// Trying with another template (#5594)
pszDSNStringTemplate = "DRIVER=Microsoft Access Driver (*.mdb, *.accdb);DBQ=%s";
CPLFree( pszDSN );
pszDSN = (char *) CPLMalloc(strlen(pszNewName)+strlen(pszDSNStringTemplate)+100);
snprintf( pszDSN,
strlen(pszNewName)+strlen(pszDSNStringTemplate)+100,
pszDSNStringTemplate, pszNewName );
CPLDebug( "ODBC", "EstablishSession(%s)", pszDSN );
if( oSession.EstablishSession( pszDSN, NULL, NULL ) )
{
bError = FALSE;
}
}
if( bError )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Unable to initialize ODBC connection to DSN for %s,\n"
"%s", pszDSN, oSession.GetLastError() );
CPLFree( pszDSN );
return FALSE;
}
}
上述代碼雖然加了匹配另一個模板,但是有個判斷if( EQUAL(pszDSN, "") ),這個判斷由於pszDSN通過上面的賦值,肯定是有值的,所以這個判斷永遠爲FALSE,也就是if內的代碼不會執行,這樣就導致修改了其實和沒有修改是一樣的。所以爲了能夠在使用第一個模板失敗時,使用第二個模板,需要將if這句話註釋掉即可。
修改完重新編譯即可。
PS:最後又發現了一個問題,在打開調試開關之後,執行會崩潰,通過調試發現位於該文件的218行的 if( oTableList.GetTables() )中執行失敗,函數GetTables的源碼如下:
int CPLODBCStatement::GetTables( const char *pszCatalog,
const char *pszSchema )
{
CPLDebug( "ODBC", "CatalogNameL: %s\nSchema name: %s",
pszCatalog , pszSchema); //這句出問題了
#if (ODBCVER >= 0x0300)
if( !m_poSession->IsInTransaction() )
{
// Commit pending transactions and set to autocommit mode.
m_poSession->ClearTransaction();
}
#endif
......
調試發現在調用CPLDebug函數時,傳入的兩個參數均爲NULL導致CPLDebug函數崩潰,此處加一個判斷就可以了。如果不啓用調試應該也不會出問題。