1
0
Эх сурвалжийг харах

Added option to save file contents into ditto's database so we don't need the file anymore

Scott Brogden 8 жил өмнө
parent
commit
c3df4a4957
15 өөрчлөгдсөн 410 нэмэгдсэн , 8 устгасан
  1. 1 0
      ActionEnums.h
  2. 1 0
      CP_Main.cpp
  3. 1 0
      CP_Main.h
  4. 1 0
      CP_Main.rc
  5. 167 3
      Clip.cpp
  6. 4 1
      Clip.h
  7. 2 2
      Md5.cpp
  8. 2 1
      Md5.h
  9. 103 0
      OleClipSource.cpp
  10. 1 0
      OleClipSource.h
  11. 20 0
      Options.cpp
  12. 6 0
      Options.h
  13. 92 0
      QPasteWnd.cpp
  14. 6 0
      QPasteWnd.h
  15. 3 1
      Resource.h

+ 1 - 0
ActionEnums.h

@@ -94,6 +94,7 @@ public:
 		DELETE_CLIP_DATA,
 		REPLACE_TOP_STICKY_CLIP,
 		PROMPT_SEND_TO_FRIEND,
+		SAVE_CF_HDROP_FIlE_DATA,
 
 		LAST_ACTION
 	};

+ 1 - 0
CP_Main.cpp

@@ -127,6 +127,7 @@ CCP_MainApp::CCP_MainApp()
 	m_cfIgnoreClipboard = ::RegisterClipboardFormat(_T("Clipboard Viewer Ignore"));
 	m_cfDelaySavingData = ::RegisterClipboardFormat(_T("Ditto Delay Saving Data"));
 	m_RemoteCF_HDROP = ::RegisterClipboardFormat(_T("Ditto Remote CF_HDROP"));
+	m_DittoFileData = ::RegisterClipboardFormat(_T("Ditto File Data"));
 }
 
 CCP_MainApp::~CCP_MainApp()

+ 1 - 0
CP_Main.h

@@ -164,6 +164,7 @@ public:
 	CLIPFORMAT m_HTML_Format;
 	CLIPFORMAT m_RemoteCF_HDROP;
 	CLIPFORMAT m_RTFFormat;
+	CLIPFORMAT m_DittoFileData;
 
 	COleDateTime m_oldtStartUp;
 

+ 1 - 0
CP_Main.rc

@@ -305,6 +305,7 @@ BEGIN
             MENUITEM "Export Clip(s) to Text File", ID_EXPORT_EXPORTTOTEXTFILE
             MENUITEM "Export Clip(s) to Image File", ID_IMPORT_EXPORTCLIP_BITMAP
             MENUITEM "Export to Google Translate",  ID_IMPORT_EXPORTTOGOOGLETRANSLATE
+            MENUITEM "Import File Contents From CF_HDROP", ID_IMPORT_IMPORTCOPIEDFILE
         END
     END
 END

+ 167 - 3
Clip.cpp

@@ -11,6 +11,7 @@
 #include "shared/TextConvert.h"
 #include "zlib/zlib.h"
 #include "Misc.h"
+#include "Md5.h"
 
 #include <Mmsystem.h>
 
@@ -250,7 +251,7 @@ void CClip::EmptyFormats()
 }
 
 // Adds a new Format to this Clip by copying the given data.
-bool CClip::AddFormat(CLIPFORMAT cfType, void* pData, UINT nLen)
+bool CClip::AddFormat(CLIPFORMAT cfType, void* pData, UINT nLen, bool setDesc)
 {
 	ASSERT(pData && nLen);
 	HGLOBAL hGlobal = ::NewGlobalP(pData, nLen);
@@ -259,8 +260,11 @@ bool CClip::AddFormat(CLIPFORMAT cfType, void* pData, UINT nLen)
 	// update the Clip statistics
 	m_Time = m_Time.GetCurrentTime();
 
-	if(!SetDescFromText(hGlobal, true))
-		SetDescFromType();
+	if (setDesc)
+	{
+		if (cfType != CF_UNICODETEXT || !SetDescFromText(hGlobal, true))
+			SetDescFromType();
+	}
 	
 	CClipFormat format(cfType,hGlobal);
 	CClipFormat *pFormat;
@@ -816,6 +820,25 @@ bool CClip::ModifyMainTable()
 	return bRet;
 }
 
