ClipboardViewer.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. // ClipboardViewer.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "cp_main.h"
  5. #include "ClipboardViewer.h"
  6. #include "Misc.h"
  7. #include "shared/Tokenizer.h"
  8. #include "WildCardMatch.h"
  9. #ifdef _DEBUG
  10. #define new DEBUG_NEW
  11. #undef THIS_FILE
  12. static char THIS_FILE[] = __FILE__;
  13. #endif
  14. /////////////////////////////////////////////////////////////////////////////
  15. // CClipboardViewer
  16. CClipboardViewer::CClipboardViewer(CCopyThread* pHandler) :
  17. m_hNextClipboardViewer(0),
  18. m_bCalling_SetClipboardViewer(false),
  19. m_pHandler(pHandler),
  20. m_bPinging(false),
  21. m_bIsConnected(false),
  22. m_bConnect(false),
  23. m_dwLastCopy(0),
  24. m_connectOnStartup(true)
  25. {
  26. }
  27. CClipboardViewer::~CClipboardViewer()
  28. {
  29. }
  30. BEGIN_MESSAGE_MAP(CClipboardViewer, CWnd)
  31. //{{AFX_MSG_MAP(CClipboardViewer)
  32. ON_WM_CREATE()
  33. ON_WM_CHANGECBCHAIN()
  34. ON_WM_DRAWCLIPBOARD()
  35. ON_WM_TIMER()
  36. ON_WM_DESTROY()
  37. //}}AFX_MSG_MAP
  38. ON_MESSAGE(WM_SETCONNECT, OnSetConnect)
  39. ON_MESSAGE(WM_CLIPBOARDUPDATE, OnClipboardChange)
  40. END_MESSAGE_MAP()
  41. /////////////////////////////////////////////////////////////////////////////
  42. // CClipboardViewer message handlers
  43. void CClipboardViewer::Create()
  44. {
  45. CString strParentClass = AfxRegisterWndClass(0);
  46. CWnd::CreateEx(0, strParentClass, _T("Ditto Clipboard Viewer"), 0, -1, -1, 0, 0, 0, 0);
  47. if(m_connectOnStartup)
  48. {
  49. SetConnect(true);
  50. }
  51. }
  52. // connects as a clipboard viewer
  53. void CClipboardViewer::Connect()
  54. {
  55. Log(_T("Connect to Clipboard"));
  56. m_bCalling_SetClipboardViewer = true;
  57. bool useSetClipboardWnd = true;
  58. if(IsVista())
  59. {
  60. HMODULE hUser32 = LoadLibrary(_T("USER32.dll"));
  61. if (hUser32)
  62. {
  63. typedef BOOL (__stdcall *AddClipFormatListener)( HWND hwnd );
  64. AddClipFormatListener addListener = (AddClipFormatListener) GetProcAddress(hUser32, "AddClipboardFormatListener");
  65. if(addListener)
  66. {
  67. Log(_T("Connecting to clipboard with function AddClipboardFormatListener"));
  68. useSetClipboardWnd = false;
  69. addListener(m_hWnd);
  70. }
  71. }
  72. }
  73. if(useSetClipboardWnd)
  74. {
  75. Log(_T("Connecting to clipboard with function SetClipboardViewer"));
  76. m_hNextClipboardViewer = CWnd::SetClipboardViewer();
  77. }
  78. m_bCalling_SetClipboardViewer = false;
  79. m_bIsConnected = true;
  80. m_bConnect = true;
  81. SetEnsureConnectedTimer();
  82. }
  83. void CClipboardViewer::SetEnsureConnectedTimer()
  84. {
  85. SetTimer(TIMER_ENSURE_VIEWER_IN_CHAIN, ONE_MINUTE*5, NULL);
  86. }
  87. // disconnects as a clipboard viewer
  88. void CClipboardViewer::Disconnect(bool bSendPing)
  89. {
  90. Log(_T("Disconnect From Clipboard"));
  91. KillTimer(TIMER_ENSURE_VIEWER_IN_CHAIN);
  92. bool removeOldWay = true;
  93. if(IsVista())
  94. {
  95. HMODULE hUser32 = LoadLibrary(_T("USER32.dll"));
  96. if (hUser32)
  97. {
  98. typedef BOOL (__stdcall *RemoveClipFormatListener)( HWND hwnd );
  99. RemoveClipFormatListener removeListener = (RemoveClipFormatListener) GetProcAddress(hUser32, "RemoveClipboardFormatListener");
  100. if(removeListener)
  101. {
  102. Log(_T("Disconnecting from clipboard with function RemoveClipboardFormatListener"));
  103. removeOldWay = false;
  104. removeListener(m_hWnd);
  105. }
  106. }
  107. }
  108. if(removeOldWay)
  109. {
  110. Log(_T("Disconnecting from clipboard with function ChangeClipboardChain"));
  111. BOOL bRet = CWnd::ChangeClipboardChain(m_hNextClipboardViewer);
  112. if(!bRet)
  113. {
  114. Log(_T("Error disconnecting from clipboard"));
  115. bRet = CWnd::ChangeClipboardChain(m_hNextClipboardViewer);
  116. if(!bRet)
  117. {
  118. Log(_T("Error disconnecting from clipboard2"));
  119. }
  120. }
  121. }
  122. m_hNextClipboardViewer = 0;
  123. m_bConnect = false;
  124. m_bIsConnected = false;
  125. if(bSendPing)
  126. SendPing();
  127. }
  128. void CClipboardViewer::SendPing()
  129. {
  130. if(g_Opt.m_bEnsureConnectToClipboard)
  131. {
  132. if(OpenClipboard())
  133. {
  134. m_bPinging = true;
  135. SetClipboardData(theApp.m_PingFormat, NewGlobalP("Ditto Ping", sizeof("Ditto Ping")));
  136. SetClipboardData(theApp.m_cfIgnoreClipboard , NewGlobalP("Ignore", sizeof("Ignore")));
  137. SetTimer(TIMER_PING, 2000, NULL);
  138. CloseClipboard();
  139. }
  140. }
  141. }
  142. void CClipboardViewer::SetConnect(bool bConnect)
  143. {
  144. m_bConnect = bConnect;
  145. if(bConnect)
  146. {
  147. if(m_bIsConnected == false)
  148. {
  149. Connect();
  150. }
  151. else
  152. {
  153. SendPing();
  154. }
  155. }
  156. else
  157. {
  158. Disconnect();
  159. }
  160. }
  161. /////////////////////////////////////////////////////////////////////////////
  162. // CClipboardViewer message handlers
  163. int CClipboardViewer::OnCreate(LPCREATESTRUCT lpCreateStruct)
  164. {
  165. if(CWnd::OnCreate(lpCreateStruct) == -1)
  166. return -1;
  167. //Set up the clip board viewer
  168. if(m_connectOnStartup)
  169. {
  170. Connect();
  171. }
  172. return 0;
  173. }
  174. void CClipboardViewer::OnDestroy()
  175. {
  176. Disconnect();
  177. CWnd::OnDestroy();
  178. }
  179. void CClipboardViewer::OnChangeCbChain(HWND hWndRemove, HWND hWndAfter)
  180. {
  181. Log(_T("OnChangeCbChain"));
  182. // If the next window is closing, repair the chain.
  183. if(m_hNextClipboardViewer == hWndRemove)
  184. {
  185. m_hNextClipboardViewer = hWndAfter;
  186. }
  187. // Otherwise, pass the message to the next link.
  188. else if (m_hNextClipboardViewer != NULL)
  189. {
  190. if(m_hNextClipboardViewer != m_hWnd)
  191. {
  192. ::SendMessage(m_hNextClipboardViewer, WM_CHANGECBCHAIN, (WPARAM) hWndRemove, (LPARAM) hWndAfter);
  193. }
  194. else
  195. {
  196. m_hNextClipboardViewer = NULL;
  197. }
  198. }
  199. }
  200. LRESULT CClipboardViewer::OnClipboardChange(WPARAM wParam, LPARAM lPara)
  201. {
  202. Log(StrF(_T("OnClipboardChange - Start")));
  203. OnDrawClipboard();
  204. Log(StrF(_T("OnClipboardChange - End")));
  205. return TRUE;
  206. }
  207. //Message that the clipboard data has changed
  208. void CClipboardViewer::OnDrawClipboard()
  209. {
  210. if(::IsClipboardFormatAvailable(theApp.m_PingFormat))
  211. {
  212. m_bPinging = false;
  213. return;
  214. }
  215. // don't process the event when we first attach
  216. if(m_pHandler && !m_bCalling_SetClipboardViewer)
  217. {
  218. if(m_bIsConnected)
  219. {
  220. if(!::IsClipboardFormatAvailable(theApp.m_cfIgnoreClipboard))
  221. {
  222. if(ValidActiveWnd())
  223. {
  224. Log(StrF(_T("OnDrawClipboard:: *** SetTimer *** %d"), GetTickCount()));
  225. KillTimer(TIMER_DRAW_CLIPBOARD);
  226. SetTimer(TIMER_DRAW_CLIPBOARD, g_Opt.m_lProcessDrawClipboardDelay, NULL);
  227. }
  228. }
  229. }
  230. else
  231. {
  232. Log(_T("Not connected, ignore clipboard change"));
  233. }
  234. }
  235. // pass the event to the next Clipboard viewer in the chain
  236. if(m_hNextClipboardViewer != NULL)
  237. {
  238. if(m_hNextClipboardViewer != m_hWnd)
  239. {
  240. ::SendMessage(m_hNextClipboardViewer, WM_DRAWCLIPBOARD, 0, 0);
  241. }
  242. else
  243. {
  244. m_hNextClipboardViewer = NULL;
  245. }
  246. }
  247. }
  248. bool CClipboardViewer::ValidActiveWnd()
  249. {
  250. m_activeWindow = _T("");
  251. HWND owner = ::GetClipboardOwner();
  252. if (owner != NULL)
  253. {
  254. DWORD PID = 0;
  255. ::GetWindowThreadProcessId(owner, &PID);
  256. if (PID != 0)
  257. {
  258. m_activeWindow = GetProcessName(NULL, PID);
  259. }
  260. }
  261. //L"RuntimeBroker.exe" is what all modern apps report as
  262. if (m_activeWindow == _T(""))
  263. {
  264. HWND active = ::GetForegroundWindow();
  265. m_activeWindow = GetProcessName(active, 0);
  266. }
  267. m_activeWindow = m_activeWindow.MakeLower();
  268. CString includeApps = CGetSetOptions::GetCopyAppInclude().MakeLower();
  269. Log(StrF(_T("INCLUDE app names: %s, Active App: %s"), includeApps, m_activeWindow));
  270. bool tokenMatch = false;
  271. CTokenizer token(includeApps, CGetSetOptions::GetCopyAppSeparator());
  272. CString line;
  273. while(token.Next(line))
  274. {
  275. if(line != "")
  276. {
  277. if(CWildCardMatch::WildMatch(line, m_activeWindow, ""))
  278. {
  279. Log(StrF(_T("Inlclude app names Found Match %s - %s"), line, m_activeWindow));
  280. tokenMatch = true;
  281. break;
  282. }
  283. }
  284. }
  285. if(tokenMatch)
  286. {
  287. CString excludeApps = CGetSetOptions::GetCopyAppExclude().MakeLower();
  288. if(excludeApps != "")
  289. {
  290. Log(StrF(_T("EXCLUDE app names %s, Active App: %s"), excludeApps, m_activeWindow));
  291. CTokenizer token2(excludeApps, CGetSetOptions::GetCopyAppSeparator());
  292. CString line2;
  293. while(token2.Next(line2))
  294. {
  295. if(line2 != "")
  296. {
  297. if(CWildCardMatch::WildMatch(line2, m_activeWindow, ""))
  298. {
  299. Log(StrF(_T("Exclude app names Found Match %s - %s - NOT SAVING COPY"), line2, m_activeWindow));
  300. return false;
  301. }
  302. }
  303. }
  304. }
  305. }
  306. else
  307. {
  308. Log(StrF(_T("Didn't find a match to INCLUDE match %s, NOT SAVING COPY"), includeApps));
  309. return false;
  310. }
  311. return true;
  312. }
  313. void CClipboardViewer::OnTimer(UINT_PTR nIDEvent)
  314. {
  315. switch(nIDEvent)
  316. {
  317. case TIMER_ENSURE_VIEWER_IN_CHAIN:
  318. SendPing();
  319. break;
  320. case TIMER_DRAW_CLIPBOARD:
  321. {
  322. KillTimer(nIDEvent);
  323. DWORD dwNow = GetTickCount();
  324. if(dwNow - m_dwLastCopy > g_Opt.m_dwSaveClipDelay || m_dwLastCopy > dwNow)
  325. {
  326. if(!::IsClipboardFormatAvailable(theApp.m_cfIgnoreClipboard))
  327. {
  328. Log(StrF(_T("OnDrawClipboard::OnTimer %d"), dwNow));
  329. m_pHandler->OnClipboardChange(m_activeWindow);
  330. m_dwLastCopy = dwNow;
  331. }
  332. }
  333. else
  334. {
  335. Log(StrF(_T("Clip copy to fast difference from last copy = %d"), (dwNow - m_dwLastCopy)));
  336. }
  337. m_activeWindow = _T("");
  338. }
  339. break;
  340. case TIMER_PING:
  341. KillTimer(TIMER_PING);
  342. //If we haven't received the change clipboard message then we are disconnected
  343. //if so reconnect
  344. if(m_bPinging)
  345. {
  346. if(m_bConnect)
  347. {
  348. Log(_T("Ping Failed Reconnecting to clipboard"));
  349. Disconnect(false);
  350. Connect();
  351. }
  352. else
  353. {
  354. Log(_T("Ping Failed but Connected set to FALSE so this is ok"));
  355. }
  356. }
  357. else
  358. {
  359. if(m_bConnect)
  360. {
  361. m_bIsConnected = true;
  362. }
  363. }
  364. break;
  365. }
  366. CWnd::OnTimer(nIDEvent);
  367. }
  368. LRESULT CClipboardViewer::OnSetConnect(WPARAM wParam, LPARAM lParam)
  369. {
  370. bool bConnect = wParam == TRUE;
  371. SetConnect(bConnect);
  372. return TRUE;
  373. }