CP_Main.cpp 26 KB

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