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.

463 lines
11 KiB

  1. // SelectFile.cpp : Implementation of CSelectFile
  2. #include "stdafx.h"
  3. #include "CompatUI.h"
  4. #include "SelectFile.h"
  5. #include "commdlg.h"
  6. #include "cderr.h"
  7. /////////////////////////////////////////////////////////////////////////////
  8. // CSelectFile
  9. //
  10. // in upload.c
  11. //
  12. wstring StrUpCase(wstring& wstr);
  13. STDMETHODIMP CSelectFile::get_BrowseTitle(BSTR *pVal)
  14. {
  15. *pVal = m_bstrTitle.Copy();
  16. return S_OK;
  17. }
  18. STDMETHODIMP CSelectFile::put_BrowseTitle(BSTR newVal)
  19. {
  20. m_bstrTitle = newVal;
  21. return S_OK;
  22. }
  23. STDMETHODIMP CSelectFile::get_BrowseFilter(BSTR *pVal)
  24. {
  25. *pVal = m_bstrFilter.Copy();
  26. return S_OK;
  27. }
  28. STDMETHODIMP CSelectFile::put_BrowseFilter(BSTR newVal)
  29. {
  30. m_bstrFilter = newVal;
  31. return S_OK;
  32. }
  33. STDMETHODIMP CSelectFile::get_BrowseInitialDirectory(BSTR *pVal)
  34. {
  35. *pVal = m_bstrInitialDirectory;
  36. return S_OK;
  37. }
  38. STDMETHODIMP CSelectFile::put_BrowseInitialDirectory(BSTR newVal)
  39. {
  40. m_bstrInitialDirectory = newVal;
  41. return S_OK;
  42. }
  43. STDMETHODIMP CSelectFile::get_BrowseFlags(long *pVal)
  44. {
  45. *pVal = (LONG)m_dwBrowseFlags;
  46. return S_OK;
  47. }
  48. STDMETHODIMP CSelectFile::put_BrowseFlags(long newVal)
  49. {
  50. m_dwBrowseFlags = (DWORD)newVal;
  51. return S_OK;
  52. }
  53. STDMETHODIMP CSelectFile::get_FileName(BSTR *pVal)
  54. {
  55. wstring sFileName;
  56. GetFileNameFromUI(sFileName);
  57. m_bstrFileName = sFileName.c_str();
  58. *pVal = m_bstrFileName.Copy();
  59. return S_OK;
  60. }
  61. STDMETHODIMP CSelectFile::put_FileName(BSTR newVal)
  62. {
  63. m_bstrFileName = newVal;
  64. SetDlgItemText(IDC_EDITFILENAME, m_bstrFileName);
  65. return S_OK;
  66. }
  67. STDMETHODIMP CSelectFile::get_ErrorCode(long *pVal)
  68. {
  69. *pVal = (LONG)m_dwErrorCode;
  70. return S_OK;
  71. }
  72. #define MAX_BUFFER 2048
  73. LRESULT CSelectFile::OnClickedBrowse(
  74. WORD wNotifyCode,
  75. WORD wID,
  76. HWND hWndCtl,
  77. BOOL& bHandled)
  78. {
  79. LRESULT lRes = 0;
  80. // TODO: Add your implementation code here
  81. OPENFILENAME ofn;
  82. LPTSTR pszFileName = NULL;
  83. DWORD dwFileNameLength = 0;
  84. DWORD dwLen;
  85. LPTSTR pszFilter = NULL, pch;
  86. m_dwErrorCode = 0;
  87. ZeroMemory(&ofn, sizeof(ofn));
  88. ofn.lStructSize = sizeof(ofn);
  89. ofn.hwndOwner = m_hWnd;
  90. //
  91. // part one (straight) - title
  92. //
  93. ofn.lpstrTitle = (LPCTSTR)m_bstrTitle; // assumes we're unicode (and we are)
  94. //
  95. // recover the filename from the edit box
  96. //
  97. wstring sFileName;
  98. if (GetFileNameFromUI(sFileName)) {
  99. m_bstrFileName = sFileName.c_str();
  100. }
  101. //
  102. // part two - init filename
  103. //
  104. dwFileNameLength = __max(MAX_BUFFER, m_bstrFileName.Length() * 2); // in characters
  105. pszFileName = new TCHAR[dwFileNameLength * sizeof(*pszFileName)];
  106. if (pszFileName == NULL) {
  107. m_dwErrorCode = ERROR_OUTOFMEMORY;
  108. goto HandleError;
  109. }
  110. // so we have the buffer now
  111. //
  112. if (m_bstrFileName.Length () > 0) {
  113. // sanitize the filename with regard to quotes
  114. _tcscpy(pszFileName, (LPCTSTR)m_bstrFileName); // hypocritical copy, we are unicode
  115. } else {
  116. // start with the contents of the text box then
  117. *pszFileName = TEXT('\0');
  118. }
  119. //
  120. // sanity check, if pszFileName ends with \ then we will get an error
  121. //
  122. PathRemoveBackslash(pszFileName);
  123. ofn.lpstrFile = pszFileName;
  124. ofn.nMaxFile = dwFileNameLength;
  125. //
  126. // see if we also need to process filter
  127. //
  128. if (m_bstrFilter.Length() > 0) {
  129. dwLen = m_bstrFilter.Length();
  130. pszFilter = new TCHAR[(dwLen + 2) * sizeof(*pszFilter)];
  131. if (pszFilter == NULL) {
  132. m_dwErrorCode = ERROR_OUTOFMEMORY;
  133. goto HandleError;
  134. }
  135. RtlZeroMemory(pszFilter, (dwLen + 2) * sizeof(*pszFilter));
  136. _tcscpy(pszFilter, m_bstrFilter);
  137. pch = pszFilter;
  138. while (pch) {
  139. pch = _tcschr(pch, TEXT('|'));
  140. if (pch) {
  141. *pch++ = TEXT('\0');
  142. }
  143. }
  144. // now that the replacement is done -- assign the filter string
  145. ofn.lpstrFilter = pszFilter;
  146. }
  147. //
  148. // now check whether we have some in the initial directory
  149. //
  150. if (m_bstrInitialDirectory.Length() > 0) {
  151. ofn.lpstrInitialDir = (LPCTSTR)m_bstrInitialDirectory;
  152. }
  153. //
  154. // flags
  155. //
  156. if (m_dwBrowseFlags) {
  157. ofn.Flags = m_dwBrowseFlags;
  158. } else {
  159. ofn.Flags = OFN_FILEMUSTEXIST|OFN_EXPLORER;
  160. }
  161. BOOL bRetry;
  162. BOOL bSuccess;
  163. do {
  164. bRetry = FALSE;
  165. bSuccess = GetOpenFileName(&ofn);
  166. if (!bSuccess) {
  167. m_dwErrorCode = CommDlgExtendedError();
  168. if (m_dwErrorCode == FNERR_INVALIDFILENAME) {
  169. *pszFileName = TEXT('\0');
  170. bRetry = TRUE;
  171. }
  172. }
  173. } while (bRetry);
  174. if (!bSuccess) {
  175. goto HandleError;
  176. }
  177. SetDlgItemText(IDC_EDITFILENAME, pszFileName);
  178. m_bstrFileName = (LPCTSTR)pszFileName;
  179. m_dwErrorCode = 0;
  180. HandleError:
  181. if (pszFileName != NULL) {
  182. delete[] pszFileName;
  183. }
  184. if (pszFilter != NULL) {
  185. delete[] pszFilter;
  186. }
  187. bHandled = TRUE;
  188. return lRes;
  189. }
  190. BOOL
  191. CSelectFile::PreTranslateAccelerator(
  192. LPMSG pMsg,
  193. HRESULT& hRet
  194. )
  195. {
  196. HWND hWndCtl;
  197. HWND hwndEdit = GetDlgItem(IDC_EDITFILENAME);
  198. HWND hwndBrowse = GetDlgItem(IDC_BROWSE);
  199. BSTR bstrFileName = NULL;
  200. WORD wCmd = 0;
  201. BOOL bBrowseHandled;
  202. hRet = S_OK;
  203. hWndCtl = ::GetFocus();
  204. if (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd) {
  205. do {
  206. hWndCtl = ::GetParent(hWndCtl);
  207. } while (::GetParent(hWndCtl) != m_hWnd);
  208. }
  209. if (pMsg->message == WM_KEYDOWN &&
  210. (LOWORD(pMsg->wParam) == VK_RETURN ||
  211. LOWORD(pMsg->wParam) == VK_EXECUTE)) {
  212. if (hWndCtl == hwndEdit) {
  213. BOOL bReturn;
  214. wstring sFileName;
  215. bReturn = GetFileNameFromUI(sFileName) &&
  216. ValidateExecutableFile(sFileName.c_str(), TRUE);
  217. if (bReturn) {
  218. Fire_SelectionComplete();
  219. return TRUE;
  220. }
  221. }
  222. // this either was hwndBrowse or filename was not there -- open
  223. // browse dialog then
  224. OnClickedBrowse(BN_CLICKED, IDC_BROWSE, hwndBrowse, bBrowseHandled);
  225. ::SetFocus(hwndEdit);
  226. }
  227. //
  228. // fixup external accelerators for internal controls (in this case -- edit)
  229. //
  230. if (m_Accel.IsAccelKey(pMsg, &wCmd) && wCmd == IDC_EDITFILENAME) {
  231. ::SetFocus(hwndEdit);
  232. return TRUE;
  233. }
  234. //
  235. // check for external accelerators because the next call is going to eat the message
  236. //
  237. if (m_ExternAccel.IsAccelKey(pMsg)) { // we do not touch external accel messages
  238. return FALSE;
  239. }
  240. //
  241. // check whether we are tabbing out of control
  242. //
  243. if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB) {
  244. // check whether we're tabbing out
  245. // (perhaps the control wants to eat tab?
  246. DWORD_PTR dwDlgCode = ::SendMessage(pMsg->hwnd, WM_GETDLGCODE, 0, 0);
  247. if (!(dwDlgCode & DLGC_WANTTAB)) {
  248. // control does not want a tab
  249. // see whether it's the last control and we're tabbing out
  250. HWND hwndFirst = GetNextDlgTabItem(NULL, FALSE); // first
  251. HWND hwndLast = GetNextDlgTabItem(hwndFirst, TRUE);
  252. BOOL bFirstOrLast;
  253. if (::GetKeyState(VK_SHIFT) & 0x8000) {
  254. // shift ?
  255. bFirstOrLast = (hWndCtl == hwndFirst);
  256. } else {
  257. bFirstOrLast = (hWndCtl == hwndLast);
  258. }
  259. if (bFirstOrLast) {
  260. IsDialogMessage(pMsg);
  261. return FALSE;
  262. }
  263. }
  264. }
  265. return CComCompositeControl<CSelectFile>::PreTranslateAccelerator(pMsg, hRet);
  266. }
  267. /*
  268. STDMETHODIMP CSelectFile::get_Accel(BSTR *pVal)
  269. {
  270. CComBSTR bstr = (LPCWSTR)m_Accel;
  271. *pVal = bstr.Copy();
  272. return S_OK;
  273. }
  274. STDMETHODIMP CSelectFile::put_Accel(BSTR newVal)
  275. {
  276. m_Accel = (LPCWSTR)newVal;
  277. return S_OK;
  278. }
  279. */
  280. STDMETHODIMP CSelectFile::get_ExternAccel(BSTR *pVal)
  281. {
  282. CComBSTR bstr = m_ExternAccel.GetAccelString(0).c_str();
  283. *pVal = bstr.Copy();
  284. return S_OK;
  285. }
  286. STDMETHODIMP CSelectFile::put_ExternAccel(BSTR newVal)
  287. {
  288. m_ExternAccel = (LPCWSTR)newVal;
  289. return S_OK;
  290. }
  291. static TCHAR szU[] = TEXT("<U>");
  292. static TCHAR szUC[] = TEXT("</U>");
  293. #define szU_Len (CHARCOUNT(szU) - 1)
  294. #define szUC_Len (CHARCOUNT(szUC) - 1)
  295. STDMETHODIMP CSelectFile::get_BrowseBtnCaption(BSTR *pVal)
  296. {
  297. // TODO: Add your implementation code here
  298. CComBSTR bstrCaption;
  299. wstring strCaption = m_BrowseBtnCaption;
  300. wstring::size_type nPos;
  301. nPos = m_BrowseBtnCaption.find(TEXT('&'));
  302. if (nPos == wstring::npos || nPos > m_BrowseBtnCaption.length() - 1) {
  303. bstrCaption = m_BrowseBtnCaption.c_str();
  304. } else {
  305. bstrCaption = m_BrowseBtnCaption.substr(0, nPos).c_str();
  306. bstrCaption += szU;
  307. bstrCaption += m_BrowseBtnCaption[nPos+1];
  308. bstrCaption += szUC;
  309. if (nPos < m_BrowseBtnCaption.length() - 1) {
  310. bstrCaption += m_BrowseBtnCaption.substr(nPos+2).c_str();
  311. }
  312. }
  313. *pVal = bstrCaption.Copy();
  314. return S_OK;
  315. }
  316. STDMETHODIMP CSelectFile::put_BrowseBtnCaption(BSTR newVal)
  317. {
  318. //
  319. // form a caption from the string
  320. //
  321. wstring strCaption = newVal;
  322. wstring strCaptionU = strCaption;
  323. wstring::size_type nPosU, nPosUC;
  324. wstring strAccel;
  325. StrUpCase(strCaptionU);
  326. //
  327. // find <u> </u> pair
  328. //
  329. nPosU = strCaptionU.find(szU);
  330. nPosUC = strCaptionU.find(szUC, nPosU);
  331. if (nPosUC == wstring::npos || nPosU == wstring::npos || nPosUC < nPosU || nPosUC <= (nPosU + szU_Len)) {
  332. goto cleanup;
  333. }
  334. // extract the char at the &
  335. //
  336. //
  337. strAccel = strCaption.substr(nPosU + szU_Len, nPosUC - (nPosU + szU_Len));
  338. //
  339. // add accel please -- with command id IDC_BROWSE
  340. //
  341. m_Accel.SetAccel(strAccel.c_str(), IDC_BROWSE);
  342. //
  343. // now we (presumably) found <u>accelchar</u>
  344. //
  345. m_BrowseBtnCaption = strCaption.substr(0, nPosU); // up to the <U>
  346. m_BrowseBtnCaption += TEXT('&');
  347. m_BrowseBtnCaption += strAccel.c_str();
  348. m_BrowseBtnCaption += strCaption.substr(nPosUC + szUC_Len); // all the rest please
  349. if (IsWindow()) {
  350. SetDlgItemText(IDC_BROWSE, m_BrowseBtnCaption.c_str());
  351. }
  352. cleanup:
  353. return S_OK;
  354. }
  355. STDMETHODIMP CSelectFile::get_AccelCmd(LONG lCmd, BSTR *pVal)
  356. {
  357. CComBSTR bstrVal = m_Accel.GetAccelString((WORD)lCmd).c_str();
  358. *pVal = bstrVal.Copy();
  359. return S_OK;
  360. }
  361. STDMETHODIMP CSelectFile::put_AccelCmd(LONG lCmd, BSTR newVal)
  362. {
  363. m_Accel.SetAccel(newVal, (WORD)lCmd);
  364. return S_OK;
  365. }
  366. STDMETHODIMP CSelectFile::ClearAccel()
  367. {
  368. m_Accel.ClearAccel();
  369. return S_OK;
  370. }
  371. STDMETHODIMP CSelectFile::ClearExternAccel()
  372. {
  373. m_ExternAccel.ClearAccel();
  374. return S_OK;
  375. }