Click here to Skip to main content
15,885,984 members
Articles / Desktop Programming / WTL

Shrinking SQL Server Transaction Logs with SQL-DMO

Rate me:
Please Sign up or sign in to vote.
4.99/5 (49 votes)
21 Apr 2004CPOL9 min read 204.2K   4.7K   70  
Using SQL-DMO to shrink SQL Server transaction logs.
/////////////////////////////////////////////////////////////////////////////
// #ifndef __ARMEN_H__
// #define __ARMEN_H__
//     Central Bank of Armenia, Information Security Department
//	   Armen Hakobyan, 2004. mailto:armen.h@web.am
//	   http://www.codeproject.com/script/articles/list_articles.asp?userid=25653
// #endif // __ARMEN_H__
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "main.h"

#if ( _ATL_VER < _ATL_VER_70 )
	#include < atlimpl.cpp >
#endif
#include < LmErr.h >

/////////////////////////////////////////////////////////////////////////////

void DoEvents( void )
{
	MSG msg = { 0 };
	while ( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
	{
		BOOL bRet = ::GetMessage( &msg, NULL, 0, 0 ); 
		if( bRet == -1 )
			continue;   // error, don't process		
		else if( bRet )
		{
			// Before you translate and dispatch you might consider
			// checking if that message does not close you window
			// you should ignore it because if you doevents() in a loop
			// and the user click the close buton it closes !
			// and you loop continues untill it ends:

			if( ( msg.message != WM_DESTROY ) && 
				( msg.message != WM_CLOSE ) &&
			  ( ( msg.message != WM_SYSCOMMAND ) && 
			    ( msg.wParam  != SC_CLOSE ) ) )
			{			
				::TranslateMessage( &msg );
				::DispatchMessage( &msg );				
			}
		}
		else
			break;
	}

	::Sleep( 0 );
}

/////////////////////////////////////////////////////////////////////////////

void TrimWorkingSet( void )
{
	// 1. Compact CRT heap
	// 2. Compact process heap
	// 3. Minimize process workingset size

	_heapmin();
	::HeapCompact( ::GetProcessHeap(), 0 );	
	::SetProcessWorkingSetSize( ::GetCurrentProcess(), (DWORD)-1, (DWORD)-1 );
}

/////////////////////////////////////////////////////////////////////////////

INT _MessageBoxEx( IN UINT uID, IN UINT uType, ... )
{
	va_list pszArgList = NULL;
	va_start( pszArgList, uType );     /* Initialize variable arguments. */	
	
	TCHAR szFmt[ 1024 ] = { 0 };
	if( AtlLoadString( uID, szFmt, _countof( szFmt ) ) )
	{
		TCHAR szOut[ 1024 ] = { 0 };
		::wvsprintf( szOut, szFmt, pszArgList );

		return _MessageBox( szOut, uType );
	}

	va_end( pszArgList );
	return ( 0 );
}

INT _MessageBox( IN UINT uID, IN UINT uType /*MB_OK | MB_ICONSTOP*/ )
{		
	TCHAR szBuffer[ 1024 ] = { 0 };
	if( AtlLoadString( uID, szBuffer, _countof( szBuffer ) ) )		
		return _MessageBox( szBuffer, uType );

	return ( 0 );
}

INT _MessageBox( IN LPCTSTR pszText, IN UINT uType /*MB_OK | MB_ICONSTOP*/ )
{
	return ::MessageBox( ::GetActiveWindow(), pszText, _Module.s_pszAppName, uType );
}

/////////////////////////////////////////////////////////////////////////////

// Not seacrhing just for last ']' occurance because it can also be
// in the user message, not only in the prefix.
// NOT REQUIRED IN DisplayComError, SEE SQLSERVER ODBCPrefix PROPERTY !!!

LPCTSTR SkipODBCPrefix( IN LPCTSTR pszSqlMsg )
{
	// ODBC error message format has prefix [0][1][2][optional 3][optional 4]
	// For example '[Microsoft][ODBC SQL Server Driver][SQL Server][SQL-DMO]...'

	static LPCTSTR sppszPrefixes[ 12 ] = {
		_T( "[Microsoft]"				),	// 0
		_T( "[ODBC Driver Manager]"		),	// 1
		_T( "[ODBC Cursor Library]"		),	// 1
		_T( "[ODBC SQL Server Driver]"	),	// 1
		_T( "[Named Pipes]"				),	// 2
		_T( "[Shared Memory]"			),	// 2
		_T( "[Multiprotocol]"			),	// 2
		_T( "[TCP/IP Sockets]"			),	// 2
		_T( "[NWLink IPX/SPX]"			),	// 2
		_T( "[Banyan VINES]"			),	// 2
		_T( "[SQL Server]"				),	// 3
		_T( "[SQL-DMO]"					)	// 4
	};

	LPCTSTR pszToken  = NULL;
	LPCTSTR pszUsrMsg = NULL;
	LPCTSTR pszTmpPtr = NULL;

	for( INT n = ( _countof( sppszPrefixes ) - 1 ); n >= 0; n-- )
	{
		pszToken  = sppszPrefixes[ n ];
		pszTmpPtr = ::StrRStrI( pszSqlMsg, NULL, pszToken );

		if( pszTmpPtr )
		{
			pszTmpPtr += ::lstrlen ( pszToken );
			pszUsrMsg = pszTmpPtr;
			break;
		}
	}

	return pszSqlMsg; //( pszUsrMsg );
}

void DisplayComError( IN _com_error& e, IN BOOL bExtended )
{
	
	LPTSTR pszMsg = ::StrDup( (LPCTSTR)e.Description() );
	if( !pszMsg )		
		pszMsg = ::StrDup( (LPCTSTR)e.ErrorMessage() );		
	
	TCHAR szMsg[ 1024 ] = { 0 };
	if( !bExtended )
		::lstrcpyn( szMsg, pszMsg, _countof( szMsg ) );		
	else
	{		
		LPCTSTR pszSrc = ::StrDup( (LPCTSTR)_bstr_t( e.Source() ) );
		if( !pszSrc )
			pszSrc = ::StrDup( _Module.s_pszAppName );
        
		::wsprintf(
			szMsg,
			_T( "The program encountered the following error:\n\n" )
			_T( "Number:\t\t%d\n" )
			_T( "Source:\t\t%s\n" )
			_T( "Description:\t%s" ),
			HRESULT_CODE( e.Error() ),
			pszSrc,
			pszMsg
		);

		_localFree( pszSrc );
	}

	_localFree( pszMsg );
	_MessageBox( szMsg );
}

/////////////////////////////////////////////////////////////////////////////
// 
//	FUNCTION:		FormatMessage()
// 
//	PURPOSE:		This function loads a string from a message file and
//					replaces the inserts if necessary (formats).
// 
//	PARAMETERS:		pszMsgDll
//						[ in ] - location of the message file
//					dwMsgCode
//						[ in ] - message identifier for the requested
//						message
//					dwLangID
//						[ in ] - language identifier for the requested
//						message
//					ppszMsg
//						[ out ] - pointer to a pointer variable that 
//						receives a pointer to an allocated, read-only 
//						buffer containing the formatted (and null-terminated)
//						message. Call the ::HeapFree function to free the 
//						buffer when you are finished with it.
//					...
//						[ in ] - Specifies one or more optional arguments. 
//						The number and type of argument parameters depend on 
//						the corresponding format-control specifications that
//						the message file was compiled with. These values are 
//						used as inserts in the formatted message. A %1 in the 
//						format string indicates the first value; a %2 indicates 
///						the second argument; and so on.
// 
//	RETURN VALUE:	Returns last error if fails, ERROR_SUCCESS otherwise.
//					See Win API ::FormatMessage for more information.
//
//	COMMENTS:		1.	Requires #include < LmErr.h >
//					2.	Call the ::HeapFree function to free the ppszMsg
//						buffer when you are finished with it.
//
//	COMPATIBILTY:	Microsoft Windows 95 or later, NT 4.0 or later
//
//	HISTORY:		15 Nov 2002 - first release
//					21 Nov 2002 - replaced ppszArgs with ... ( va_list )
//					22 Nov 2002 - added MSMQ errors processing
//					24 Nov 2002	- removed r�peated message buffer allocation
//
//	LAST REVISION:	24 Nov 2002 by Armen Hakobyan
//
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
//
//	SAMPLE USAGE:
//
//	// Assuming that the message has format: "%s %s"
//
//	LPTSTR  pszMsg = NULL;
//	LPCTSTR pszArgs[ 2 ] = { _T( "Hello" ), _T( "Armen" ) };
//
//	if( FormatMessage( &pszMsg, MSG_PRINTER_INSTALLED, 
//		pszArgs,  _T( "pmsvcmsg.dll" ), 0 ) )
//	{
//		::MessageBox( ::GetActiveWindow(), pszMsg, 
//			_T( "Sample" ), MB_OK | MB_ICONINFORMATION );
//
//		::HeapFree( ::GetProcessHeap(), 0, pszMsg );
//	}
//
//	// We'll get : "Hello Armen"
//	//				 %s     %s
//
/////////////////////////////////////////////////////////////////////////////

DWORD FormatMessage( IN  LPCTSTR pszMsgDll,
					 IN  DWORD   dwMsgCode,
					 IN  DWORD   dwLangID,					 
					 OUT LPTSTR* ppszMsg,
					 IN  ...			 )
{
	// No check for pszMsgDll, because
	// ::LoadLibraryEx will silently fail later.
	
	ATLASSERT( !::IsBadReadPtr( ppszMsg, sizeof( LPTSTR* ) ) );

	HMODULE hModule = NULL;
	DWORD	dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER;

	if( pszMsgDll == NULL )
	{
		if( HRESULT_FACILITY( dwMsgCode ) == FACILITY_MSMQ )		// MSMQ errors only
			pszMsgDll = _T( "mqutil.dll" );
		else if( dwMsgCode >= NERR_BASE && dwMsgCode <= MAX_NERR )	// Get network errors
			pszMsgDll = _T( "netmsg.dll" );
		else														// Get system errors
			dwFlags |= FORMAT_MESSAGE_FROM_SYSTEM;
	}

	if( pszMsgDll != NULL )
	{
		hModule = ::LoadLibraryEx( pszMsgDll, NULL, LOAD_LIBRARY_AS_DATAFILE );
		if( hModule != NULL )
			dwFlags |= FORMAT_MESSAGE_FROM_HMODULE;
		else
			return ::GetLastError();
	}

	va_list pszArgs = NULL;
	va_start( pszArgs, ppszMsg );

	DWORD dwRet = ::FormatMessage( dwFlags, hModule, dwMsgCode, dwLangID, 
		(LPTSTR)ppszMsg, 0, (va_list*)&pszArgs );

	va_end( pszArgs );
	return ( dwRet );
}

/////////////////////////////////////////////////////////////////////////////

BOOL CheckDlgItemText( IN HWND hWnd, IN INT nID )
{
	ATLASSERT( IS_INTRESOURCE( nID ) );

	CWindow wndCtl = ::GetDlgItem( hWnd, nID );		
	ATLASSERT( wndCtl.IsWindow() );

	if( wndCtl.GetWindowTextLength() <= 0 )
	{		
		TCHAR szPar[ 256 ] = { 0 };
		if( AtlLoadString( nID, szPar, _countof( szPar ) ) )
			_MessageBoxEx( IDP_INVALID_STR, MB_ICONEXCLAMATION | MB_OK, szPar );
		else
			::MessageBeep( MB_ICONEXCLAMATION );

		wndCtl.SetFocus();
		return ( FALSE );
	}

	return ( TRUE );
}

/////////////////////////////////////////////////////////////////////////////

BOOL GetSqlServerPath( IN OUT LPTSTR pszPath, 
					   IN OUT PULONG pulChars, 
					   IN SQL_ROOTS  eRoot )
{
	ATLASSERT( pszPath != NULL );
	ATLASSERT( AtlIsValidString( pszPath, *pulChars ) );

	static LPCTSTR spszKeys[ 2 ] = {
		_T( "SOFTWARE\\Microsoft\\Microsoft SQL Server\\80\\Tools\\ClientSetup" ),
		_T( "SOFTWARE\\Microsoft\\MSSQLServer\\Setup" )
	};

	CRegKey regKey;
	LONG lRetval = regKey.Open( HKEY_LOCAL_MACHINE, spszKeys[ eRoot ] );

	if( lRetval == ERROR_SUCCESS )
	{
		#if defined( _ATL_VER ) && ( _ATL_VER >= _ATL_VER_70 )
			lRetval = regKey.QueryStringValue( _T( "SQLPath" ), pszPath, pulChars );
		#else
			lRetval = regKey.QueryValue( pszPath, _T( "SQLPath" ), pulChars );
		#endif

		return ( lRetval == ERROR_SUCCESS );
	}

	return ( FALSE );
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) SafeNet Inc
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions