Index: src/ch/CustomCopyDlg.cpp
===================================================================
diff -u -r2fe97a93f21771d75901d4b6559057d1ea055104 -r503a68180cbb933c97e9af965744bf106994c05a
--- src/ch/CustomCopyDlg.cpp	(.../CustomCopyDlg.cpp)	(revision 2fe97a93f21771d75901d4b6559057d1ea055104)
+++ src/ch/CustomCopyDlg.cpp	(.../CustomCopyDlg.cpp)	(revision 503a68180cbb933c97e9af965744bf106994c05a)
@@ -57,7 +57,6 @@
 	ictranslate::CLanguageDialog(CCustomCopyDlg::IDD),
 	m_tTaskDefinition(rTaskDefinition)
 {
-
 }
 
 void CCustomCopyDlg::DoDataExchange(CDataExchange* pDX)
@@ -98,6 +97,7 @@
 	ON_BN_CLICKED(IDC_IMPORT_BUTTON, OnImportButton)
 	ON_BN_CLICKED(IDC_IGNOREFOLDERS_CHECK, OnIgnorefoldersCheck)
 	ON_BN_CLICKED(IDC_FORCEDIRECTORIES_CHECK, OnForcedirectoriesCheck)
+	ON_BN_CLICKED(IDC_EXPORT_BUTTON, OnExportButtonClicked)
 	//}}AFX_MSG_MAP
 END_MESSAGE_MAP()
 
@@ -460,36 +460,14 @@
 {
 	UpdateData(TRUE);
 
-	CString strPath;
-	m_ctlDstPath.GetWindowText(strPath);
-
-	if(strPath.IsEmpty() || m_ctlFiles.GetItemCount() == 0)
+	if(!HasBasicTaskData())
 	{
 		MsgBox(IDS_MISSINGDATA_STRING);
 		return;
 	}
 
-	// copy files from listctrl to an array
-	m_tTaskDefinition.ClearSourcePaths();
+	UpdateInternalTaskDefinition();
 
-	// dest path
-	m_tTaskDefinition.SetDestinationPath(chcore::PathFromString(strPath));
-
-	for (int i = 0; i < m_ctlFiles.GetItemCount(); i++)
-	{
-		m_tTaskDefinition.AddSourcePath(chcore::PathFromString(m_ctlFiles.GetItemText(i, 0)));
-	}
-
-	// operation type
-	m_tTaskDefinition.SetOperationType(m_ctlOperation.GetCurSel() == 0 ? chcore::eOperation_Copy: chcore::eOperation_Move);
-
-	// priority
-	chcore::SetTaskPropValue<chcore::eTO_ThreadPriority>(m_tTaskDefinition.GetConfiguration(), IndexToPriority(m_ctlPriority.GetCurSel()));
-
-	chcore::SetTaskPropValue<chcore::eTO_IgnoreDirectories>(m_tTaskDefinition.GetConfiguration(), (m_bIgnoreFolders != 0));
-	chcore::SetTaskPropValue<chcore::eTO_CreateDirectoriesRelativeToRoot>(m_tTaskDefinition.GetConfiguration(), (m_bForceDirectories != 0));
-	chcore::SetTaskPropValue<chcore::eTO_CreateEmptyFiles>(m_tTaskDefinition.GetConfiguration(), (m_bOnlyCreate != 0));
-
 	CLanguageDialog::OnOK();
 }
 
@@ -1058,3 +1036,77 @@
 
 	GetDlgItem(IDC_FORCEDIRECTORIES_CHECK)->EnableWindow(!m_bIgnoreFolders);
 }