+bool CClip::ModifyDescription()
+{
+	bool bRet = false;
+	try
+	{
+		m_Desc.Replace(_T("'"), _T("''"));
+
+		theApp.m_db.execDMLEx(_T("UPDATE Main SET mText = '%s' ")
+			_T("WHERE lID = %d;"),
+			m_Desc,
+			m_id);
+
+		bRet = true;
+	}
+	CATCH_SQLITE_EXCEPTION_AND_RETURN(false)
+
+		return bRet;
+}
+
 // Empties m_Formats as it saves them to the Data Table.
 bool CClip::AddToDataTable()
 {
@@ -1515,6 +1538,147 @@ BOOL CClip::WriteTextToFile(CString path, BOOL unicode, BOOL asci, BOOL utf8)
 	return ret;
 }
 
+bool CClip::AddFileDataToData(CString &errorMessage)
+{
+	INT_PTR size = m_Formats.GetSize();
+	if (size <= 0)
+	{
+		errorMessage = _T("No CF_HDROP formats to convert");
+		return false;
+	}
+
+	bool addedFileData = false;
+
+	int nCF_HDROPIndex = -1;
+	int dittoDataIndex = -1;
+	for (int i = 0; i < size; i++)
+	{
+		if (m_Formats[i].m_cfType == CF_HDROP)
+		{
+			nCF_HDROPIndex = i;
+		}
+		else if(m_Formats[i].m_cfType == theApp.m_DittoFileData)
+		{
+			dittoDataIndex = i;
+		}
+	}	
+
+	if (nCF_HDROPIndex < 0)
+	{
+		errorMessage = _T("No CF_HDROP formats to convert");
+		return false;
+	}
+	else if (dittoDataIndex >= 0)
+	{
+		return false;
+	}
+	else
+	{
+		using namespace nsPath;
+
+		HDROP drop = (HDROP)GlobalLock(m_Formats[nCF_HDROPIndex].m_hgData);
+		int nNumFiles = DragQueryFile(drop, -1, NULL, 0);
+		
+		TCHAR filePath[MAX_PATH];
+
+		CString newDesc = _T("File Contents - ");
+				
+		for (int nFile = 0; nFile < nNumFiles; nFile++)
+		{
+			if (DragQueryFile(drop, nFile, filePath, sizeof(filePath)) > 0)
+			{
+				CFile file;
+				CFileException ex;
+				if (file.Open(filePath, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone, &ex))
+				{
+					ULONGLONG fileSize = file.GetLength();
+					int maxSize = CGetSetOptions::GetMaxFileContentsSize();
+					if (fileSize < maxSize)
+					{
+						CString src(filePath);
+						CStringA csFilePath;
+						CTextConvert::ConvertToUTF8(src, csFilePath);
+						
+						int bufferSize = fileSize + csFilePath.GetLength() + 1 + md5StringLength + 1;;
+						char *pBuffer = new char[bufferSize];
+						if (pBuffer != NULL)
+						{
+							//data contents
+							//original file<null terminator>md5<null terminator>file data
+
+							memset(pBuffer, 0, bufferSize);
+							strncpy(pBuffer, csFilePath, csFilePath.GetLength());
+							CClipFormat* pCF;
+						
+							//move the buffer start past the file path and md5 string
+							char *bufferStart = pBuffer + csFilePath.GetLength() + 1 + md5StringLength + 1;
+
+							int readBytes = file.Read(bufferStart, fileSize);
+
+							CMd5 md5;
+							CStringA md5String = md5.CalcMD5FromString(bufferStart, fileSize);
+
+							char *bufferMd5 = pBuffer + csFilePath.GetLength() + 1;
+							strncpy(bufferMd5, md5String, md5StringLength);
+
+							AddFormat(theApp.m_DittoFileData, pBuffer, bufferSize);
+
+							addedFileData = true;
+
+							newDesc += filePath;
+							newDesc += _T("\n");
+
+							Log(StrF(_T("Saving file contents to Ditto Database, file: %s, size: %d, md5: %s"), filePath, fileSize, md5String));
+						}
+					}
+					else
+					{
+						const int MAX_FILE_SIZE_BUFFER = 255;
+						TCHAR szFileSize[MAX_FILE_SIZE_BUFFER];
+						TCHAR szMaxFileSize[MAX_FILE_SIZE_BUFFER];
+						StrFormatByteSize(fileSize, szFileSize, MAX_FILE_SIZE_BUFFER);
+						StrFormatByteSize(maxSize, szMaxFileSize, MAX_FILE_SIZE_BUFFER);
+
+						errorMessage += StrF(_T("File is to large: %s, Size: %s, Max Size: %s\r\n"), filePath, szFileSize, szMaxFileSize);
+					}
+				}
+				else
+				{
+					TCHAR szError[200];
+					ex.GetErrorMessage(szError, 200);
+					errorMessage += StrF(_T("Error opening file: %s, Error: %s\r\n"), filePath, szError);
+				}
+			}
+		}
+
+		GlobalUnlock(m_Formats[nCF_HDROPIndex].m_hgData);
+
+		if (addedFileData)
+		{
+			for (int i = 0; i < size; i++)
+			{
+				this->m_Formats.RemoveAt(i, 1);
+			}
+
+			this->m_Desc = newDesc;
+
+			if (this->ModifyDescription())
+			{
+				if (this->AddToDataTable() == FALSE)
+				{
+					errorMessage += _T("Error saving data to database.");
+				}
+			}
+			else
+			{
+				errorMessage += _T("Error saving main table to database.");
+			}
+		}
+	}
+
+	return addedFileData;
+}
+
 /*----------------------------------------------------------------------------*\
 CClipList
 \*----------------------------------------------------------------------------*/

