Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

509 lines
11 KiB

  1. // ProgView.cpp : Implementation of CProgView
  2. #include "stdafx.h"
  3. #include <commctrl.h>
  4. #include "CompatUI.h"
  5. #include "ProgView.h"
  6. /////////////////////////////////////////////////////////////////////////////
  7. // CProgView
  8. HRESULT
  9. CProgView::InPlaceActivate(
  10. LONG iVerb,
  11. const RECT* prcPosRect
  12. )
  13. {
  14. HRESULT hr = CComCompositeControl<CProgView>::InPlaceActivate(iVerb, prcPosRect);
  15. /*
  16. //
  17. // this code below might be useful in order to deal with accelerators
  18. // but ie host does not appear to be paying any attention
  19. //
  20. CComPtr<IOleControlSite> spCtlSite;
  21. HRESULT hRet = InternalGetSite(IID_IOleControlSite, (void**)&spCtlSite);
  22. if (SUCCEEDED(hRet)) {
  23. spCtlSite->OnControlInfoChanged();
  24. }
  25. */
  26. return hr;
  27. }
  28. LRESULT
  29. CProgView::OnNotifyListView(
  30. int idCtrl,
  31. LPNMHDR pnmh,
  32. BOOL& bHandled
  33. )
  34. {
  35. if (idCtrl != IDC_LISTPROGRAMS) {
  36. bHandled = FALSE;
  37. return 0;
  38. }
  39. // see that we get the notification to fill-in the details
  40. return NotifyProgramList(m_pProgramList, pnmh, bHandled);
  41. }
  42. LRESULT
  43. CProgView::OnDblclkListprograms(
  44. int idCtrl,
  45. LPNMHDR pnmh,
  46. BOOL& bHandled)
  47. {
  48. LPNMITEMACTIVATE lpnmh;
  49. if (idCtrl != IDC_LISTPROGRAMS) {
  50. bHandled = FALSE;
  51. return 0;
  52. }
  53. // we have a double-click !
  54. lpnmh = (LPNMITEMACTIVATE)pnmh;
  55. Fire_DblClk((LONG)lpnmh->uKeyFlags);
  56. bHandled = TRUE;
  57. return 0;
  58. }
  59. STDMETHODIMP CProgView::GetSelectedItem()
  60. {
  61. GetProgramListSelection(m_pProgramList);
  62. return S_OK;
  63. }
  64. STDMETHODIMP CProgView::get_SelectionName(VARIANT*pVal)
  65. {
  66. GetProgramListSelectionDetails(m_pProgramList, 0, pVal);
  67. return S_OK;
  68. }
  69. STDMETHODIMP CProgView::GetSelectionInformation(LONG lInformationClass, VARIANT *pVal)
  70. {
  71. GetProgramListSelectionDetails(m_pProgramList, lInformationClass, pVal);
  72. return S_OK;
  73. }
  74. VOID
  75. CProgView::ShowProgressWindows(BOOL bProgress)
  76. {
  77. HDWP hDefer = ::BeginDeferWindowPos(4);
  78. DWORD dwProgressFlag = bProgress ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  79. DWORD dwListFlag = bProgress ? SWP_HIDEWINDOW : SWP_SHOWWINDOW;
  80. hDefer = ::DeferWindowPos(hDefer, GetDlgItem(IDC_ANIMATEFIND), NULL,
  81. 0, 0, 0, 0,
  82. SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|dwProgressFlag);
  83. hDefer = ::DeferWindowPos(hDefer, GetDlgItem(IDC_STATUSLINE1), NULL,
  84. 0, 0, 0, 0,
  85. SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|dwProgressFlag);
  86. hDefer = ::DeferWindowPos(hDefer, GetDlgItem(IDC_STATUSLINE2), NULL,
  87. 0, 0, 0, 0,
  88. SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|dwProgressFlag);
  89. hDefer = ::DeferWindowPos(hDefer, GetDlgItem(IDC_LISTPROGRAMS), NULL,
  90. 0, 0, 0, 0,
  91. SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|dwListFlag);
  92. EndDeferWindowPos(hDefer);
  93. }
  94. STDMETHODIMP CProgView::PopulateList()
  95. {
  96. HANDLE hThread;
  97. ResetEvent(m_hEventCancel);
  98. ResetEvent(m_hEventCmd);
  99. if (!m_bInPlaceActive) {
  100. InPlaceActivate(OLEIVERB_INPLACEACTIVATE);
  101. }
  102. if (m_hThreadPopulate == NULL) {
  103. m_hThreadPopulate = CreateThread(NULL, 0, _PopulateThreadProc, (LPVOID)this, 0, NULL);
  104. }
  105. if (m_hThreadPopulate != NULL && !IsScanInProgress()) {
  106. m_nCmdPopulate = CMD_SCAN;
  107. SetEvent(m_hEventCmd);
  108. }
  109. return S_OK;
  110. }
  111. BOOL CProgView::PopulateListInternal()
  112. {
  113. if (InterlockedCompareExchange(&m_PopulateInProgress, TRUE, FALSE) == TRUE) {
  114. //
  115. // populate in progress -- quit
  116. //
  117. return FALSE;
  118. }
  119. if (m_pProgramList != NULL) {
  120. CleanupProgramList(m_pProgramList);
  121. m_pProgramList = NULL;
  122. }
  123. ShowProgressWindows(TRUE);
  124. Animate_OpenEx(GetDlgItem(IDC_ANIMATEFIND), _Module.GetModuleInstance(), MAKEINTRESOURCE(IDA_FINDANIM));
  125. Animate_Play(GetDlgItem(IDC_ANIMATEFIND), 0, -1, -1);
  126. PostMessage(WM_VIEW_CHANGED);
  127. // FireViewChange();
  128. // if (m_bInPlaceActive) {
  129. /* HCURSOR hcWait = (HCURSOR)::LoadImage(NULL,
  130. MAKEINTRESOURCE(IDC_WAIT),
  131. IMAGE_CURSOR,
  132. 0, 0,
  133. LR_DEFAULTSIZE|LR_SHARED);
  134. // HCURSOR hcWait = ::LoadCursor(_Module.GetResourceInstance(),
  135. // MAKEINTRESOURCE(IDC_WAIT));
  136. HCURSOR hcSave = SetCursor(hcWait);
  137. */
  138. //
  139. // malloc used on this thread should NOT be used on UI thread
  140. //
  141. InitializeProgramList(&m_pProgramList, GetDlgItem(IDC_LISTPROGRAMS));
  142. PopulateProgramList(m_pProgramList, this, m_hEventCancel);
  143. // SetCursor(hcSave);
  144. Animate_Stop(GetDlgItem(IDC_ANIMATEFIND));
  145. Animate_Close(GetDlgItem(IDC_ANIMATEFIND));
  146. ShowProgressWindows();
  147. InterlockedCompareExchange(&m_PopulateInProgress, FALSE, TRUE);
  148. PostMessage(WM_VIEW_CHANGED);
  149. PostMessage(WM_LIST_POPULATED); // we are done, signal to the main thread
  150. // FireViewChange();
  151. // } else {
  152. // m_bPendingPopulate = TRUE;
  153. // }
  154. return TRUE;
  155. }
  156. DWORD WINAPI
  157. CProgView::_PopulateThreadProc(
  158. LPVOID lpvParam
  159. )
  160. {
  161. CProgView* pProgView = (CProgView*)lpvParam;
  162. DWORD dwWait;
  163. BOOL bExit = FALSE;
  164. HRESULT hr = CoInitialize(NULL);
  165. if (!SUCCEEDED(hr)) {
  166. return FALSE;
  167. }
  168. //
  169. // keep this thread alive, block it on a command event
  170. //
  171. while(!bExit) {
  172. dwWait = WaitForSingleObject(pProgView->m_hEventCmd, INFINITE);
  173. if (dwWait != WAIT_OBJECT_0) {
  174. break; // get out, we are being killed
  175. }
  176. //
  177. // get the command
  178. //
  179. switch(pProgView->m_nCmdPopulate) {
  180. case CMD_NONE:
  181. break;
  182. case CMD_EXIT:
  183. bExit = TRUE;
  184. //
  185. // intentional fall-through
  186. //
  187. case CMD_CLEANUP:
  188. if (pProgView->m_pProgramList) {
  189. CleanupProgramList(pProgView->m_pProgramList);
  190. pProgView->m_pProgramList = NULL;
  191. }
  192. break;
  193. case CMD_SCAN:
  194. pProgView->PopulateListInternal();
  195. break;
  196. }
  197. pProgView->m_nCmdPopulate = CMD_NONE;
  198. }
  199. CoUninitialize();
  200. return TRUE;
  201. }
  202. STDMETHODIMP
  203. CProgView::UpdateListItem(
  204. BSTR pTarget,
  205. VARIANT *pKeys,
  206. BOOL *pResult
  207. )
  208. {
  209. VARIANT vKeys;
  210. VariantInit(&vKeys);
  211. CComBSTR bstrKeys;
  212. HRESULT hr;
  213. if (!m_pProgramList) {
  214. return S_OK;
  215. }
  216. if (pKeys->vt == VT_NULL || pKeys->vt == VT_EMPTY) {
  217. *pResult = UpdateProgramListItem(m_pProgramList, pTarget, NULL);
  218. return S_OK;
  219. }
  220. hr = VariantChangeType(&vKeys, pKeys, 0, VT_BSTR);
  221. if (SUCCEEDED(hr)) {
  222. bstrKeys = vKeys.bstrVal;
  223. if (bstrKeys.Length()) {
  224. *pResult = UpdateProgramListItem(m_pProgramList, pTarget, bstrKeys);
  225. } else {
  226. *pResult = FALSE;
  227. }
  228. }
  229. VariantClear(&vKeys);
  230. return S_OK;
  231. }
  232. BOOL
  233. CProgView::PreTranslateAccelerator(
  234. LPMSG pMsg,
  235. HRESULT& hRet
  236. )
  237. {
  238. HWND hWndCtl;
  239. HWND hwndList = GetDlgItem(IDC_LISTPROGRAMS);
  240. hRet = S_OK;
  241. hWndCtl = ::GetFocus();
  242. if (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd) {
  243. do {
  244. hWndCtl = ::GetParent(hWndCtl);
  245. } while (::GetParent(hWndCtl) != m_hWnd);
  246. }
  247. if (hWndCtl == hwndList &&
  248. pMsg->message == WM_KEYDOWN &&
  249. (LOWORD(pMsg->wParam) == VK_RETURN ||
  250. LOWORD(pMsg->wParam) == VK_EXECUTE)) {
  251. if (ListView_GetNextItem(hwndList, -1, LVNI_SELECTED) >= 0) {
  252. Fire_DblClk(0);
  253. return TRUE;
  254. }
  255. }
  256. //
  257. // check for external accelerators because the next call is going to eat the message
  258. //
  259. if (m_ExternAccel.IsAccelKey(pMsg)) { // we do not touch external accel messages
  260. return FALSE;
  261. }
  262. return CComCompositeControl<CProgView>::PreTranslateAccelerator(pMsg, hRet);
  263. }
  264. STDMETHODIMP CProgView::CancelPopulateList()
  265. {
  266. if (m_hEventCancel && InterlockedCompareExchange(&m_PopulateInProgress, TRUE, TRUE) == TRUE) {
  267. SetEvent(m_hEventCancel);
  268. }
  269. return S_OK;
  270. }
  271. STDMETHODIMP CProgView::get_AccelCmd(LONG lCmd, BSTR *pVal)
  272. {
  273. CComBSTR bstrAccel = m_Accel.GetAccelString((WORD)lCmd).c_str();
  274. *pVal = bstrAccel.Copy();
  275. return S_OK;
  276. }
  277. STDMETHODIMP CProgView::put_AccelCmd(LONG lCmd, BSTR newVal)
  278. {
  279. m_Accel.SetAccel(newVal);
  280. return S_OK;
  281. }
  282. STDMETHODIMP CProgView::ClearAccel()
  283. {
  284. m_Accel.ClearAccel();
  285. return S_OK;
  286. }
  287. STDMETHODIMP CProgView::get_ExternAccel(BSTR *pVal)
  288. {
  289. CComBSTR bstrAccel = m_ExternAccel.GetAccelString().c_str();
  290. *pVal = bstrAccel.Copy();
  291. return S_OK;
  292. }
  293. STDMETHODIMP CProgView::put_ExternAccel(BSTR newVal)
  294. {
  295. m_ExternAccel.SetAccel(newVal);
  296. return S_OK;
  297. }
  298. STDMETHODIMP CProgView::ClearExternAccel()
  299. {
  300. m_ExternAccel.ClearAccel();
  301. return S_OK;
  302. }
  303. //
  304. // in upload.c
  305. //
  306. wstring StrUpCase(wstring& wstr);
  307. //
  308. // expand env -- lives in util.cpp
  309. // we have a bit differing implementation here
  310. //
  311. wstring
  312. ExpandEnvironmentVars(
  313. LPCTSTR lpszCmd
  314. )
  315. {
  316. DWORD dwLength;
  317. LPTSTR lpBuffer = NULL;
  318. BOOL bExpanded = FALSE;
  319. wstring strCmd;
  320. TCHAR szBuffer[MAX_PATH];
  321. if (_tcschr(lpszCmd, TEXT('%')) == NULL) {
  322. goto out;
  323. }
  324. dwLength = ExpandEnvironmentStrings(lpszCmd, NULL, 0);
  325. if (!dwLength) {
  326. goto out;
  327. }
  328. if (dwLength < CHARCOUNT(szBuffer)) {
  329. lpBuffer = szBuffer;
  330. } else {
  331. lpBuffer = new TCHAR[dwLength];
  332. if (NULL == lpBuffer) {
  333. goto out;
  334. }
  335. }
  336. dwLength = ExpandEnvironmentStrings(lpszCmd, lpBuffer, dwLength);
  337. if (!dwLength) {
  338. goto out;
  339. }
  340. strCmd = lpBuffer;
  341. bExpanded = TRUE;
  342. out:
  343. if (!bExpanded) {
  344. strCmd = lpszCmd;
  345. }
  346. if (lpBuffer && lpBuffer != szBuffer) {
  347. delete[] lpBuffer;
  348. }
  349. return strCmd;
  350. }
  351. STDMETHODIMP CProgView::put_ExcludeFiles(BSTR newVal)
  352. {
  353. // parse exclude files, put them into our blacklist
  354. wstring strFile;
  355. LPCWSTR pch = newVal;
  356. LPCWSTR pend;
  357. m_ExcludedFiles.clear();
  358. while (pch != NULL && *pch != TEXT('\0')) {
  359. pch += _tcsspn(pch, TEXT(" \t"));
  360. // begining
  361. // find the ;
  362. pend = _tcschr(pch, TEXT(';'));
  363. if (pend == NULL) {
  364. // from pch to the end
  365. strFile = pch;
  366. pch = NULL; // will bail out
  367. } else {
  368. strFile = wstring(pch, (wstring::size_type)(pend - pch));
  369. pch = pend + 1; // one past ;
  370. }
  371. // add
  372. if (strFile.length()) {
  373. strFile = ExpandEnvironmentVars(strFile.c_str());
  374. m_ExcludedFiles.insert(StrUpCase(strFile));
  375. }
  376. }
  377. return S_OK;
  378. }
  379. STDMETHODIMP CProgView::get_ExcludeFiles(BSTR* pVal)
  380. {
  381. // parse exclude files, put them into our blacklist
  382. STRSET::iterator iter;
  383. CComBSTR bstrFiles;
  384. for (iter = m_ExcludedFiles.begin(); iter != m_ExcludedFiles.end(); ++iter) {
  385. if (bstrFiles.Length()) {
  386. bstrFiles += TEXT(';');
  387. }
  388. bstrFiles += (*iter).c_str();
  389. }
  390. *pVal = bstrFiles.Copy();
  391. return S_OK;
  392. }
  393. BOOL CProgView::IsFileExcluded(LPCTSTR pszFile)
  394. {
  395. wstring strFile = pszFile;
  396. STRSET::iterator iter;
  397. iter = m_ExcludedFiles.find(StrUpCase(strFile));
  398. return iter != m_ExcludedFiles.end();
  399. }