CP_Main.cpp 26 KB

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