+ 4 - 1
Clip.h

@@ -125,12 +125,13 @@ public:
 
 	void Clear();
 	void EmptyFormats();
-	bool AddFormat(CLIPFORMAT cfType, void* pData, UINT nLen);
+	bool AddFormat(CLIPFORMAT cfType, void* pData, UINT nLen, bool setDesc = false);
 	bool LoadFromClipboard(CClipTypes* pClipTypes, bool checkClipboardIgnore = true);
 	bool SetDescFromText(HGLOBAL hgData, bool unicode);
 	bool SetDescFromType();
 	bool AddToDB(bool bCheckForDuplicates = true);
 	bool ModifyMainTable();
+	bool ModifyDescription();
 	bool SaveFromEditWnd(BOOL bUpdateDesc);
 	void MakeLatestOrder();
 	void MakeLatestGroupOrder();
@@ -157,6 +158,8 @@ public:
 	static double GetNewOrder(int parentId, int clipId);
 	static double GetNewTopSticky(int parentId, int clipId);
 	static double GetNewLastSticky(int parentId, int clipId);
+
+	bool AddFileDataToData(CString &errorMessage);
 	
 protected:
 	bool AddToMainTable();

+ 2 - 2
Md5.cpp

@@ -70,10 +70,10 @@ char* CMd5::CalcMD5FromFile(const TCHAR *s8_Path)
 //                calculate MD5 from a string
 //
 /********************************************************************/
-char* CMd5::CalcMD5FromString(const char *s8_Input)
+char* CMd5::CalcMD5FromString(const char *s8_Input, int len)
 {
 	MD5Init();
-	MD5Update((unsigned char*)s8_Input, strlen(s8_Input));
+	MD5Update((unsigned char*)s8_Input, len);
 
 	return MD5FinalToString();
 }

