Click here to Skip to main content
15,886,806 members
Articles / Database Development / SQL Server
Article

Data Transformation Services Package Progress Dialog

Rate me:
Please Sign up or sign in to vote.
4.67/5 (5 votes)
3 Dec 20012 min read 75.5K   2K   28   5
Show a progress dialog when you execute your DTS Package at runtime.

Sample Image - DTS.gif

Introduction

Microsoft® SQL Server™ Data Transformation Services (DTS) is a set of graphical tools and programmable objects that lets you extract, transform, and consolidate data from various sources into single or multiple destinations. This article will not go into the fine details on what DTS is; if you want to find out more details on DTS, see Microsoft site.

When you execute the DTS package using the DTS editor via SQL Server Enterprise Manager, you get a nice dialog that shows the progress of each step in the DTS package. This nice progress dialog does not show up when you execute the package at runtime in your C++ code. In order to get the progress dialog at runtime, I have created the CDTSProgressThreadDlg.

The CDTSProgressThreadDlg mimics the progress dialog that is used to execute the DTS package in Enterprise Manager.

Note - You can use SQL NS to execute a DTS package that shows a progress dialog, but you need to redistribute SQL NS components.

Using DTS COM Objects

Use the following import statement to access DTS COM object, this should be done in your stdafx.h file.

#import "c:\mssql7\binn\resources\1033\dtspkg.rll"

Using the CDTSProgressThreadDlg

Due to the use of worker threads, the calling process is a bit untidy. The following code shows how a DTS Package is executed:

bOK = ProcessDTS(m_sPackageName, sCaption, "SQL Server", "FoxPro", 
      CDTSProgressThreadDlg::SQL_SERVER_ICON, 
      CDTSProgressThreadDlg::FOXPRO_ICON, bCancelled);

A helper function called ProcessDTS is called. This takes the DTS Package name, the caption that will appear on the progress dialog, the description of the source database, the description of the destination database, the icon to use for the source database, the icon to use for the destination database, and finally a bool is passed in to see if the package was cancelled.

