CP_Main.cpp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  1. #include "stdafx.h"
  2. #include "CP_Main.h"
  3. #include "MainFrm.h"
  4. #include "Misc.h"
  5. #include ".\cp_main.h"
  6. #include "server.h"
  7. #include "Client.h"
  8. #include "InternetUpdate.h"
  9. #include <io.h>
  10. #include "Path.h"
  11. #include "Clip_ImportExport.h"
  12. #include "HyperLink.h"
  13. #include "OptionsSheet.h"
  14. #include "DittoCopyBuffer.h"
  15. #include "SendKeys.h"
  16. #include "MainTableFunctions.h"
  17. #include "ShowTaskBarIcon.h"
  18. #include "NoDbFrameWnd.h"
  19. #include <clocale>
  20. #ifdef _DEBUG
  21. #define new DEBUG_NEW
  22. #undef THIS_FILE
  23. static char THIS_FILE[] = __FILE__;
  24. #endif
  25. class DittoCommandLineInfo : public CCommandLineInfo
  26. {
  27. public:
  28. DittoCommandLineInfo()
  29. {
  30. m_bDisconnect = FALSE;
  31. m_bConnect = FALSE;
  32. m_uacPID = 0;
  33. m_bOpenWindow = FALSE;
  34. m_bCloseWindow = FALSE;
  35. m_plainTextPaste = FALSE;
  36. m_pasteClip = FALSE;
  37. m_clipID = -1;
  38. m_editClip = FALSE;
  39. m_restartFromRestartManager = FALSE;
  40. }
  41. virtual void ParseParam(const TCHAR* pszParam, BOOL bFlag, BOOL bLast)
  42. {
  43. if(bFlag)
  44. {
  45. if(STRICMP(pszParam, _T("Connect")) == 0)
  46. {
  47. m_bConnect = TRUE;
  48. }
  49. else if(STRICMP(pszParam, _T("Disconnect")) == 0)
  50. {
  51. m_bDisconnect = TRUE;
  52. }
  53. else if(wcsncmp(pszParam, _T("uacpaste"), 8) == 0)
  54. {
  55. CString pidCommand(pszParam);
  56. long sep = pidCommand.ReverseFind(':');
  57. if(sep > -1)
  58. {
  59. CString pid = pidCommand.Right(pidCommand.GetLength() - sep - 1);
  60. m_uacPID = ATOI(pid);
  61. }
  62. }
  63. else if(STRICMP(pszParam, _T("open")) == 0)
  64. {
  65. m_bOpenWindow = TRUE;
  66. }
  67. else if(STRICMP(pszParam, _T("close")) == 0)
  68. {
  69. m_bCloseWindow = TRUE;
  70. }
  71. else if (STRICMP(pszParam, _T("PlainTextPaste")) == 0)
  72. {
  73. m_plainTextPaste = TRUE;
  74. }
  75. else if (wcsnicmp(pszParam, _T("paste"), 5) == 0)
  76. {
  77. CString pidCommand(pszParam);
  78. long sep = pidCommand.ReverseFind(':');
  79. if (sep > -1)
  80. {
  81. CString id = pidCommand.Right(pidCommand.GetLength() - sep - 1);
  82. m_clipID = ATOI(id);
  83. m_pasteClip = TRUE;
  84. }
  85. }
  86. else if (wcsnicmp(pszParam, _T("edit"), 4) == 0)
  87. {
  88. CString pidCommand(pszParam);
  89. long sep = pidCommand.ReverseFind(':');
  90. if (sep > -1)
  91. {
  92. CString id = pidCommand.Right(pidCommand.GetLength() - sep - 1);
  93. m_clipID = ATOI(id);
  94. m_editClip = TRUE;
  95. }
  96. }
  97. else if (wcsnicmp(pszParam, _T("RestartByRestartManager"), 23) == 0)
  98. {
  99. m_restartFromRestartManager = true;
  100. }
  101. }
  102. CCommandLineInfo::ParseParam(pszParam, bFlag, bLast);
  103. }
  104. BOOL m_bDisconnect;
  105. BOOL m_bConnect;
  106. BOOL m_pasteClip;
  107. int m_uacPID;
  108. int m_clipID;
  109. BOOL m_bCloseWindow;
  110. BOOL m_bOpenWindow;
  111. BOOL m_plainTextPaste;
  112. BOOL m_editClip;
  113. BOOL m_restartFromRestartManager;
  114. };
  115. CCP_MainApp theApp;
  116. BEGIN_MESSAGE_MAP(CCP_MainApp, CWinApp)
  117. //{{AFX_MSG_MAP(CCP_MainApp)
  118. // NOTE - the ClassWizard will add and remove mapping macros here.
  119. // DO NOT EDIT what you see in these blocks of generated code!
  120. //}}AFX_MSG_MAP
  121. END_MESSAGE_MAP()
  122. CCP_MainApp::CCP_MainApp()
  123. {
  124. m_copyReason = CopyReasonEnum::COPY_TO_UNKOWN;
  125. m_copyReasonStartTime = 0;
  126. m_activeGroupId = -1;
  127. m_activeGroupStartTime = 0;
  128. m_pUacPasteThread = NULL;
  129. m_bAppRunning = false;
  130. m_bAppExiting = false;
  131. m_connectOnStartup = -1;
  132. m_MainhWnd = NULL;
  133. m_pMainFrame = NULL;
  134. BOOL set = ::AllowSetForegroundWindow(ASFW_ANY);
  135. m_bShowingQuickPaste = false;
  136. m_GroupDefaultID = 0;
  137. m_GroupID = -1;
  138. m_GroupParentID = 0;
  139. m_GroupText = "History";
  140. m_FocusID = -1;
  141. ClearOldGroupState();
  142. m_bAsynchronousRefreshView = true;
  143. m_lClipsSent = 0;
  144. m_lClipsRecieved = 0;
  145. m_oldtStartUp = COleDateTime::GetCurrentTime();
  146. m_bExitServerThread = false;
  147. m_lLastGoodIndexForNextworkPassword = -2;
  148. m_RTFFormat = ::RegisterClipboardFormat(_T("Rich Text Format"));
  149. m_HTML_Format = ::RegisterClipboardFormat(_T("HTML Format"));
  150. m_PingFormat = ::RegisterClipboardFormat(_T("Ditto Ping Format"));
  151. m_cfIgnoreClipboard = ::RegisterClipboardFormat(_T("Clipboard Viewer Ignore"));
  152. m_cfDelaySavingData = ::RegisterClipboardFormat(_T("Ditto Delay Saving Data"));
  153. m_RemoteCF_HDROP = ::RegisterClipboardFormat(_T("Ditto Remote CF_HDROP"));
  154. m_DittoFileData = ::RegisterClipboardFormat(_T("Ditto File Data"));
  155. m_PNG_Format = GetFormatID(_T("PNG"));
  156. m_pNoDbMainFrame = NULL;
  157. m_databaseOnNetworkShare = false;
  158. m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
  159. }
  160. CCP_MainApp::~CCP_MainApp()
  161. {
  162. }
  163. BOOL CCP_MainApp::InitInstance()
  164. {
  165. INITCOMMONCONTROLSEX InitCtrls;
  166. InitCtrls.dwSize = sizeof(InitCtrls);
  167. // Set this to include all the common control classes you want to use
  168. // in your application.
  169. InitCtrls.dwICC = ICC_WIN95_CLASSES;
  170. InitCommonControlsEx(&InitCtrls);
  171. AfxEnableControlContainer();
  172. AfxOleInit();
  173. AfxInitRichEditEx();
  174. Gdiplus::GdiplusStartupInput gdiplusStartupInput;
  175. Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
  176. LoadLibrary(TEXT("MSFTEDIT.DLL"));
  177. setlocale(LC_TIME, ".OCP"); // defines the date/time formatting
  178. //MessageBox(NULL, _T("ditto starting"), _T("d"), MB_OK);
  179. DittoCommandLineInfo cmdInfo;
  180. ParseCommandLine(cmdInfo);
  181. g_Opt.LoadSettings();
  182. theApp.m_activeWnd.TrackActiveWnd(false);
  183. if(cmdInfo.m_uacPID > 0)
  184. {
  185. Log(StrF(_T("Startup up ditto as admin to paste to admin windows, parent process id: %d"), cmdInfo.m_uacPID));
  186. CString mutex;
  187. mutex.Format(_T("DittoAdminPaste_%d"), cmdInfo.m_uacPID);
  188. m_adminPasteMutex = CreateMutex(NULL, FALSE, mutex);
  189. m_pUacPasteThread = new CUAC_Thread(cmdInfo.m_uacPID);
  190. m_pUacPasteThread->Start();
  191. m_pUacPasteThread->WaitForThreadToExit(INT_MAX);
  192. return FALSE;
  193. }
  194. if (cmdInfo.m_restartFromRestartManager)
  195. {
  196. Log(StrF(_T("Ditto was restarted from restart manager")));
  197. }
  198. else if(cmdInfo.m_strFileName.IsEmpty() == FALSE)
  199. {
  200. try
  201. {
  202. g_Opt.m_bEnableDebugLogging = g_Opt.GetEnableDebugLogging();
  203. CClip_ImportExport Clip;
  204. CppSQLite3DB db;
  205. db.open(cmdInfo.m_strFileName);
  206. CClip_ImportExport clip;
  207. if(clip.ImportFromSqliteDB(db, false, true))
  208. {
  209. ShowCommandLineError("Ditto", theApp.m_Language.GetString("Importing_Good", "Clip placed on clipboard"));
  210. }
  211. else
  212. {
  213. ShowCommandLineError("Ditto", theApp.m_Language.GetString("Error_Importing", "Error importing exported clip"));
  214. }
  215. }
  216. catch (CppSQLite3Exception& e)
  217. {
  218. ASSERT(FALSE);
  219. CString csError;
  220. csError.Format(_T("%s - Exception - %d - %s"), theApp.m_Language.GetString("Error_Parsing", "Error parsing exported clip"), e.errorCode(), e.errorMessage());
  221. ShowCommandLineError("Ditto", csError);
  222. }
  223. return FALSE;
  224. }
  225. else if(cmdInfo.m_bConnect || cmdInfo.m_bDisconnect)
  226. {
  227. //First get the saved hwnd and send it a message
  228. //If ditt is running then this will return 1, meening the running ditto process
  229. //handled this message
  230. //If it didn't handle the message(ditto is not running) then startup this processes of ditto
  231. //disconnected from the clipboard
  232. LRESULT ret = 0;
  233. HWND hWnd = (HWND)(LONG_PTR)CGetSetOptions::GetMainHWND();
  234. if(hWnd)
  235. {
  236. ret = ::SendMessage(hWnd, WM_SET_CONNECTED, cmdInfo.m_bConnect, cmdInfo.m_bDisconnect);
  237. }
  238. //passed off to the running instance of ditto, exit this instance
  239. if(ret == 1)
  240. {
  241. return FALSE;
  242. }
  243. if(cmdInfo.m_bConnect)
  244. {
  245. m_connectOnStartup = TRUE;
  246. }
  247. else if(cmdInfo.m_bDisconnect)
  248. {
  249. m_connectOnStartup = FALSE;
  250. }
  251. }
  252. else if(cmdInfo.m_bOpenWindow || cmdInfo.m_bCloseWindow)
  253. {
  254. //First get the saved hwnd and send it a message
  255. //If ditt is running then this will return 1, meening the running ditto process
  256. //handled this message
  257. //If it didn't handle the message(ditto is not running) then startup this processes of ditto
  258. //disconnected from the clipboard
  259. LRESULT ret = 0;
  260. HWND hWnd = (HWND)(LONG_PTR)CGetSetOptions::GetMainHWND();
  261. if(hWnd)
  262. {
  263. ret = ::SendMessage(hWnd, WM_OPEN_CLOSE_WINDWOW, cmdInfo.m_bOpenWindow, cmdInfo.m_bCloseWindow);
  264. }
  265. return FALSE;
  266. }
  267. else if (cmdInfo.m_plainTextPaste)
  268. {
  269. LRESULT ret = 0;
  270. HWND hWnd = (HWND)(LONG_PTR)CGetSetOptions::GetMainHWND();
  271. if (hWnd)
  272. {
  273. ret = ::SendMessage(hWnd, WM_PLAIN_TEXT_PASTE, NULL, NULL);
  274. }
  275. return FALSE;
  276. }
  277. else if (cmdInfo.m_pasteClip)
  278. {
  279. LRESULT ret = 0;
  280. HWND hWnd = (HWND)(LONG_PTR)CGetSetOptions::GetMainHWND();
  281. if (hWnd)
  282. {
  283. ret = ::SendMessage(hWnd, WM_PASTE_CLIP, cmdInfo.m_clipID, NULL);
  284. }
  285. return FALSE;
  286. }
  287. else if (cmdInfo.m_editClip)
  288. {
  289. LRESULT ret = 0;
  290. HWND hWnd = (HWND)(LONG_PTR)CGetSetOptions::GetMainHWND();
  291. if (hWnd)
  292. {
  293. ret = ::SendMessage(hWnd, WM_EDIT_CLIP, cmdInfo.m_clipID, NULL);
  294. }
  295. return FALSE;
  296. }
  297. CInternetUpdate update;
  298. auto runningVersion = update.GetRunningVersion();
  299. CString cs = update.GetVersionString(runningVersion);
  300. cs.Insert(0, _T("InitInstance - Running Version - "));
  301. Log(cs);
  302. CString csMutex("Ditto Is Now Running");
  303. if(g_Opt.GetIsPortableDitto() || g_Opt.GetIsWindowsApp() || g_Opt.GetIsChocolateyApp())
  304. {
  305. csMutex += " ";
  306. csMutex += g_Opt.GetExeFileName();
  307. }
  308. CWinApp::RegisterWithRestartManager(false, csMutex);
  309. //create mutex doesn't like slashes, remove them, it always returns NULL with them in
  310. csMutex.Replace(_T("\\"), _T("_"));
  311. m_hMutex = CreateMutex(NULL, TRUE, csMutex);
  312. DWORD dwError = GetLastError();
  313. if(m_hMutex == NULL ||
  314. dwError == ERROR_ALREADY_EXISTS)
  315. {
  316. Log(StrF(_T("Ditto is already running, closing, mutex: %s"), csMutex));
  317. HWND hWnd = (HWND)(LONG_PTR)CGetSetOptions::GetMainHWND();
  318. if(hWnd)
  319. ::SendMessage(hWnd, WM_SHOW_TRAY_ICON, TRUE, TRUE);
  320. return TRUE;
  321. }
  322. Log(StrF(_T("Starting up ditto with mutex: %s"), csMutex));
  323. CString csFile = CGetSetOptions::GetLanguageFile();
  324. if(m_Language.LoadLanguageFile(csFile) == false)
  325. {
  326. CString cs;
  327. cs.Format(_T("Error loading language file - %s - \n\n%s"), csFile, m_Language.m_csLastError);
  328. Log(cs);
  329. m_Language.LoadLanguageFile(_T("English.xml"));
  330. }
  331. m_icuString.Load();
  332. int nRet = CheckDBExists(CGetSetOptions::GetDBPath());
  333. if(nRet == FALSE)
  334. {
  335. m_pNoDbMainFrame = new CNoDbFrameWnd();
  336. m_pMainWnd = m_pNoDbMainFrame;
  337. m_pNoDbMainFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL);
  338. m_pNoDbMainFrame->ShowWindow(SW_SHOW);
  339. m_pNoDbMainFrame->UpdateWindow();
  340. }
  341. else
  342. {
  343. CreateMainWnd();
  344. }
  345. return TRUE;
  346. }
  347. void CCP_MainApp::CreateMainWnd()
  348. {
  349. CMainFrame* pFrame = new CMainFrame;
  350. m_pMainWnd = m_pMainFrame = pFrame;
  351. pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL);
  352. pFrame->ShowWindow(SW_SHOW);
  353. pFrame->UpdateWindow();
  354. }
  355. void CCP_MainApp::CloseNoDbWindow()
  356. {
  357. if (m_pNoDbMainFrame != NULL)
  358. {
  359. m_pNoDbMainFrame->CloseWindow();
  360. delete m_pNoDbMainFrame;
  361. m_pNoDbMainFrame = NULL;
  362. }
  363. }
  364. void CCP_MainApp::AfterMainCreate()
  365. {
  366. m_MainhWnd = m_pMainFrame->m_hWnd;
  367. ASSERT( ::IsWindow(m_MainhWnd) );
  368. g_Opt.SetMainHWND((long)(LONG_PTR)m_MainhWnd);
  369. g_HotKeys.Init(m_MainhWnd);
  370. // create hotkeys here. They are automatically deleted on exit
  371. m_pDittoHotKey = new CHotKey(CString("DittoHotKey"), 704); //704 is ctrl-tilda
  372. m_pDittoHotKey2 = new CHotKey(CString("DittoHotKey2"));
  373. m_pDittoHotKey3 = new CHotKey(CString("DittoHotKey3"));
  374. m_pPosOne = new CHotKey("Position1", 0, true);
  375. m_pPosTwo = new CHotKey("Position2", 0, true);
  376. m_pPosThree = new CHotKey("Position3", 0, true);
  377. m_pPosFour = new CHotKey("Position4", 0, true);
  378. m_pPosFive = new CHotKey("Position5", 0, true);
  379. m_pPosSix = new CHotKey("Position6", 0, true);
  380. m_pPosSeven = new CHotKey("Position7", 0, true);
  381. m_pPosEight = new CHotKey("Position8", 0, true);
  382. m_pPosNine = new CHotKey("Position9", 0, true);
  383. m_pPosTen = new CHotKey("Position10", 0, true);
  384. m_pCopyBuffer1 = new CHotKey("CopyBufferCopyHotKey_0", 0, true);
  385. m_pPasteBuffer1 = new CHotKey("CopyBufferPasteHotKey_0", 0, true);
  386. m_pCutBuffer1 = new CHotKey("CopyBufferCutHotKey_0", 0, true);
  387. m_pCopyBuffer2 = new CHotKey("CopyBufferCopyHotKey_1", 0, true);
  388. m_pPasteBuffer2 = new CHotKey("CopyBufferPasteHotKey_1", 0, true);
  389. m_pCutBuffer2 = new CHotKey("CopyBufferCutHotKey_1", 0, true);
  390. m_pCopyBuffer3 = new CHotKey("CopyBufferCopyHotKey_2", 0, true);
  391. m_pPasteBuffer3 = new CHotKey("CopyBufferPasteHotKey_2", 0, true);
  392. m_pCutBuffer3 = new CHotKey("CopyBufferCutHotKey_2", 0, true);
  393. m_pTextOnlyPaste = new CHotKey("TextOnlyPaste", 0, true);
  394. m_pSaveClipboard = new CHotKey("SaveClipboard", 0, false);
  395. m_pCopyAndSaveClipboard = new CHotKey("CopyAndSaveClipboard", 0, false);
  396. LoadGlobalClips();
  397. g_HotKeys.RegisterAll();
  398. StartCopyThread();
  399. StartStopServerThread();
  400. #ifdef UNICODE
  401. m_Addins.LoadAll();
  402. #endif
  403. m_bAppRunning = true;
  404. }
  405. void CCP_MainApp::LoadGlobalClips()
  406. {
  407. try
  408. {
  409. {
  410. CppSQLite3Query q = m_db.execQuery(_T("SELECT lID, lShortCut, mText FROM Main WHERE lShortCut > 0 AND globalShortCut = 1"));
  411. while(q.eof() == false)
  412. {
  413. int id = q.getIntField(_T("lID"));
  414. int shortcut = q.getIntField(_T("lShortCut"));
  415. CString desc = q.getStringField(_T("mText"));
  416. //Constructor will add to a global list and free
  417. CHotKey* globalHotKey = new CHotKey(StrF(_T("GlobalClip: %d"), id), shortcut, true, CHotKey::PASTE_OPEN_CLIP, desc);
  418. if(globalHotKey != NULL)
  419. {
  420. globalHotKey->m_clipId = id;
  421. }
  422. q.nextRow();
  423. }
  424. }
  425. {
  426. CppSQLite3Query q2 = m_db.execQuery(_T("SELECT lID, MoveToGroupShortCut, mText FROM Main WHERE MoveToGroupShortCut > 0 AND GlobalMoveToGroupShortCut = 1"));
  427. while(q2.eof() == false)
  428. {
  429. int id = q2.getIntField(_T("lID"));
  430. int shortcut = q2.getIntField(_T("MoveToGroupShortCut"));
  431. CString desc = q2.getStringField(_T("mText"));
  432. //Constructor will add to a global list and free
  433. CHotKey* globalHotKey = new CHotKey(StrF(_T("MoveToGroup: %d"), id), shortcut, true, CHotKey::MOVE_TO_GROUP, desc);
  434. if(globalHotKey != NULL)
  435. {
  436. globalHotKey->m_clipId = id;
  437. }
  438. q2.nextRow();
  439. }
  440. }
  441. }
  442. CATCH_SQLITE_EXCEPTION
  443. }
  444. void CCP_MainApp::StartStopServerThread()
  445. {
  446. if(CGetSetOptions::GetDisableRecieve() == FALSE && g_Opt.GetAllowFriends())
  447. {
  448. AfxBeginThread(MTServerThread, m_MainhWnd);
  449. }
  450. else
  451. {
  452. m_bExitServerThread = true;
  453. closesocket(theApp.m_sSocket);
  454. }
  455. }
  456. void CCP_MainApp::StopServerThread()
  457. {
  458. m_bExitServerThread = true;
  459. closesocket(theApp.m_sSocket);
  460. }
  461. void CCP_MainApp::BeforeMainClose()
  462. {
  463. ASSERT( m_bAppRunning && !m_bAppExiting );
  464. m_bAppRunning = false;
  465. m_bAppExiting = true;
  466. g_HotKeys.UnregisterAll();
  467. StopServerThread();
  468. StopCopyThread();
  469. }
  470. void CCP_MainApp::StartCopyThread()
  471. {
  472. ASSERT( m_MainhWnd );
  473. CClipTypes* pTypes = LoadTypesFromDB();
  474. // initialize to:
  475. // - m_MainhWnd = send WM_CLIPBOARD_COPIED messages to m_MainhWnd
  476. // - true = use Asynchronous communication (PostMessage)
  477. // - true = enable copying on clipboard changes
  478. // - pTypes = the supported types to use
  479. m_CopyThread.Init(CCopyConfig(m_MainhWnd, true, true, pTypes));
  480. if(m_connectOnStartup == FALSE || g_Opt.GetConnectedToClipboard() == FALSE)
  481. {
  482. m_CopyThread.m_connectOnStartup = false;
  483. Log(StrF(_T("Starting Ditto up disconnected from the clipboard, commandLine: %d, saved value: %d"), m_connectOnStartup, g_Opt.GetConnectedToClipboard()));
  484. SetConnectCV(false);
  485. }
  486. else if(m_connectOnStartup == TRUE)
  487. {
  488. SetConnectCV(true);
  489. Log(_T("Starting Ditto up connected from the clipboard, passed in true from command line to start connected"));
  490. }
  491. VERIFY(m_CopyThread.CreateThread(CREATE_SUSPENDED));
  492. m_CopyThread.ResumeThread();
  493. }
  494. void CCP_MainApp::StopCopyThread()
  495. {
  496. EnableCbCopy(false);
  497. m_CopyThread.Quit();
  498. }
  499. // returns the current Clipboard Viewer Connect state (though it might not yet
  500. // be actually connected -- check IsClipboardViewerConnected())
  501. bool CCP_MainApp::ToggleConnectCV()
  502. {
  503. bool bConnect = !GetConnectCV();
  504. SetConnectCV(bConnect);
  505. return bConnect;
  506. }
  507. // Sets a menu entry according to the current Clipboard Viewer Connection status
  508. // - the menu text indicates the available command (opposite the current state)
  509. // - a check mark appears in the rare cases that the menu text actually represents
  510. // the current state, e.g. if we are supposed to be connected, but we somehow
  511. // lose that connection, "Disconnect from Clipboard" will have a check next to it.
  512. void CCP_MainApp::UpdateMenuConnectCV(CMenu* pMenu, UINT nMenuID)
  513. {
  514. if(pMenu == NULL)
  515. return;
  516. bool bConnect = theApp.GetConnectCV();
  517. CString cs;
  518. if(bConnect)
  519. {
  520. cs = theApp.m_Language.GetString("Disconnect_Clipboard", "Disconnect from Clipboard.");
  521. pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, cs);
  522. }
  523. else
  524. {
  525. cs = theApp.m_Language.GetString("Connect_Clipboard", "Connect to Clipboard.");
  526. pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, cs);
  527. }
  528. }
  529. // Allocates a new CClipTypes
  530. CClipTypes* CCP_MainApp::LoadTypesFromDB()
  531. {
  532. CClipTypes* pTypes = new CClipTypes;
  533. try
  534. {
  535. CppSQLite3Query q = theApp.m_db.execQuery(_T("SELECT TypeText FROM Types"));
  536. while(q.eof() == false)
  537. {
  538. pTypes->Add(GetFormatID(q.getStringField(_T("TypeText"))));
  539. q.nextRow();
  540. }
  541. }
  542. CATCH_SQLITE_EXCEPTION
  543. if(pTypes->GetSize() <= 0)
  544. {
  545. pTypes->Add(CF_TEXT);
  546. pTypes->Add(RegisterClipboardFormat(CF_RTF));
  547. pTypes->Add(CF_UNICODETEXT);
  548. pTypes->Add(CF_HDROP);
  549. pTypes->Add(CF_DIB);
  550. pTypes->Add(GetFormatID(_T("HTML Format")));
  551. }
  552. return pTypes;
  553. }
  554. void CCP_MainApp::ReloadTypes()
  555. {
  556. CClipTypes* pTypes = LoadTypesFromDB();
  557. if(pTypes)
  558. {
  559. m_CopyThread.SetSupportedTypes(pTypes);
  560. }
  561. }
  562. void CCP_MainApp::RefreshView(CopyReasonEnum::CopyReason copyReason)
  563. {
  564. CQPasteWnd *pWnd = QPasteWnd();
  565. if(pWnd)
  566. {
  567. if(m_bAsynchronousRefreshView)
  568. {
  569. pWnd->PostMessage(WM_REFRESH_VIEW, copyReason, 0);
  570. }
  571. else
  572. {
  573. pWnd->SendMessage(WM_REFRESH_VIEW, copyReason, 0);
  574. }
  575. }
  576. }
  577. void CCP_MainApp::RefreshClipAfterPaste(int clipId, int updateFlags)
  578. {
  579. CQPasteWnd *pWnd = QPasteWnd();
  580. if(pWnd)
  581. {
  582. if(m_bAsynchronousRefreshView)
  583. {
  584. pWnd->PostMessage(WM_RELOAD_CLIP_AFTER_PASTE, clipId, updateFlags);
  585. }
  586. else
  587. {
  588. pWnd->SendMessage(WM_RELOAD_CLIP_AFTER_PASTE, clipId, updateFlags);
  589. }
  590. }
  591. }
  592. void CCP_MainApp::OnPasteCompleted()
  593. {
  594. }
  595. void CCP_MainApp::OnCopyCompleted(long lLastID, int count, CopyReasonEnum::CopyReason copyReason)
  596. {
  597. if(count <= 0)
  598. {
  599. return;
  600. }
  601. // update copy statistics
  602. CGetSetOptions::SetTripCopyCount(-count);
  603. CGetSetOptions::SetTotalCopyCount(-count);
  604. if(m_CopyBuffer.Active())
  605. {
  606. m_CopyBuffer.EndCopy(lLastID);
  607. }
  608. RefreshView(copyReason);
  609. }
  610. void CCP_MainApp::SaveCurrentGroupState()
  611. {
  612. m_oldGroupID = m_GroupID;
  613. m_oldGroupParentID = m_GroupParentID;
  614. m_oldGroupText = m_GroupText;
  615. }
  616. void CCP_MainApp::ClearOldGroupState()
  617. {
  618. m_oldGroupID = -2;
  619. m_oldGroupParentID = -2;
  620. m_oldGroupText = _T("");
  621. }
  622. BOOL CCP_MainApp::TryEnterOldGroupState()
  623. {
  624. BOOL enteredGroup = FALSE;
  625. if(m_oldGroupID > -2)
  626. {
  627. m_GroupID = m_oldGroupID;
  628. m_GroupParentID = m_oldGroupParentID;
  629. m_GroupText = m_oldGroupText;
  630. ClearOldGroupState();
  631. theApp.RefreshView();
  632. if(QPasteWnd())
  633. QPasteWnd()->UpdateStatus(true);
  634. enteredGroup = TRUE;
  635. }
  636. return enteredGroup;
  637. }
  638. BOOL CCP_MainApp::EnterGroupID(long lID, BOOL clearOldGroupState/* = TRUE*/, BOOL saveCurrentGroupState/* = FALSE*/)
  639. {
  640. BOOL bResult = FALSE;
  641. if(m_GroupID == lID)
  642. return TRUE;
  643. DWORD startTick = GetTickCount();
  644. if(clearOldGroupState)
  645. {
  646. ClearOldGroupState();
  647. }
  648. if(saveCurrentGroupState)
  649. {
  650. SaveCurrentGroupState();
  651. }
  652. // if we are switching to the parent, focus on the previous group
  653. if(m_GroupParentID == lID && m_GroupID > 0)
  654. m_FocusID = m_GroupID;
  655. switch(lID)
  656. {
  657. case -1:
  658. m_FocusID = -1;
  659. m_GroupID = -1;
  660. m_GroupParentID = -1;
  661. m_GroupText = "History";
  662. bResult = TRUE;
  663. break;
  664. default: // Normal Group
  665. try
  666. {
  667. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lParentID, mText, bIsGroup FROM Main WHERE lID = %d"), lID);
  668. if(q.eof() == false)
  669. {
  670. if(q.getIntField(_T("bIsGroup")) > 0)
  671. {
  672. m_GroupID = lID;
  673. m_GroupParentID = q.getIntField(_T("lParentID"));
  674. m_GroupText = q.getStringField(_T("mText"));
  675. bResult = TRUE;
  676. }
  677. }
  678. }
  679. CATCH_SQLITE_EXCEPTION
  680. break;
  681. }
  682. if(bResult)
  683. {
  684. theApp.RefreshView();
  685. if(QPasteWnd())
  686. QPasteWnd()->UpdateStatus(true);
  687. }
  688. DWORD endTick = GetTickCount();
  689. if((endTick-startTick) > 150)
  690. Log(StrF(_T("Paste Timing EnterParentId: %d"), endTick-startTick));
  691. return bResult;
  692. }
  693. // returns a usable group id (not negative)
  694. long CCP_MainApp::GetValidGroupID()
  695. {
  696. return m_GroupID;
  697. }
  698. // sets a valid id
  699. void CCP_MainApp::SetGroupDefaultID(long lID)
  700. {
  701. if(m_GroupDefaultID == lID)
  702. {
  703. return;
  704. }
  705. if(lID <= 0)
  706. {
  707. m_GroupDefaultID = 0;
  708. }
  709. else
  710. {
  711. m_GroupDefaultID = lID;
  712. }
  713. if(QPasteWnd())
  714. {
  715. QPasteWnd()->UpdateStatus();
  716. }
  717. }
  718. void CCP_MainApp::SetStatus(const TCHAR* status, bool bRepaintImmediately)
  719. {
  720. m_Status = status;
  721. if(QPasteWnd())
  722. {
  723. QPasteWnd()->UpdateStatus(bRepaintImmediately);
  724. }
  725. }
  726. void CCP_MainApp::ShowPersistent(bool bVal)
  727. {
  728. g_Opt.SetShowPersistent(bVal);
  729. // give some visual indication
  730. if(m_bShowingQuickPaste)
  731. {
  732. ASSERT(QPasteWnd());
  733. QPasteWnd()->SetCaptionColorActive(g_Opt.m_bShowPersistent, theApp.GetConnectCV());
  734. QPasteWnd()->RefreshNc();
  735. }
  736. }
  737. /////////////////////////////////////////////////////////////////////////////
  738. // CCP_MainApp message handlers
  739. int CCP_MainApp::ExitInstance()
  740. {
  741. Log(_T("ExitInstance"));
  742. DeleteDittoTempFiles(FALSE);
  743. m_db.close();
  744. if(m_pUacPasteThread != NULL)
  745. {
  746. if(m_pUacPasteThread->ThreadWasStarted() == false)
  747. {
  748. m_pUacPasteThread->FireExit();
  749. }
  750. delete m_pUacPasteThread;
  751. }
  752. Gdiplus::GdiplusShutdown(m_gdiplusToken);
  753. return CWinApp::ExitInstance();
  754. }
  755. // return TRUE if there is more idle processing to do
  756. BOOL CCP_MainApp::OnIdle(LONG lCount)
  757. {
  758. // let winapp handle its idle processing
  759. if(CWinApp::OnIdle(lCount))
  760. return TRUE;
  761. return FALSE;
  762. }
  763. void CCP_MainApp::SetConnectCV(bool bConnect)
  764. {
  765. m_CopyThread.SetConnectCV(bConnect);
  766. g_Opt.SetConnectedToClipboard(bConnect == true);
  767. if(bConnect)
  768. {
  769. m_pMainFrame->m_trayIcon.SetIcon(IDR_MAINFRAME);
  770. m_pMainFrame->m_trayIcon.SetTooltipText(_T("Ditto"));
  771. }
  772. else
  773. {
  774. m_pMainFrame->m_trayIcon.SetIcon(IDI_DITTO_NOCOPYCB);
  775. CString cs;
  776. cs = _T("Ditto ");
  777. cs += theApp.m_Language.GetString("disconnected", "[Disconnected]");
  778. m_pMainFrame->m_trayIcon.SetTooltipText(cs);
  779. }
  780. if(QPasteWnd())
  781. {
  782. QPasteWnd()->SetCaptionColorActive(g_Opt.m_bShowPersistent, theApp.GetConnectCV());
  783. QPasteWnd()->RefreshNc();
  784. }
  785. }
  786. void CCP_MainApp::OnDeleteID(long lID)
  787. {
  788. if(QPasteWnd())
  789. {
  790. QPasteWnd()->PostMessage(NM_ITEM_DELETED, lID, 0);
  791. }
  792. }
  793. bool CCP_MainApp::ImportClips(HWND hWnd)
  794. {
  795. OPENFILENAME FileName;
  796. TCHAR szFileName[400];
  797. TCHAR szDir[400];
  798. memset(&FileName, 0, sizeof(FileName));
  799. memset(szFileName, 0, sizeof(szFileName));
  800. memset(&szDir, 0, sizeof(szDir));
  801. CString csInitialDir = CGetSetOptions::GetLastImportDir();
  802. STRCPY(szDir, csInitialDir);
  803. FileName.lStructSize = sizeof(FileName);
  804. FileName.lpstrTitle = _T("Import Clips");
  805. FileName.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;
  806. FileName.nMaxFile = 400;
  807. FileName.lpstrFile = szFileName;
  808. FileName.lpstrInitialDir = szDir;
  809. FileName.lpstrFilter = _T("Exported Ditto Clips (.dto)\0*.dto\0\0");
  810. FileName.lpstrDefExt = _T("dto");
  811. if(GetOpenFileName(&FileName) == 0)
  812. {
  813. return false;
  814. }
  815. using namespace nsPath;
  816. CPath path(FileName.lpstrFile);
  817. CString csPath = path.GetPath();
  818. CGetSetOptions::SetLastImportDir(csPath);
  819. try
  820. {
  821. CppSQLite3DB db;
  822. db.open(FileName.lpstrFile);
  823. CClip_ImportExport clip;
  824. if(clip.ImportFromSqliteDB(db, true, false))
  825. {
  826. CShowTaskBarIcon show;
  827. CString cs;
  828. cs.Format(_T("%s %d "), theApp.m_Language.GetString("Import_Successfully", "Successfully imported"), clip.m_importCount);
  829. if(clip.m_importCount = 1)
  830. cs += theApp.m_Language.GetString("Clip", "clip");
  831. else
  832. cs += theApp.m_Language.GetString("Clips", "clips");
  833. MessageBox(hWnd, cs, _T("Ditto"), MB_OK);
  834. }
  835. else
  836. {
  837. CShowTaskBarIcon show;
  838. MessageBox(hWnd, theApp.m_Language.GetString("Error_Importing", "Error importing exported clip"), _T("Ditto"), MB_OK);
  839. }
  840. }
  841. catch (CppSQLite3Exception& e)
  842. {
  843. ASSERT(FALSE);
  844. CString csError;
  845. csError.Format(_T("%s - Exception - %d - %s"), theApp.m_Language.GetString("Error_Parsing", "Error parsing exported clip"), e.errorCode(), e.errorMessage());
  846. MessageBox(hWnd, csError, _T("Ditto"), MB_OK);
  847. }
  848. return true;
  849. }
  850. void CCP_MainApp::ShowCommandLineError(CString csTitle, CString csMessage)
  851. {
  852. Log(StrF(_T("ShowCommandLineError %s - %s"), csTitle, csMessage));
  853. CToolTipEx *pErrorWnd = new CToolTipEx;
  854. pErrorWnd->Create(NULL);
  855. pErrorWnd->SetToolTipText(csTitle + "\n\n" + csMessage);
  856. CPoint pt;
  857. CRect rcScreen = DefaultMonitorRect();
  858. pt = rcScreen.BottomRight();
  859. CRect cr = pErrorWnd->GetBoundsRect();
  860. pt.x -= max(cr.Width()+50, 150);
  861. pt.y -= max(cr.Height()+50, 150);
  862. pErrorWnd->Show(pt);
  863. PumpMessageEx(pErrorWnd->m_hWnd);
  864. Sleep(4000);
  865. pErrorWnd->DestroyWindow();
  866. }
  867. BOOL CCP_MainApp::GetClipData(long parentId, CClipFormat &Clip)
  868. {
  869. BOOL bRet = FALSE;
  870. try
  871. {
  872. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT ooData FROM Data WHERE lParentID = %d AND strClipboardFormat = '%s'"), parentId, GetFormatName(Clip.m_cfType));
  873. if(q.eof() == false)
  874. {
  875. int nDataLen = 0;
  876. const unsigned char *cData = q.getBlobField(_T("ooData"), nDataLen);
  877. if(cData != NULL)
  878. {
  879. Clip.m_hgData = NewGlobal(nDataLen);
  880. ::CopyToGlobalHP(Clip.m_hgData, (LPVOID)cData, nDataLen);
  881. bRet = TRUE;
  882. }
  883. }
  884. }
  885. CATCH_SQLITE_EXCEPTION
  886. return bRet;
  887. }
  888. bool CCP_MainApp::EditItems(CClipIDs &Ids, bool bShowError)
  889. {
  890. m_pMainFrame->ShowEditWnd(Ids);
  891. return true;
  892. }
  893. void CCP_MainApp::PumpMessageEx(HWND hWnd)
  894. {
  895. MSG KeyboardMsg;
  896. while (::PeekMessage(&KeyboardMsg, hWnd, 0, 0, PM_REMOVE))
  897. {
  898. ::TranslateMessage(&KeyboardMsg);
  899. ::DispatchMessage(&KeyboardMsg);
  900. }
  901. }
  902. HWND CCP_MainApp::QPastehWnd()
  903. {
  904. if(m_pMainFrame != NULL)
  905. {
  906. if(m_pMainFrame->m_quickPaste.m_pwndPaste != NULL)
  907. {
  908. return m_pMainFrame->m_quickPaste.m_pwndPaste->GetSafeHwnd();
  909. }
  910. }
  911. return NULL;
  912. }
  913. CQPasteWnd* CCP_MainApp::QPasteWnd()
  914. {
  915. if(m_pMainFrame != NULL)
  916. {
  917. return m_pMainFrame->m_quickPaste.m_pwndPaste;
  918. }
  919. return NULL;
  920. }
  921. bool CCP_MainApp::UACPaste()
  922. {
  923. if(m_pUacPasteThread == NULL)
  924. {
  925. m_pUacPasteThread = new CUAC_Thread(GetCurrentProcessId());
  926. }
  927. return m_pUacPasteThread->UACPaste();
  928. }
  929. bool CCP_MainApp::UACCopy()
  930. {
  931. if(m_pUacPasteThread == NULL)
  932. {
  933. m_pUacPasteThread = new CUAC_Thread(GetCurrentProcessId());
  934. }
  935. return m_pUacPasteThread->UACCopy();
  936. }
  937. bool CCP_MainApp::UACCut()
  938. {
  939. if(m_pUacPasteThread == NULL)
  940. {
  941. m_pUacPasteThread = new CUAC_Thread(GetCurrentProcessId());
  942. }
  943. return m_pUacPasteThread->UACCut();
  944. }
  945. bool CCP_MainApp::UACThreadRunning()
  946. {
  947. if(m_pUacPasteThread != NULL)
  948. {
  949. return m_pUacPasteThread->IsRunning();
  950. }
  951. return false;
  952. }
  953. void CCP_MainApp::RefreshShowInTaskBar()
  954. {
  955. if(m_pMainFrame != NULL)
  956. {
  957. m_pMainFrame->RefreshShowInTaskBar();
  958. }
  959. }
  960. void CCP_MainApp::SetActiveGroupId(int groupId)
  961. {
  962. m_activeGroupId = groupId;
  963. m_activeGroupStartTime = GetTickCount();
  964. }
  965. int CCP_MainApp::GetActiveGroupId()
  966. {
  967. int ret = -1;
  968. DWORD maxDiff = CGetSetOptions::GetSaveToGroupTimeoutMS();
  969. DWORD diff = GetTickCount() - m_activeGroupStartTime;
  970. if(m_activeGroupId > -1 &&
  971. diff < maxDiff)
  972. {
  973. ret = m_activeGroupId;
  974. }
  975. m_activeGroupId = -1;
  976. m_activeGroupStartTime = 0;
  977. return ret;
  978. }
  979. void CCP_MainApp::SetCopyReason(CopyReasonEnum::CopyReason copyReason)
  980. {
  981. m_copyReason = copyReason;
  982. m_copyReasonStartTime = GetTickCount();
  983. }
  984. CopyReasonEnum::CopyReason CCP_MainApp::GetCopyReason()
  985. {
  986. CopyReasonEnum::CopyReason ret = CopyReasonEnum::COPY_TO_UNKOWN;
  987. DWORD maxDiff = CGetSetOptions::GetCopyReasonTimeoutMS();
  988. DWORD diff = GetTickCount() - m_copyReasonStartTime;
  989. if(m_copyReason != CopyReasonEnum::COPY_TO_UNKOWN &&
  990. diff < maxDiff)
  991. {
  992. ret = m_copyReason;
  993. }
  994. m_copyReason = CopyReasonEnum::COPY_TO_UNKOWN;
  995. m_copyReasonStartTime = 0;
  996. return ret;
  997. }