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