If you look at the code for ProcessDTS, you will see that this function calls a static function called ExecuteDTSFunctionWithProgressDialog. (This type of execution has been based on PJ Naughter's thread based progress dialogs.) The ExecuteDTSFunctionWithProgressDialog uses the CDTSProgressThreadDlg.

bool CDTSDlg::ProcessDTS(const CString& sDTSName, const CString& sDTSTitle, 
                         const CString& sSourceDesc, const CString& sDestinationDesc, 
                         int nSourceIcon, int nDestinationIcon, bool& bCancelled) 
{
    USES_CONVERSION;

    DTS::_PackagePtr pDTSPackage;
    HRESULT hr;

    CInfo info;
    try
    {
        if(SUCCEEDED(hr = pDTSPackage.CreateInstance(__uuidof(DTS::Package))))
        {
            info.m_pPackage = pDTSPackage;
            info.m_sDTSName = sDTSName;
            info.m_bOK = true;
            info.m_bCancelled = false;
            info.m_bSaveDTSPackage = false;
            info.m_sSourceDescription = sSourceDesc;
            info.m_sDestinationDescription = sDestinationDesc;
            info.m_nSourceIcon = nSourceIcon;
            info.m_nDestinationIcan = nDestinationIcon;
            info.m_sServerName = m_sServerName;
            info.m_sUsername = m_sUsername;
            info.m_sPassword = m_sPassword;
            info.m_bUseTrusteConenction = m_bUseTrusteConenction;

            DWORD dwFlags = PSTAT_CONFIRMCANCEL;

            CString sCancelPrompt = 
                 "Are you sure you want to cancel ?\n\n"
                 "This will terminate when the connection to the "
                 "current task terminates";
            if(!ExecuteDTSFunctionWithProgressDialog(DoDTSProcess, 
                                      _T(sDTSTitle), &info, 
                                      dwFlags, _T(sCancelPrompt), 
                                      THREAD_PRIORITY_NORMAL, 
                                      this, pDTSPackage))
                AfxMessageBox("User cancelled transfer");
        }
        else
        {
            IUnknown* pIUnk = NULL;
            pDTSPackage->QueryInterface(IID_IUnknown, (LPVOID*)&pIUnk); 
            _com_issue_errorex(hr, pIUnk, __uuidof(DTS::Package));

        }pDTSPackage->UnInitialize();

    }
    catch(_com_error e)
    {
        AfxMessageBox(ReportError(e));
    }

    bCancelled = info.m_bCancelled;
    return info.m_bOK;
}

DTS Package Events (Connection Points)

The DTS::PackageEvents COM object provides all the information (events) about the status of the package when it is being executed. This COM object is used in the CDTSProgressThreadDlg. Once an event is fired by the DTS Execution procedure, this information is captured on the sink object (CPackageSink) and updated on the List control on the progress dialog.

Conclusion

This class can be easily used at runtime to execute a DTS package.

Reference and Credits

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
Was made redundant in early 2003 after 10 years in computer programming, since then started my own business (selling computer books on the net)
www.pricecutbook.co.uk


Comments and Discussions

 
GeneralOrdering the display of the DTS package steps Pin
RAClarke15-Dec-05 4:29
RAClarke15-Dec-05 4:29 
When DTS returns the list of package steps, they may not be in the order needed for display. The following code extract shows changes made on InsertSteps to put the On Failure steps after the On Completion and On Success steps.

<code>
// ========================================================================================================
// Function name	: CDTSProgressThreadDlg::InsertSteps
// Description	        : Inserts the DTS Steps into the list
// Return type		: BOOL 
// 12-13-05  BC		Simplified calls to get rid of GetInterfacePtr() calls.
// ========================================================================================================
BOOL CDTSProgressThreadDlg::InsertSteps()
{
	USES_CONVERSION;

	// Insert the DTS steps on the list
	// Lets get all the steps
	DTS::StepsPtr pPackageSteps;
	pPackageSteps = m_pPackage->GetSteps();
	
	long lCount = pPackageSteps->GetCount();
	m_pPackageSink->SetNumberOfSteps(lCount);

	// 12-13-05 BC
	// Before the steps are inserted, make sure they are in
	// the correct display sequence by examining their precedence constraints.
	// The first step(s) will be the ones without any constraint step name.
	// Starting with the name of the first step, look for its name in the
	// constraint step name of the other steps. The step(s) where it is found
	// come next in the sequence.
	vector<TFFStep> vSteps;
	int nListCount = 0;
	DTS::StepPtr pStep;
	for (short j = 1; j <= lCount; j++)
	{
		pStep = pPackageSteps->Item(j);

		TFFStep tff;
		tff.m_Description = pStep->GetDescription();
		tff.m_Name = pStep->GetName();

		DTS::PrecedenceConstraintsPtr conPtr = pStep->GetPrecedenceConstraints();
		int conCount = conPtr->GetCount();

		// If no constraints, it must be first
		if(conCount == 0)
		{
			vSteps.push_back(tff);
			continue;
		}

		_variant_t varCon((short)1);
		DTS::PrecedenceConstraintPtr precPtr = conPtr->Item(varCon);
		tff.m_ConstraintStepName = precPtr->GetStepName();
		enum DTS::DTSStepPrecedenceBasis tffBasis;
		precPtr->get_PrecedenceBasis(&tffBasis);
		tff.m_PrecedenceBasis = tffBasis;
		vSteps.push_back(tff);
	}


/*
#ifdef _DEBUG
	// dump vector contents
	int szDbg = vSteps.size();
	char dbgBuff[5];
	CString msg;
	for(int dbg = 0; dbg < szDbg; ++dbg)
	{
		msg += "Vector item ";
		itoa(dbg, dbgBuff, 10);
		msg += dbgBuff;
		msg += ":\r\nstep name: ";
		msg += vSteps[dbg].m_Name;
		msg += "\r\nConstraintStepName: ";
		msg += vSteps[dbg].m_ConstraintStepName;
		msg += "\r\n\r\n";
	}

	::MessageBox(NULL, (LPCTSTR)msg, "Steps of DTS package", MB_OK|MB_ICONINFORMATION);
#endif
*/


	vector<TFFStep> vSortedSteps;

	// Pull out steps with no constraint step name
	std::vector<TFFStep>::iterator it = vSteps.begin();

	while(it != vSteps.end())
	{
		TFFStep tff = *it;
		if( tff.m_ConstraintStepName.length() == 0)
		{
			// This is a root step
			vSortedSteps.push_back(tff);

			// remove this one
			it = vSteps.erase(it);
			continue;
		}

		++it;
	}


	// Now get the steps that follow the root step(s),
	// Ignoring the Fail steps -- they go last

	it = vSortedSteps.begin();
	while(it != vSortedSteps.end())
	{
		TFFStep sortStep = *it;
		std::vector<TFFStep>::iterator itInner = vSteps.begin();
		while(itInner != vSteps.end())
		{
			TFFStep tffInner = *itInner;
			if( tffInner.m_ConstraintStepName == sortStep.m_Name && 
			    tffInner.m_PrecedenceBasis == DTS::DTSStepPrecedenceBasis_ExecStatus)
			{
				// push_back() will invalidate vSortedSteps iterator,
				// so save current position, then reinstate it

				int pos = it - vSortedSteps.begin();
				vSortedSteps.push_back(tffInner);
				it = vSortedSteps.begin() + pos;
				
				itInner = vSteps.erase(itInner);
				continue;
			}
			++itInner;
		}

		++it;
	}

	// Grab whatever is left -- the Fail steps
	if(vSteps.size() > 0)
	{
		vSortedSteps.insert(vSortedSteps.end(), vSteps.begin(), vSteps.end());
	}


/*
#ifdef _DEBUG
	// dump vector contents
	msg = "";
	szDbg = vSortedSteps.size();
	for(dbg = 0; dbg < szDbg; ++dbg)
	{
		msg += "Vector item ";
		itoa(dbg, dbgBuff, 10);
		msg += dbgBuff;
		msg += ":\r\nstep name: ";
		msg += vSortedSteps[dbg].m_Name;
		msg += "\r\nConstraintStepName: ";
		msg += vSortedSteps[dbg].m_ConstraintStepName;
		msg += "\r\n\r\n";
	}

	::MessageBox(NULL, (LPCTSTR)msg, "Steps of DTS package", MB_OK|MB_ICONINFORMATION);
#endif
*/


	// display steps
	int sz = vSortedSteps.size();
	for (short k = 0; k < sz; k++)
	{
		USES_CONVERSION;
		string desc = OLE2A(vSortedSteps[k].m_Description);

		m_ctlReportList.InsertItem(nListCount, "");
		m_ctlReportList.SetItem(nListCount,1,LVIF_TEXT, desc.c_str(),0,0,0,0);
		m_ctlReportList.SetItem(nListCount,2,LVIF_TEXT,"Waiting",0,0,0,0);		
		nListCount++;
	}

	return TRUE;
}

</code>

GeneralRe: Ordering the display of the DTS package steps Pin
RAClarke15-Dec-05 4:44
RAClarke15-Dec-05 4:44 
Generalcompiler error Pin
Member 15833620-May-04 8:30
Member 15833620-May-04 8:30 
GeneralRe: compiler error Pin
RAClarke9-Dec-05 13:21
RAClarke9-Dec-05 13:21 
Generalvery excellent Pin
bsd91117-Dec-02 14:41
bsd91117-Dec-02 14:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.