CP_Main.cpp 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166
  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_QuickPasteMode = NONE_QUICK_PASTE;
  108. m_pQuickPasteClip = NULL;
  109. m_bDittoHasFocus = false;
  110. }
  111. CCP_MainApp::~CCP_MainApp()
  112. {
  113. }
  114. /////////////////////////////////////////////////////////////////////////////
  115. // CCP_MainApp initialization
  116. BOOL CCP_MainApp::InitInstance()
  117. {
  118. AfxEnableControlContainer();
  119. AfxOleInit();
  120. AfxInitRichEditEx();
  121. DittoCommandLineInfo cmdInfo;
  122. ParseCommandLine(cmdInfo);
  123. if(cmdInfo.m_strFileName.IsEmpty() == FALSE)
  124. {
  125. try
  126. {
  127. g_Opt.m_bEnableDebugLogging = g_Opt.GetEnableDebugLogging();
  128. CClip_ImportExport Clip;
  129. CppSQLite3DB db;
  130. db.open(cmdInfo.m_strFileName);
  131. CClip_ImportExport clip;
  132. if(clip.ImportFromSqliteDB(db, false, true))
  133. {
  134. ShowCommandLineError("Ditto", theApp.m_Language.GetString("Importing_Good", "Clip placed on clipboard"));
  135. }
  136. else
  137. {
  138. ShowCommandLineError("Ditto", theApp.m_Language.GetString("Error_Importing", "Error importing exported clip"));
  139. }
  140. }
  141. catch (CppSQLite3Exception& e)
  142. {
  143. ASSERT(FALSE);
  144. CString csError;
  145. csError.Format(_T("%s - Exception - %d - %s"), theApp.m_Language.GetString("Error_Parsing", "Error parsing exported clip"), e.errorCode(), e.errorMessage());
  146. ShowCommandLineError("Ditto", csError);
  147. }
  148. return FALSE;
  149. }
  150. else if(cmdInfo.m_bConnect || cmdInfo.m_bDisconnect)
  151. {
  152. HWND hWnd = (HWND)CGetSetOptions::GetMainHWND();
  153. if(hWnd)
  154. ::SendMessage(hWnd, WM_SET_CONNECTED, cmdInfo.m_bConnect, cmdInfo.m_bDisconnect);
  155. return FALSE;
  156. }
  157. //if starting from a u3 device we will pass in -U3Start
  158. if(cmdInfo.m_bU3)
  159. g_Opt.m_bU3 = cmdInfo.m_bU3 ? TRUE : FALSE;
  160. g_Opt.LoadSettings();
  161. CInternetUpdate update;
  162. long lRunningVersion = update.GetRunningVersion();
  163. CString cs = update.GetVersionString(lRunningVersion);
  164. cs.Insert(0, _T("InitInstance - Running Version - "));
  165. Log(cs);
  166. CString csMutex("Ditto Is Now Running");
  167. if(g_Opt.m_bU3)
  168. {
  169. //If running from a U3 device then allow other ditto's to run
  170. //only prevent Ditto from running from the same device
  171. csMutex += " ";
  172. csMutex += GETENV(_T("U3_DEVICE_SERIAL"));
  173. }
  174. else if(g_Opt.GetIsPortableDitto())
  175. {
  176. csMutex += " ";
  177. csMutex += g_Opt.GetExeFileName();
  178. }
  179. m_hMutex = CreateMutex(NULL, FALSE, csMutex);
  180. DWORD dwError = GetLastError();
  181. if(dwError == ERROR_ALREADY_EXISTS)
  182. {
  183. HWND hWnd = (HWND)CGetSetOptions::GetMainHWND();
  184. if(hWnd)
  185. ::SendMessage(hWnd, WM_SHOW_TRAY_ICON, TRUE, TRUE);
  186. return TRUE;
  187. }
  188. CString csFile = CGetSetOptions::GetLanguageFile();
  189. if(csFile.GetLength() > 0 && !m_Language.LoadLanguageFile(csFile))
  190. {
  191. CString cs;
  192. cs.Format(_T("Error loading language file - %s - \n\n%s"), csFile, m_Language.m_csLastError);
  193. Log(cs);
  194. }
  195. //The first time we run Ditto on U3 show a web page about ditto
  196. if(g_Opt.m_bU3)
  197. {
  198. if(FileExists(CGetSetOptions::GetDBPath()) == FALSE)
  199. {
  200. CString csFile = CGetSetOptions::GetPath(PATH_HELP);
  201. csFile += "U3_Install.htm";
  202. CHyperLink::GotoURL(csFile, SW_SHOW);
  203. }
  204. }
  205. int nRet = CheckDBExists(CGetSetOptions::GetDBPath());
  206. if(nRet == FALSE)
  207. {
  208. AfxMessageBox(theApp.m_Language.GetString("Error_Opening_Database", "Error Opening Database."));
  209. return FALSE;
  210. }
  211. CMainFrame* pFrame = new CMainFrame;
  212. m_pMainWnd = m_pMainFrame = pFrame;
  213. // prevent no one having focus on startup
  214. TargetActiveWindow();
  215. pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL);
  216. pFrame->ShowWindow(SW_SHOW);
  217. pFrame->UpdateWindow();
  218. // prevent no one having focus on startup
  219. ReleaseFocus();
  220. m_Addins.LoadAll();
  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("CopyBufferCutHotKey_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. if(guiThreadInfo.hwndFocus != NULL)
  327. {
  328. hNew = guiThreadInfo.hwndFocus;
  329. }
  330. }
  331. if(hNew == m_hTargetWnd || !::IsWindow(hNew) || IsAppWnd(hNew))
  332. return false;
  333. m_hTargetWnd = hNew;
  334. if(QPasteWnd())
  335. QPasteWnd()->UpdateStatus(true);
  336. // Tracking / Debugging
  337. //Log( StrF(
  338. // _T("Target Changed") \
  339. // _T("\n\tOld = 0x%08x: \"%s\"") \
  340. // _T("\n\tNew = 0x%08x: \"%s\"\n"),
  341. // hOld, (LPCTSTR) GetWndText(hOld),
  342. // hNew, (LPCTSTR) GetWndText(hNew) ) );
  343. return true;
  344. }
  345. bool CCP_MainApp::ActivateTarget()
  346. {
  347. ::SetForegroundWindow(m_hTargetWnd);
  348. ::SetFocus(m_hTargetWnd);
  349. return true;
  350. }
  351. bool CCP_MainApp::ReleaseFocus()
  352. {
  353. if( IsAppWnd(::GetForegroundWindow()) )
  354. return ActivateTarget();
  355. return false;
  356. }
  357. // sends Ctrl-V to the TargetWnd
  358. void CCP_MainApp::SendPaste(bool bActivateTarget)
  359. {
  360. char ch;
  361. //Make sure all the keys are up
  362. for(ch = '0'; ch <= '9'; ch++)
  363. {
  364. keybd_event(ch, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  365. }
  366. for(ch = 'A'; ch <= 'Z'; ch++)
  367. {
  368. keybd_event(ch, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  369. }
  370. keybd_event(VK_SHIFT, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  371. keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  372. keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  373. keybd_event(VK_LWIN, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  374. Sleep(50);
  375. if(bActivateTarget && !ActivateTarget())
  376. {
  377. SetStatus(_T("SendPaste FAILED!"), TRUE);
  378. return;
  379. }
  380. PumpMessageEx();
  381. CString csPasteToApp = GetProcessName(m_hTargetWnd);
  382. CString csPasteString = g_Opt.GetPasteString(csPasteToApp);
  383. CString csMessage;
  384. csMessage = "Sending paste to app " + csPasteToApp + " key stroke " + csPasteString;
  385. Log(csMessage);
  386. CSendKeys send;
  387. //CString cs("^v");
  388. //CString cs("%e{DELAY=50}p");
  389. send.SendKeys(csPasteString);
  390. }
  391. // sends Ctrl-V to the TargetWnd
  392. void CCP_MainApp::SendCopy()
  393. {
  394. char ch;
  395. //Make sure all the keys are up
  396. for(ch = '0'; ch <= '9'; ch++)
  397. {
  398. keybd_event(ch, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  399. }
  400. for(ch = 'A'; ch <= 'Z'; ch++)
  401. {
  402. keybd_event(ch, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  403. }
  404. keybd_event(VK_SHIFT, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  405. keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  406. keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  407. keybd_event(VK_LWIN, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  408. Sleep(50);
  409. PumpMessageEx();
  410. CString csToApp = GetProcessName(m_hTargetWnd);
  411. CString csString = g_Opt.GetCopyString(csToApp);
  412. CString csMessage;
  413. csMessage = "Sending copy to app " + csToApp + " key stroke " + csString;
  414. Log(csMessage);
  415. CSendKeys send;
  416. //CString cs("^c");
  417. send.SendKeys(csString);
  418. }
  419. // sends Ctrl-X to the TargetWnd
  420. void CCP_MainApp::SendCut()
  421. {
  422. char ch;
  423. //Make sure all the keys are up
  424. for(ch = '0'; ch <= '9'; ch++)
  425. {
  426. keybd_event(ch, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  427. }
  428. for(ch = 'A'; ch <= 'Z'; ch++)
  429. {
  430. keybd_event(ch, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  431. }
  432. keybd_event(VK_SHIFT, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  433. keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  434. keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  435. keybd_event(VK_LWIN, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  436. Sleep(50);
  437. PumpMessageEx();
  438. CString csToApp = GetProcessName(m_hTargetWnd);
  439. CString csString = g_Opt.GetCutString(csToApp);
  440. CString csMessage;
  441. csMessage = "Sending cut to app " + csToApp + " key stroke " + csString;
  442. Log(csMessage);
  443. CSendKeys send;
  444. //CString cs("^x");
  445. send.SendKeys(csString);
  446. }
  447. // CopyThread
  448. void CCP_MainApp::StartCopyThread()
  449. {
  450. ASSERT( m_MainhWnd );
  451. CClipTypes* pTypes = LoadTypesFromDB();
  452. // initialize to:
  453. // - m_MainhWnd = send WM_CLIPBOARD_COPIED messages to m_MainhWnd
  454. // - true = use Asynchronous communication (PostMessage)
  455. // - true = enable copying on clipboard changes
  456. // - pTypes = the supported types to use
  457. m_CopyThread.Init( CCopyConfig( m_MainhWnd, true, true, pTypes ) );
  458. VERIFY( m_CopyThread.CreateThread(CREATE_SUSPENDED) );
  459. m_CopyThread.ResumeThread();
  460. }
  461. void CCP_MainApp::StopCopyThread()
  462. {
  463. EnableCbCopy(false);
  464. m_CopyThread.Quit();
  465. SaveCopyClips();
  466. }
  467. // returns the current Clipboard Viewer Connect state (though it might not yet
  468. // be actually connected -- check IsClipboardViewerConnected())
  469. bool CCP_MainApp::ToggleConnectCV()
  470. {
  471. bool bConnect = !GetConnectCV();
  472. SetConnectCV(bConnect);
  473. return bConnect;
  474. }
  475. // Sets a menu entry according to the current Clipboard Viewer Connection status
  476. // - the menu text indicates the available command (opposite the current state)
  477. // - a check mark appears in the rare cases that the menu text actually represents
  478. // the current state, e.g. if we are supposed to be connected, but we somehow
  479. // lose that connection, "Disconnect from Clipboard" will have a check next to it.
  480. void CCP_MainApp::UpdateMenuConnectCV(CMenu* pMenu, UINT nMenuID)
  481. {
  482. if(pMenu == NULL)
  483. return;
  484. bool bConnect = theApp.GetConnectCV();
  485. CString cs;
  486. if(bConnect)
  487. {
  488. cs = theApp.m_Language.GetString("Disconnect_Clipboard", "Disconnect from Clipboard.");
  489. pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, cs);
  490. }
  491. else
  492. {
  493. cs = theApp.m_Language.GetString("Connect_Clipboard", "Connect to Clipboard.");
  494. pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, cs);
  495. }
  496. }
  497. // Allocates a new CClipTypes
  498. CClipTypes* CCP_MainApp::LoadTypesFromDB()
  499. {
  500. CClipTypes* pTypes = new CClipTypes;
  501. try
  502. {
  503. CppSQLite3Query q = theApp.m_db.execQuery(_T("SELECT TypeText FROM Types"));
  504. while(q.eof() == false)
  505. {
  506. pTypes->Add(GetFormatID(q.getStringField(_T("TypeText"))));
  507. q.nextRow();
  508. }
  509. }
  510. CATCH_SQLITE_EXCEPTION
  511. if(pTypes->GetSize() <= 0)
  512. {
  513. pTypes->Add(CF_TEXT);
  514. pTypes->Add(RegisterClipboardFormat(CF_RTF));
  515. pTypes->Add(CF_UNICODETEXT);
  516. pTypes->Add(CF_HDROP);
  517. if(g_Opt.m_bU3 == false)
  518. {
  519. pTypes->Add(CF_DIB);
  520. }
  521. }
  522. return pTypes;
  523. }
  524. void CCP_MainApp::ReloadTypes()
  525. {
  526. CClipTypes* pTypes = LoadTypesFromDB();
  527. if( pTypes )
  528. m_CopyThread.SetSupportedTypes( pTypes );
  529. }
  530. long CCP_MainApp::SaveCopyClips()
  531. {
  532. long lID = 0;
  533. int count;
  534. CClipList* pClips = m_CopyThread.GetClips(); // we now own pClips
  535. if(!pClips)
  536. return 0;
  537. CClipList* pCopyOfClips = NULL;
  538. if(g_Opt.m_lAutoSendClientCount > 0)
  539. {
  540. //The thread will free these
  541. pCopyOfClips = new CClipList;
  542. if(pCopyOfClips != NULL)
  543. {
  544. *pCopyOfClips = *pClips;
  545. }
  546. }
  547. bool bEnteredThread = false;
  548. bool bDeletepClips = true;
  549. if(m_QuickPasteMode == ADDING_QUICK_PASTE)
  550. {
  551. //this will be added when they are done entering the quick paste text
  552. m_pQuickPasteClip = pClips;
  553. bDeletepClips = false;
  554. //go ahead and send the clips out even though it won't be added for a bit
  555. count = 1;
  556. }
  557. else
  558. {
  559. count = pClips->AddToDB(true);
  560. if(count > 0)
  561. {
  562. lID = pClips->GetTail()->m_ID;
  563. OnCopyCompleted(lID, count);
  564. if(m_CopyBuffer.Active())
  565. {
  566. m_CopyBuffer.EndCopy(lID);
  567. }
  568. }
  569. }
  570. if(count > 0)
  571. {
  572. if(g_Opt.m_lAutoSendClientCount > 0)
  573. {
  574. AfxBeginThread(SendClientThread, pCopyOfClips);
  575. bEnteredThread = true;
  576. }
  577. }
  578. if(bEnteredThread == false)
  579. delete pCopyOfClips;
  580. if(bDeletepClips)
  581. delete pClips;
  582. return lID;
  583. }
  584. void CCP_MainApp::RefreshView()
  585. {
  586. CQPasteWnd *pWnd = QPasteWnd();
  587. if(pWnd)
  588. {
  589. if(m_bAsynchronousRefreshView)
  590. pWnd->PostMessage(WM_REFRESH_VIEW);
  591. else
  592. pWnd->SendMessage(WM_REFRESH_VIEW);
  593. }
  594. }
  595. void CCP_MainApp::OnPasteCompleted()
  596. {
  597. // the list only changes if UpdateTimeOnPaste is true (updated time)
  598. if(g_Opt.m_bUpdateTimeOnPaste)
  599. RefreshView();
  600. }
  601. void CCP_MainApp::OnCopyCompleted(long lLastID, int count)
  602. {
  603. if(count <= 0)
  604. return;
  605. // queue a message to RemoveOldEntries
  606. Delayed_RemoveOldEntries(60000);
  607. // update copy statistics
  608. CGetSetOptions::SetTripCopyCount(-count);
  609. CGetSetOptions::SetTotalCopyCount(-count);
  610. RefreshView();
  611. }
  612. // Internal Clipboard for cut/copy/paste items between Groups
  613. // if NULL, this uses the current QPaste selection
  614. void CCP_MainApp::IC_Cut(ARRAY* pIDs)
  615. {
  616. if( pIDs == NULL )
  617. {
  618. if( QPasteWnd() )
  619. QPasteWnd()->m_lstHeader.GetSelectionItemData( m_IC_IDs );
  620. else
  621. m_IC_IDs.SetSize(0);
  622. }
  623. else
  624. m_IC_IDs.Copy( *pIDs );
  625. m_IC_bCopy = false;
  626. if( QPasteWnd() )
  627. QPasteWnd()->UpdateStatus();
  628. }
  629. // if NULL, this uses the current QPaste selection
  630. void CCP_MainApp::IC_Copy(ARRAY* pIDs)
  631. {
  632. if(pIDs == NULL)
  633. {
  634. if(QPasteWnd())
  635. QPasteWnd()->m_lstHeader.GetSelectionItemData(m_IC_IDs);
  636. else
  637. m_IC_IDs.SetSize(0);
  638. }
  639. else
  640. m_IC_IDs.Copy(*pIDs);
  641. m_IC_bCopy = true;
  642. if(QPasteWnd())
  643. QPasteWnd()->UpdateStatus();
  644. }
  645. void CCP_MainApp::IC_Paste()
  646. {
  647. if(m_IC_IDs.GetSize() <= 0)
  648. return;
  649. if(m_IC_bCopy)
  650. m_IC_IDs.CopyTo(GetValidGroupID());
  651. else // Move
  652. m_IC_IDs.MoveTo(GetValidGroupID());
  653. // don't process the same items twice.
  654. m_IC_IDs.SetSize(0);
  655. RefreshView();
  656. }
  657. // Groups
  658. BOOL CCP_MainApp::EnterGroupID(long lID)
  659. {
  660. BOOL bResult = FALSE;
  661. if(m_GroupID == lID)
  662. return TRUE;
  663. // if we are switching to the parent, focus on the previous group
  664. if(m_GroupParentID == lID && m_GroupID > 0)
  665. m_FocusID = m_GroupID;
  666. switch(lID)
  667. {
  668. case -1:
  669. m_FocusID = -1;
  670. m_GroupID = -1;
  671. m_GroupParentID = -1;
  672. m_GroupText = "History";
  673. bResult = TRUE;
  674. break;
  675. default: // Normal Group
  676. try
  677. {
  678. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lParentID, mText, bIsGroup FROM Main WHERE lID = %d"), lID);
  679. if(q.eof() == false)
  680. {
  681. if(q.getIntField(_T("bIsGroup")) > 0)
  682. {
  683. m_GroupID = lID;
  684. m_GroupParentID = q.getIntField(_T("lParentID"));
  685. // if( m_GroupParentID == 0 )
  686. // m_GroupParentID = -1; // back out into "all top-level groups" list.
  687. m_GroupText = q.getStringField(_T("mText"));
  688. bResult = TRUE;
  689. }
  690. }
  691. }
  692. CATCH_SQLITE_EXCEPTION
  693. break;
  694. }
  695. if(bResult)
  696. {
  697. theApp.RefreshView();
  698. if(QPasteWnd())
  699. QPasteWnd()->UpdateStatus(true);
  700. }
  701. return bResult;
  702. }
  703. // returns a usable group id (not negative)
  704. long CCP_MainApp::GetValidGroupID()
  705. {
  706. return m_GroupID;
  707. }
  708. // sets a valid id
  709. void CCP_MainApp::SetGroupDefaultID( long lID )
  710. {
  711. if( m_GroupDefaultID == lID )
  712. return;
  713. if( lID <= 0 )
  714. m_GroupDefaultID = 0;
  715. else
  716. m_GroupDefaultID = lID;
  717. if( QPasteWnd() )
  718. QPasteWnd()->UpdateStatus();
  719. }
  720. // Window States
  721. void CCP_MainApp::SetStatus( const TCHAR* status, bool bRepaintImmediately )
  722. {
  723. m_Status = status;
  724. if( QPasteWnd() )
  725. QPasteWnd()->UpdateStatus( bRepaintImmediately );
  726. }
  727. void CCP_MainApp::ShowPersistent( bool bVal )
  728. {
  729. g_Opt.SetShowPersistent( bVal );
  730. // give some visual indication
  731. if( m_bShowingQuickPaste )
  732. {
  733. ASSERT( QPasteWnd() );
  734. QPasteWnd()->SetCaptionColorActive(g_Opt.m_bShowPersistent, theApp.GetConnectCV());
  735. QPasteWnd()->RefreshNc();
  736. }
  737. }
  738. void CCP_MainApp::Delayed_RemoveOldEntries( UINT delay )
  739. {
  740. if( !m_bRemoveOldEntriesPending )
  741. {
  742. m_bRemoveOldEntriesPending = true;
  743. ((CMainFrame*)theApp.m_pMainWnd)->SetTimer( REMOVE_OLD_ENTRIES_TIMER, delay, 0 );
  744. }
  745. }
  746. /////////////////////////////////////////////////////////////////////////////
  747. // CCP_MainApp message handlers
  748. int CCP_MainApp::ExitInstance()
  749. {
  750. Log(_T("ExitInstance"));
  751. m_db.close();
  752. // if(g_Opt.m_bU3)
  753. // {
  754. // if(g_Opt.IsU3DeviceAvailable())
  755. // {
  756. // CopyUpDatabase();
  757. // }
  758. // else
  759. // {
  760. // Log(_T("Needed to copy up database but device was not available to copy to"));
  761. // }
  762. // }
  763. return CWinApp::ExitInstance();
  764. }
  765. // return TRUE if there is more idle processing to do
  766. BOOL CCP_MainApp::OnIdle(LONG lCount)
  767. {
  768. // let winapp handle its idle processing
  769. if( CWinApp::OnIdle(lCount) )
  770. return TRUE;
  771. return FALSE;
  772. }
  773. CString CCP_MainApp::GetTargetName()
  774. {
  775. TCHAR cWindowText[200];
  776. HWND hParent = m_hTargetWnd;
  777. ::GetWindowText(hParent, cWindowText, 100);
  778. int nCount = 0;
  779. while(STRLEN(cWindowText) <= 0)
  780. {
  781. hParent = ::GetParent(hParent);
  782. if(hParent == NULL)
  783. break;
  784. ::GetWindowText(hParent, cWindowText, 100);
  785. nCount++;
  786. if(nCount > 100)
  787. {
  788. Log(_T("GetTargetName reached maximum search depth of 100"));
  789. break;
  790. }
  791. }
  792. return cWindowText;
  793. }
  794. void CCP_MainApp::SetConnectCV(bool bConnect)
  795. {
  796. m_CopyThread.SetConnectCV(bConnect);
  797. if(bConnect)
  798. m_pMainFrame->m_TrayIcon.SetIcon(IDR_MAINFRAME);
  799. else
  800. m_pMainFrame->m_TrayIcon.SetIcon(IDI_DITTO_NOCOPYCB);
  801. if(QPasteWnd())
  802. {
  803. QPasteWnd()->SetCaptionColorActive(g_Opt.m_bShowPersistent, theApp.GetConnectCV());
  804. QPasteWnd()->RefreshNc();
  805. }
  806. }
  807. void CCP_MainApp::OnDeleteID(long lID)
  808. {
  809. if(QPasteWnd())
  810. {
  811. QPasteWnd()->PostMessage(NM_ITEM_DELETED, lID, 0);
  812. }
  813. }
  814. bool CCP_MainApp::ImportClips(HWND hWnd)
  815. {
  816. OPENFILENAME FileName;
  817. TCHAR szFileName[400];
  818. TCHAR szDir[400];
  819. memset(&FileName, 0, sizeof(FileName));
  820. memset(szFileName, 0, sizeof(szFileName));
  821. memset(&szDir, 0, sizeof(szDir));
  822. CString csInitialDir = CGetSetOptions::GetLastImportDir();
  823. STRCPY(szDir, csInitialDir);
  824. FileName.lStructSize = sizeof(FileName);
  825. FileName.lpstrTitle = _T("Import Clips");
  826. FileName.Flags = OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST;
  827. FileName.nMaxFile = 400;
  828. FileName.lpstrFile = szFileName;
  829. FileName.lpstrInitialDir = szDir;
  830. FileName.lpstrFilter = _T("Exported Ditto Clips (.dto)\0*.dto\0\0");
  831. FileName.lpstrDefExt = _T("dto");
  832. if(GetOpenFileName(&FileName) == 0)
  833. return false;
  834. using namespace nsPath;
  835. CPath path(FileName.lpstrFile);
  836. CString csPath = path.GetPath();
  837. CGetSetOptions::SetLastImportDir(csPath);
  838. try
  839. {
  840. CppSQLite3DB db;
  841. db.open(FileName.lpstrFile);
  842. CClip_ImportExport clip;
  843. if(clip.ImportFromSqliteDB(db, true, false))
  844. {
  845. CShowMainFrame Show;
  846. CString cs;
  847. cs.Format(_T("%s %d "), theApp.m_Language.GetString("Import_Successfully", "Successfully imported"), clip.m_lImportCount);
  848. if(clip.m_lImportCount = 1)
  849. cs += theApp.m_Language.GetString("Clip", "clip");
  850. else
  851. cs += theApp.m_Language.GetString("Clips", "clips");
  852. MessageBox(hWnd, cs, _T("Ditto"), MB_OK);
  853. }
  854. else
  855. {
  856. CShowMainFrame Show;
  857. MessageBox(hWnd, theApp.m_Language.GetString("Error_Importing", "Error importing exported clip"), _T("Ditto"), MB_OK);
  858. }
  859. }
  860. catch (CppSQLite3Exception& e)
  861. {
  862. ASSERT(FALSE);
  863. CString csError;
  864. csError.Format(_T("%s - Exception - %d - %s"), theApp.m_Language.GetString("Error_Parsing", "Error parsing exported clip"), e.errorCode(), e.errorMessage());
  865. MessageBox(hWnd, csError, _T("Ditto"), MB_OK);
  866. }
  867. return true;
  868. }
  869. void CCP_MainApp::ShowCommandLineError(CString csTitle, CString csMessage)
  870. {
  871. Log(StrF(_T("ShowCommandLineError %s - %s"), csTitle, csMessage));
  872. CToolTipEx *pErrorWnd = new CToolTipEx;
  873. pErrorWnd->Create(NULL);
  874. pErrorWnd->SetToolTipText(csTitle + "\n\n" + csMessage);
  875. CPoint pt;
  876. CRect rcScreen;
  877. GetMonitorRect(0, &rcScreen);
  878. pt = rcScreen.BottomRight();
  879. CRect cr = pErrorWnd->GetBoundsRect();
  880. pt.x -= max(cr.Width()+50, 150);
  881. pt.y -= max(cr.Height()+50, 150);
  882. pErrorWnd->Show(pt);
  883. Sleep(4000);
  884. pErrorWnd->DestroyWindow();
  885. }
  886. BOOL CCP_MainApp::GetClipData(long lID, CClipFormat &Clip)
  887. {
  888. BOOL bRet = FALSE;
  889. try
  890. {
  891. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT ooData FROM Data WHERE lParentID = %d AND strClipboardFormat = '%s'"), lID, GetFormatName(Clip.m_cfType));
  892. if(q.eof() == false)
  893. {
  894. int nDataLen = 0;
  895. const unsigned char *cData = q.getBlobField(_T("ooData"), nDataLen);
  896. if(cData != NULL)
  897. {
  898. Clip.m_hgData = NewGlobal(nDataLen);
  899. ::CopyToGlobalHP(Clip.m_hgData, (LPVOID)cData, nDataLen);
  900. bRet = TRUE;
  901. }
  902. }
  903. }
  904. CATCH_SQLITE_EXCEPTION
  905. return bRet;
  906. }
  907. bool CCP_MainApp::EditItems(CClipIDs &Ids, bool bShowError)
  908. {
  909. m_pMainFrame->ShowEditWnd(Ids);
  910. return true;
  911. }
  912. int CCP_MainApp::ShowOptionsDlg()
  913. {
  914. static bool bShowingOptions = false;
  915. int nRet = IDABORT;
  916. if(bShowingOptions == false)
  917. {
  918. bShowingOptions = true;
  919. CShowMainFrame Show;
  920. COptionsSheet Sheet(_T(""), m_pMainFrame);
  921. int nRet = Sheet.DoModal();
  922. if(nRet == IDOK)
  923. {
  924. m_pMainFrame->QuickPaste.ShowQPasteWnd(m_pMainFrame, false, false, TRUE);
  925. }
  926. bShowingOptions = false;
  927. }
  928. return nRet;
  929. }
  930. void CCP_MainApp::PumpMessageEx()
  931. {
  932. MSG KeyboardMsg;
  933. while (::PeekMessage(&KeyboardMsg, NULL, 0, 0, PM_REMOVE))
  934. {
  935. ::TranslateMessage(&KeyboardMsg);
  936. ::DispatchMessage(&KeyboardMsg);
  937. }
  938. }
  939. HWND CCP_MainApp::QPastehWnd()
  940. {
  941. if(m_pMainFrame != NULL)
  942. {
  943. if(m_pMainFrame->QuickPaste.m_pwndPaste != NULL)
  944. {
  945. return m_pMainFrame->QuickPaste.m_pwndPaste->GetSafeHwnd();
  946. }
  947. }
  948. return NULL;
  949. }