+ 2 - 1
Md5.h

@@ -1,11 +1,12 @@
 #pragma once
 
 #define _ReadBufSize 1000000
+#define md5StringLength 32
 
 class CMd5  
 {
 public:
-	char* CalcMD5FromString(const char *s8_Input);
+	char* CalcMD5FromString(const char *s8_Input, int len);
 	char* CalcMD5FromFile(const TCHAR *s8_Path);
 
 	void MD5Init();

+ 103 - 0
OleClipSource.cpp

@@ -12,6 +12,8 @@
 #include "Client.h"
 #include "sqlite\unicode\unistr.h"
 #include "sqlite\unicode\uchar.h"
+#include "Path.h"
+#include "Md5.h"
 
 /*------------------------------------------------------------------*\
 COleClipSource
@@ -181,6 +183,8 @@ BOOL COleClipSource::DoImmediateRender()
 	{
 		AddDateTime(clip);
 	}
+	
+	SaveDittoFileDataToFile(clip);
 
 	return PutFormatOnClipboard(&clip.m_Formats) > 0;
 }
@@ -697,6 +701,96 @@ void COleClipSource::AddDateTime(CClip &clip)
 	}
 }
 
+void COleClipSource::SaveDittoFileDataToFile(CClip &clip)
+{
+	CFileRecieve hDrpData;
+	CClipFormat* pCF;
+	int hDropIndex = -1;
+	bool savedFile = false;
+	INT_PTR	count = clip.m_Formats.GetSize();
+	for (int i = 0; i < count; i++)
+	{
+		pCF = &clip.m_Formats.ElementAt(i);
+
+		if (pCF->m_cfType == theApp.m_DittoFileData)
+		{
+			IClipFormat *dittoFileData = &clip.m_Formats.ElementAt(i);
+			if (dittoFileData != NULL)
+			{
+				HGLOBAL data = dittoFileData->Data();
+				char * stringData = (char *)GlobalLock(data);
+
+				//original source is store in the first string ending in the null terminator
+				CStringA src(stringData);
+				stringData += src.GetLength() + 1;
+
+				CStringA originalMd5(stringData);
+				stringData += originalMd5.GetLength() + 1;
+
+				int dataSize = (int)GlobalSize(data) - (src.GetLength() + 1) - (originalMd5.GetLength() + 1);
+
+				CMd5 calcMd5;
+				CStringA md5String = calcMd5.CalcMD5FromString(stringData, dataSize);
+
+				CString unicodeFilePath;
+				CTextConvert::ConvertFromUTF8(src, unicodeFilePath);
+
+				CString unicodeMd5;
+				CTextConvert::ConvertFromUTF8(md5String, unicodeMd5);
+
+				Log(StrF(_T("Saving file contents from Ditto, original file: %s, size: %d, md5: %s"), unicodeFilePath, dataSize, unicodeMd5));
+
+				if (md5String == originalMd5)
+				{
+					using namespace nsPath;
+					CPath path(unicodeFilePath);
+					CString fileName = path.GetName();
+
+					CString newFilePath = CGetSetOptions::GetPath(PATH_DRAG_FILES);
+					newFilePath += fileName;
+
+					CFile f;
+					if (f.Open(newFilePath, CFile::modeWrite | CFile::modeCreate))
+					{
+						f.Write(stringData, dataSize);
+
+						f.Close();
+
+						savedFile = true;
+						hDrpData.AddFile(newFilePath);
+					}
+					else
+					{
+						Log(StrF(_T("Error saving file: %s"), unicodeFilePath));
+					}
+				}
+				else
+				{
+					Log(StrF(_T("MD5 ERROR, file: %s, original md5: %s, calc md5: %s"), unicodeFilePath, originalMd5, md5String));
+				}
+			}
+		}
+		else if (pCF->m_cfType == CF_HDROP)
+		{
+			hDropIndex = i;
+		}
+	}
+
+	if (hDropIndex >= 0)
+	{
+		clip.m_Formats.RemoveAt(hDropIndex);
+	}
+
+	if (savedFile)
+	{
+		CClipFormat cf(CF_HDROP, hDrpData.CreateCF_HDROPBuffer());
+		clip.m_Formats.Add(cf);
+
+		//clip.m_Formats now owns the global data
+		cf.m_autoDeleteData = false;
+	}
+}
+
 void COleClipSource::Typoglycemia(CClip &clip)
 {
 	IClipFormat *unicodeTextFormat = clip.m_Formats.FindFormatEx(CF_UNICODETEXT);
@@ -783,6 +877,7 @@ INT_PTR COleClipSource::PutFormatOnClipboard(CClipFormats *pFormats)
 	CClipFormat* pCF;
 	INT_PTR	count = pFormats->GetSize();
 	bool bDelayedRenderCF_HDROP = false;
+	bool dittoFileData = false;
 	INT_PTR i = 0;
 
 	//see if the html format is in the list
@@ -795,6 +890,14 @@ INT_PTR COleClipSource::PutFormatOnClipboard(CClipFormats *pFormats)
 		{
 			bDelayedRenderCF_HDROP = true;
 		}
+
+		if (pCF->m_cfType == theApp.m_DittoFileData)
+		{
+			dittoFileData = true;
+
+			//save file data
+			//adjust hdrop
+		}
 	}
 
 	for(i = 0; i < count; i++)

+ 1 - 0
OleClipSource.h

@@ -40,4 +40,5 @@ protected:
 	void Typoglycemia(CClip &clip);
 	HGLOBAL ConvertToFileDrop();
 	void AddDateTime(CClip &clip);
+	void SaveDittoFileDataToFile(CClip &clip);
 };

+ 20 - 0
Options.cpp

@@ -2419,4 +2419,24 @@ void CGetSetOptions::SetCustomSendToList(CString val)
 CString	CGetSetOptions::GetCustomSendToList()
 {
 	return GetProfileString("CustomSendToList", "");
+}
+
+int CGetSetOptions::GetMaxFileContentsSize()
+{
+	return GetProfileLong(_T("MaxFileContentsSize"), 64000000);
+}
+
+void CGetSetOptions::SetMaxFileContentsSize(int val)
+{
+	SetProfileLong(_T("MaxFileContentsSize"), val);
+}
+
+int CGetSetOptions::GetErrorMsgPopupTimeout()
+{
+	return GetProfileLong(_T("ErrorMsgPopupTimeout"), 3500);
+}
+
+void CGetSetOptions::SetErrorMsgPopupTimeout(int val)
+{
+	SetProfileLong(_T("ErrorMsgPopupTimeout"), val);
 }

+ 6 - 0
Options.h

@@ -549,6 +549,12 @@ public:
 
 	static void		SetCustomSendToList(CString val);
 	static CString	GetCustomSendToList();
+
+	static int GetMaxFileContentsSize();
+	static void SetMaxFileContentsSize(int val);
+
+	static int GetErrorMsgPopupTimeout();
+	static void SetErrorMsgPopupTimeout(int val);
 };
 
 // global for easy access and for initialization of fast access variables

+ 92 - 0
QPasteWnd.cpp

@@ -49,6 +49,7 @@
 #define TIMER_FILL_CACHE		1
 #define TIMER_DO_SEARCH			2
 #define TIMER_PASTE_FROM_MODIFER	3
+#define TIMER_ERROR_MSG			4
 
 #define THREAD_DO_QUERY				0
 #define THREAD_EXIT_THREAD			1
@@ -292,6 +293,8 @@ ON_COMMAND(ID_CLIPORDER_REPLACETOPSTICKYCLIP, &CQPasteWnd::OnCliporderReplacetop
 ON_UPDATE_COMMAND_UI(ID_CLIPORDER_REPLACETOPSTICKYCLIP, &CQPasteWnd::OnUpdateCliporderReplacetopstickyclip)
 ON_COMMAND(ID_SENDTO_PROMPTFORNAME, &CQPasteWnd::OnSendtoPromptforname)
 ON_UPDATE_COMMAND_UI(ID_SENDTO_PROMPTFORNAME, &CQPasteWnd::OnUpdateSendtoPromptforname)
+ON_COMMAND(ID_IMPORT_IMPORTCOPIEDFILE, &CQPasteWnd::OnImportImportcopiedfile)
+ON_UPDATE_COMMAND_UI(ID_IMPORT_IMPORTCOPIEDFILE, &CQPasteWnd::OnUpdateImportImportcopiedfile)
 END_MESSAGE_MAP()
 
 
@@ -440,6 +443,8 @@ int CQPasteWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
 	m_alwaysOnToWarningStatic.SetToggleCursor(true);
 	m_alwaysOnToWarningStatic.SetFont(&m_groupFont);
 
+	m_popupMsg.m_hWndPosRelativeTo = m_hWnd;
+
 	LoadShortcuts();
 
 	InvalidateNc();
@@ -525,6 +530,8 @@ void CQPasteWnd::OnSize(UINT nType, int cx, int cy)
         return ;
     }
 
+	m_popupMsg.Hide();
+
     MoveControls();
 }
 
@@ -693,6 +700,8 @@ BOOL CQPasteWnd::HideQPasteWindow (bool releaseFocus, bool clearSearchData)
 
 	m_lstHeader.HidePopup();
 
+	m_popupMsg.Hide();
+
     //Save the size
     SaveWindowSize();
 
@@ -3016,6 +3025,9 @@ bool CQPasteWnd::DoAction(DWORD actionId)
 	case ActionEnums::PROMPT_SEND_TO_FRIEND:
 		ret = DoActionPromptSendToFriend();
 		break;
+	case ActionEnums::SAVE_CF_HDROP_FIlE_DATA:
+		ret = DoActionSaveCF_HDROP_FileData();
+		break;
 	}
 
 	return ret;
@@ -3275,6 +3287,7 @@ bool CQPasteWnd::DoActionEditClip()
 
 	CClipIDs IDs;
 	m_lstHeader.GetSelectionItemData(IDs);
+
 	theApp.EditItems(IDs, true);
 
 	HideQPasteWindow(false);
@@ -4358,6 +4371,64 @@ bool CQPasteWnd::DoActionReplaceTopStickyClip()
 	return true;
 }
 
+bool CQPasteWnd::DoActionSaveCF_HDROP_FileData()
+{
+	if (m_lstHeader.GetSelectedCount() == 0)
+	{
+		return false;
+	}
+
+	CWaitCursor wait;
+
+	CString errorMessage;
+
+	CClipIDs IDs;
+	m_lstHeader.GetSelectionItemData(IDs);
+	ARRAY Indexs;
+	m_lstHeader.GetSelectionIndexes(Indexs);
+
+	if (IDs.GetCount() > 0)
+	{
+		for(int i = 0; i < min(Indexs.GetCount(), IDs.GetCount()); i++)
+		{
+			int row = Indexs[i];
+			int id = IDs[i];
+			CClip clip;
+			if (clip.LoadMainTable(id))
+			{
+				if (clip.LoadFormats(id))
+				{
+					CString localErrorMessage;
+					if (clip.AddFileDataToData(localErrorMessage))
+					{
+						if (row >= 0 &&
+							row < (int)m_listItems.size())
+						{
+							CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT * FROM Main WHERE lID = %d"), id);
+							if (!q.eof())
+							{
+								FillMainTable(m_listItems[row], q);
+							}
+						}
+					}
+					
+					errorMessage += localErrorMessage;
+				}
+			}
+		}
+	}
+
+	if (errorMessage.GetLength() > 0)
+	{
+		m_popupMsg.Show(errorMessage, CPoint(0, 0), true);
+		SetTimer(TIMER_ERROR_MSG, CGetSetOptions::GetErrorMsgPopupTimeout(), NULL);
+	}
+
+	m_lstHeader.RefreshVisibleRows();
+
+	return true;
+}
+
 bool CQPasteWnd::DoActionPromptSendToFriend()
 {
 	m_bHideWnd = false;
@@ -5380,6 +5451,11 @@ void CQPasteWnd::OnTimer(UINT_PTR nIDEvent)
             Log(_T("m_bModifersMoveActive set to false\n"));
         }
     }
+	else if (nIDEvent == TIMER_ERROR_MSG)
+	{
+		KillTimer(TIMER_ERROR_MSG);
+		m_popupMsg.Hide();
+	}
 
     CWndEx::OnTimer(nIDEvent);
 }
@@ -6197,3 +6273,19 @@ void CQPasteWnd::OnUpdateSendtoPromptforname(CCmdUI *pCmdUI)
 
 	UpdateMenuShortCut(pCmdUI, ActionEnums::PROMPT_SEND_TO_FRIEND);
 }
+
+
+void CQPasteWnd::OnImportImportcopiedfile()
+{
+	DoAction(ActionEnums::SAVE_CF_HDROP_FIlE_DATA);
+}
+
+void CQPasteWnd::OnUpdateImportImportcopiedfile(CCmdUI *pCmdUI)
+{
+	if (!pCmdUI->m_pMenu)
+	{
+		return;
+	}
+
+	UpdateMenuShortCut(pCmdUI, ActionEnums::SAVE_CF_HDROP_FIlE_DATA);
+}

+ 6 - 0
QPasteWnd.h

@@ -18,6 +18,8 @@
 #include "SpecialPasteOptions.h"
 #include "ClipIds.h"
 #include "SymbolEdit.h"
+#include "Popup.h"
+
 class CMainTable
 {
 public:
@@ -163,6 +165,7 @@ public:
 	bool m_showScrollBars;
 	int m_leftSelectedCompareId;
 	INT64 m_extraDataCounter;
+	CPopup m_popupMsg;
 
     void RefreshNc();
     void UpdateStatus(bool bRepaintImmediately = false); // regenerates the status (caption) text
@@ -272,6 +275,7 @@ public:
 	bool OnRemoveStickySetting();	
 	bool DoActionReplaceTopStickyClip();
 	bool DoActionPromptSendToFriend();
+	bool DoActionSaveCF_HDROP_FileData();
 
 	bool OnNewClip();
 	bool OnImportClip();
@@ -503,4 +507,6 @@ public:
 	afx_msg void OnUpdateCliporderReplacetopstickyclip(CCmdUI *pCmdUI);
 	afx_msg void OnSendtoPromptforname();
 	afx_msg void OnUpdateSendtoPromptforname(CCmdUI *pCmdUI);
+	afx_msg void OnImportImportcopiedfile();
+	afx_msg void OnUpdateImportImportcopiedfile(CCmdUI *pCmdUI);
 };

+ 3 - 1
Resource.h

@@ -668,6 +668,8 @@
 #define ID_MENU_NEWCLIP32937            32937
 #define ID_CLIPORDER_REPLACETOPSTICKYCLIP 32938
 #define ID_SENDTO_PROMPTFORNAME         32939
+#define ID_MENU_SAVE                    32940
+#define ID_IMPORT_IMPORTCOPIEDFILE      32941
 
 // Next default values for new objects
 // 
@@ -675,7 +677,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_3D_CONTROLS                     1
 #define _APS_NEXT_RESOURCE_VALUE        326
-#define _APS_NEXT_COMMAND_VALUE         32940
+#define _APS_NEXT_COMMAND_VALUE         32942
 #define _APS_NEXT_CONTROL_VALUE         2151
 #define _APS_NEXT_SYMED_VALUE           104
 #endif