+
+void CCustomCopyDlg::OnExportButtonClicked()
+{
+	UpdateData(TRUE);
+
+	if (!HasBasicTaskData())
+	{
+		MsgBox(IDS_MISSINGDATA_STRING);
+		return;
+	}
+
+	UpdateInternalTaskDefinition();
+
+	CFileDialog dlg(FALSE, _T("xml"), _T("Task"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, GetResManager().LoadString(IDS_FLTALLFILTER_STRING));
+	if (dlg.DoModal() == IDOK)
+	{
+		CString strError;
+		try
+		{
+			m_tTaskDefinition.Store(chcore::PathFromString(dlg.GetPathName()));
+		}
+		catch (const std::exception& e)
+		{
+			strError = e.what();
+		}
+
+		if (!strError.IsEmpty())
+		{
+			ictranslate::CFormat fmt;
+			fmt.SetFormat(GetResManager().LoadString(IDS_EXPORTING_TASK_FAILED));
+			fmt.SetParam(_t("%reason"), strError);
+
+			AfxMessageBox(fmt, MB_OK | MB_ICONERROR);
+		}
+	}
+}
+
+void CCustomCopyDlg::UpdateInternalTaskDefinition()
+{
+	CString strDstPath;
+	m_ctlDstPath.GetWindowText(strDstPath);
+
+	// copy files from listctrl to an array
+	m_tTaskDefinition.ClearSourcePaths();
+
+	// dest path
+	m_tTaskDefinition.SetDestinationPath(chcore::PathFromString(strDstPath));
+
+	for (int i = 0; i < m_ctlFiles.GetItemCount(); i++)
+	{
+		m_tTaskDefinition.AddSourcePath(chcore::PathFromString(m_ctlFiles.GetItemText(i, 0)));
+	}
+
+	// operation type
+	m_tTaskDefinition.SetOperationType(m_ctlOperation.GetCurSel() == 0 ? chcore::eOperation_Copy : chcore::eOperation_Move);
+
+	// priority
+	chcore::SetTaskPropValue<chcore::eTO_ThreadPriority>(m_tTaskDefinition.GetConfiguration(), IndexToPriority(m_ctlPriority.GetCurSel()));
+
+	chcore::SetTaskPropValue<chcore::eTO_IgnoreDirectories>(m_tTaskDefinition.GetConfiguration(), (m_bIgnoreFolders != 0));
+	chcore::SetTaskPropValue<chcore::eTO_CreateDirectoriesRelativeToRoot>(m_tTaskDefinition.GetConfiguration(), (m_bForceDirectories != 0));
+	chcore::SetTaskPropValue<chcore::eTO_CreateEmptyFiles>(m_tTaskDefinition.GetConfiguration(), (m_bOnlyCreate != 0));
+}
+
+bool CCustomCopyDlg::HasBasicTaskData()
+{
+	CString strDstPath;
+	m_ctlDstPath.GetWindowText(strDstPath);
+
+	if (strDstPath.IsEmpty() || m_ctlFiles.GetItemCount() == 0)
+		return false;
+
+	return true;
+}
Index: src/ch/CustomCopyDlg.h
===================================================================
diff -u -rba802caea92ee56a154d1da3fe89a4b2f7875f0e -r503a68180cbb933c97e9af965744bf106994c05a
--- src/ch/CustomCopyDlg.h	(.../CustomCopyDlg.h)	(revision ba802caea92ee56a154d1da3fe89a4b2f7875f0e)
+++ src/ch/CustomCopyDlg.h	(.../CustomCopyDlg.h)	(revision 503a68180cbb933c97e9af965744bf106994c05a)
@@ -52,6 +52,9 @@
 
 	void SetBuffersizesString();
 
+	bool HasBasicTaskData();
+	void UpdateInternalTaskDefinition();
+
 	// Generated message map functions
 	virtual BOOL OnInitDialog();
 	afx_msg void OnAddDirectoryButton();
@@ -72,6 +75,7 @@
 	afx_msg void OnImportButton();
 	afx_msg void OnIgnorefoldersCheck();
 	afx_msg void OnForcedirectoriesCheck();
+	afx_msg void OnExportButtonClicked();
 
 	DECLARE_MESSAGE_MAP()
 
Index: src/ch/ch.rc
===================================================================
diff -u -r1716e3b1c975937ae6f9583f91e8940d5bc855a2 -r503a68180cbb933c97e9af965744bf106994c05a
--- src/ch/ch.rc	(.../ch.rc)	(revision 1716e3b1c975937ae6f9583f91e8940d5bc855a2)
+++ src/ch/ch.rc	(.../ch.rc)	(revision 503a68180cbb933c97e9af965744bf106994c05a)
@@ -252,6 +252,7 @@
     CONTROL         "Create directory structure in destination folder (relatively to root directory)",IDC_FORCEDIRECTORIES_CHECK,
                     "Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,13,266,329,10,0,HIDC_FORCEDIRECTORIES_CHECK
     PUSHBUTTON      "&Help",IDC_HELP_BUTTON,294,297,50,14,0,0,HIDC_HELP_BUTTON
+    PUSHBUTTON      "&Export...",IDC_EXPORT_BUTTON,7,297,50,14
 END
 
 IDD_FILTER_DIALOG DIALOGEX 0, 0, 291, 266
@@ -1131,6 +1132,7 @@
 STRINGTABLE
 BEGIN
     IDS_INFO_REASON_STRING  "Reason: %reason"
+	IDS_EXPORTING_TASK_FAILED "Exporting task data failed. Reason: %reason."
 END
 
 #endif    // English (United States) resources
Index: src/ch/resource.h
===================================================================
diff -u -ref0341282095cec2957225e031580d0c0bbaa5f6 -r503a68180cbb933c97e9af965744bf106994c05a
--- src/ch/resource.h	(.../resource.h)	(revision ef0341282095cec2957225e031580d0c0bbaa5f6)
+++ src/ch/resource.h	(.../resource.h)	(revision 503a68180cbb933c97e9af965744bf106994c05a)
@@ -349,6 +349,7 @@
 #define IDC_HORIZONTAL_BAR_STATIC       1320
 #define IDC_MSG_RICHEDIT2               1321
 #define IDC_MEASURE_RICHEDIT            1321
+#define IDC_EXPORT_BUTTON               1322
 #define IDS_APPNAME_STRING              5000
 #define IDS_PRIORITY0_STRING            5001
 #define IDS_PRIORITY1_STRING            5002
@@ -643,6 +644,7 @@
 #define IDS_STATUS_FASTMOVE_STRING      21553
 #define IDS_EMPTYSUBTASKNAME_STRING     21554
 #define IDS_STATUS_LOADERROR_STRING         21555
+#define IDS_EXPORTING_TASK_FAILED       21556
 #define ID_POPUP_SHOW_STATUS            32773
 #define ID_POPUP_TIME_CRITICAL          32774
 #define ID_POPUP_HIGHEST                32775
@@ -671,7 +673,7 @@
 #define _APS_3D_CONTROLS                     1
 #define _APS_NEXT_RESOURCE_VALUE        216
 #define _APS_NEXT_COMMAND_VALUE         32818
-#define _APS_NEXT_CONTROL_VALUE         1322
+#define _APS_NEXT_CONTROL_VALUE         1323
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
Index: src/libchcore/TTaskDefinition.cpp
===================================================================
diff -u -rc3e925d02d72f7e70178520c58c2a870f11cbbdc -r503a68180cbb933c97e9af965744bf106994c05a
--- src/libchcore/TTaskDefinition.cpp	(.../TTaskDefinition.cpp)	(revision c3e925d02d72f7e70178520c58c2a870f11cbbdc)
+++ src/libchcore/TTaskDefinition.cpp	(.../TTaskDefinition.cpp)	(revision 503a68180cbb933c97e9af965744bf106994c05a)
@@ -172,6 +172,11 @@
 	TConfig tTaskInfo;
 	tTaskInfo.Read(strPath.ToString());
 
+	Load(tTaskInfo, false);
+}
+
+void TTaskDefinition::Load(const TConfig& rDataSrc, bool bAllowEmptyDstPath)
+{
 	// clear everything
 	m_strTaskName.Clear();
 	m_vSourcePaths.Clear();
@@ -184,7 +189,7 @@
 
 	// get information from config file
 	// task unique id - use if provided, generate otherwise
-	if(!GetConfigValue(tTaskInfo, _T("TaskDefinition.UniqueID"), m_strTaskName) || m_strTaskName.IsEmpty())
+	if (!GetConfigValue(rDataSrc, _T("TaskDefinition.UniqueID"), m_strTaskName) || m_strTaskName.IsEmpty())
 	{
 		boost::uuids::random_generator gen;
 		boost::uuids::uuid u = gen();
@@ -195,29 +200,29 @@
 
 	// basic information
 	// source paths to be processed
-	if(!GetConfigValue(tTaskInfo, _T("TaskDefinition.SourcePaths.Path"), m_vSourcePaths) || m_vSourcePaths.IsEmpty())
+	if (!GetConfigValue(rDataSrc, _T("TaskDefinition.SourcePaths.Path"), m_vSourcePaths) || m_vSourcePaths.IsEmpty())
 		THROW_CORE_EXCEPTION(eErr_MissingXmlData);
 
-	GetConfigValue(tTaskInfo, _T("TaskDefinition.Filters"), m_afFilters);
+	GetConfigValue(rDataSrc, _T("TaskDefinition.Filters"), m_afFilters);
 
 	// destination path
-	if(!GetConfigValue(tTaskInfo, _T("TaskDefinition.DestinationPath"), m_pathDestinationPath) || m_pathDestinationPath.IsEmpty())
+	if (!GetConfigValue(rDataSrc, _T("TaskDefinition.DestinationPath"), m_pathDestinationPath) || (!bAllowEmptyDstPath && m_pathDestinationPath.IsEmpty()))
 		THROW_CORE_EXCEPTION(eErr_MissingXmlData);
 
 	m_pathDestinationPath.AppendSeparatorIfDoesNotExist();
 
 	// type of the operation
 	int iOperation = eOperation_None;
-	if(!tTaskInfo.GetValue(_T("TaskDefinition.OperationType"), iOperation))
+	if (!rDataSrc.GetValue(_T("TaskDefinition.OperationType"), iOperation))
 		THROW_CORE_EXCEPTION(eErr_MissingXmlData);
 
-	m_tOperationPlan.SetOperationType((EOperationType)iOperation);
+	m_tOperationPlan.SetOperationType((EOperationType) iOperation);
 
 	// and version of the task
-	if(!GetConfigValue(tTaskInfo, _T("TaskDefinition.Version"), m_ullTaskVersion))
+	if (!GetConfigValue(rDataSrc, _T("TaskDefinition.Version"), m_ullTaskVersion))
 		THROW_CORE_EXCEPTION(eErr_MissingXmlData);
 
-	if(m_ullTaskVersion < CURRENT_TASK_VERSION)
+	if (m_ullTaskVersion < CURRENT_TASK_VERSION)
 	{
 		// migrate the task to the newer version
 		// (nothing to migrate at this point, since 1.40 is the first release with xml-based tasks).
@@ -226,102 +231,58 @@
 		m_ullTaskVersion = CURRENT_TASK_VERSION;
 		m_bModified = true;
 	}
-	else if(m_ullTaskVersion > CURRENT_TASK_VERSION)
+	else if (m_ullTaskVersion > CURRENT_TASK_VERSION)
 		THROW_CORE_EXCEPTION(eErr_UnsupportedVersion);
 
-	tTaskInfo.ExtractSubConfig(_T("TaskDefinition.TaskSettings"), m_tConfiguration);
+	rDataSrc.ExtractSubConfig(_T("TaskDefinition.TaskSettings"), m_tConfiguration);
 }
 
-void TTaskDefinition::StoreInString(TString& strOutput)
+void TTaskDefinition::LoadFromString(const TString& strInput, bool bAllowEmptyDstPath)
 {
 	// read everything
 	TConfig tTaskInfo;
+	tTaskInfo.ReadFromString(strInput);
 
-	// get information from config file
-	// task unique id - use if provided, generate otherwise
-	SetConfigValue(tTaskInfo, _T("TaskDefinition.UniqueID"), m_strTaskName);
+	Load(tTaskInfo, bAllowEmptyDstPath);
+}
 
-	// basic information
-	SetConfigValue(tTaskInfo, _T("TaskDefinition.SourcePaths.Path"), m_vSourcePaths);
-	SetConfigValue(tTaskInfo, _T("TaskDefinition.Filters"), m_afFilters);
-	SetConfigValue(tTaskInfo, _T("TaskDefinition.DestinationPath"), m_pathDestinationPath);
+void TTaskDefinition::StoreInString(TString& strOutput)
+{
+	TConfig tTaskInfo;
+	Store(tTaskInfo);
 
-	int iOperation = m_tOperationPlan.GetOperationType();
-	SetConfigValue(tTaskInfo, _T("TaskDefinition.OperationType"), iOperation);
-
-	SetConfigValue(tTaskInfo, _T("TaskDefinition.Version"), m_ullTaskVersion);
-
-	tTaskInfo.PutSubConfig(_T("TaskDefinition.TaskSettings"), m_tConfiguration);
-
 	tTaskInfo.WriteToString(strOutput);
 }
 
-void TTaskDefinition::LoadFromString(const TString& strInput, bool bAllowEmptyDstPath)
+void chcore::TTaskDefinition::Store(const TSmartPath& strPath) const
 {
-	// read everything
 	TConfig tTaskInfo;
-	tTaskInfo.ReadFromString(strInput);
+	Store(tTaskInfo);
 
-	// clear everything
-	m_strTaskName.Clear();
-	m_vSourcePaths.Clear();
-	m_pathDestinationPath.Clear();
+	tTaskInfo.SetFilePath(strPath.ToString());
+	tTaskInfo.Write();
+}
 
-	m_tConfiguration.Clear();
-
-	m_bModified = false;
-
+void chcore::TTaskDefinition::Store(TConfig& rConfig) const
+{
 	// get information from config file
 	// task unique id - use if provided, generate otherwise
-	if(!GetConfigValue(tTaskInfo, _T("TaskDefinition.UniqueID"), m_strTaskName) || m_strTaskName.IsEmpty())
-	{
-		boost::uuids::random_generator gen;
-		boost::uuids::uuid u = gen();
-		m_strTaskName = boost::lexical_cast<std::wstring>(u).c_str();
+	SetConfigValue(rConfig, _T("TaskDefinition.UniqueID"), m_strTaskName);
 
-		m_bModified = true;
-	}
-
 	// basic information
-	// source paths to be processed
-	if(!GetConfigValue(tTaskInfo, _T("TaskDefinition.SourcePaths.Path"), m_vSourcePaths) || m_vSourcePaths.IsEmpty())
-		THROW_CORE_EXCEPTION(eErr_MissingXmlData);
+	SetConfigValue(rConfig, _T("TaskDefinition.SourcePaths.Path"), m_vSourcePaths);
+	SetConfigValue(rConfig, _T("TaskDefinition.Filters"), m_afFilters);
+	SetConfigValue(rConfig, _T("TaskDefinition.DestinationPath"), m_pathDestinationPath);
 
-	GetConfigValue(tTaskInfo, _T("TaskDefinition.Filters"), m_afFilters);
+	int iOperation = m_tOperationPlan.GetOperationType();
+	SetConfigValue(rConfig, _T("TaskDefinition.OperationType"), iOperation);
 
-	// destination path
-	if(!GetConfigValue(tTaskInfo, _T("TaskDefinition.DestinationPath"), m_pathDestinationPath) || (!bAllowEmptyDstPath && m_pathDestinationPath.IsEmpty()))
-		THROW_CORE_EXCEPTION(eErr_MissingXmlData);
+	SetConfigValue(rConfig, _T("TaskDefinition.Version"), m_ullTaskVersion);
 
-	if(!m_pathDestinationPath.IsEmpty())
-		m_pathDestinationPath.AppendSeparatorIfDoesNotExist();
-
-	// type of the operation
-	int iOperation = eOperation_None;
-	if(!tTaskInfo.GetValue(_T("TaskDefinition.OperationType"), iOperation))
-		THROW_CORE_EXCEPTION(eErr_MissingXmlData);
-
-	m_tOperationPlan.SetOperationType((EOperationType)iOperation);
-
-	// and version of the task
-	if(!GetConfigValue(tTaskInfo, _T("TaskDefinition.Version"), m_ullTaskVersion))
-		THROW_CORE_EXCEPTION(eErr_MissingXmlData);
-
-	if(m_ullTaskVersion < CURRENT_TASK_VERSION)
-	{
-		// migrate the task to the newer version
-		// (nothing to migrate at this point, since 1.40 is the first release with xml-based tasks).
-
-		// then mark it as a newest version task
-		m_ullTaskVersion = CURRENT_TASK_VERSION;
-		m_bModified = true;
-	}
-	else if(m_ullTaskVersion > CURRENT_TASK_VERSION)
-		THROW_CORE_EXCEPTION(eErr_UnsupportedVersion);
-
-	tTaskInfo.ExtractSubConfig(_T("TaskDefinition.TaskSettings"), m_tConfiguration);
+	rConfig.PutSubConfig(_T("TaskDefinition.TaskSettings"), m_tConfiguration);
 }
 
+
 const TFileFiltersArray& TTaskDefinition::GetFilters() const
 {
 	return m_afFilters;
Index: src/libchcore/TTaskDefinition.h
===================================================================
diff -u -ra44714d5c7ec0f50a376f4d0ea919ee5a224f834 -r503a68180cbb933c97e9af965744bf106994c05a
--- src/libchcore/TTaskDefinition.h	(.../TTaskDefinition.h)	(revision a44714d5c7ec0f50a376f4d0ea919ee5a224f834)
+++ src/libchcore/TTaskDefinition.h	(.../TTaskDefinition.h)	(revision 503a68180cbb933c97e9af965744bf106994c05a)
@@ -76,9 +76,12 @@
 
 	// Serialization
 	void Load(const TSmartPath& strPath);
+	void Load(const TConfig& rDataSrc, bool bAllowEmptyDstPath);
+	void LoadFromString(const TString& strInput, bool bAllowEmptyDstPath = false);
 
+	void Store(const TSmartPath& strPath) const;
+	void Store(TConfig& rConfig) const;
 	void StoreInString(TString& strInput);
-	void LoadFromString(const TString& strInput, bool bAllowEmptyDstPath = false);
 
 private:
 	TString m_strTaskName;				///< Unique ID of the task that will process this request (generated automatically)