CP_Main.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194
  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 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. //Constructor will add to a global list and free
  416. CHotKey* globalHotKey = new CHotKey(StrF(_T("GlobalClip: %d"), id), shortcut, true, CHotKey::PASTE_OPEN_CLIP);
  417. if(globalHotKey != NULL)
  418. {
  419. globalHotKey->m_clipId = id;
  420. }
  421. q.nextRow();
  422. }
  423. }
  424. {
  425. CppSQLite3Query q2 = m_db.execQuery(_T("SELECT lID, MoveToGroupShortCut, mText FROM Main WHERE MoveToGroupShortCut > 0 AND GlobalMoveToGroupShortCut = 1"));
  426. while(q2.eof() == false)
  427. {
  428. int id = q2.getIntField(_T("lID"));
  429. int shortcut = q2.getIntField(_T("MoveToGroupShortCut"));
  430. CString desc = q2.getStringField(_T("mText"));
  431. //Constructor will add to a global list and free
  432. CHotKey* globalHotKey = new CHotKey(desc, shortcut, true, CHotKey::MOVE_TO_GROUP);
  433. if(globalHotKey != NULL)
  434. {
  435. globalHotKey->m_clipId = id;
  436. }
  437. q2.nextRow();
  438. }
  439. }
  440. }
  441. CATCH_SQLITE_EXCEPTION
  442. }
  443. void CCP_MainApp::StartStopServerThread()
  444. {
  445. if(CGetSetOptions::GetDisableRecieve() == FALSE && g_Opt.GetAllowFriends())
  446. {
  447. AfxBeginThread(MTServerThread, m_MainhWnd);
  448. }
  449. else
  450. {
  451. m_bExitServerThread = true;
  452. closesocket(theApp.m_sSocket);
  453. }
  454. }
  455. void CCP_MainApp::StopServerThread()
  456. {
  457. m_bExitServerThread = true;
  458. closesocket(theApp.m_sSocket);
  459. }
  460. void CCP_MainApp::BeforeMainClose()
  461. {
  462. ASSERT( m_bAppRunning && !m_bAppExiting );
  463. m_bAppRunning = false;
  464. m_bAppExiting = true;
  465. g_HotKeys.UnregisterAll();
  466. StopServerThread();
  467. StopCopyThread();
  468. }
  469. void CCP_MainApp::StartCopyThread()
  470. {
  471. ASSERT( m_MainhWnd );
  472. CClipTypes* pTypes = LoadTypesFromDB();
  473. // initialize to:
  474. // - m_MainhWnd = send WM_CLIPBOARD_COPIED messages to m_MainhWnd
  475. // - true = use Asynchronous communication (PostMessage)
  476. // - true = enable copying on clipboard changes
  477. // - pTypes = the supported types to use
  478. m_CopyThread.Init(CCopyConfig(m_MainhWnd, true, true, pTypes));
  479. if(m_connectOnStartup == FALSE || g_Opt.GetConnectedToClipboard() == FALSE)
  480. {
  481. m_CopyThread.m_connectOnStartup = false;
  482. Log(StrF(_T("Starting Ditto up disconnected from the clipboard, commandLine: %d, saved value: %d"), m_connectOnStartup, g_Opt.GetConnectedToClipboard()));
  483. SetConnectCV(false);
  484. }
  485. else if(m_connectOnStartup == TRUE)
  486. {
  487. SetConnectCV(true);
  488. Log(_T("Starting Ditto up connected from the clipboard, passed in true from command line to start connected"));
  489. }
  490. VERIFY(m_CopyThread.CreateThread(CREATE_SUSPENDED));
  491. m_CopyThread.ResumeThread();
  492. }
  493. void CCP_MainApp::StopCopyThread()
  494. {
  495. EnableCbCopy(false);
  496. m_CopyThread.Quit();
  497. }
  498. // returns the current Clipboard Viewer Connect state (though it might not yet
  499. // be actually connected -- check IsClipboardViewerConnected())
  500. bool CCP_MainApp::ToggleConnectCV()
  501. {
  502. bool bConnect = !GetConnectCV();
  503. SetConnectCV(bConnect);
  504. return bConnect;
  505. }
  506. // Sets a menu entry according to the current Clipboard Viewer Connection status
  507. // - the menu text indicates the available command (opposite the current state)
  508. // - a check mark appears in the rare cases that the menu text actually represents
  509. // the current state, e.g. if we are supposed to be connected, but we somehow
  510. // lose that connection, "Disconnect from Clipboard" will have a check next to it.
  511. void CCP_MainApp::UpdateMenuConnectCV(CMenu* pMenu, UINT nMenuID)
  512. {
  513. if(pMenu == NULL)
  514. return;
  515. bool bConnect = theApp.GetConnectCV();
  516. CString cs;
  517. if(bConnect)
  518. {
  519. cs = theApp.m_Language.GetString("Disconnect_Clipboard", "Disconnect from Clipboard.");
  520. pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, cs);
  521. }
  522. else
  523. {
  524. cs = theApp.m_Language.GetString("Connect_Clipboard", "Connect to Clipboard.");
  525. pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, cs);
  526. }
  527. }
  528. // Allocates a new CClipTypes
  529. CClipTypes* CCP_MainApp::LoadTypesFromDB()
  530. {
  531. CClipTypes* pTypes = new CClipTypes;
  532. try
  533. {
  534. CppSQLite3Query q = theApp.m_db.execQuery(_T("SELECT TypeText FROM Types"));
  535. while(q.eof() == false)
  536. {
  537. pTypes->Add(GetFormatID(q.getStringField(_T("TypeText"))));
  538. q.nextRow();
  539. }
  540. }
  541. CATCH_SQLITE_EXCEPTION
  542. if(pTypes->GetSize() <= 0)
  543. {
  544. pTypes->Add(CF_TEXT);
  545. pTypes->Add(RegisterClipboardFormat(CF_RTF));
  546. pTypes->Add(CF_UNICODETEXT);
  547. pTypes->Add(CF_HDROP);
  548. pTypes->Add(CF_DIB);
  549. pTypes->Add(GetFormatID(_T("HTML Format")));
  550. }
  551. return pTypes;
  552. }
  553. void CCP_MainApp::ReloadTypes()
  554. {
  555. CClipTypes* pTypes = LoadTypesFromDB();
  556. if(pTypes)
  557. {
  558. m_CopyThread.SetSupportedTypes(pTypes);
  559. }
  560. }
  561. void CCP_MainApp::RefreshView(CopyReasonEnum::CopyReason copyReason)
  562. {
  563. CQPasteWnd *pWnd = QPasteWnd();
  564. if(pWnd)
  565. {
  566. if(m_bAsynchronousRefreshView)
  567. {
  568. pWnd->PostMessage(WM_REFRESH_VIEW, copyReason, 0);
  569. }
  570. else
  571. {
  572. pWnd->SendMessage(WM_REFRESH_VIEW, copyReason, 0);
  573. }
  574. }
  575. }
  576. void CCP_MainApp::RefreshClipAfterPaste(int clipId, int updateFlags)
  577. {
  578. CQPasteWnd *pWnd = QPasteWnd();
  579. if(pWnd)
  580. {
  581. if(m_bAsynchronousRefreshView)
  582. {
  583. pWnd->PostMessage(WM_RELOAD_CLIP_AFTER_PASTE, clipId, updateFlags);
  584. }
  585. else
  586. {
  587. pWnd->SendMessage(WM_RELOAD_CLIP_AFTER_PASTE, clipId, updateFlags);
  588. }
  589. }
  590. }
  591. void CCP_MainApp::OnPasteCompleted()
  592. {
  593. }
  594. void CCP_MainApp::OnCopyCompleted(long lLastID, int count, CopyReasonEnum::CopyReason copyReason)
  595. {
  596. if(count <= 0)
  597. {
  598. return;
  599. }
  600. // update copy statistics
  601. CGetSetOptions::SetTripCopyCount(-count);
  602. CGetSetOptions::SetTotalCopyCount(-count);
  603. if(m_CopyBuffer.Active())
  604. {
  605. m_CopyBuffer.EndCopy(lLastID);
  606. }
  607. RefreshView(copyReason);
  608. }
  609. void CCP_MainApp::SaveCurrentGroupState()
  610. {
  611. m_oldGroupID = m_GroupID;
  612. m_oldGroupParentID = m_GroupParentID;
  613. m_oldGroupText = m_GroupText;
  614. }
  615. void CCP_MainApp::ClearOldGroupState()
  616. {
  617. m_oldGroupID = -2;
  618. m_oldGroupParentID = -2;
  619. m_oldGroupText = _T("");
  620. }
  621. BOOL CCP_MainApp::TryEnterOldGroupState()
  622. {
  623. BOOL enteredGroup = FALSE;
  624. if(m_oldGroupID > -2)
  625. {
  626. m_GroupID = m_oldGroupID;
  627. m_GroupParentID = m_oldGroupParentID;
  628. m_GroupText = m_oldGroupText;
  629. ClearOldGroupState();
  630. theApp.RefreshView();
  631. if(QPasteWnd())
  632. QPasteWnd()->UpdateStatus(true);
  633. enteredGroup = TRUE;
  634. }
  635. return enteredGroup;
  636. }
  637. BOOL CCP_MainApp::EnterGroupID(long lID, BOOL clearOldGroupState/* = TRUE*/, BOOL saveCurrentGroupState/* = FALSE*/)
  638. {
  639. BOOL bResult = FALSE;
  640. if(m_GroupID == lID)
  641. return TRUE;
  642. DWORD startTick = GetTickCount();
  643. if(clearOldGroupState)
  644. {
  645. ClearOldGroupState();
  646. }
  647. if(saveCurrentGroupState)
  648. {
  649. SaveCurrentGroupState();
  650. }
  651. // if we are switching to the parent, focus on the previous group
  652. if(m_GroupParentID == lID && m_GroupID > 0)
  653. m_FocusID = m_GroupID;
  654. switch(lID)
  655. {
  656. case -1:
  657. m_FocusID = -1;
  658. m_GroupID = -1;
  659. m_GroupParentID = -1;
  660. m_GroupText = "History";
  661. bResult = TRUE;
  662. break;
  663. default: // Normal Group
  664. try
  665. {
  666. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lParentID, mText, bIsGroup FROM Main WHERE lID = %d"), lID);
  667. if(q.eof() == false)
  668. {
  669. if(q.getIntField(_T("bIsGroup")) > 0)
  670. {
  671. m_GroupID = lID;
  672. m_GroupParentID = q.getIntField(_T("lParentID"));
  673. m_GroupText = q.getStringField(_T("mText"));
  674. bResult = TRUE;
  675. }
  676. }
  677. }
  678. CATCH_SQLITE_EXCEPTION
  679. break;
  680. }
  681. if(bResult)
  682. {
  683. theApp.RefreshView();
  684. if(QPasteWnd())
  685. QPasteWnd()->UpdateStatus(true);
  686. }
  687. DWORD endTick = GetTickCount();
  688. if((endTick-startTick) > 150)
  689. Log(StrF(_T("Paste Timing EnterParentId: %d"), endTick-startTick));
  690. return bResult;
  691. }
  692. // returns a usable group id (not negative)
  693. long CCP_MainApp::GetValidGroupID()
  694. {
  695. return m_GroupID;
  696. }
  697. // sets a valid id
  698. void CCP_MainApp::SetGroupDefaultID(long lID)
  699. {
  700. if(m_GroupDefaultID == lID)
  701. {
  702. return;
  703. }
  704. if(lID <= 0)
  705. {
  706. m_GroupDefaultID = 0;
  707. }
  708. else
  709. {
  710. m_GroupDefaultID = lID;
  711. }
  712. if(QPasteWnd())
  713. {
  714. QPasteWnd()->UpdateStatus();
  715. }
  716. }
  717. void CCP_MainApp::SetStatus(const TCHAR* status, bool bRepaintImmediately)
  718. {
  719. m_Status = status;
  720. if(QPasteWnd())
  721. {
  722. QPasteWnd()->UpdateStatus(bRepaintImmediately);
  723. }
  724. }
  725. void CCP_MainApp::ShowPersistent(bool bVal)
  726. {
  727. g_Opt.SetShowPersistent(bVal);
  728. // give some visual indication
  729. if(m_bShowingQuickPaste)
  730. {
  731. ASSERT(QPasteWnd());
  732. QPasteWnd()->SetCaptionColorActive(g_Opt.m_bShowPersistent, theApp.GetConnectCV());
  733. QPasteWnd()->RefreshNc();
  734. }
  735. }
  736. /////////////////////////////////////////////////////////////////////////////
  737. // CCP_MainApp message handlers
  738. int CCP_MainApp::ExitInstance()
  739. {
  740. Log(_T("ExitInstance"));
  741. DeleteDittoTempFiles(FALSE);
  742. m_db.close();
  743. if(m_pUacPasteThread != NULL)
  744. {
  745. if(m_pUacPasteThread->ThreadWasStarted() == false)
  746. {
  747. m_pUacPasteThread->FireExit();
  748. }
  749. delete m_pUacPasteThread;
  750. }
  751. Gdiplus::GdiplusShutdown(m_gdiplusToken);
  752. return CWinApp::ExitInstance();
  753. }
  754. // return TRUE if there is more idle processing to do
  755. BOOL CCP_MainApp::OnIdle(LONG lCount)
  756. {
  757. // let winapp handle its idle processing
  758. if(CWinApp::OnIdle(lCount))
  759. return TRUE;
  760. return FALSE;
  761. }
  762. void CCP_MainApp::SetConnectCV(bool bConnect)
  763. {
  764. m_CopyThread.SetConnectCV(bConnect);
  765. g_Opt.SetConnectedToClipboard(bConnect == true);
  766. if(bConnect)
  767. {
  768. m_pMainFrame->m_trayIcon.SetIcon(IDR_MAINFRAME);
  769. m_pMainFrame->m_trayIcon.SetTooltipText(_T("Ditto"));
  770. }
  771. else
  772. {
  773. m_pMainFrame->m_trayIcon.SetIcon(IDI_DITTO_NOCOPYCB);
  774. CString cs;
  775. cs = _T("Ditto ");
  776. cs += theApp.m_Language.GetString("disconnected", "[Disconnected]");
  777. m_pMainFrame->m_trayIcon.SetTooltipText(cs);
  778. }
  779. if(QPasteWnd())
  780. {
  781. QPasteWnd()->SetCaptionColorActive(g_Opt.m_bShowPersistent, theApp.GetConnectCV());
  782. QPasteWnd()->RefreshNc();
  783. }
  784. }
  785. void CCP_MainApp::OnDeleteID(long lID)
  786. {
  787. if(QPasteWnd())
  788. {
  789. QPasteWnd()->PostMessage(NM_ITEM_DELETED, lID, 0);
  790. }
  791. }
  792. bool CCP_MainApp::ImportClips(HWND hWnd)
  793. {
  794. OPENFILENAME FileName;
  795. TCHAR szFileName[400];
  796. TCHAR szDir[400];
  797. memset(&FileName, 0, sizeof(FileName));
  798. memset(szFileName, 0, sizeof(szFileName));
  799. memset(&szDir, 0, sizeof(szDir));
  800. CString csInitialDir = CGetSetOptions::GetLastImportDir();
  801. STRCPY(szDir, csInitialDir);
  802. FileName.lStructSize = sizeof(FileName);
  803. FileName.lpstrTitle = _T("Import Clips");
  804. FileName.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;
  805. FileName.nMaxFile = 400;
  806. FileName.lpstrFile = szFileName;
  807. FileName.lpstrInitialDir = szDir;
  808. FileName.lpstrFilter = _T("Exported Ditto Clips (.dto)\0*.dto\0\0");
  809. FileName.lpstrDefExt = _T("dto");
  810. if(GetOpenFileName(&FileName) == 0)
  811. {
  812. return false;
  813. }
  814. using namespace nsPath;
  815. CPath path(FileName.lpstrFile);
  816. CString csPath = path.GetPath();
  817. CGetSetOptions::SetLastImportDir(csPath);
  818. try
  819. {
  820. CppSQLite3DB db;
  821. db.open(FileName.lpstrFile);
  822. CClip_ImportExport clip;
  823. if(clip.ImportFromSqliteDB(db, true, false))
  824. {
  825. CShowTaskBarIcon show;
  826. CString cs;
  827. cs.Format(_T("%s %d "), theApp.m_Language.GetString("Import_Successfully", "Successfully imported"), clip.m_importCount);
  828. if(clip.m_importCount = 1)
  829. cs += theApp.m_Language.GetString("Clip", "clip");
  830. else
  831. cs += theApp.m_Language.GetString("Clips", "clips");
  832. MessageBox(hWnd, cs, _T("Ditto"), MB_OK);
  833. }
  834. else
  835. {
  836. CShowTaskBarIcon show;
  837. MessageBox(hWnd, theApp.m_Language.GetString("Error_Importing", "Error importing exported clip"), _T("Ditto"), MB_OK);
  838. }
  839. }
  840. catch (CppSQLite3Exception& e)
  841. {
  842. ASSERT(FALSE);
  843. CString csError;
  844. csError.Format(_T("%s - Exception - %d - %s"), theApp.m_Language.GetString("Error_Parsing", "Error parsing exported clip"), e.errorCode(), e.errorMessage());
  845. MessageBox(hWnd, csError, _T("Ditto"), MB_OK);
  846. }
  847. return true;
  848. }
  849. void CCP_MainApp::ShowCommandLineError(CString csTitle, CString csMessage)
  850. {
  851. Log(StrF(_T("ShowCommandLineError %s - %s"), csTitle, csMessage));
  852. CToolTipEx *pErrorWnd = new CToolTipEx;
  853. pErrorWnd->Create(NULL);
  854. pErrorWnd->SetToolTipText(csTitle + "\n\n" + csMessage);
  855. CPoint pt;
  856. CRect rcScreen = DefaultMonitorRect();
  857. pt = rcScreen.BottomRight();
  858. CRect cr = pErrorWnd->GetBoundsRect();
  859. pt.x -= max(cr.Width()+50, 150);
  860. pt.y -= max(cr.Height()+50, 150);
  861. pErrorWnd->Show(pt);
  862. PumpMessageEx(pErrorWnd->m_hWnd);
  863. Sleep(4000);
  864. pErrorWnd->DestroyWindow();
  865. }
  866. BOOL CCP_MainApp::GetClipData(long parentId, CClipFormat &Clip)
  867. {
  868. BOOL bRet = FALSE;
  869. try
  870. {
  871. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT ooData FROM Data WHERE lParentID = %d AND strClipboardFormat = '%s'"), parentId, GetFormatName(Clip.m_cfType));
  872. if(q.eof() == false)
  873. {
  874. int nDataLen = 0;
  875. const unsigned char *cData = q.getBlobField(_T("ooData"), nDataLen);
  876. if(cData != NULL)
  877. {
  878. Clip.m_hgData = NewGlobal(nDataLen);
  879. ::CopyToGlobalHP(Clip.m_hgData, (LPVOID)cData, nDataLen);
  880. bRet = TRUE;
  881. }
  882. }
  883. }
  884. CATCH_SQLITE_EXCEPTION
  885. return bRet;
  886. }
  887. bool CCP_MainApp::EditItems(CClipIDs &Ids, bool bShowError)
  888. {
  889. m_pMainFrame->ShowEditWnd(Ids);
  890. return true;
  891. }
  892. void CCP_MainApp::PumpMessageEx(HWND hWnd)
  893. {
  894. MSG KeyboardMsg;
  895. while (::PeekMessage(&KeyboardMsg, hWnd, 0, 0, PM_REMOVE))
  896. {
  897. ::TranslateMessage(&KeyboardMsg);
  898. ::DispatchMessage(&KeyboardMsg);
  899. }
  900. }
  901. HWND CCP_MainApp::QPastehWnd()
  902. {
  903. if(m_pMainFrame != NULL)
  904. {
  905. if(m_pMainFrame->m_quickPaste.m_pwndPaste != NULL)
  906. {
  907. return m_pMainFrame->m_quickPaste.m_pwndPaste->GetSafeHwnd();
  908. }
  909. }
  910. return NULL;
  911. }
  912. CQPasteWnd* CCP_MainApp::QPasteWnd()
  913. {
  914. if(m_pMainFrame != NULL)
  915. {
  916. return m_pMainFrame->m_quickPaste.m_pwndPaste;
  917. }
  918. return NULL;
  919. }
  920. bool CCP_MainApp::UACPaste()
  921. {
  922. if(m_pUacPasteThread == NULL)
  923. {
  924. m_pUacPasteThread = new CUAC_Thread(GetCurrentProcessId());
  925. }
  926. return m_pUacPasteThread->UACPaste();
  927. }
  928. bool CCP_MainApp::UACCopy()
  929. {
  930. if(m_pUacPasteThread == NULL)
  931. {
  932. m_pUacPasteThread = new CUAC_Thread(GetCurrentProcessId());
  933. }
  934. return m_pUacPasteThread->UACCopy();
  935. }
  936. bool CCP_MainApp::UACCut()
  937. {
  938. if(m_pUacPasteThread == NULL)
  939. {
  940. m_pUacPasteThread = new CUAC_Thread(GetCurrentProcessId());
  941. }
  942. return m_pUacPasteThread->UACCut();
  943. }
  944. bool CCP_MainApp::UACThreadRunning()
  945. {
  946. if(m_pUacPasteThread != NULL)
  947. {
  948. return m_pUacPasteThread->IsRunning();
  949. }
  950. return false;
  951. }
  952. void CCP_MainApp::RefreshShowInTaskBar()
  953. {
  954. if(m_pMainFrame != NULL)
  955. {
  956. m_pMainFrame->RefreshShowInTaskBar();
  957. }
  958. }
  959. void CCP_MainApp::SetActiveGroupId(int groupId)
  960. {
  961. m_activeGroupId = groupId;
  962. m_activeGroupStartTime = GetTickCount();
  963. }
  964. int CCP_MainApp::GetActiveGroupId()
  965. {
  966. int ret = -1;
  967. DWORD maxDiff = CGetSetOptions::GetSaveToGroupTimeoutMS();
  968. DWORD diff = GetTickCount() - m_activeGroupStartTime;
  969. if(m_activeGroupId > -1 &&
  970. diff < maxDiff)
  971. {
  972. ret = m_activeGroupId;
  973. }
  974. m_activeGroupId = -1;
  975. m_activeGroupStartTime = 0;
  976. return ret;
  977. }
  978. void CCP_MainApp::SetCopyReason(CopyReasonEnum::CopyReason copyReason)
  979. {
  980. m_copyReason = copyReason;
  981. m_copyReasonStartTime = GetTickCount();
  982. }
  983. CopyReasonEnum::CopyReason CCP_MainApp::GetCopyReason()
  984. {
  985. CopyReasonEnum::CopyReason ret = CopyReasonEnum::COPY_TO_UNKOWN;
  986. DWORD maxDiff = CGetSetOptions::GetCopyReasonTimeoutMS();
  987. DWORD diff = GetTickCount() - m_copyReasonStartTime;
  988. if(m_copyReason != CopyReasonEnum::COPY_TO_UNKOWN &&
  989. diff < maxDiff)
  990. {
  991. ret = m_copyReason;
  992. }
  993. m_copyReason = CopyReasonEnum::COPY_TO_UNKOWN;
  994. m_copyReasonStartTime = 0;
  995. return ret;
  996. }