CP_Main.cpp 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. // CP_Main.cpp : Defines the class behaviors for the application.
  2. //
  3. #include "stdafx.h"
  4. //#include "vld.h"
  5. #include "CP_Main.h"
  6. #include "MainFrm.h"
  7. #include "Misc.h"
  8. #include ".\cp_main.h"
  9. #include "server.h"
  10. #include "Client.h"
  11. #include "InternetUpdate.h"
  12. #include <io.h>
  13. #include "Path.h"
  14. #include "Clip_ImportExport.h"
  15. #include "HyperLink.h"
  16. #include "OptionsSheet.h"
  17. #ifdef _DEBUG
  18. #define new DEBUG_NEW
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22. /////////////////////////////////////////////////////////////////////////////
  23. // The one and only CCP_MainApp object
  24. class DittoCommandLineInfo : public CCommandLineInfo
  25. {
  26. public:
  27. DittoCommandLineInfo()
  28. {
  29. m_bDisconnect = FALSE;
  30. m_bConnect = FALSE;
  31. m_bU3 = FALSE;
  32. m_bU3Stop = FALSE;
  33. m_bU3Install = FALSE;
  34. }
  35. virtual void ParseParam(const TCHAR* pszParam, BOOL bFlag, BOOL bLast)
  36. {
  37. if(bFlag)
  38. {
  39. if(STRICMP(pszParam, _T("Connect")) == 0)
  40. {
  41. m_bConnect = TRUE;
  42. }
  43. else if(STRICMP(pszParam, _T("Disconnect")) == 0)
  44. {
  45. m_bDisconnect = TRUE;
  46. }
  47. else if(STRICMP(pszParam, _T("U3")) == 0)
  48. {
  49. m_bU3 = TRUE;
  50. }
  51. else if(STRICMP(pszParam, _T("U3appStop")) == 0)
  52. {
  53. m_bU3Stop = TRUE;
  54. }
  55. else if(STRICMP(pszParam, _T("U3Install")) == 0)
  56. {
  57. m_bU3Install = TRUE;
  58. }
  59. }
  60. }
  61. BOOL m_bDisconnect;
  62. BOOL m_bConnect;
  63. BOOL m_bU3;
  64. BOOL m_bU3Stop;
  65. BOOL m_bU3Install;
  66. };
  67. CCP_MainApp theApp;
  68. /////////////////////////////////////////////////////////////////////////////
  69. // CCP_MainApp
  70. BEGIN_MESSAGE_MAP(CCP_MainApp, CWinApp)
  71. //{{AFX_MSG_MAP(CCP_MainApp)
  72. // NOTE - the ClassWizard will add and remove mapping macros here.
  73. // DO NOT EDIT what you see in these blocks of generated code!
  74. //}}AFX_MSG_MAP
  75. END_MESSAGE_MAP()
  76. /////////////////////////////////////////////////////////////////////////////
  77. // CCP_MainApp construction
  78. CCP_MainApp::CCP_MainApp()
  79. {
  80. m_bAppRunning = false;
  81. m_bAppExiting = false;
  82. m_MainhWnd = NULL;
  83. m_pMainFrame = NULL;
  84. m_bShowingQuickPaste = false;
  85. m_bRemoveOldEntriesPending = false;
  86. m_IC_bCopy = false;
  87. m_GroupDefaultID = 0;
  88. m_GroupID = -1;
  89. m_GroupParentID = 0;
  90. m_GroupText = "History";
  91. m_FocusID = -1;
  92. m_bAsynchronousRefreshView = true;
  93. m_lClipsSent = 0;
  94. m_lClipsRecieved = 0;
  95. m_oldtStartUp = COleDateTime::GetCurrentTime();
  96. m_bExitServerThread = false;
  97. m_lLastGoodIndexForNextworkPassword = -2;
  98. m_HTML_Format = ::RegisterClipboardFormat(_T("HTML Format"));
  99. m_PingFormat = ::RegisterClipboardFormat(_T("Ditto Ping Format"));
  100. m_cfIgnoreClipboard = ::RegisterClipboardFormat(_T("Clipboard Viewer Ignore"));
  101. m_cfDelaySavingData = ::RegisterClipboardFormat(_T("Ditto Delay Saving Data"));
  102. m_RemoteCF_HDROP = ::RegisterClipboardFormat(_T("Ditto Remote CF_HDROP"));
  103. m_QuickPasteMode = NONE_QUICK_PASTE;
  104. m_pQuickPasteClip = NULL;
  105. m_bDittoHasFocus = false;
  106. ::InitializeCriticalSection(&m_CriticalSection);
  107. }
  108. CCP_MainApp::~CCP_MainApp()
  109. {
  110. ::DeleteCriticalSection(&m_CriticalSection);
  111. }
  112. /////////////////////////////////////////////////////////////////////////////
  113. // CCP_MainApp initialization
  114. BOOL CCP_MainApp::InitInstance()
  115. {
  116. AfxEnableControlContainer();
  117. AfxOleInit();
  118. AfxInitRichEditEx();
  119. DittoCommandLineInfo cmdInfo;
  120. ParseCommandLine(cmdInfo);
  121. if(cmdInfo.m_strFileName.IsEmpty() == FALSE)
  122. {
  123. try
  124. {
  125. CClip_ImportExport Clip;
  126. CppSQLite3DB db;
  127. db.open(cmdInfo.m_strFileName);
  128. CClip_ImportExport clip;
  129. if(clip.ImportFromSqliteDB(db, false, true))
  130. {
  131. ShowCommandLineError("Ditto", theApp.m_Language.GetString("Importing_Good", "Clip placed on clipboard"));
  132. }
  133. else
  134. {
  135. ShowCommandLineError("Ditto", theApp.m_Language.GetString("Error_Importing", "Error importing exported clip"));
  136. }
  137. }
  138. catch (CppSQLite3Exception& e)
  139. {
  140. ASSERT(FALSE);
  141. CString csError;
  142. csError.Format(_T("%s - Exception - %d - %s"), theApp.m_Language.GetString("Error_Parsing", "Error parsing exported clip"), e.errorCode(), e.errorMessage());
  143. ShowCommandLineError("Ditto", csError);
  144. }
  145. return FALSE;
  146. }
  147. else if(cmdInfo.m_bConnect || cmdInfo.m_bDisconnect)
  148. {
  149. HWND hWnd = (HWND)CGetSetOptions::GetMainHWND();
  150. if(hWnd)
  151. ::SendMessage(hWnd, WM_SET_CONNECTED, cmdInfo.m_bConnect, cmdInfo.m_bDisconnect);
  152. return FALSE;
  153. }
  154. //if starting from a u3 device we will pass in -U3Start
  155. if(cmdInfo.m_bU3)
  156. g_Opt.m_bU3 = cmdInfo.m_bU3 ? TRUE : FALSE;
  157. g_Opt.LoadSettings();
  158. CInternetUpdate update;
  159. long lRunningVersion = update.GetRunningVersion();
  160. CString cs = update.GetVersionString(lRunningVersion);
  161. cs.Insert(0, _T("InitInstance - Running Version - "));
  162. Log(cs);
  163. CString csMutex("Ditto Is Now Running");
  164. if(g_Opt.m_bU3)
  165. {
  166. //If running from a U3 device then allow other ditto's to run
  167. //only prevent Ditto from running from the same device
  168. csMutex += " ";
  169. csMutex += GETENV(_T("U3_DEVICE_SERIAL"));
  170. }
  171. m_hMutex = CreateMutex(NULL, FALSE, csMutex);
  172. DWORD dwError = GetLastError();
  173. if(dwError == ERROR_ALREADY_EXISTS)
  174. {
  175. HWND hWnd = (HWND)CGetSetOptions::GetMainHWND();
  176. if(hWnd)
  177. ::SendMessage(hWnd, WM_SHOW_TRAY_ICON, TRUE, TRUE);
  178. return TRUE;
  179. }
  180. CString csFile = CGetSetOptions::GetLanguageFile();
  181. if(csFile.GetLength() > 0 && !m_Language.LoadLanguageFile(csFile))
  182. {
  183. CString cs;
  184. cs.Format(_T("Error loading language file - %s - \n\n%s"), csFile, m_Language.m_csLastError);
  185. Log(cs);
  186. }
  187. //The first time we run Ditto on U3 show a web page about ditto
  188. if(g_Opt.m_bU3)
  189. {
  190. if(FileExists(CGetSetOptions::GetDBPath()) == FALSE)
  191. {
  192. CString csFile = CGetSetOptions::GetPath(PATH_HELP);
  193. csFile += "U3_Install.htm";
  194. CHyperLink::GotoURL(csFile, SW_SHOW);
  195. }
  196. }
  197. int nRet = CheckDBExists(CGetSetOptions::GetDBPath());
  198. if(nRet == FALSE)
  199. {
  200. AfxMessageBox(theApp.m_Language.GetString("Error_Opening_Database", "Error Opening Database."));
  201. return FALSE;
  202. }
  203. CMainFrame* pFrame = new CMainFrame;
  204. m_pMainWnd = m_pMainFrame = pFrame;
  205. // prevent no one having focus on startup
  206. TargetActiveWindow();
  207. pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL);
  208. pFrame->ShowWindow(SW_SHOW);
  209. pFrame->UpdateWindow();
  210. // prevent no one having focus on startup
  211. ReleaseFocus();
  212. return TRUE;
  213. }
  214. void CCP_MainApp::AfterMainCreate()
  215. {
  216. m_MainhWnd = m_pMainFrame->m_hWnd;
  217. ASSERT( ::IsWindow(m_MainhWnd) );
  218. g_Opt.SetMainHWND((long)m_MainhWnd);
  219. //Save the HWND so the stop app can send us a close message
  220. if(g_Opt.m_bU3)
  221. {
  222. CGetSetOptions::WriteU3Hwnd(m_MainhWnd);
  223. }
  224. g_HotKeys.Init(m_MainhWnd);
  225. // create hotkeys here. They are automatically deleted on exit
  226. m_pDittoHotKey = new CHotKey(CString("DittoHotKey"), 704); //704 is ctrl-tilda
  227. //A U3 device is unable to use the keyboard hooks, so named paste and copy
  228. //can't be used
  229. if(!g_Opt.m_bU3)
  230. {
  231. m_pNamedCopy = new CHotKey("CopyHotKey");
  232. m_pNamedPaste = new CHotKey("NamedPaste");
  233. }
  234. m_pPosOne = new CHotKey("Position1", 0, true);
  235. m_pPosTwo = new CHotKey("Position2", 0, true);
  236. m_pPosThree = new CHotKey("Position3", 0, true);
  237. m_pPosFour = new CHotKey("Position4", 0, true);
  238. m_pPosFive = new CHotKey("Position5", 0, true);
  239. m_pPosSix = new CHotKey("Position6", 0, true);
  240. m_pPosSeven = new CHotKey("Position7", 0, true);
  241. m_pPosEight = new CHotKey("Position8", 0, true);
  242. m_pPosNine = new CHotKey("Position9", 0, true);
  243. m_pPosTen = new CHotKey("Position10", 0, true);
  244. g_HotKeys.RegisterAll();
  245. // CopyThread initialization
  246. StartCopyThread();
  247. StartStopServerThread();
  248. m_bAppRunning = true;
  249. }
  250. void CCP_MainApp::StartStopServerThread()
  251. {
  252. if(CGetSetOptions::GetDisableRecieve() == FALSE)
  253. {
  254. AfxBeginThread(MTServerThread, m_MainhWnd);
  255. }
  256. else
  257. {
  258. m_bExitServerThread = true;
  259. closesocket(theApp.m_sSocket);
  260. }
  261. }
  262. void CCP_MainApp::StopServerThread()
  263. {
  264. m_bExitServerThread = true;
  265. closesocket(theApp.m_sSocket);
  266. }
  267. void CCP_MainApp::BeforeMainClose()
  268. {
  269. ASSERT( m_bAppRunning && !m_bAppExiting );
  270. m_bAppRunning = false;
  271. m_bAppExiting = true;
  272. g_HotKeys.UnregisterAll();
  273. StopServerThread();
  274. StopCopyThread();
  275. }
  276. /*
  277. Re: Targeting the previous focus window
  278. We usually gain focus after the following messages:
  279. keyboard: WM_KEYUP(0x0101),WM_CHAR(0x0102),WM_HOTKEY(0x0312)
  280. mouse: WM_MOUSEFIRST(0x0200),WM_MOUSEMOVE(0x0200),WM_LBUTTONDOWN(0x0201)
  281. CMainFrame::PreTranslateMessage is used to intercept messages before
  282. they are processed (before we are actually given focus) in order to
  283. save the previous window that had focus.
  284. - It currently just handles "activating" mouse messages when showing.
  285. ShowQPasteWnd also has a call to "TargetActiveWindow" which handles
  286. finding the Target on hotkey activation.
  287. This works well for most window switching (mouse or hotkey), but does
  288. not work well for <Alt>-<Tab> or other window switching applications
  289. (e.g. the taskbar tray), since the previous window was only a means to
  290. switching and not the target itself.
  291. - one solution might be to always monitor the current foreground
  292. window using system hooks or a short (e.g. 1 sec) timer... though this
  293. *might* be cpu intensive (slow). I'm currently looking into using
  294. WH_CBT system hooks in a separate dll (see: robpitt's
  295. http://website.lineone.net/~codebox/focuslog.zip).
  296. */
  297. bool CCP_MainApp::TargetActiveWindow()
  298. {
  299. if(g_Opt.m_bUseHookDllForFocus)
  300. return true;
  301. HWND hOld = m_hTargetWnd;
  302. GUITHREADINFO guiThreadInfo;
  303. guiThreadInfo.cbSize = sizeof(GUITHREADINFO);
  304. HWND hNew = ::GetForegroundWindow();
  305. DWORD OtherThreadID = GetWindowThreadProcessId(hNew, NULL);
  306. if(GetGUIThreadInfo(OtherThreadID, &guiThreadInfo))
  307. {
  308. hNew = guiThreadInfo.hwndFocus;
  309. }
  310. if(hNew == m_hTargetWnd || !::IsWindow(hNew) || IsAppWnd(hNew))
  311. return false;
  312. m_hTargetWnd = hNew;
  313. if(QPasteWnd())
  314. QPasteWnd()->UpdateStatus(true);
  315. // Tracking / Debugging
  316. /*
  317. LOG( StrF(
  318. "Target Changed" \
  319. "\n\tOld = 0x%08x: \"%s\"" \
  320. "\n\tNew = 0x%08x: \"%s\"\n",
  321. hOld, (LPCTSTR) GetWndText(hOld),
  322. hNew, (LPCTSTR) GetWndText(hNew) ) );
  323. */
  324. return true;
  325. }
  326. bool CCP_MainApp::ActivateTarget()
  327. {
  328. ::SetForegroundWindow(m_hTargetWnd);
  329. ::SetFocus(m_hTargetWnd);
  330. return true;
  331. }
  332. bool CCP_MainApp::ReleaseFocus()
  333. {
  334. if( IsAppWnd(::GetForegroundWindow()) )
  335. return ActivateTarget();
  336. return false;
  337. }
  338. // sends Ctrl-V to the TargetWnd
  339. void CCP_MainApp::SendPaste(bool bActivateTarget)
  340. {
  341. Log(_T("SendPaste"));
  342. char ch;
  343. //Make sure all the keys are up
  344. for(ch = '0'; ch <= '9'; ch++)
  345. {
  346. keybd_event(ch, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  347. }
  348. for(ch = 'A'; ch <= 'Z'; ch++)
  349. {
  350. keybd_event(ch, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  351. }
  352. keybd_event(VK_SHIFT, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  353. keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  354. keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  355. keybd_event(VK_LWIN, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  356. Sleep(50);
  357. if(bActivateTarget && !ActivateTarget())
  358. {
  359. SetStatus(_T("SendPaste FAILED!"), TRUE);
  360. return;
  361. }
  362. MSG KeyboardMsg;
  363. while (::PeekMessage(&KeyboardMsg, NULL, 0, 0, PM_REMOVE))
  364. {
  365. ::TranslateMessage(&KeyboardMsg);
  366. ::DispatchMessage(&KeyboardMsg);
  367. }
  368. Sleep(50);
  369. keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
  370. keybd_event('V', 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
  371. Sleep(50);
  372. keybd_event('V', 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  373. keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  374. Log(_T("END SendPaste"));
  375. }
  376. // sends Ctrl-V to the TargetWnd
  377. void CCP_MainApp::SendCopy()
  378. {
  379. char ch;
  380. //Make sure all the keys are up
  381. for(ch = '0'; ch <= '9'; ch++)
  382. {
  383. keybd_event(ch, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  384. }
  385. for(ch = 'A'; ch <= 'Z'; ch++)
  386. {
  387. keybd_event(ch, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  388. }
  389. keybd_event(VK_SHIFT, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  390. keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  391. keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  392. keybd_event(VK_LWIN, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  393. Sleep(50);
  394. MSG KeyboardMsg;
  395. while (::PeekMessage(&KeyboardMsg, NULL, 0, 0, PM_REMOVE))
  396. {
  397. ::TranslateMessage(&KeyboardMsg);
  398. ::DispatchMessage(&KeyboardMsg);
  399. }
  400. Sleep(50);
  401. keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
  402. keybd_event('C', 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
  403. Sleep(50);
  404. keybd_event('C', 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  405. keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  406. }
  407. // CopyThread
  408. void CCP_MainApp::StartCopyThread()
  409. {
  410. ASSERT( m_MainhWnd );
  411. CClipTypes* pTypes = LoadTypesFromDB();
  412. // initialize to:
  413. // - m_MainhWnd = send WM_CLIPBOARD_COPIED messages to m_MainhWnd
  414. // - true = use Asynchronous communication (PostMessage)
  415. // - true = enable copying on clipboard changes
  416. // - pTypes = the supported types to use
  417. m_CopyThread.Init( CCopyConfig( m_MainhWnd, true, true, pTypes ) );
  418. VERIFY( m_CopyThread.CreateThread(CREATE_SUSPENDED) );
  419. m_CopyThread.ResumeThread();
  420. }
  421. void CCP_MainApp::StopCopyThread()
  422. {
  423. EnableCbCopy(false);
  424. m_CopyThread.Quit();
  425. SaveCopyClips();
  426. }
  427. // returns the current Clipboard Viewer Connect state (though it might not yet
  428. // be actually connected -- check IsClipboardViewerConnected())
  429. bool CCP_MainApp::ToggleConnectCV()
  430. {
  431. bool bConnect = !GetConnectCV();
  432. SetConnectCV(bConnect);
  433. return bConnect;
  434. }
  435. // Sets a menu entry according to the current Clipboard Viewer Connection status
  436. // - the menu text indicates the available command (opposite the current state)
  437. // - a check mark appears in the rare cases that the menu text actually represents
  438. // the current state, e.g. if we are supposed to be connected, but we somehow
  439. // lose that connection, "Disconnect from Clipboard" will have a check next to it.
  440. void CCP_MainApp::UpdateMenuConnectCV(CMenu* pMenu, UINT nMenuID)
  441. {
  442. if(pMenu == NULL)
  443. return;
  444. bool bConnect = theApp.GetConnectCV();
  445. CString cs;
  446. if(bConnect)
  447. {
  448. cs = theApp.m_Language.GetString("Disconnect_Clipboard", "Disconnect from Clipboard.");
  449. pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, cs);
  450. }
  451. else
  452. {
  453. cs = theApp.m_Language.GetString("Connect_Clipboard", "Connect to Clipboard.");
  454. pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, cs);
  455. }
  456. }
  457. // Allocates a new CClipTypes
  458. CClipTypes* CCP_MainApp::LoadTypesFromDB()
  459. {
  460. CClipTypes* pTypes = new CClipTypes;
  461. try
  462. {
  463. CppSQLite3Query q = theApp.m_db.execQuery(_T("SELECT TypeText FROM Types"));
  464. while(q.eof() == false)
  465. {
  466. pTypes->Add(GetFormatID(q.getStringField(_T("TypeText"))));
  467. q.nextRow();
  468. }
  469. }
  470. CATCH_SQLITE_EXCEPTION
  471. if(pTypes->GetSize() <= 0)
  472. {
  473. pTypes->Add(CF_TEXT);
  474. pTypes->Add(RegisterClipboardFormat(CF_RTF));
  475. pTypes->Add(CF_UNICODETEXT);
  476. pTypes->Add(CF_HDROP);
  477. if(g_Opt.m_bU3 == false)
  478. {
  479. pTypes->Add(CF_DIB);
  480. }
  481. }
  482. return pTypes;
  483. }
  484. void CCP_MainApp::ReloadTypes()
  485. {
  486. CClipTypes* pTypes = LoadTypesFromDB();
  487. if( pTypes )
  488. m_CopyThread.SetSupportedTypes( pTypes );
  489. }
  490. long CCP_MainApp::SaveCopyClips()
  491. {
  492. long lID = 0;
  493. int count;
  494. CClipList* pClips = m_CopyThread.GetClips(); // we now own pClips
  495. if(!pClips)
  496. return 0;
  497. CClipList* pCopyOfClips = NULL;
  498. if(g_Opt.m_lAutoSendClientCount > 0)
  499. {
  500. //The thread will free these
  501. pCopyOfClips = new CClipList;
  502. if(pCopyOfClips != NULL)
  503. {
  504. *pCopyOfClips = *pClips;
  505. }
  506. }
  507. bool bEnteredThread = false;
  508. bool bDeletepClips = true;
  509. if(m_QuickPasteMode == ADDING_QUICK_PASTE)
  510. {
  511. //this will be added when they are done entering the quick paste text
  512. m_pQuickPasteClip = pClips;
  513. bDeletepClips = false;
  514. //go ahead and send the clips out even though it won't be added for a bit
  515. count = 1;
  516. }
  517. else
  518. {
  519. count = pClips->AddToDB(true);
  520. if(count > 0)
  521. {
  522. lID = pClips->GetTail()->m_ID;
  523. OnCopyCompleted(lID, count);
  524. }
  525. }
  526. if(count > 0)
  527. {
  528. if(g_Opt.m_lAutoSendClientCount > 0)
  529. {
  530. AfxBeginThread(SendClientThread, pCopyOfClips);
  531. bEnteredThread = true;
  532. }
  533. }
  534. if(bEnteredThread == false)
  535. delete pCopyOfClips;
  536. if(bDeletepClips)
  537. delete pClips;
  538. return lID;
  539. }
  540. void CCP_MainApp::RefreshView()
  541. {
  542. CQPasteWnd *pWnd = QPasteWnd();
  543. if(pWnd)
  544. {
  545. if(m_bAsynchronousRefreshView)
  546. pWnd->PostMessage(WM_REFRESH_VIEW);
  547. else
  548. pWnd->SendMessage(WM_REFRESH_VIEW);
  549. }
  550. }
  551. void CCP_MainApp::OnPasteCompleted()
  552. {
  553. // the list only changes if UpdateTimeOnPaste is true (updated time)
  554. if(g_Opt.m_bUpdateTimeOnPaste)
  555. RefreshView();
  556. }
  557. void CCP_MainApp::OnCopyCompleted(long lLastID, int count)
  558. {
  559. if(count <= 0)
  560. return;
  561. // queue a message to RemoveOldEntries
  562. Delayed_RemoveOldEntries(60000);
  563. // update copy statistics
  564. CGetSetOptions::SetTripCopyCount(-count);
  565. CGetSetOptions::SetTotalCopyCount(-count);
  566. RefreshView();
  567. }
  568. // Internal Clipboard for cut/copy/paste items between Groups
  569. // if NULL, this uses the current QPaste selection
  570. void CCP_MainApp::IC_Cut(ARRAY* pIDs)
  571. {
  572. if( pIDs == NULL )
  573. {
  574. if( QPasteWnd() )
  575. QPasteWnd()->m_lstHeader.GetSelectionItemData( m_IC_IDs );
  576. else
  577. m_IC_IDs.SetSize(0);
  578. }
  579. else
  580. m_IC_IDs.Copy( *pIDs );
  581. m_IC_bCopy = false;
  582. if( QPasteWnd() )
  583. QPasteWnd()->UpdateStatus();
  584. }
  585. // if NULL, this uses the current QPaste selection
  586. void CCP_MainApp::IC_Copy(ARRAY* pIDs)
  587. {
  588. if(pIDs == NULL)
  589. {
  590. if(QPasteWnd())
  591. QPasteWnd()->m_lstHeader.GetSelectionItemData(m_IC_IDs);
  592. else
  593. m_IC_IDs.SetSize(0);
  594. }
  595. else
  596. m_IC_IDs.Copy(*pIDs);
  597. m_IC_bCopy = true;
  598. if(QPasteWnd())
  599. QPasteWnd()->UpdateStatus();
  600. }
  601. void CCP_MainApp::IC_Paste()
  602. {
  603. if(m_IC_IDs.GetSize() <= 0)
  604. return;
  605. if(m_IC_bCopy)
  606. m_IC_IDs.CopyTo(GetValidGroupID());
  607. else // Move
  608. m_IC_IDs.MoveTo(GetValidGroupID());
  609. // don't process the same items twice.
  610. m_IC_IDs.SetSize(0);
  611. RefreshView();
  612. }
  613. // Groups
  614. BOOL CCP_MainApp::EnterGroupID(long lID)
  615. {
  616. BOOL bResult = FALSE;
  617. if(m_GroupID == lID)
  618. return TRUE;
  619. // if we are switching to the parent, focus on the previous group
  620. if(m_GroupParentID == lID && m_GroupID > 0)
  621. m_FocusID = m_GroupID;
  622. switch(lID)
  623. {
  624. case -1:
  625. m_FocusID = -1;
  626. m_GroupID = -1;
  627. m_GroupParentID = -1;
  628. m_GroupText = "History";
  629. bResult = TRUE;
  630. break;
  631. default: // Normal Group
  632. try
  633. {
  634. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lParentID, mText, bIsGroup FROM Main WHERE lID = %d"), lID);
  635. if(q.eof() == false)
  636. {
  637. if(q.getIntField(_T("bIsGroup")) > 0)
  638. {
  639. m_GroupID = lID;
  640. m_GroupParentID = q.getIntField(_T("lParentID"));
  641. // if( m_GroupParentID == 0 )
  642. // m_GroupParentID = -1; // back out into "all top-level groups" list.
  643. m_GroupText = q.getStringField(_T("mText"));
  644. bResult = TRUE;
  645. }
  646. }
  647. }
  648. CATCH_SQLITE_EXCEPTION
  649. break;
  650. }
  651. if(bResult)
  652. {
  653. theApp.RefreshView();
  654. if(QPasteWnd())
  655. QPasteWnd()->UpdateStatus(true);
  656. }
  657. return bResult;
  658. }
  659. // returns a usable group id (not negative)
  660. long CCP_MainApp::GetValidGroupID()
  661. {
  662. return m_GroupID;
  663. }
  664. // sets a valid id
  665. void CCP_MainApp::SetGroupDefaultID( long lID )
  666. {
  667. if( m_GroupDefaultID == lID )
  668. return;
  669. if( lID <= 0 )
  670. m_GroupDefaultID = 0;
  671. else
  672. m_GroupDefaultID = lID;
  673. if( QPasteWnd() )
  674. QPasteWnd()->UpdateStatus();
  675. }
  676. // Window States
  677. void CCP_MainApp::SetStatus( const TCHAR* status, bool bRepaintImmediately )
  678. {
  679. m_Status = status;
  680. if( QPasteWnd() )
  681. QPasteWnd()->UpdateStatus( bRepaintImmediately );
  682. }
  683. void CCP_MainApp::ShowPersistent( bool bVal )
  684. {
  685. g_Opt.SetShowPersistent( bVal );
  686. // give some visual indication
  687. if( m_bShowingQuickPaste )
  688. {
  689. ASSERT( QPasteWnd() );
  690. QPasteWnd()->SetCaptionColorActive(!g_Opt.m_bShowPersistent, theApp.GetConnectCV());
  691. QPasteWnd()->RefreshNc();
  692. }
  693. }
  694. void CCP_MainApp::Delayed_RemoveOldEntries( UINT delay )
  695. {
  696. if( !m_bRemoveOldEntriesPending )
  697. {
  698. m_bRemoveOldEntriesPending = true;
  699. ((CMainFrame*)theApp.m_pMainWnd)->SetTimer( REMOVE_OLD_ENTRIES_TIMER, delay, 0 );
  700. }
  701. }
  702. /////////////////////////////////////////////////////////////////////////////
  703. // CCP_MainApp message handlers
  704. int CCP_MainApp::ExitInstance()
  705. {
  706. Log(_T("ExitInstance"));
  707. m_db.close();
  708. // if(g_Opt.m_bU3)
  709. // {
  710. // if(g_Opt.IsU3DeviceAvailable())
  711. // {
  712. // CopyUpDatabase();
  713. // }
  714. // else
  715. // {
  716. // Log(_T("Needed to copy up database but device was not available to copy to"));
  717. // }
  718. // }
  719. return CWinApp::ExitInstance();
  720. }
  721. // return TRUE if there is more idle processing to do
  722. BOOL CCP_MainApp::OnIdle(LONG lCount)
  723. {
  724. // let winapp handle its idle processing
  725. if( CWinApp::OnIdle(lCount) )
  726. return TRUE;
  727. return FALSE;
  728. }
  729. CString CCP_MainApp::GetTargetName()
  730. {
  731. TCHAR cWindowText[100];
  732. HWND hParent = m_hTargetWnd;
  733. ::GetWindowText(hParent, cWindowText, 100);
  734. int nCount = 0;
  735. while(STRLEN(cWindowText) <= 0)
  736. {
  737. hParent = ::GetParent(hParent);
  738. if(hParent == NULL)
  739. break;
  740. ::GetWindowText(hParent, cWindowText, 100);
  741. nCount++;
  742. if(nCount > 100)
  743. {
  744. Log(_T("GetTargetName reached maximum search depth of 100"));
  745. break;
  746. }
  747. }
  748. return cWindowText;
  749. }
  750. void CCP_MainApp::SetConnectCV(bool bConnect)
  751. {
  752. m_CopyThread.SetConnectCV(bConnect);
  753. if(bConnect)
  754. m_pMainFrame->m_TrayIcon.SetIcon(IDR_MAINFRAME);
  755. else
  756. m_pMainFrame->m_TrayIcon.SetIcon(IDI_DITTO_NOCOPYCB);
  757. if(QPasteWnd())
  758. {
  759. QPasteWnd()->SetCaptionColorActive(!g_Opt.m_bShowPersistent, theApp.GetConnectCV());
  760. QPasteWnd()->RefreshNc();
  761. }
  762. }
  763. void CCP_MainApp::OnDeleteID(long lID)
  764. {
  765. if(QPasteWnd())
  766. {
  767. QPasteWnd()->PostMessage(NM_ITEM_DELETED, lID, 0);
  768. }
  769. }
  770. bool CCP_MainApp::ImportClips(HWND hWnd)
  771. {
  772. OPENFILENAME FileName;
  773. TCHAR szFileName[400];
  774. TCHAR szDir[400];
  775. memset(&FileName, 0, sizeof(FileName));
  776. memset(szFileName, 0, sizeof(szFileName));
  777. memset(&szDir, 0, sizeof(szDir));
  778. CString csInitialDir = CGetSetOptions::GetLastImportDir();
  779. STRCPY(szDir, csInitialDir);
  780. FileName.lStructSize = sizeof(FileName);
  781. FileName.lpstrTitle = _T("Import Clips");
  782. FileName.Flags = OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST;
  783. FileName.nMaxFile = 400;
  784. FileName.lpstrFile = szFileName;
  785. FileName.lpstrInitialDir = szDir;
  786. FileName.lpstrFilter = _T("Exported Ditto Clips (.dto)\0*.dto\0\0");
  787. FileName.lpstrDefExt = _T("dto");
  788. if(GetOpenFileName(&FileName) == 0)
  789. return false;
  790. using namespace nsPath;
  791. CPath path(FileName.lpstrFile);
  792. CString csPath = path.GetPath();
  793. CGetSetOptions::SetLastImportDir(csPath);
  794. try
  795. {
  796. CppSQLite3DB db;
  797. db.open(FileName.lpstrFile);
  798. CClip_ImportExport clip;
  799. if(clip.ImportFromSqliteDB(db, true, false))
  800. {
  801. CShowMainFrame Show;
  802. CString cs;
  803. cs.Format(_T("%s %d "), theApp.m_Language.GetString("Import_Successfully", "Successfully imported"), clip.m_lImportCount);
  804. if(clip.m_lImportCount = 1)
  805. cs += theApp.m_Language.GetString("Clip", "clip");
  806. else
  807. cs += theApp.m_Language.GetString("Clips", "clips");
  808. MessageBox(hWnd, cs, _T("Ditto"), MB_OK);
  809. }
  810. else
  811. {
  812. CShowMainFrame Show;
  813. MessageBox(hWnd, theApp.m_Language.GetString("Error_Importing", "Error importing exported clip"), _T("Ditto"), MB_OK);
  814. }
  815. }
  816. catch (CppSQLite3Exception& e)
  817. {
  818. ASSERT(FALSE);
  819. CString csError;
  820. csError.Format(_T("%s - Exception - %d - %s"), theApp.m_Language.GetString("Error_Parsing", "Error parsing exported clip"), e.errorCode(), e.errorMessage());
  821. MessageBox(hWnd, csError, _T("Ditto"), MB_OK);
  822. }
  823. return true;
  824. }
  825. void CCP_MainApp::ShowCommandLineError(CString csTitle, CString csMessage)
  826. {
  827. Log(StrF(_T("ShowCommandLineError %s - %s"), csTitle, csMessage));
  828. CToolTipEx *pErrorWnd = new CToolTipEx;
  829. pErrorWnd->Create(NULL);
  830. pErrorWnd->SetToolTipText(csTitle + "\n\n" + csMessage);
  831. CPoint pt;
  832. CRect rcScreen;
  833. GetMonitorRect(0, &rcScreen);
  834. pt = rcScreen.BottomRight();
  835. CRect cr = pErrorWnd->GetBoundsRect();
  836. pt.x -= max(cr.Width()+50, 150);
  837. pt.y -= max(cr.Height()+50, 150);
  838. pErrorWnd->Show(pt);
  839. Sleep(4000);
  840. pErrorWnd->DestroyWindow();
  841. }
  842. BOOL CCP_MainApp::GetClipData(long lID, CClipFormat &Clip)
  843. {
  844. BOOL bRet = FALSE;
  845. try
  846. {
  847. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT ooData FROM Data WHERE lParentID = %d AND strClipboardFormat = '%s'"), lID, GetFormatName(Clip.m_cfType));
  848. if(q.eof() == false)
  849. {
  850. int nDataLen = 0;
  851. const unsigned char *cData = q.getBlobField(_T("ooData"), nDataLen);
  852. if(cData != NULL)
  853. {
  854. Clip.m_hgData = NewGlobal(nDataLen);
  855. ::CopyToGlobalHP(Clip.m_hgData, (LPVOID)cData, nDataLen);
  856. bRet = TRUE;
  857. }
  858. }
  859. }
  860. CATCH_SQLITE_EXCEPTION
  861. return bRet;
  862. }
  863. bool CCP_MainApp::EditItems(CClipIDs &Ids, bool bShowError)
  864. {
  865. m_pMainFrame->ShowEditWnd(Ids);
  866. return true;
  867. }
  868. int CCP_MainApp::ShowOptionsDlg()
  869. {
  870. static bool bShowingOptions = false;
  871. int nRet = IDABORT;
  872. if(bShowingOptions = false)
  873. {
  874. bShowingOptions = true;
  875. CShowMainFrame Show;
  876. COptionsSheet Sheet(_T(""), m_pMainFrame);
  877. int nRet = Sheet.DoModal();
  878. if(nRet == IDOK)
  879. {
  880. m_pMainFrame->QuickPaste.ShowQPasteWnd(m_pMainFrame, false, false, TRUE);
  881. }
  882. bShowingOptions = false;
  883. }
  884. return nRet;
  885. }