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.

469 lines
14 KiB

  1. // SelectFile.h : Declaration of the CSelectFile
  2. #ifndef __SELECTFILE_H_
  3. #define __SELECTFILE_H_
  4. #include "resource.h" // main symbols
  5. #include <atlctl.h>
  6. #include "compatuiCP.h"
  7. extern "C" {
  8. #include "shimdb.h"
  9. }
  10. #pragma warning(disable:4786)
  11. #include <string>
  12. #include <xstring>
  13. #include <map>
  14. #include <locale>
  15. #include <algorithm>
  16. #include <vector>
  17. using namespace std;
  18. //
  19. // Accel containment code
  20. //
  21. #include "AccelContainer.h"
  22. //
  23. // in ProgList.cpp
  24. //
  25. BOOL
  26. ValidateExecutableFile(
  27. LPCTSTR pszPath,
  28. BOOL bValidateFileExists
  29. );
  30. //
  31. // in util.cpp
  32. //
  33. wstring
  34. ShimUnquotePath(
  35. LPCTSTR pwszFileName
  36. );
  37. /////////////////////////////////////////////////////////////////////////////
  38. // CSelectFile
  39. class ATL_NO_VTABLE CSelectFile :
  40. public CComObjectRootEx<CComSingleThreadModel>,
  41. public CStockPropImpl<CSelectFile, ISelectFile, &IID_ISelectFile, &LIBID_COMPATUILib>,
  42. public CComCompositeControl<CSelectFile>,
  43. public IPersistStreamInitImpl<CSelectFile>,
  44. public IOleControlImpl<CSelectFile>,
  45. public IOleObjectImpl<CSelectFile>,
  46. public IOleInPlaceActiveObjectImpl<CSelectFile>,
  47. public IViewObjectExImpl<CSelectFile>,
  48. public IOleInPlaceObjectWindowlessImpl<CSelectFile>,
  49. public CComCoClass<CSelectFile, &CLSID_SelectFile>,
  50. public ISupportErrorInfo,
  51. public IPersistPropertyBagImpl<CSelectFile>,
  52. public IConnectionPointContainerImpl<CSelectFile>,
  53. public CProxy_ISelectFileEvents< CSelectFile >,
  54. public IPropertyNotifySinkCP< CSelectFile >,
  55. public IProvideClassInfo2Impl<&CLSID_SelectFile, &DIID__ISelectFileEvents, &LIBID_COMPATUILib>,
  56. public CProxy_IProgViewEvents< CSelectFile >
  57. {
  58. public:
  59. CSelectFile() :
  60. m_dwBrowseFlags(0)
  61. {
  62. m_bWindowOnly = TRUE;
  63. m_bTabStop = TRUE;
  64. m_bMouseActivate = FALSE;
  65. CalcExtent(m_sizeExtent);
  66. }
  67. DECLARE_REGISTRY_RESOURCEID(IDR_SELECTFILE)
  68. DECLARE_PROTECT_FINAL_CONSTRUCT()
  69. BEGIN_COM_MAP(CSelectFile)
  70. COM_INTERFACE_ENTRY(ISelectFile)
  71. COM_INTERFACE_ENTRY(IDispatch)
  72. COM_INTERFACE_ENTRY(IViewObjectEx)
  73. COM_INTERFACE_ENTRY(IViewObject2)
  74. COM_INTERFACE_ENTRY(IViewObject)
  75. COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
  76. COM_INTERFACE_ENTRY(IOleInPlaceObject)
  77. COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
  78. COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
  79. COM_INTERFACE_ENTRY(IOleControl)
  80. COM_INTERFACE_ENTRY(IOleObject)
  81. COM_INTERFACE_ENTRY(IPersistStreamInit)
  82. COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
  83. // COM_INTERFACE_ENTRY(ISupportErrorInfo)
  84. // COM_INTERFACE_ENTRY(IConnectionPointContainer)
  85. COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
  86. COM_INTERFACE_ENTRY(IProvideClassInfo2)
  87. COM_INTERFACE_ENTRY(IProvideClassInfo)
  88. COM_INTERFACE_ENTRY(IPersistPropertyBag)
  89. END_COM_MAP()
  90. BEGIN_PROP_MAP(CSelectFile)
  91. PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
  92. PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
  93. PROP_ENTRY("BackColor", DISPID_BACKCOLOR, CLSID_StockColorPage)
  94. PROP_ENTRY("BackStyle", DISPID_BACKSTYLE, CLSID_NULL)
  95. // PROP_ENTRY("BorderColor", DISPID_BORDERCOLOR, CLSID_StockColorPage)
  96. // PROP_ENTRY("BorderVisible", DISPID_BORDERVISIBLE, CLSID_NULL)
  97. PROP_ENTRY("Enabled", DISPID_ENABLED, CLSID_NULL)
  98. // Example entries
  99. // PROP_ENTRY("Property Description", dispid, clsid)
  100. // PROP_PAGE(CLSID_StockColorPage)
  101. PROP_ENTRY("Accel", 7, CLSID_NULL)
  102. PROP_ENTRY("ExternAccel", 8, CLSID_NULL)
  103. PROP_ENTRY("BrowseBtnCaption", 9, CLSID_NULL)
  104. END_PROP_MAP()
  105. BEGIN_CONNECTION_POINT_MAP(CSelectFile)
  106. CONNECTION_POINT_ENTRY(DIID__ISelectFileEvents)
  107. // CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
  108. CONNECTION_POINT_ENTRY(DIID__IProgViewEvents)
  109. END_CONNECTION_POINT_MAP()
  110. BEGIN_MSG_MAP(CSelectFile)
  111. COMMAND_HANDLER(IDC_BROWSE, BN_CLICKED, OnClickedBrowse)
  112. // MESSAGE_HANDLER(WM_CTLCOLORDLG, OnColorDlg)
  113. // MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorDlg)
  114. MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  115. MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
  116. MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
  117. CHAIN_MSG_MAP(CComCompositeControl<CSelectFile>)
  118. // ALT_MSG_MAP(1)
  119. END_MSG_MAP()
  120. // Handler prototypes:
  121. // LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
  122. // LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
  123. // LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
  124. BEGIN_SINK_MAP(CSelectFile)
  125. //Make sure the Event Handlers have __stdcall calling convention
  126. END_SINK_MAP()
  127. STDMETHOD(OnAmbientPropertyChange)(DISPID dispid)
  128. {
  129. if (dispid == DISPID_AMBIENT_BACKCOLOR)
  130. {
  131. SetBackgroundColorFromAmbient();
  132. FireViewChange();
  133. }
  134. return IOleControlImpl<CSelectFile>::OnAmbientPropertyChange(dispid);
  135. }
  136. HRESULT FireOnChanged(DISPID dispID) {
  137. if (dispID == DISPID_ENABLED) {
  138. ::EnableWindow(GetDlgItem(IDC_EDITFILENAME), m_bEnabled);
  139. ::EnableWindow(GetDlgItem(IDC_BROWSE), m_bEnabled);
  140. }
  141. return S_OK;
  142. }
  143. STDMETHOD(GetControlInfo)(CONTROLINFO* pCI) {
  144. if (NULL == pCI) {
  145. return E_POINTER;
  146. }
  147. pCI->hAccel = NULL;
  148. pCI->cAccel = 0;
  149. pCI->dwFlags = 0;
  150. return S_OK;
  151. }
  152. // ISupportsErrorInfo
  153. STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
  154. {
  155. static const IID* arr[] =
  156. {
  157. &IID_ISelectFile,
  158. };
  159. for (int i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
  160. {
  161. if (InlineIsEqualGUID(*arr[i], riid))
  162. return S_OK;
  163. }
  164. return S_FALSE;
  165. }
  166. STDMETHOD(SetExtent)(DWORD dwDrawAspect, SIZEL* psizel) {
  167. HRESULT hr = IOleObjectImpl<CSelectFile>::SetExtent(dwDrawAspect, psizel);
  168. PositionControls();
  169. return hr;
  170. }
  171. STDMETHOD(SetObjectRects)(LPCRECT prcPos, LPCRECT prcClip) {
  172. IOleInPlaceObjectWindowlessImpl<CSelectFile>::SetObjectRects(prcPos, prcClip);
  173. PositionControls(prcPos);
  174. return S_OK;
  175. }
  176. HRESULT InPlaceActivate(LONG iVerb, const RECT* prcPosRect = NULL) {
  177. HRESULT hr = CComCompositeControl<CSelectFile>::InPlaceActivate(iVerb, prcPosRect);
  178. Fire_StateChanged(iVerb);
  179. return hr;
  180. }
  181. STDMETHOD(UIDeactivate)() {
  182. HRESULT hr = IOleInPlaceObjectWindowlessImpl<CSelectFile>::UIDeactivate();
  183. //
  184. // We are being deactivated
  185. // when we loose focus, nuke default button out of here
  186. //
  187. DWORD dwDefBtn = (DWORD)SendMessage(DM_GETDEFID, 0);
  188. if (HIWORD(dwDefBtn) == DC_HASDEFID) {
  189. // SendMessage(DM_SETDEFID, IDC_EDITFILENAME); // basically forget the default button
  190. dwDefBtn = LOWORD(dwDefBtn);
  191. DWORD dwStyle = ::GetWindowLong(GetDlgItem(dwDefBtn), GWL_STYLE);
  192. if (dwStyle & BS_DEFPUSHBUTTON) {
  193. dwStyle &= ~BS_DEFPUSHBUTTON;
  194. dwStyle |= BS_PUSHBUTTON;
  195. SendDlgItemMessage(dwDefBtn, BM_SETSTYLE, dwStyle, TRUE);
  196. }
  197. }
  198. // send killfocus
  199. SendMessage(WM_KILLFOCUS);
  200. return hr;
  201. }
  202. LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  203. {
  204. // Manually activate the control
  205. LRESULT lRes = CComCompositeControl<CSelectFile>::OnMouseActivate(uMsg, wParam, lParam, bHandled);
  206. m_bMouseActivate = TRUE;
  207. return 0;
  208. }
  209. BOOL PreTranslateAccelerator(LPMSG pMsg, HRESULT& hrRet);
  210. // IViewObjectEx
  211. DECLARE_VIEW_STATUS(0)
  212. // ISelectFile
  213. public:
  214. STDMETHOD(ClearAccel)();
  215. STDMETHOD(ClearExternAccel)();
  216. STDMETHOD(get_AccelCmd)(/*[in]*/ LONG lCmd, /*[out, retval]*/ BSTR *pVal);
  217. STDMETHOD(put_AccelCmd)(/*[in]*/ LONG lCmd, /*[in]*/ BSTR newVal);
  218. STDMETHOD(get_BrowseBtnCaption)(/*[out, retval]*/ BSTR *pVal);
  219. STDMETHOD(put_BrowseBtnCaption)(/*[in]*/ BSTR newVal);
  220. STDMETHOD(get_ExternAccel)(/*[out, retval]*/ BSTR *pVal);
  221. STDMETHOD(put_ExternAccel)(/*[in]*/ BSTR newVal);
  222. #if 0
  223. STDMETHOD(get_Accel)(/*[out, retval]*/ BSTR *pVal);
  224. STDMETHOD(put_Accel)(/*[in]*/ BSTR newVal);
  225. #endif
  226. STDMETHOD(get_ErrorCode)(/*[out, retval]*/ long *pVal);
  227. STDMETHOD(get_FileName)(/*[out, retval]*/ BSTR *pVal);
  228. STDMETHOD(put_FileName)(/*[in]*/ BSTR newVal);
  229. STDMETHOD(get_BrowseFlags)(/*[out, retval]*/ long *pVal);
  230. STDMETHOD(put_BrowseFlags)(/*[in]*/ long newVal);
  231. STDMETHOD(get_BrowseInitialDirectory)(/*[out, retval]*/ BSTR *pVal);
  232. STDMETHOD(put_BrowseInitialDirectory)(/*[in]*/ BSTR newVal);
  233. STDMETHOD(get_BrowseFilter)(/*[out, retval]*/ BSTR *pVal);
  234. STDMETHOD(put_BrowseFilter)(/*[in]*/ BSTR newVal);
  235. STDMETHOD(get_BrowseTitle)(/*[out, retval]*/ BSTR *pVal);
  236. STDMETHOD(put_BrowseTitle)(/*[in]*/ BSTR newVal);
  237. OLE_COLOR m_clrBackColor;
  238. LONG m_nBackStyle;
  239. OLE_COLOR m_clrBorderColor;
  240. BOOL m_bBorderVisible;
  241. BOOL m_bEnabled;
  242. // browse dialog props
  243. CComBSTR m_bstrTitle;
  244. CComBSTR m_bstrFilter;
  245. CComBSTR m_bstrInitialDirectory;
  246. CComBSTR m_bstrFileName;
  247. DWORD m_dwBrowseFlags;
  248. DWORD m_dwErrorCode;
  249. wstring m_BrowseBtnCaption;
  250. BOOL m_bMouseActivate;
  251. enum { IDD = IDD_SELECTFILE };
  252. LRESULT OnClickedBrowse(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
  253. protected:
  254. VOID PositionControls(LPCRECT lprc = NULL) {
  255. if (NULL == lprc) {
  256. lprc = &m_rcPos;
  257. }
  258. if (IsWindow()) {
  259. // position the edit ctl first
  260. HDWP hdwp = BeginDeferWindowPos(2);
  261. HWND hedit = GetDlgItem(IDC_EDITFILENAME);
  262. HWND hbtn = GetDlgItem(IDC_BROWSE);
  263. LONG lWidthEdit;
  264. LONG lWidthBtn;
  265. RECT rcBtn;
  266. RECT rcEdit;
  267. LONG lSpace = ::GetSystemMetrics(SM_CXFRAME);
  268. ::GetWindowRect(hbtn, &rcBtn); // get the rectangle for the button
  269. ::GetWindowRect(hedit, &rcEdit);
  270. lWidthBtn = rcBtn.right - rcBtn.left; // width of the button - 1
  271. lWidthEdit = lprc->right - lprc->left - lSpace - lWidthBtn;
  272. hdwp = ::DeferWindowPos(hdwp, hedit, NULL, 0, 0, lWidthEdit, rcEdit.bottom - rcEdit.top, SWP_NOZORDER);
  273. hdwp = ::DeferWindowPos(hdwp, hbtn, NULL, lWidthEdit + lSpace, 0, lWidthBtn, rcBtn.bottom - rcBtn.top, SWP_NOZORDER);
  274. ::EndDeferWindowPos(hdwp);
  275. }
  276. }
  277. LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  278. WORD wCmd = 0;
  279. //
  280. // determine whether we came here with accel
  281. //
  282. CComCompositeControl<CSelectFile>::OnSetFocus(uMsg, wParam, lParam, bHandled);
  283. if (!m_bMouseActivate) {
  284. DoVerbUIActivate(&m_rcPos, NULL);
  285. if (m_Accel.IsAccelKey(NULL, &wCmd)) {
  286. //
  287. // we are to be accelerated
  288. // we look into the accel cmd to see what is there
  289. //
  290. switch(wCmd) {
  291. case IDC_BROWSE:
  292. ::SetFocus(GetDlgItem(IDC_BROWSE));
  293. OnClickedBrowse(BN_CLICKED, IDC_BROWSE, GetDlgItem(IDC_BROWSE), bHandled);
  294. break;
  295. case IDC_EDITFILENAME:
  296. ::SetFocus(GetDlgItem(IDC_EDITFILENAME));
  297. break;
  298. }
  299. }
  300. //
  301. // did we arrive here with the tab?
  302. //
  303. if (!IsChild(GetFocus())) {
  304. if (GetKeyState(VK_TAB) & 0x8000) { // was that the tab key ?
  305. HWND hwndFirst = GetNextDlgTabItem(NULL, FALSE); // first
  306. HWND hwndLast = GetNextDlgTabItem(hwndFirst, TRUE);
  307. if ((GetKeyState(VK_SHIFT) & 0x8000)) {
  308. // aha, came here with a shift-tab! -- what is the last control ?
  309. ::SetFocus(hwndLast);
  310. } else {
  311. ::SetFocus(hwndFirst);
  312. }
  313. } else {
  314. ::SetFocus(GetDlgItem(IDC_EDITFILENAME));
  315. }
  316. }
  317. }
  318. //
  319. // set the default pushbutton
  320. //
  321. SendMessage(DM_SETDEFID, IDC_BROWSE);
  322. SendDlgItemMessage(IDC_BROWSE, BM_SETSTYLE, BS_DEFPUSHBUTTON);
  323. m_bMouseActivate = FALSE;
  324. bHandled = TRUE;
  325. return 0;
  326. }
  327. LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  328. {
  329. /* // this code sets the same font as the container is using
  330. // we do not care for now, we're using MS Shell Dlg instead
  331. CComVariant varFont;
  332. HFONT hFont;
  333. HWND hwnd;
  334. HRESULT hr = GetAmbientProperty(DISPID_AMBIENT_FONT, varFont);
  335. if (SUCCEEDED(hr)) {
  336. CComQIPtr<IFont, &IID_IFont> pFont (varFont.pdispVal);
  337. if (SUCCEEDED(pFont->get_hFont(&hFont))) {
  338. for (hwnd = GetTopWindow(); hwnd != NULL;
  339. hwnd = ::GetNextWindow(hwnd, GW_HWNDNEXT)) {
  340. ::SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
  341. }
  342. }
  343. }
  344. */
  345. SHAutoComplete(GetDlgItem(IDC_EDITFILENAME), SHACF_FILESYSTEM);
  346. if (m_BrowseBtnCaption.length()) {
  347. SetDlgItemText(IDC_BROWSE, m_BrowseBtnCaption.c_str());
  348. }
  349. //
  350. // show ui hints
  351. //
  352. SendMessage(WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEACCEL | UISF_HIDEFOCUS));
  353. return 0;
  354. }
  355. //
  356. // Accelerators
  357. //
  358. CAccelContainer m_Accel;
  359. CAccelContainer m_ExternAccel;
  360. BOOL GetFileNameFromUI(wstring& sFileName) {
  361. BSTR bstrFileName = NULL;
  362. BOOL bReturn = FALSE;
  363. bReturn = GetDlgItemText(IDC_EDITFILENAME, bstrFileName);
  364. if (bReturn) {
  365. sFileName = ShimUnquotePath(bstrFileName);
  366. } else {
  367. sFileName.erase();
  368. }
  369. if (bstrFileName) {
  370. ::SysFreeString(bstrFileName);
  371. }
  372. return bReturn;
  373. }
  374. };
  375. #endif //__SELECTFILE_H_