Re: SHBrowseForFolder works only one time when connecting to SQL server in between when using a manifest file
-
Hi all, I experienced a strange behaviour, maybe one of you knows something about it. I have a little application that call SHBrowseForFolder, after that it connects to an SQL server via SQLDriverConnect. After some work it releases every allocated ODBC handle. Any subsequent call to SHBrowseForFolder will display an empty dialog, not even the controls are drawn. This happens only if there is a manifest file for this application to use the new common controls. I included the source code as a sample a little bit more down, if you would like the complete Devstudio workspace, just email me. I would be happy if any of you knows something about this, thanks in advance, Jens Source code: ----------------- #ifndef BIF_NEWDIALOGSTYLE #define BIF_NEWDIALOGSTYLE 0x0040 #define BIF_USENEWUI (BIF_NEWDIALOGSTYLE | BIF_EDITBOX) #endif void Go() { // *** Doesn't help... // ::CoInitialize( 0 ); BROWSEINFO bi; ZeroMemory( &bi, sizeof( bi ) ); bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS; SHBrowseForFolder( &bi ); SQLHENV env = NULL; SQLRETURN sqlRet = SQLAllocEnv( &env ); SQLHDBC conn = NULL; sqlRet = SQLAllocConnect( env, &conn ); SQLCHAR szOut[ 2048 ] = {0}; SQLCHAR sqlConn[ 1024 ] = "DRIVER={SQL Server};SERVER=(local)"; // SQLCHAR sqlConn[ 1024 ] = "DRIVER={Microsoft Text Driver (*.txt; *.csv)};DBQ=test\\"; SWORD len = 0; sqlRet = SQLDriverConnect( conn, NULL, sqlConn, SQL_NTS, szOut, sizeof( szOut ), &len, SQL_DRIVER_COMPLETE_REQUIRED ); if ( ( SQL_SUCCESS != sqlRet ) && ( SQL_SUCCESS_WITH_INFO != sqlRet ) ) { SWORD nMessageLen = 0; UCHAR szMessage[ SQL_MAX_MESSAGE_LENGTH ] = {0}; SDWORD dwNativeErrorCode = 0; UCHAR szErrorState[ SQL_SQLSTATE_SIZE + 1 ] = {0}; sqlRet = SQLError( env, conn, SQL_NULL_HSTMT, szErrorState, &dwNativeErrorCode, szMessage, SQL_MAX_MESSAGE_LENGTH - 1, &nMessageLen ); ::MessageBox( NULL, (CHAR*)szMessage, (CHAR*)szErrorState, MB_OK ); } sqlRet = SQLDisconnect( conn ); sqlRet
-
Hi all, I experienced a strange behaviour, maybe one of you knows something about it. I have a little application that call SHBrowseForFolder, after that it connects to an SQL server via SQLDriverConnect. After some work it releases every allocated ODBC handle. Any subsequent call to SHBrowseForFolder will display an empty dialog, not even the controls are drawn. This happens only if there is a manifest file for this application to use the new common controls. I included the source code as a sample a little bit more down, if you would like the complete Devstudio workspace, just email me. I would be happy if any of you knows something about this, thanks in advance, Jens Source code: ----------------- #ifndef BIF_NEWDIALOGSTYLE #define BIF_NEWDIALOGSTYLE 0x0040 #define BIF_USENEWUI (BIF_NEWDIALOGSTYLE | BIF_EDITBOX) #endif void Go() { // *** Doesn't help... // ::CoInitialize( 0 ); BROWSEINFO bi; ZeroMemory( &bi, sizeof( bi ) ); bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS; SHBrowseForFolder( &bi ); SQLHENV env = NULL; SQLRETURN sqlRet = SQLAllocEnv( &env ); SQLHDBC conn = NULL; sqlRet = SQLAllocConnect( env, &conn ); SQLCHAR szOut[ 2048 ] = {0}; SQLCHAR sqlConn[ 1024 ] = "DRIVER={SQL Server};SERVER=(local)"; // SQLCHAR sqlConn[ 1024 ] = "DRIVER={Microsoft Text Driver (*.txt; *.csv)};DBQ=test\\"; SWORD len = 0; sqlRet = SQLDriverConnect( conn, NULL, sqlConn, SQL_NTS, szOut, sizeof( szOut ), &len, SQL_DRIVER_COMPLETE_REQUIRED ); if ( ( SQL_SUCCESS != sqlRet ) && ( SQL_SUCCESS_WITH_INFO != sqlRet ) ) { SWORD nMessageLen = 0; UCHAR szMessage[ SQL_MAX_MESSAGE_LENGTH ] = {0}; SDWORD dwNativeErrorCode = 0; UCHAR szErrorState[ SQL_SQLSTATE_SIZE + 1 ] = {0}; sqlRet = SQLError( env, conn, SQL_NULL_HSTMT, szErrorState, &dwNativeErrorCode, szMessage, SQL_MAX_MESSAGE_LENGTH - 1, &nMessageLen ); ::MessageBox( NULL, (CHAR*)szMessage, (CHAR*)szErrorState, MB_OK ); } sqlRet = SQLDisconnect( conn ); sqlRet
After the first call to SHBrowseForFolder(), the 'bi' variable is not used again until the end of Go(). Is this intentional? What happens if you remove everything SQL/ODBC related? Does SHBrowseForFolder() work repeatedly then?
-
After the first call to SHBrowseForFolder(), the 'bi' variable is not used again until the end of Go(). Is this intentional? What happens if you remove everything SQL/ODBC related? Does SHBrowseForFolder() work repeatedly then?
bi is used again in the second call to SHBrowseForFolder. You could use another instance, that doesn't matter. SHBrowseForFolder works repeatedly is I remove the call to "sqlRet = SQLFreeHandle( SQL_HANDLE_ENV, env );" This happens only with the MS SQL Server ODBC driver. If another driver is used (MS Text driver, Sybase Anywhere) it works fine. Thanks, Jens
-
bi is used again in the second call to SHBrowseForFolder. You could use another instance, that doesn't matter. SHBrowseForFolder works repeatedly is I remove the call to "sqlRet = SQLFreeHandle( SQL_HANDLE_ENV, env );" This happens only with the MS SQL Server ODBC driver. If another driver is used (MS Text driver, Sybase Anywhere) it works fine. Thanks, Jens
Jens Doose wrote: bi is used again in the second call to SHBrowseForFolder. Right, but's it's still not being used. ;) The code pieces are disparate. The usage of 'bi' and the success/failure of the calls to SHBrowseForFolder() have nothing to do with the SQL-related stuff. It's considered good practice to check the return values from all function calls. Something like:
void Go( void )
{
BROWSEINFO bi = {0};
SQLRETURN sqlRet
SQLHENV env = NULL;
SQLHDBC conn = NULL;
SWORD len = 0,
nMessageLen = 0;
SQLCHAR szOut[2048] = {0},
sqlConn[1024] = "DRIVER={SQL Server};SERVER=(local)";
UCHAR szMessage[ SQL_MAX_MESSAGE_LENGTH ] = {0},
szErrorState[ SQL_SQLSTATE_SIZE + 1 ] = {0};
SDWORD dwNativeErrorCode = 0;bi.ulFlags = BIF\_NEWDIALOGSTYLE | BIF\_RETURNONLYFSDIRS; SHBrowseForFolder( &bi ); sqlRet = SQLAllocEnv(&env); if (SQL\_SUCCESS == sqlRet) { sqlRet = SQLAllocConnect(env, &conn); if (SQL\_SUCCESS == sqlRet) { sqlRet = SQLDriverConnect(conn, NULL, sqlConn, SQL\_NTS, szOut, sizeof(szOut), &len, SQL\_DRIVER\_COMPLETE\_REQUIRED); if (SQL\_SUCCESS != sqlRet && SQL\_SUCCESS\_WITH\_INFO != sqlRet) { sqlRet = SQLError(env, conn, SQL\_NULL\_HSTMT, szErrorState, &dwNativeErrorCode, szMessage, SQL\_MAX\_MESSAGE\_LENGTH - 1, &nMessageLen); ::MessageBox(NULL, (CHAR \*) szMessage, (CHAR \*) szErrorState, MB\_OK); } sqlRet = SQLDisconnect(conn); sqlRet = SQLFreeHandle(SQL\_HANDLE\_DBC, conn); } sqlRet = SQLFreeHandle( SQL\_HANDLE\_ENV, env ); } ZeroMemory(&bi, sizeof(bi)); bi.ulFlags = BIF\_NEWDIALOGSTYLE | BIF\_RETURNONLYFSDIRS; SHBrowseForFolder(&bi);
}
Jens Doose wrote: This happens only with the MS SQL Server ODBC driver. If another driver is used (MS Text driver, Sybase Anywhere) it works fine. Or it's just being masked such that it appears fine.
-
Jens Doose wrote: bi is used again in the second call to SHBrowseForFolder. Right, but's it's still not being used. ;) The code pieces are disparate. The usage of 'bi' and the success/failure of the calls to SHBrowseForFolder() have nothing to do with the SQL-related stuff. It's considered good practice to check the return values from all function calls. Something like:
void Go( void )
{
BROWSEINFO bi = {0};
SQLRETURN sqlRet
SQLHENV env = NULL;
SQLHDBC conn = NULL;
SWORD len = 0,
nMessageLen = 0;
SQLCHAR szOut[2048] = {0},
sqlConn[1024] = "DRIVER={SQL Server};SERVER=(local)";
UCHAR szMessage[ SQL_MAX_MESSAGE_LENGTH ] = {0},
szErrorState[ SQL_SQLSTATE_SIZE + 1 ] = {0};
SDWORD dwNativeErrorCode = 0;bi.ulFlags = BIF\_NEWDIALOGSTYLE | BIF\_RETURNONLYFSDIRS; SHBrowseForFolder( &bi ); sqlRet = SQLAllocEnv(&env); if (SQL\_SUCCESS == sqlRet) { sqlRet = SQLAllocConnect(env, &conn); if (SQL\_SUCCESS == sqlRet) { sqlRet = SQLDriverConnect(conn, NULL, sqlConn, SQL\_NTS, szOut, sizeof(szOut), &len, SQL\_DRIVER\_COMPLETE\_REQUIRED); if (SQL\_SUCCESS != sqlRet && SQL\_SUCCESS\_WITH\_INFO != sqlRet) { sqlRet = SQLError(env, conn, SQL\_NULL\_HSTMT, szErrorState, &dwNativeErrorCode, szMessage, SQL\_MAX\_MESSAGE\_LENGTH - 1, &nMessageLen); ::MessageBox(NULL, (CHAR \*) szMessage, (CHAR \*) szErrorState, MB\_OK); } sqlRet = SQLDisconnect(conn); sqlRet = SQLFreeHandle(SQL\_HANDLE\_DBC, conn); } sqlRet = SQLFreeHandle( SQL\_HANDLE\_ENV, env ); } ZeroMemory(&bi, sizeof(bi)); bi.ulFlags = BIF\_NEWDIALOGSTYLE | BIF\_RETURNONLYFSDIRS; SHBrowseForFolder(&bi);
}
Jens Doose wrote: This happens only with the MS SQL Server ODBC driver. If another driver is used (MS Text driver, Sybase Anywhere) it works fine. Or it's just being masked such that it appears fine.
Hi David, that is true. But that was not my point, maybe I didn't make myself clear enough. The problem is that with Windows XP the second call to
SHBrowseForFolder
does not work, either it isn't shown at all (when there is no manifest file) or the dialog is shown, but it doesn't contain the control, which displays all the folders (when having a manifest file). And this problem only occurs when making aSQLDriverConnect
to an MS SQL ODBC driver in between this two calls. Any other driver is fine. I discovered the problem in a much more complex environment, and believe me, it did cost me some hours of my life to hunt the problem down to this constellation ;-). To clarify the problem I wrote a simple test app that just callsSHBrowseForFolder
andSQLDriverConnect
. That is why there is no error checking or why I don't use the result value withinbi
. Thanks Jens -
Hi David, that is true. But that was not my point, maybe I didn't make myself clear enough. The problem is that with Windows XP the second call to
SHBrowseForFolder
does not work, either it isn't shown at all (when there is no manifest file) or the dialog is shown, but it doesn't contain the control, which displays all the folders (when having a manifest file). And this problem only occurs when making aSQLDriverConnect
to an MS SQL ODBC driver in between this two calls. Any other driver is fine. I discovered the problem in a much more complex environment, and believe me, it did cost me some hours of my life to hunt the problem down to this constellation ;-). To clarify the problem I wrote a simple test app that just callsSHBrowseForFolder
andSQLDriverConnect
. That is why there is no error checking or why I don't use the result value withinbi
. Thanks JensJens Doose wrote: The problem is that with Windows XP Have you tried this on another platform to see if it is OS related? Jens Doose wrote: That is why there is no error checking or why I don't use the result value within bi. That's fine, and is common practice. I just wanted to emphasize that omitting error checking might have been the crux of the problem. If you commented out both calls to
SHBrowseForFolder()
, thus leaving only the SQL-related code, canGo()
be called repeatedly? Perhaps after you are done withSHBrowseForFolder()
, you should callIMalloc::Free()
.HRESULT hr;
LPMALLOC pMalloc;
LPITEMIDLIST pidlSelected = NULL;
hr = SHGetMalloc(&pMalloc);
pidlSelected = SHBrowseForFolder(&bi);
...
pMalloc->Free(pidlSelected);