FileEditCtrl.cpp
上传用户:dengkfang
上传日期:2008-12-30
资源大小:5233k
文件大小:99k
源码类别:

CA认证

开发平台:

Visual C++

  1. /****************************************************************************
  2. FileEditCtrl.cpp : implementation file for the CFileEditCtrl control class
  3. written by PJ Arends
  4. pja@telus.net
  5. For updates check http://www3.telus.net/pja/CFileEditCtrl.htm
  6. -----------------------------------------------------------------------------
  7. This code is provided as is, with no warranty as to it's suitability or usefulness
  8. in any application in which it may be used. This code has not been tested for
  9. UNICODE builds, nor has it been tested on a network ( with UNC paths ).
  10. This code may be used in any way you desire. This file may be redistributed by any
  11. means as long as it is not sold for profit, and providing that this notice and the
  12. authors name are included.
  13. If any bugs are found and fixed, a note to the author explaining the problem and
  14. fix would be nice.
  15. -----------------------------------------------------------------------------
  16. created : October 2000
  17.       
  18. Revision History:
  19. Some changes by :  Philippe Lhoste - PhiLho@gmx.net - http://jove.prohosting.com/~philho/
  20.                    Perry Rapp      - PRapp@smartronix.com
  21.                    Remon           - Remon@Hotmail.com
  22. November 11, 2000        - allowed the control to work with dialog templates
  23. November 22, 2000        - register the control's window class, can now be added to dialog as custom control
  24. January 4, 2001          - near total rewrite of the control, now derived from CEdit
  25.                          - control can now be added to dialog template using an edit control
  26.                          - browse button now drawn in nonclient area of control
  27. January 5, 2001          - removed OnKillFocus(), replaced with OnDestroy()
  28. January 15, 2001         - added DDX_ and DDV_ support
  29.                          - modified GetStartPosition() and GetNextPathName()
  30.                          - modified how FECOpenFile() updates the control text when multiple files are selected
  31.                          - added FillBuffers()
  32.                          - added support for relative paths
  33.                          - added OnChange handler
  34.                          - added drag and drop support
  35. January 26, 2001         - fixed bug where SHBrowseForFolder does not like trailing slash
  36. January 27, 2001         - fixed bug where if control is initialized with text, FillBuffers was not called.
  37. January 28, 2001         - removed GetFindFolder() and SetFindFolder() replaced with GetFlags() and SetFlags()
  38.                          - modified the DDX_ and DDV_ functions to accept these flags
  39.                          - modified the Create() function to accept these flags
  40.                          - allowed option for returned folder to contain trailing slash
  41.                          - allowed browse button to be on the left side of the control
  42.                          - added ScreenPointInButtonRect() to better tell if mouse cursor is over the button
  43.                          - modified how OnDropFiles() updates the control text when multiple files are dropped
  44. February 25, 2001        - fixed EN_CHANGE notification bug. Now parent window recieves this notification message
  45.                            used ON_CONTROL_REFLECT_EX macro instead of ON_CONTROL_REFLECT
  46. April 12, 2001           - added OnSize handler, fixed button drawing problem when control size changed
  47. April 21, 2001           - added a tooltip for the browse button
  48. May 12, 2001             - removed OnDestroy, replaced with PostNCDestroy
  49.                          - added tooltip support to client area
  50.                          - modified the FECBrowseForFolder and FECFolderProc functions
  51.                          - added a one pixel neutral area between the client area and browse button when the
  52.                            button is on the right hand side of the control. (looks better IMO)
  53. May 29, 2001       - PL -- removed the filename from the m_pCFileDialog->m_ofn.lpstrInitialDir
  54.                            variable, so when browsing back for file, we open the correct folder.
  55.                          - used smaller (exact size) arrays for file, extension and path components.
  56.                          - some cosmetic changes.
  57. May 29, 2001             - FECFolderProc now checks for UNC path. SHBrowseForFolder can not be initialized with UNC
  58. June 2, 2001             - modified ButtonClicked function. Now sends a WM_NOTIFY message to parent window before
  59.                            showing dialog, allows parent window to cancel action by setting result to nonzero. also
  60.                            sends WM_NOTIFY message to parent window after dialog closes with successful return
  61. June 9, 2001             - added OnNcLButtonDblClk handler. Double click on button treated as two single clicks
  62. June 23, 2001            - placed a declaration for the FECFolderProc global callback function into the header file
  63.                          - fixed bug that occured when removing the filename from the
  64.                            m_pCFileDialog->m_ofn.lpstrInitialDir variable when there was no file to remove
  65. August 2, 2001           - replaced SetWindowText() with OnSetText() message handler. now correctly handles
  66.                            WM_SETTEXT messages
  67. August 12, 2001          - added GetValidFolder() function and modified FECOpenFile() function. we now start
  68.                            browsing in the correct folder -- it finally works!!!  {:o)
  69.                          - modified SetFlags() so the button could be moved by setting the FEC_BUTTONLEFT flag
  70.                          - removed the m_bCreatingControl variable
  71.                          - removed the call to SetWindowPos() from the Create() and DDX_FileEditCtrl() functions.
  72.                            Now done in SetFlags() function
  73. August 14, 2001          - modified FECOpenFile(). Now sets the file name in CFileDialog to first file name in
  74.                            CFileEditCtrl
  75. August 18, 2001          - Set the tooltip font to the same font used in the CFileEditCtrl
  76. September 2, 2001        - added the ModifyFlags() function and changed how the flags are handled
  77.                          - modified the GetFlags() function
  78.                          - added the FEC_MULTIPLE and FEC_MULTIPLEFILES flags
  79.                          - added support for wildcards ( '*' and '?') in filenames
  80.                            Involved : modifying the GetStartPosition(), GetNextPathName(), SetFlags(), and
  81.                                           FillBuffers() functions
  82.                                       adding the ExpandWildCards() function
  83.                                       replacing the m_lpstrFiles variable with the m_Files array
  84.                                       adding the FEC_WILDCARDS flag.
  85. September 3, 2001        - added ability to dereference shortcut files (*.lnk) 
  86.                          - added the FEC_NODEREFERENCELINKS flag.
  87.                          - added the DereferenceLink() function.
  88. September 5, 2001        - fixed the Create() function - now destroys the control if the SetFlags() function fails
  89. September 8, 2001        - added the AddFiles() function to be better able to handle shortcut (*.lnk) files
  90.                            modified the OnDropFiles() function to be better able to handle shortcut (*.lnk) files
  91. September 12, 2001 - PR -- added #include <shlobj.h> to the FileEditCtrl.h header file
  92.                          - UNICODE fixes, added _T() macro in Create() function and in TRACE() calls.
  93.                          - Perry states that the code now works perfectly with UNICODE builds and UNC paths.
  94.                                 {:o)  {:o)  {:o)  {:o)  {:o)  {:o)  {:o)  {:o)  {:o)  {:o)  {:o)  {:o)
  95. September 18, 2001       - added ability to use icons or bitmaps on the browse button
  96.                            Involved : adding SetButtonImage() function.
  97.                                       modifying the DrawButton() function
  98.                                       adding the FECButtonImage class.
  99. September 20, 2001       - fixed resource leak in FECButtonImage class
  100.                          - cleaned up the FECButtonImage class code
  101.                          - added ability to resize the browse button
  102.                            Involved : adding m_nButtonWidth variable
  103.                                       adding SetButtonWidth() and GetButtonWidth() functions
  104.                                       modifying OnNcCalcSize() and DrawButton() functions
  105. September 24, 2001       - fixed bug in GetNextPathName() and ExpandWildCards() where multiple files could not
  106.                            start from the current drive   ie folderfile.ext as second file would give an error
  107. September 26, 2001       - fixed bug in GetNextPathName() to allow incomplete relative paths (ie ....) when
  108.                            browsing for files.
  109. October 5, 2001    - PR -- Added #include <afxcmn.h> to the CFileEditCtrl.h header file
  110. October 14, 2001         - rewrote the FECButtonImage::DrawImage() function, it now handles disabled transparent
  111.                            bitmaps better (the transparent colour can be any colour, no longer just light colours),
  112.                            and now also handles pattern and bitmap background brushes
  113.                          - various other touch ups (comments mostly)
  114. November 20, 2001        - added ability to dereference *.pif (shortcut to MS-DOS) files
  115. November 26, 2001        - added abilty to be flat, hot to mouse (FEC_FLAT flag)
  116.                            Involved : adding OnKillFocus(), OnLButtonDown(), and OnNCMouseMove() message handlers
  117.                                       adding Redraw() and SetReadOnly() member functions
  118.                                       modifying OnEnable(), OnMouseMove(), OnNCPaint(), and OnSetFocus() message handlers
  119.                                       modifying DrawButton() and SetFlags() member functions
  120.                                       modifying the CFECButtonImage::DrawImage() function
  121. December 1, 2001         - clean up code from November 26, 2001
  122. December 5, 2001         - added the FEC_GRAYSCALE flag. Flat buttons can be drawn in full colour or grayscale.
  123. December 8, 2001         - greatly improved the button drawing code.
  124. December 18, 2001        - removed the CFECButtonImage class, replaced with the CPJAImage class.
  125.                          - rewrote the SetButtonImage() function.
  126.                          - rewrote the DrawButton() function.
  127. January 7, 2002 - Remon -- added the FEC_NM_DROP notification. The control now sends a WM_NOTIFY message to its
  128.                            parent window after a file or folder has been dropped onto it.
  129. January 14, 2002         - fixed a bug that prevented the tooltips from displaying properly.
  130. February 18, 2002        - replaced SetReadOnly() with OnSetReadOnly(), the control now properly handles the
  131.                            EM_SETREADONLY message.
  132. March 27, 2002           - fixed border drawing when control is drawn flat. Now the control does not appear to
  133.                            change size when it switches from edit mode to readonly or disabled.
  134. March 28, 2002           - moved the FEC_NM_POSTBROWSE notification. Now it is sent after the dialog closes,
  135.                            but before the edit control's text is updated. The parent window can now return
  136.                            a nonzero value to stop the edit control from updating.
  137.                            Involved : modifying the ButtonClicked(), FECBrowseForFolder() and FECOpenFile() functions
  138.                                       adding the pNewText pointer to the FEC_NOTIFY structure
  139.                          - modified FEC_NM_DROP notification. The parent window can now return a nonzero
  140.                            value to stop the edit control from updating.
  141. April 1, 2002            - Removed the CStringArray used to store file names, now using a linked list (CStringList)
  142.                            Involved : modifying the AddFile(), GetStartPosition(), GetNextPathName, and FillBuffers() functions
  143. April 2, 2002            - Added the ability for the CFECFileDialog to dynamicly manage the memory needed by the
  144.                            lpstrFile member of the OPENFILENAME structure. ( thanks to Philippe Lhoste )
  145.                            Involved : adding the DoModal(), OnFileNameChange() and Reset() functions to the CFECFileDialog class
  146.                                       modifying the FECOpenFile() function.
  147. November 23, 2002        - The April 2, 2002 changes did not work with WinNT and above. No idea why not. I fixed it by adding
  148.                            the GetStartPosition() and GetNextPathName() functions and a destructor to the CFECFileDialog class.
  149.                            I also removed the Reset() function, and modified the DoModal() and FECOpenFile() functions.
  150. December 4, 2002         - Added the FEC_FILEOPEN and FEC_FILESAVEAS flags. FEC_FILEOPEN replaces the FEC_FILE flag.
  151.                            The FEC_FILESAVEAS flag causes the browse button to open the 'File Save As' dialog.
  152.                          - Improved the drawing code for flat control
  153. ****************************************************************************/
  154. #include "stdafx.h"
  155. #include "FileEditCtrl.h"
  156. // see http://www.codeproject.com/tools/imageviewer.asp
  157. //#define ACTIVATE_VIEWER
  158. //#include <ImageViewer.h>
  159. #ifndef __ATLCONV_H__
  160. #include <atlconv.h>   // for T2COLE() macro in DereferenceLinks() function
  161. #endif // __ATLCONV_H__
  162. #ifndef _INC_CDERR
  163. #include <cderr.h>     // for FNERR_BUFFERTOSMALL
  164. #endif // _INC_CDERR
  165. // resource.h is only needed for the string table resources. If you do not put the
  166. // FEC_IDS_* strings in a string table, you do not need to include resource.h
  167. #include "....resource.h"
  168. #ifdef _DEBUG
  169. #define new DEBUG_NEW
  170. #undef THIS_FILE
  171. static char THIS_FILE[] = __FILE__;
  172. #endif
  173. /////////////////////////////////////////////////////////////////////////////
  174. // These strings should be entered into a string table resource with the 
  175. // FEC_IDS_* identifiers defined here, although this class will work
  176. // properly if they are not.
  177. //
  178. // string usage:
  179. //
  180. // FEC_IDS_ALLFILES         - default file filter for CFileDialog
  181. // FEC_IDS_BUTTONTIP        - Text for the browse button tooltip
  182. // FEC_IDS_FILEDIALOGTITLE  - default dialog caption for CFileDialog
  183. // FEC_IDS_SEPARATOR        - character used to seperate files when FEC_MULTIPLE flag is used
  184. // FEC_IDS_NOFILE           - Error message for DDV_FileEditCtrl() when no files or folders are entered
  185. // FEC_IDS_NOTEXIST         - Error message for DDV_FileEditCtrl() when the specified file or folder could not be found
  186. // FEC_IDS_NOTFILE          - Error message for DDV_FileEditCtrl() when the specified file is actually a folder
  187. // FEC_IDS_NOTFOLDER        - Error message for DDV_FileEditCtrl() when the specified folder is actually a file
  188. // FEC_IDS_OKBUTTON         - Text for the 'OK' (Open) button on CFileDialog
  189. //
  190. // FEC_IDS_ALLFILES will be defined in resource.h if these strings
  191. // are in a string table resource
  192. #if !defined FEC_IDS_ALLFILES
  193. #define FEC_NORESOURCESTRINGS /* so this class knows how to handle these strings */
  194. #define FEC_IDS_ALLFILES        _T("所有文件 (*.*)|*.*||")
  195. #define FEC_IDS_BUTTONTIP       _T("浏览")
  196. #define FEC_IDS_FILEDIALOGTITLE _T("浏览文件")
  197. #define FEC_IDS_SEPARATOR       _T(";")
  198. #define FEC_IDS_NOFILE          _T("Enter an existing file.")
  199. #define FEC_IDS_NOTEXIST        _T("%s does not exist.")
  200. #define FEC_IDS_NOTFILE         _T("%s is not a file.")
  201. #define FEC_IDS_NOTFOLDER       _T("%s is not a folder.")
  202. #define FEC_IDS_OKBUTTON        _T("OK")
  203. #endif
  204. /////////////////////////////////////////////////////////////////////////////
  205. // Button states
  206. #define BTN_UP          0x01
  207. #define BTN_DOWN        0x02
  208. #define BTN_DISABLED    0x04
  209. #define BTN_FLAT        0x08
  210. /////////////////////////////////////////////////////////////////////////////
  211. // ToolTip IDs
  212. #define ID_BUTTONTIP    1
  213. #define ID_CLIENTTIP    2
  214. /////////////////////////////////////////////////////////////////////////////
  215. // Brush sizes for drawing the button background
  216. #define BRUSHWIDTH      8
  217. #define BRUSHHEIGHT     8
  218. /////////////////////////////////////////////////////////////////////////////
  219. // Helper functions
  220. /////////////////////////////////////////////////////////////////////////////
  221. //
  222. //  IsWindow  (Global function)
  223. //    Checks if the given window is active
  224. //
  225. //  Parameters :
  226. //    pWnd [in] - points to the CWnd object to check
  227. //
  228. //  Returns :
  229. //    TRUE if the window is active
  230. //    FALSE if not
  231. //
  232. /////////////////////////////////////////////////////////////////////////////
  233. BOOL IsWindow(CWnd *pWnd)
  234. {
  235.     if (!pWnd)
  236.         return FALSE;
  237.     return ::IsWindow(pWnd->m_hWnd);
  238. }
  239. /////////////////////////////////////////////////////////////////////////////
  240. // CFileEditCtrl
  241. IMPLEMENT_DYNAMIC(CFileEditCtrl, CEdit)
  242. /////////////////////////////////////////////////////////////////////////////
  243. //
  244. //  CFileEditCtrl constructor  (public member function)
  245. //    Initializes all the internal variables
  246. //
  247. //  Parameters :
  248. //    bAutoDelete [in] - Auto delete flag
  249. //
  250. //  Returns :
  251. //    Nothing
  252. //
  253. //  Note :
  254. //    If bAutoDelete is TRUE, this class object will be deleted
  255. //    when it's window is destroyed (in CFileEditCtrl::PostNCDestroy).
  256. //    The only time this should be used is when the control is
  257. //    created dynamicly in the
  258. //    DDX_FileEditCtrl(CDataExchange*,int,CString&,DWORD) function.
  259. //
  260. /////////////////////////////////////////////////////////////////////////////
  261. CFileEditCtrl::CFileEditCtrl(BOOL bAutoDelete /* = FALSE */)
  262. {
  263.     m_bAutoDelete       = bAutoDelete;
  264.     m_bButtonLeft       = (DWORD)~0;  // 0xFFFFFFFF
  265.     m_bMouseCaptured    = FALSE;
  266.     m_bTextChanged      = TRUE;
  267.     m_dwFlags           = 0;
  268.     m_dwImageDrawFlags  = 0;
  269.     m_Files.RemoveAll();
  270.     m_nButtonState      = BTN_UP;
  271.     m_nButtonWidth      = -1;
  272.     m_pBROWSEINFO       = NULL;
  273.     m_rcButtonRect.SetRectEmpty();
  274.     m_szCaption.Empty();
  275.     m_szClientTip.Empty();
  276.     m_szFolder.Empty();
  277. m_bIsFocused = FALSE;
  278. m_bIsMouseOver = FALSE;
  279. m_strFilter = FEC_IDS_ALLFILES;
  280. #ifdef AFX_PJAIMAGE_H__F15965B0_B05A_11D4_B625_A1459D96AB20__INCLUDED_
  281.     m_pButtonImage      = NULL;
  282. #endif
  283. }
  284. /////////////////////////////////////////////////////////////////////////////
  285. //
  286. //  CFileEditCtrl destructor  (public member function)
  287. //    cleans up internal data variables
  288. //
  289. //  Parameters :
  290. //    None
  291. //
  292. //  Returns :
  293. //    Nothing
  294. //
  295. /////////////////////////////////////////////////////////////////////////////
  296. CFileEditCtrl::~CFileEditCtrl()
  297. {
  298.     if (m_pBROWSEINFO)
  299.         delete m_pBROWSEINFO;
  300. #ifdef AFX_PJAIMAGE_H__F15965B0_B05A_11D4_B625_A1459D96AB20__INCLUDED_
  301.     if (m_pButtonImage)
  302.         delete m_pButtonImage;
  303. #endif
  304. }
  305. /////////////////////////////////////////////////////////////////////////////
  306. // Message Map
  307. BEGIN_MESSAGE_MAP(CFileEditCtrl, CEdit)
  308. ON_CONTROL_REFLECT_EX(EN_CHANGE, OnChange)
  309. ON_MESSAGE(EM_SETREADONLY, OnSetReadOnly)
  310. ON_MESSAGE(WM_SETTEXT, OnSetText)
  311. ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnTTNNeedText)
  312. ON_WM_DROPFILES()
  313. ON_WM_ENABLE()
  314. ON_WM_KEYDOWN()
  315. ON_WM_KILLFOCUS()
  316. ON_WM_LBUTTONDOWN()
  317. ON_WM_LBUTTONUP()
  318. ON_WM_MOUSEMOVE()
  319. ON_WM_NCCALCSIZE()
  320. ON_WM_NCHITTEST()
  321. ON_WM_NCLBUTTONDBLCLK()
  322. ON_WM_NCLBUTTONDOWN()
  323. ON_WM_NCMOUSEMOVE()
  324. ON_WM_NCPAINT()
  325. ON_WM_SETFOCUS()
  326. ON_WM_SIZE()
  327. END_MESSAGE_MAP()
  328. /////////////////////////////////////////////////////////////////////////////
  329. // CFileEditCtrl member functions
  330. /////////////////////////////////////////////////////////////////////////////
  331. //
  332. //  CFileEditCtrl::AddFile  (protected member function)
  333. //    Adds the specified file to the m_Files list. Removes the path info
  334. //    if it is the same as the path in m_szFolder
  335. //
  336. //  Parameters :
  337. //    FileName [in] - The file to add
  338. //
  339. //  Returns :
  340. //    Nothing
  341. //
  342. /////////////////////////////////////////////////////////////////////////////
  343. void CFileEditCtrl::AddFile(CString File)
  344. {
  345.     DWORD Flags = GetFlags();
  346.     if (Flags & FEC_FILE && !(Flags & FEC_NODEREFERENCELINKS))
  347.     {   // resolve shortcuts (*.lnk or *.pif)
  348.         CString Ext = File.Right(4);
  349.         Ext.MakeLower();
  350.         if (_T(".lnk") == Ext || _T(".pif") == Ext)
  351.             DereferenceLink(File);
  352.     }
  353.     int FolderLength = m_szFolder.GetLength();
  354.     if (File.Left(FolderLength) == m_szFolder)
  355.         File.Delete(0, FolderLength);
  356.     m_Files.AddTail(File);
  357. }
  358. /////////////////////////////////////////////////////////////////////////////
  359. //
  360. //  CFileEditCtrl::ButtonClicked  (protected member function)
  361. //    Called when the user clicks on the browse button.
  362. //
  363. //  Parameters :
  364. //    None
  365. //
  366. //  Returns :
  367. //    Nothing
  368. //
  369. //  Note :
  370. //    Sends a WM_NOTIFY message to the parent window both before and after the dialogs have run.
  371. //    The NMHDR parameter points to a FEC_NOTIFY structure.
  372. //
  373. //    Before : Sends the FEC_NM_PREBROWSE notification. Returning non-zero aborts this function.
  374. //    After  : Sends the FEC_NM_POSTBROWSE notification. (update Mar 28, 2002 - now sent by called functions)
  375. //
  376. /////////////////////////////////////////////////////////////////////////////
  377. void CFileEditCtrl::ButtonClicked()
  378. {
  379.     CWnd *pParent = GetParent();
  380.     if (IsWindow(pParent))
  381.     {
  382.         FEC_NOTIFY notify(this, FEC_NM_PREBROWSE);
  383.         if (pParent->SendMessage (WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&notify) != 0)
  384.             return; // SendMessage returned nonzero, do not show dialog
  385.     }
  386.     DWORD Flags = GetFlags();
  387.     if (Flags & FEC_FOLDER)
  388.         FECBrowseForFolder();
  389.     else if (Flags & (FEC_FILEOPEN | FEC_FILESAVEAS))
  390.         FECOpenFile();
  391.     else
  392.         ASSERT (FALSE);  // control flags not properly set (should never get here)
  393. }
  394. /////////////////////////////////////////////////////////////////////////////
  395. //
  396. //  CFileEditCtrl::Create  (public member function)
  397. //    Creates the CFileEditCtrl in any window.
  398. //
  399. //  Parameters :
  400. //    dwFlags        [in] - CFileEditCtrl flags ( FEC_* )
  401. //    dwExStyle      [in] - Windows extended styles ( WS_EX_* )
  402. //    lpszWindowName [in] - The initial text in the control
  403. //    dwStyle        [in] - Windows and Edit control styles ( WS_* and ES_* )
  404. //    rect           [in] - The position and size of the control
  405. //    pParentWnd     [in] - Pointer to the control's parent window
  406. //    nID            [in] - the control's ID
  407. //
  408. //  Returns :
  409. //    TRUE if the control was successfully created
  410. //    FALSE if not
  411. //
  412. //  Note :
  413. //    See the FileEditCtrl.h file for descriptions of the flags used
  414. //
  415. /////////////////////////////////////////////////////////////////////////////
  416. BOOL CFileEditCtrl::Create(DWORD dwFlags,
  417.                            DWORD dwExStyle,
  418.                            LPCTSTR lpszWindowName,
  419.                            DWORD dwStyle,
  420.                            const RECT& rect,
  421.                            CWnd* pParentWnd,
  422.                            UINT nID) 
  423. {
  424.     BOOL bResult = CreateEx(dwExStyle,
  425.                             _T("EDIT"),
  426.                             lpszWindowName,
  427.                             dwStyle,
  428.                             rect,
  429.                             pParentWnd,
  430.                             nID);
  431.     if (bResult)
  432.     {   // call CFileEditCtrl::SetFlags() to initialize the internal data structures
  433.         bResult = SetFlags(dwFlags);
  434.         if (bResult)
  435.         {   // set the font to the font used by the parent window
  436.             if (IsWindow(pParentWnd))
  437.                 SetFont(pParentWnd->GetFont());
  438.         }
  439.         else   // SetFlags() failed - destroy the window
  440.             DestroyWindow();
  441.     }
  442.     return bResult;
  443. }
  444. /////////////////////////////////////////////////////////////////////////////
  445. //
  446. //  CFileEditCtrl::DereferenceLinks  (protected member function)
  447. //    Gets the file path name pointed to by shortcut (*.lnk or *.pif) file
  448. //
  449. //  Parameters :
  450. //    FileName [in]  : the shortcut file to be dereferenced
  451. //             [out] : if successful, the complete path name of the file the
  452. //                     shortcut points to, or unchanged if not successful
  453. //
  454. //  Returns :
  455. //    TRUE if the link was dereferenced
  456. //    FALSE if not
  457. //
  458. //  Note :
  459. //    Thanks to Michael Dunn for his article "Introduction to COM - What It Is and How to Use It."
  460. //    found at http://www.codeproject.com/com/comintro.asp
  461. //
  462. /////////////////////////////////////////////////////////////////////////////
  463. BOOL CFileEditCtrl::DereferenceLink(CString &FileName)
  464. {
  465.     BOOL ret = FALSE;       // assume failure
  466.     IShellLink *pIShellLink;
  467.     IPersistFile *pIPersistFile;
  468.     // initialize the COM libraries
  469.     CoInitialize (NULL);
  470.     // create an IShellLink object
  471.     HRESULT hr = CoCreateInstance(CLSID_ShellLink,
  472.                                   NULL,
  473.                                   CLSCTX_INPROC_SERVER,
  474.                                   IID_IShellLink,
  475.                                   (void **) &pIShellLink);
  476.     if (SUCCEEDED (hr))
  477.     {
  478.         // get the IPersistFile interface for this IShellLink object
  479.         hr = pIShellLink->QueryInterface(IID_IPersistFile, (void **)&pIPersistFile);
  480.         if (SUCCEEDED (hr))
  481.         {
  482.             int len = FileName.GetLength();
  483.             WCHAR *pWFile = new WCHAR[len + 1];
  484.             USES_CONVERSION;
  485.             wcscpy(pWFile, T2COLE(FileName));
  486.             // open and read the .lnk or .pif file
  487.             hr = pIPersistFile->Load(pWFile, 0);
  488.             if (SUCCEEDED(hr))
  489.             {
  490.                 TCHAR buffer[_MAX_PATH];
  491.                 // get the file path name 
  492.                 hr = pIShellLink->GetPath(buffer, _MAX_PATH, NULL, 0 /*SLGP_UNCPRIORITY*/);
  493.                 if (SUCCEEDED(hr))
  494.                 {
  495.                     FileName = buffer;
  496.                     ret = TRUE;
  497.                 }
  498.             }
  499.             delete[] pWFile;
  500.         }
  501.         // release the IShellLink interface
  502.         pIShellLink->Release();
  503.     }
  504.     // close the COM libraries
  505.     CoUninitialize();
  506.     return ret;
  507. }
  508. /////////////////////////////////////////////////////////////////////////////
  509. //
  510. //  CFileEditCtrl::DrawButton  (protected member function)
  511. //    Draws the button on the control
  512. //
  513. //  Parameters :
  514. //    nButtonState [in] - the state of the button ( Up, Down, or Disabled )
  515. //
  516. //  Returns :
  517. //    Nothing
  518. //
  519. /////////////////////////////////////////////////////////////////////////////
  520. void CFileEditCtrl::DrawButton(int nButtonState)
  521. {   // if the button is too small, do not draw it
  522.     if (m_rcButtonRect.Width() < 3 || m_rcButtonRect.Height() < 3)
  523.         return;
  524.     ASSERT(IsWindow(this));
  525.     // if the control is disabled, ensure the button is drawn disabled
  526.     if (GetStyle() & WS_DISABLED)
  527.         nButtonState = BTN_DISABLED;
  528.     nButtonState |= m_nButtonState & BTN_FLAT;
  529.     CRect DrawRect(m_rcButtonRect);
  530.     DrawRect.OffsetRect(0 - m_rcButtonRect.left, 0 - m_rcButtonRect.top);
  531.     CWindowDC WndDC(this);     // get the DC for drawing
  532.     // Create a memory DC to prevent flicker
  533.     CDC MemDC;
  534.     MemDC.CreateCompatibleDC(&WndDC);
  535.     int savedDC = MemDC.SaveDC();
  536.     CBitmap Bitmap;
  537.     Bitmap.CreateCompatibleBitmap(&WndDC, m_rcButtonRect.Width(), m_rcButtonRect.Height());
  538.     MemDC.SelectObject(&Bitmap);
  539.     // use HS_DIAGCROSS pattern brush to test brush alignment
  540.     CBrush theBrush(/*HS_DIAGCROSS,*/ GetSysColor(COLOR_3DFACE));     // the colour of the button background
  541.     CPoint BrushOrg;
  542.     CPoint Origin = WndDC.GetBrushOrg();
  543.     BrushOrg.x = (BRUSHWIDTH - (m_rcButtonRect.left - Origin.x) % BRUSHWIDTH);
  544.     BrushOrg.y = (BRUSHHEIGHT - (m_rcButtonRect.top - Origin.y) % BRUSHHEIGHT);
  545.     MemDC.SetBrushOrg(BrushOrg);
  546.     MemDC.SelectObject(&theBrush);
  547.     MemDC.FillRect(&DrawRect, &theBrush);
  548.     if (nButtonState & BTN_DOWN)
  549.     {
  550.         // draw the border
  551.         CPen thePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
  552.         CPen *pOldPen = MemDC.SelectObject(&thePen);
  553.         MemDC.Rectangle(DrawRect);
  554.         MemDC.SelectObject(pOldPen);
  555.         thePen.DeleteObject();
  556. #ifdef AFX_PJAIMAGE_H__F15965B0_B05A_11D4_B625_A1459D96AB20__INCLUDED_
  557.         if (m_pButtonImage)
  558.         {   // draw the image
  559.             if (DrawRect.Width() > 5 && DrawRect.Height() > 5)
  560.                 m_pButtonImage->DrawImage(&MemDC,
  561.                 3,
  562.                 3,
  563.                 DrawRect.Width() - 5,
  564.                 DrawRect.Height() - 5,
  565.                 m_dwImageDrawFlags);
  566.         }
  567.         else   // draw the dots
  568. #endif
  569.             DrawDots(&MemDC, GetSysColor(COLOR_BTNTEXT), 1);
  570.     }
  571.     else    // draw button as up
  572.     {
  573.         // draw the border
  574.         if (nButtonState & BTN_FLAT)
  575.         {
  576.             CPen thePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOW));
  577.             CPen *pOldPen = MemDC.SelectObject(&thePen);
  578.             if (m_rcButtonRect.left < 4) // button on left side of control
  579.                 MemDC.Rectangle(DrawRect.left - 1, DrawRect.top - 1, DrawRect.right, DrawRect.bottom + 1);
  580.             else
  581.                 MemDC.Rectangle(DrawRect.left, DrawRect.top - 1, DrawRect.right + 1, DrawRect.bottom + 1);
  582.             MemDC.SelectObject(pOldPen);
  583.             thePen.DeleteObject();
  584.         }
  585. else
  586.             MemDC.DrawEdge(DrawRect, EDGE_RAISED, BF_RECT);
  587.         if (nButtonState & BTN_DISABLED)
  588.         {
  589. #ifdef AFX_PJAIMAGE_H__F15965B0_B05A_11D4_B625_A1459D96AB20__INCLUDED_
  590.             if (m_pButtonImage)
  591.             {   // draw the image
  592.                 if (DrawRect.Width() > 5 && DrawRect.Height() > 5)
  593.                     m_pButtonImage->DrawImage(&MemDC,
  594.                     2,
  595.                     2,
  596.                     DrawRect.Width() - 5,
  597.                     DrawRect.Height() - 5,
  598.                     PJAI_DISABLED | m_dwImageDrawFlags);
  599.             }
  600.             else
  601. #endif
  602.             {   // draw the dots
  603.                 DrawDots(&MemDC, GetSysColor(COLOR_3DHILIGHT), 1);
  604.                 DrawDots(&MemDC, GetSysColor(COLOR_3DSHADOW));
  605.             }
  606.         }
  607.         else if (nButtonState & BTN_UP)
  608.         {
  609. #ifdef AFX_PJAIMAGE_H__F15965B0_B05A_11D4_B625_A1459D96AB20__INCLUDED_
  610.             if (m_pButtonImage)
  611.             {   // draw the image
  612.                 if (DrawRect.Width() > 5 && DrawRect.Height() > 5)
  613.                     m_pButtonImage->DrawImage(&MemDC,
  614.                     2,
  615.                     2,
  616.                     DrawRect.Width() - 5,
  617.                     DrawRect.Height() - 5,
  618.                     (((m_nButtonState & BTN_FLAT) && (GetFlags() & FEC_GRAYSCALE)) ? PJAI_GRAYSCALE : 0) | m_dwImageDrawFlags);
  619.             }
  620.             else   // draw the dots
  621. #endif
  622.             {
  623.                 COLORREF dotcolour = GetSysColor(COLOR_BTNTEXT);
  624.                 if ((m_nButtonState & BTN_FLAT) && (GetFlags() & FEC_GRAYSCALE))
  625.                 {
  626.                     int grayscale = (((GetBValue(dotcolour) * 11) + (GetGValue(dotcolour) * 59) + (GetRValue(dotcolour) * 30)) / 100);
  627.                     dotcolour = RGB(grayscale, grayscale, grayscale);
  628.                 }
  629.                 DrawDots(&MemDC, dotcolour);
  630.             }
  631.         }
  632.         else
  633.         {
  634.             ASSERT(FALSE);  // Invalid nButtonState
  635.         }
  636.     }
  637. //  ShowDC(MemDC);
  638.     // Blit the button image onto the screen
  639.     WndDC.BitBlt(m_rcButtonRect.left,
  640.         m_rcButtonRect.top,
  641.         m_rcButtonRect.Width(),
  642.         m_rcButtonRect.Height(),
  643.         &MemDC,
  644.         0,
  645.         0,
  646.         SRCCOPY);
  647.     // clean up the memory DC
  648.     MemDC.RestoreDC(savedDC);
  649.     Bitmap.DeleteObject();
  650.     // update m_nButtonState
  651.     m_nButtonState = nButtonState;
  652. }
  653. /////////////////////////////////////////////////////////////////////////////
  654. //
  655. //  CFileEditCtrl::DrawDots  (protected member function)
  656. //    Draws the dots on the button
  657. //
  658. //  Parameters :
  659. //    pDC     [in] - Pointer to the device context needed for drawing
  660. //    CR      [in] - The colour of the dots
  661. //    nOffset [in] - How far down and to the right to shift the dots
  662. //
  663. //  Returns :
  664. //    Nothing
  665. //
  666. /////////////////////////////////////////////////////////////////////////////
  667. void CFileEditCtrl::DrawDots(CDC *pDC, COLORREF CR, int nOffset /* = 0 */)
  668. {
  669.     int width = m_rcButtonRect.Width();         // width of the button
  670.     div_t divt = div(width, 4);
  671.     int delta = divt.quot;                      // space between dots
  672.     int left = width / 2 - delta - (divt.rem ? 0 : 1); // left side of first dot
  673.     width = width / 10;                         // width and height of one dot
  674.     int top = m_rcButtonRect.Height() / 2 - width / 2;  // top of dots
  675.     left += nOffset;                            // draw dots shifted? (for button pressed)
  676.     top += nOffset;
  677.     // draw the dots
  678.     if (width < 2)
  679.     {
  680.         pDC->SetPixelV(left, top, CR);
  681.         left += delta;
  682.         pDC->SetPixelV(left, top, CR);
  683.         left += delta;
  684.         pDC->SetPixelV(left, top, CR);
  685.     }
  686.     else
  687.     {
  688.         CPen thePen(PS_SOLID, 1, CR);           // set the dot colour
  689.         CPen *pOldPen = pDC->SelectObject(&thePen);
  690.         CBrush theBrush(CR);
  691.         CBrush *pOldBrush = pDC->SelectObject(&theBrush);
  692.         pDC->Ellipse(left, top, left + width, top + width);
  693.         left += delta;
  694.         pDC->Ellipse(left, top, left + width, top + width);
  695.         left += delta;
  696.         pDC->Ellipse(left, top, left + width, top + width);
  697.         pDC->SelectObject(pOldBrush);           // reset the DC
  698.         theBrush.DeleteObject();
  699.         pDC->SelectObject(pOldPen);
  700.         thePen.DeleteObject();
  701.     }
  702. }
  703. /////////////////////////////////////////////////////////////////////////////
  704. //
  705. //  CFileEditCtrl::ExpandWildCards  (protected member function)
  706. //    resolves any wildcards ('*' and/or '?') found in the file name
  707. //    calls AddFile() to add the files to the m_Files list
  708. //
  709. //  Parameters :
  710. //    FileName [in] - the file name
  711. //
  712. //  Returns :
  713. //    Nothing
  714. //
  715. /////////////////////////////////////////////////////////////////////////////
  716. void CFileEditCtrl::ExpandWildCards(const CString &FileName)
  717. {
  718.     DWORD Flags = GetFlags();
  719.     if (!(Flags & FEC_WILDCARDS) || -1 == FileName.FindOneOf(_T("*?")))
  720.     {   // wildcards not permitted or not found
  721.         AddFile(FileName);
  722.         return;
  723.     }
  724.     CString Temp;
  725.     CString Path;
  726.     if (_T('\') == FileName[0] || (FileName.GetLength() > 1 && _T(':') == FileName[1]))
  727.         Temp = FileName;
  728.     else
  729.         Temp = m_szFolder + FileName;
  730.     _tfullpath(Path.GetBuffer(_MAX_PATH), Temp, _MAX_PATH);
  731.     Path.ReleaseBuffer();
  732.     CFileFind cff;
  733.     BOOL Finding = cff.FindFile(Path);
  734.     while (Finding)
  735.     {
  736.         Finding = cff.FindNextFile();
  737.         Path = cff.GetFilePath();
  738.         if (!cff.IsDirectory())
  739.         {
  740.             AddFile(Path);
  741.             if (!(Flags & FEC_MULTIPLE))
  742.                 break;
  743.         }
  744.     }
  745. }
  746. /////////////////////////////////////////////////////////////////////////////
  747. //
  748. //  CFileEditCtrl::FECBrowseForFolder  (protected member function)
  749. //    Set up and call SHBrowseForFolder().
  750. //    Update the control to the users selection
  751. //
  752. //  Parameters :
  753. //    None
  754. //
  755. //  Returns :
  756. //    TRUE if user clicks OK in SHBrowseForFolder dialog
  757. //    FALSE otherwise
  758. //
  759. /////////////////////////////////////////////////////////////////////////////
  760. BOOL CFileEditCtrl::FECBrowseForFolder()
  761. {
  762.     BOOL bReturnValue = FALSE;
  763. #if defined _DEBUG
  764.     if (m_pBROWSEINFO->lpfn == FECFolderProc)
  765.         ASSERT((CWnd *)m_pBROWSEINFO->lParam == this);
  766. #endif
  767.     ITEMIDLIST *idl = SHBrowseForFolder(m_pBROWSEINFO);
  768.     if (idl)  // SHBrowseForFolder returned successfully
  769.     {
  770.         CString Buffer = _T("");
  771.         BOOL result = SHGetPathFromIDList(idl, Buffer.GetBuffer(_MAX_PATH));  // get path string from ITEMIDLIST
  772.         Buffer.ReleaseBuffer();
  773.         if (result)
  774.         {
  775.             if (GetFlags() & FEC_TRAILINGSLASH) // add a trailing slash if it is not already there
  776.             {
  777.                 if (_T('\') != Buffer[Buffer.GetLength() - 1])
  778.                    Buffer+= _T("\");
  779.             }
  780.             LRESULT retval = 0;
  781.             CWnd *pParent = GetParent();
  782.             if (IsWindow(pParent))
  783.             {                                   // notify parent window that the control text is about to be updated
  784.                 FEC_NOTIFY notify(this, FEC_NM_POSTBROWSE);
  785.                 notify.pNewText = &Buffer;
  786.                 retval = pParent->SendMessage (WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&notify);
  787.             }
  788.             if (0 == retval)
  789.             {
  790.                 SetWindowText(Buffer);          // update edit control text
  791.                 bReturnValue = TRUE;
  792.             }
  793.         }
  794.         LPMALLOC lpm;
  795.         if (SHGetMalloc(&lpm) == NOERROR)
  796.             lpm->Free(idl);                     // free memory returned by SHBrowseForFolder
  797.     }
  798.     else
  799.     {   // notify parent window that ShBrowseForFolder was cancelled
  800.         CWnd *pParent = GetParent();
  801.         if (IsWindow(pParent))
  802.         {
  803.             FEC_NOTIFY notify(this, FEC_NM_POSTBROWSE);
  804.             pParent->SendMessage (WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&notify);
  805.         }
  806.     }
  807.     SetFocus();                                 // ensure focus returns to this control
  808.     return bReturnValue;
  809. }
  810. /////////////////////////////////////////////////////////////////////////////
  811. //
  812. //  FECFolderProc  (Global CALLBACK function)
  813. //    This is the default callback procedure for the SHBrowseForFolder function.
  814. //    It sets the initial selection to the directory specified in the edit control
  815. //
  816. //  Parameters :
  817. //    hwnd   [in] - Handle of the SHBrowseForFolder dialog
  818. //    nMsg   [in] - Message to be handled
  819. //    lpData [in] - the lparam member of the BROWSEINFO structure, must be a pointer
  820. //                  to the CFileEditCtrl
  821. //
  822. //  Returns :
  823. //    zero
  824. //
  825. //  Note :
  826. //    See 'SHBrowseForFolder' in MSDN for more info on the callback function for SHBrowseForFolder()
  827. //
  828. /////////////////////////////////////////////////////////////////////////////
  829. int CALLBACK FECFolderProc(HWND hWnd, UINT nMsg, LPARAM, LPARAM lpData)
  830. {
  831.     if (BFFM_INITIALIZED == nMsg)
  832.     {   // ensure we are passed a pointer to the CFileEditCtrl
  833.         CWnd *pWnd = (CWnd *)lpData;
  834.         ASSERT (pWnd->IsKindOf(RUNTIME_CLASS(CFileEditCtrl)));
  835.         CFileEditCtrl* pCFEC = (CFileEditCtrl *)pWnd;
  836.         CString szPath;
  837.         POSITION pos = pCFEC->GetStartPosition();
  838.         if (pos)
  839.         {
  840.             szPath = pCFEC->GetNextPathName(pos);
  841.             if (_T("\\") != szPath.Left(2)) // SHBrowseForFolder does not like UNC path
  842.             {
  843.                 int len = szPath.GetLength() - 1;
  844.                 if (2 != len && _T('\') == szPath[len])
  845.                     szPath.Delete(len); // remove trailing slash (SHBrowseForFolder does not like it)
  846.                 ::SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)szPath);
  847.             }
  848.         }
  849.     }
  850.     return 0;
  851. }
  852. /////////////////////////////////////////////////////////////////////////////
  853. //
  854. //  CFileEditCtrl::FECOpenFile  (protected member function)
  855. //    Set up the CFECFileDialog and call CFECFileDialog::DoModal().
  856. //    Update the control to the users selection
  857. //
  858. //  Parameters :
  859. //    None
  860. //
  861. //  Returns :
  862. //    TRUE if the user clicked the OK button in the CFileDialog
  863. //    FALSE otherwise
  864. //
  865. /////////////////////////////////////////////////////////////////////////////
  866. BOOL CFileEditCtrl::FECOpenFile()
  867. {
  868. CFileDialog dlgOpen(true,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
  869. m_strFilter,NULL);
  870. dlgOpen.m_ofn.lpstrTitle = m_szCaption;//标题条
  871.   
  872. /*if (bOpen)
  873.             m_pCFileDialog->m_ofn.Flags |= OFN_FILEMUSTEXIST;
  874.         else
  875.             m_pCFileDialog->m_ofn.Flags |= OFN_OVERWRITEPROMPT;*/
  876. if (m_dwFlags & FEC_MULTIPLE)
  877. dlgOpen.m_ofn.Flags |= OFN_ALLOWMULTISELECT;
  878. else
  879. dlgOpen.m_ofn.Flags &= ~OFN_ALLOWMULTISELECT;
  880. if (m_dwFlags & FEC_NODEREFERENCELINKS)
  881. dlgOpen.m_ofn.Flags |= OFN_NODEREFERENCELINKS;
  882. else
  883. dlgOpen.m_ofn.Flags &= ~OFN_NODEREFERENCELINKS;
  884.     BOOL bReturnValue = FALSE;
  885.     BOOL bDirectory = TRUE;                     // assume user of this class has set the initial directory
  886.     TCHAR lpstrDirectory[_MAX_PATH] = _T("");
  887.     if (NULL == dlgOpen.m_ofn.lpstrInitialDir)  // user has not set the initial directory
  888.     {                                                   // flag it, and set the initial directory
  889.         bDirectory = FALSE;                             // to the directory in the edit control
  890.         POSITION pos = GetStartPosition();
  891.         if (pos)
  892.         {
  893.             _tcscpy(lpstrDirectory, GetNextPathName(pos));
  894.             
  895.             DWORD attrib = GetFileAttributes(lpstrDirectory);
  896.             if (((0xFFFFFFFF != attrib) && (!(attrib & FILE_ATTRIBUTE_DIRECTORY)))
  897.                 || ((0xFFFFFFFF == attrib) && (!(dlgOpen.m_ofn.Flags & OFN_FILEMUSTEXIST))))
  898.                 // if ((file exists && is not a folder) || (does not exist && does not have to exist))
  899.             {
  900.                 // set the filename editbox in CFileDialog to the name of the
  901.                 // first file in the control
  902.                 TCHAR Name[_MAX_FNAME];
  903.                 TCHAR Ext[_MAX_EXT];
  904.                 _tsplitpath(lpstrDirectory, NULL, NULL, Name, Ext);
  905.                 _tcscat(Name, Ext);
  906.                 _tcscpy(dlgOpen.m_ofn.lpstrFile, Name);
  907.             }
  908.             else
  909.                 // empty the filename edit box
  910.                 _tcscpy(dlgOpen.m_ofn.lpstrFile, _T(""));
  911.             
  912.             // Start browsing in the correct folder
  913.             GetValidFolder(lpstrDirectory);
  914.             dlgOpen.m_ofn.lpstrInitialDir = lpstrDirectory;
  915.         }
  916.     }
  917.     
  918. if (IDOK == dlgOpen.DoModal())      // Start the CFECFileDialog
  919.     {                                           // user clicked OK, enter files selected into edit control
  920. CString szFileSeparator;
  921. #if defined FEC_NORESOURCESTRINGS
  922.         szFileSeparator = FEC_IDS_SEPARATOR;
  923. #else
  924.         szFileSeparator.LoadString(FEC_IDS_SEPARATOR);
  925. #endif
  926.         ASSERT(szFileSeparator.GetLength() == 1);   // must be one character only
  927.         szFileSeparator += _T(" ");
  928.         CString szPath;
  929.         POSITION pos = dlgOpen.GetStartPosition();
  930.         if (pos)                                // first file has complete path
  931.             szPath = dlgOpen.GetNextPathName(pos);
  932.         TCHAR lpstrName[_MAX_FNAME];
  933.         TCHAR lpstrExt[_MAX_EXT];
  934.         CString szTempPath;
  935.         while (pos)
  936.         {                                       // remaining files are name and extension only
  937.             szTempPath = dlgOpen.GetNextPathName(pos);
  938.             _tsplitpath(szTempPath, NULL, NULL, lpstrName, lpstrExt);
  939.             szPath += szFileSeparator + lpstrName + lpstrExt;
  940.         }
  941.         LRESULT result = 0;
  942.         CWnd *pParent = GetParent();
  943.         if (IsWindow(pParent))
  944.         {                                       // notify parent window that the control text is about to be updated
  945.             FEC_NOTIFY notify(this, FEC_NM_POSTBROWSE);
  946.             notify.pNewText = &szPath;
  947.             result = pParent->SendMessage (WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&notify);
  948.         }
  949.         
  950.         if (0 == result)
  951.         {                                       // update the window text
  952.             SetWindowText(szPath);
  953.             bReturnValue = TRUE;
  954.         }
  955. }
  956. else
  957. {                                           // CFileDialog cancelled
  958. CWnd *pParent = GetParent();
  959. if (IsWindow(pParent))
  960.         {                                       // notify parent window
  961. FEC_NOTIFY notify(this, FEC_NM_POSTBROWSE);
  962. pParent->SendMessage (WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&notify);
  963.         }
  964. }
  965.     SetFocus();                                 // ensure focus returns to this control
  966. return bReturnValue;
  967. }
  968. /////////////////////////////////////////////////////////////////////////////
  969. //
  970. //  CFileEditCtrl::FillBuffers  (protected member function)
  971. //    Fills the m_szFolder and m_Files member variables
  972. //
  973. //  Parameters :
  974. //    None
  975. //
  976. //  Returns :
  977. //    Nothing
  978. //
  979. //  Note :
  980. //    The m_szFolder and m_Files member variables are used by the GetStartPosition()
  981. //    and GetNextPathName() functions to retrieve the file names entered by the user.
  982. //
  983. //    If the user entered a folder, m_Files will contain the complete path for the
  984. //    folder, and m_szFolder will be empty
  985. //
  986. //    If the user entered multiple files, m_szFolder will contain the drive and folder
  987. //    path of the first file entered, and m_Files will contain all the files. The files
  988. //    may contain any complete or relative paths. Any relative paths will be evaluated
  989. //    as being relative to the path contained in m_szFolder.
  990. //
  991. /////////////////////////////////////////////////////////////////////////////
  992. void CFileEditCtrl::FillBuffers()
  993. {
  994.     ASSERT(IsWindow(this));                     // Control window must exist
  995. #if defined FEC_NORESOURCESTRINGS
  996.     m_szFolder = FEC_IDS_SEPARATOR;
  997. #else
  998.     m_szFolder.LoadString(FEC_IDS_SEPARATOR);
  999. #endif
  1000.     TCHAR chSeparator = m_szFolder[0];          // get the character used to seperate the files
  1001.     m_szFolder.Empty();                         // empty the buffers of old data
  1002.     m_Files.RemoveAll(); // Empty();
  1003.     int len = GetWindowTextLength();
  1004.     if (!len)                                   // no files entered, leave buffers empty
  1005.         return;
  1006.     LPTSTR lpstrWindow = new TCHAR[len + 1];    // working buffer
  1007.     GetWindowText(lpstrWindow, len + 1);
  1008.     LPTSTR lpstrStart = lpstrWindow;            // points to the first character in a file name
  1009.     LPTSTR lpstrEnd = NULL;                     // points to the next separator character
  1010.     LPTSTR lpstrNext = NULL;
  1011.     while (*lpstrStart == chSeparator || _istspace(*lpstrStart))
  1012.         lpstrStart = CharNext(lpstrStart);      // skip over leading spaces and separator characters
  1013.     if (!*lpstrStart)
  1014.     {                                           // no files entered, leave buffers empty
  1015.         delete lpstrWindow;
  1016.         return;
  1017.     }
  1018.     lpstrEnd = _tcschr(lpstrStart, chSeparator);// find separator character
  1019.     if (lpstrEnd)
  1020.     {
  1021.         lpstrNext = CharNext(lpstrEnd);
  1022.         *lpstrEnd = 0;                          // mark end of string
  1023.     }
  1024.     LPTSTR temp = lpstrStart + _tcslen(lpstrStart);// - 1;
  1025.     temp = CharPrev(lpstrStart, temp);
  1026.     while (_istspace(*temp))                    // remove trailing white spaces from string
  1027.     {
  1028.         *temp = 0;
  1029.         temp = CharPrev(lpstrStart, temp);
  1030.     }
  1031.     DWORD dwFlags = GetFlags();
  1032.     CString File;
  1033.     if (dwFlags & FEC_FOLDER)
  1034.     {
  1035.         _tfullpath(File.GetBuffer(_MAX_PATH), lpstrStart, _MAX_PATH); // get absolute path
  1036.         File.ReleaseBuffer();
  1037.         int len = File.GetLength();
  1038.         if (dwFlags & FEC_TRAILINGSLASH)        // add a trailing slash if it is not already there
  1039.         {
  1040.             if (_T('\') != File[len - 1])
  1041.                 File += _T("\");
  1042.         }
  1043.         else                                    // remove the trailing slash if it is there
  1044.         {
  1045.             if (3 != len && _T('\') == File[len - 1])
  1046.                 File.Delete(len - 1);
  1047.         }
  1048.         AddFile(File);
  1049.         delete lpstrWindow;
  1050.         return;
  1051.     }
  1052.     _TCHAR drive[_MAX_DRIVE];
  1053.     _TCHAR folder[_MAX_DIR];
  1054.     _TCHAR file[_MAX_FNAME];
  1055.     _TCHAR ext[_MAX_EXT];
  1056.     _tsplitpath(lpstrStart, drive, folder, file, ext);
  1057.     m_szFolder = (CString)drive + folder;       // drive and directory placed in m_szFolder
  1058.     File = (CString)file + ext;
  1059.     ExpandWildCards(File);
  1060.     if (dwFlags & FEC_MULTIPLE)
  1061.     {
  1062.         lpstrStart = lpstrNext;                 // reset to the start of the next string
  1063.         while (lpstrEnd)
  1064.         {   // add the rest of the files as they have been typed (include any path information)
  1065.             while (*lpstrStart == chSeparator || _istspace(*lpstrStart))
  1066.                 lpstrStart = CharNext(lpstrStart); // remove leading spaces and separator characters
  1067.             if (!*lpstrStart)                   // last file was followed by spaces and/or separator characters,
  1068.                 break;                          // there are no more files entered
  1069.             lpstrEnd = _tcschr(lpstrStart, chSeparator); // find next separator character
  1070.             if (lpstrEnd)
  1071.             {
  1072.                 lpstrNext = CharNext(lpstrEnd);
  1073.                 *lpstrEnd = 0;                  // mark end of string
  1074.             }
  1075.             temp = lpstrStart + _tcslen(lpstrStart);
  1076.             temp = CharPrev(lpstrStart, temp);
  1077.             while (_istspace(*temp))            // remove trailing white spaces from string
  1078.             {
  1079.                 *temp = 0;
  1080.                 temp = CharPrev(lpstrStart, temp);
  1081.             }
  1082.             ExpandWildCards(lpstrStart);
  1083.             lpstrStart = lpstrNext;             // reset to the start of the next string
  1084.         }
  1085.     }
  1086.     delete lpstrWindow;                         // delete working buffer
  1087. }
  1088. /////////////////////////////////////////////////////////////////////////////
  1089. //
  1090. //  CFileEditCtrl::GetBrowseInfo  (public member function)
  1091. //    Retrieve a pointer to the BROWSEINFO structure
  1092. //
  1093. //  Parameters :
  1094. //    None
  1095. //
  1096. //  Returns :
  1097. //    A pointer to the BROWSEINFO structure if the FEC_FOLDER flag was set
  1098. //    NULL otherwise
  1099. //
  1100. //  Note :
  1101. //    If the default SHBrowseForFolder settings do not fit your use, Use the pointer
  1102. //    returned by this function to set up the SHBrowseForFolder using your own settings
  1103. //    
  1104. /////////////////////////////////////////////////////////////////////////////
  1105. BROWSEINFO* CFileEditCtrl::GetBrowseInfo() const
  1106. {
  1107.     return m_pBROWSEINFO;
  1108. }
  1109. /////////////////////////////////////////////////////////////////////////////
  1110. //
  1111. //  CFileEditCtrl::GetButtonWidth  (public member function)
  1112. //    Retrieves the width, in pixels, of the browse button 
  1113. //
  1114. //  Parameters :
  1115. //    None
  1116. //
  1117. //  Returns :
  1118. //    The width of the browse button
  1119. //
  1120. /////////////////////////////////////////////////////////////////////////////
  1121. int CFileEditCtrl::GetButtonWidth()
  1122. {
  1123.     return m_rcButtonRect.Width();
  1124. }
  1125. /////////////////////////////////////////////////////////////////////////////
  1126. //
  1127. //  CFileEditCtrl::GetFlags  (public member function)
  1128. //    Retrieves the current flags
  1129. //
  1130. //  Parameters :
  1131. //    None
  1132. //
  1133. //  Returns :
  1134. //    the current flags
  1135. //
  1136. //  Note :
  1137. //    See the FileEditCtrl.h file for descriptions of the flags used
  1138. //    Because some flags can be changed via GetOpenFileName(), always use this
  1139. //    function to get the current state of the flags. Do not use m_dwFlags directly.
  1140. //
  1141. /////////////////////////////////////////////////////////////////////////////
  1142. DWORD CFileEditCtrl::GetFlags()
  1143. {
  1144.     DWORD Flags = m_dwFlags;
  1145. /*    if (m_pCFileDialog)
  1146.     {   // coordinate the FEC_* flags with the OFN_* flags
  1147.         if (m_pCFileDialog->m_ofn.Flags & OFN_NODEREFERENCELINKS)
  1148.             Flags |= FEC_NODEREFERENCELINKS;
  1149.         else
  1150.             Flags &= ~FEC_NODEREFERENCELINKS;
  1151.         if (m_pCFileDialog->m_ofn.Flags & OFN_ALLOWMULTISELECT)
  1152.             Flags |= FEC_MULTIPLE;
  1153.         else
  1154.             Flags &= ~FEC_MULTIPLE;
  1155.     }*/
  1156.     return Flags;
  1157. }
  1158. /////////////////////////////////////////////////////////////////////////////
  1159. //
  1160. //  CFileEditCtrl::GetNextPathName  (public member function)
  1161. //    Returns the file name at the specified position in the buffer.
  1162. //
  1163. //  Parameters :
  1164. //    pos [in]  - The position of the file name to retrieve
  1165. //        [out] - the position of the next file name
  1166. //
  1167. //  Returns :
  1168. //    The complete path name of the file or folder
  1169. //
  1170. //  Note :
  1171. //    The starting position is retrieved using the GetStartPosition() function.
  1172. //    pos will be set to NULL when there are no more files
  1173. //
  1174. /////////////////////////////////////////////////////////////////////////////
  1175. CString CFileEditCtrl::GetNextPathName(POSITION &pos)
  1176. {
  1177.     ASSERT(pos);                                // pos must not be NULL
  1178.     CString ReturnString;
  1179.     CString Temp = m_Files.GetNext(pos);
  1180.     
  1181.     if (0 == Temp.GetLength())
  1182.         Temp = m_szFolder;
  1183.     else if ((Temp.GetLength() > 1 && _T(':') != Temp[1])   // not drive
  1184.               && _T('\') != Temp[0])           // nor current drive nor UNC
  1185.         Temp.Insert(0, m_szFolder);
  1186.     
  1187.     _tfullpath(ReturnString.GetBuffer(_MAX_PATH), Temp, _MAX_PATH); // get absolute path from any relative paths
  1188.     ReturnString.ReleaseBuffer();
  1189.     DWORD Flags = GetFlags();
  1190.     
  1191.     if (Flags & FEC_FILE)
  1192.     {
  1193.         Temp = ReturnString.Right(4);
  1194.         Temp.MakeLower();
  1195.         if ((_T(".lnk") == Temp || _T(".pif") == Temp) && !(Flags & FEC_NODEREFERENCELINKS))
  1196.             // resolve shortcuts (*.lnk  or *.pif files)
  1197.             DereferenceLink(ReturnString);
  1198.     }
  1199.     
  1200.     return ReturnString;
  1201. }
  1202. /////////////////////////////////////////////////////////////////////////////
  1203. //
  1204. //  CFileEditCtrl::GetOpenFileName  (public member function)
  1205. //    Retrieves a pointer to the OPENFILENAME structure
  1206. //
  1207. //  Parameters :
  1208. //    None
  1209. //
  1210. //  Returns :
  1211. //    A pointer to the OPENFILENAME structure if the FEC_FILE flag was set
  1212. //    NULL otherwise
  1213. //
  1214. //  Note :
  1215. //    If the default CFileDialog settings do not fit your use, Use the pointer
  1216. //    returned by this function to set up the CFileDialog using your own settings
  1217. //
  1218. /////////////////////////////////////////////////////////////////////////////
  1219. OPENFILENAME* CFileEditCtrl::GetOpenFileName() const
  1220. {
  1221.  //   if (m_pCFileDialog)
  1222.  //       return (&m_pCFileDialog->m_ofn);
  1223.     return NULL;
  1224. }
  1225. /////////////////////////////////////////////////////////////////////////////
  1226. //
  1227. //  CFileEditCtrl::GetStartPosition  (public member function)
  1228. //    If the control is active, calls FillBuffers() if the text has changed
  1229. //    returns the position of the first file in the buffers
  1230. //
  1231. //  Parameters :
  1232. //    None
  1233. //
  1234. //  Returns :
  1235. //    A MFC POSITION structure that points to the first file in the control
  1236. //
  1237. //  Note :
  1238. //    Use this function to get the starting position for the GetNextPathName() function
  1239. //
  1240. /////////////////////////////////////////////////////////////////////////////
  1241. POSITION CFileEditCtrl::GetStartPosition()
  1242. {
  1243.     if (IsWindow(this) && m_bTextChanged)
  1244.     {
  1245.         FillBuffers();
  1246.         m_bTextChanged = FALSE;
  1247.     }
  1248.     return m_Files.GetHeadPosition();
  1249. }
  1250. /////////////////////////////////////////////////////////////////////////////
  1251. //
  1252. //  CFileEditCtrl::GetValidFolder  (protected member function)
  1253. //    Removes all files and nonexistant folders from the given path
  1254. //    Adds a slash to the end of the path string if it is not already there
  1255. //
  1256. //  Parameters :
  1257. //    Path [in]  - The path to check
  1258. //         [out] - The new path
  1259. //
  1260. //  Returns :
  1261. //    TRUE if the original path is valid
  1262. //    FALSE if the original path was invalid and has been changed
  1263. //
  1264. /////////////////////////////////////////////////////////////////////////////
  1265. BOOL CFileEditCtrl::GetValidFolder(LPTSTR Path)
  1266. {
  1267.     CString buffer = Path;
  1268.     BOOL valid = TRUE;
  1269.     int pos = -1;
  1270.     do {
  1271.         DWORD attrib = GetFileAttributes(buffer);
  1272.         if (0xffffffff != attrib && (attrib & FILE_ATTRIBUTE_DIRECTORY))
  1273.         {   // the path is a valid folder
  1274.             if (_T('\') != buffer[buffer.GetLength() - 1])
  1275.                 buffer += _T("\");
  1276.             _tcscpy (Path, buffer);
  1277.             return valid;
  1278.         }
  1279.         valid = FALSE;
  1280.         pos = buffer.ReverseFind(_T('\'));
  1281.         if (pos > 0)
  1282.         {
  1283.             int len = buffer.GetLength();
  1284.             buffer.Delete(pos, len - pos);
  1285.         }
  1286.     } while (pos > 0);
  1287.     // no valid folder, set 'Path' to empty string
  1288.     *Path = _T('');
  1289.     return valid;
  1290. }
  1291. /////////////////////////////////////////////////////////////////////////////
  1292. //
  1293. //  CFileEditCtrl::ModifyFlags  (public member function)
  1294. //    Modifies the control flags
  1295. //
  1296. //  Parameters :
  1297. //    remove [in] - The flags to remove
  1298. //    add    [in] - The flags to add
  1299. //
  1300. //  Returns :
  1301. //    TRUE if the flags are successfully modified
  1302. //    FALSE if not
  1303. //
  1304. //  Note :
  1305. //    See the FileEditCtrl.h file for descriptions of the flags used
  1306. //
  1307. /////////////////////////////////////////////////////////////////////////////
  1308. BOOL CFileEditCtrl::ModifyFlags(DWORD remove, DWORD add)
  1309. {
  1310.     DWORD Flags = GetFlags();
  1311.     Flags &= ~remove;
  1312.     Flags |= add;
  1313.     return SetFlags(Flags);
  1314. }
  1315. /////////////////////////////////////////////////////////////////////////////
  1316. //
  1317. //  CFileEditCtrl::OnChange  (protected member function)
  1318. //    Handles the EN_CHANGE message
  1319. //    Sets the m_bTextChanged flag
  1320. //
  1321. //  Parameters :
  1322. //    None
  1323. //
  1324. //  Returns :
  1325. //    FALSE
  1326. //
  1327. //  Note :
  1328. //    Returning FALSE allows the parent window to also handle the EN_CHANGE message
  1329. //
  1330. /////////////////////////////////////////////////////////////////////////////
  1331. BOOL CFileEditCtrl::OnChange() 
  1332. {
  1333.     m_bTextChanged = TRUE;
  1334.     return FALSE;
  1335. }
  1336. /////////////////////////////////////////////////////////////////////////////
  1337. //
  1338. //  CFileEditCtrl::OnDropFiles  (protected member function)
  1339. //    Handles the WM_DROPFILES message
  1340. //    Sets the control text to display the files dropped onto the control
  1341. //
  1342. //  Parameters :
  1343. //    hDropInfo [in] - handle to the drop structure supplied by windows
  1344. //
  1345. //  Returns :
  1346. //    Nothing
  1347. //
  1348. //  Note :
  1349. //    The control must have the WS_EX_ACCEPTFILES extended windows
  1350. //    style bit set in order for drag and drop to work
  1351. //
  1352. /////////////////////////////////////////////////////////////////////////////
  1353. void CFileEditCtrl::OnDropFiles(HDROP hDropInfo) 
  1354. {
  1355.     if (this == GetCapture())
  1356.         ReleaseCapture();
  1357.     int FolderLength = 0;
  1358.     CString szDroppedFiles = _T("");            // the new window text
  1359.     CString DropBuffer;                         // buffer to contain the dropped files
  1360.     CString szSeparator;
  1361. #if defined FEC_NORESOURCESTRINGS
  1362.     szSeparator = FEC_IDS_SEPARATOR;            // get the file separator character
  1363. #else
  1364.     szSeparator.LoadString(FEC_IDS_SEPARATOR);
  1365. #endif
  1366.     ASSERT(szSeparator.GetLength() == 1);       // must be one character only
  1367.     szSeparator += _T(" ");
  1368.     DWORD Flags = GetFlags();
  1369.     UINT nDropCount = DragQueryFile(hDropInfo, 0xffffffff, NULL, 0);
  1370.     if (nDropCount && ((Flags & FEC_FOLDER) || ((Flags & FEC_FILE) && !(Flags & FEC_MULTIPLE))))
  1371.         // if (files dropped && (finding folder || (finding files && finding only one file)))
  1372.         nDropCount = 1;
  1373.     for (UINT x = 0; x < nDropCount; x++)
  1374.     {
  1375.         DragQueryFile(hDropInfo, x, DropBuffer.GetBuffer(_MAX_PATH), _MAX_PATH);
  1376.         DropBuffer.ReleaseBuffer();
  1377.         if ((Flags & FEC_FILE) && !(Flags & FEC_NODEREFERENCELINKS))
  1378.         {   // resolve any shortcut (*.lnk or *.pif) files
  1379.             CString Ext = DropBuffer.Right(4);
  1380.             Ext.MakeLower();
  1381.             if (_T(".lnk") == Ext || _T(".pif") == Ext)
  1382.                 DereferenceLink(DropBuffer);
  1383.         }
  1384.         if (0 == x)
  1385.         {   // first file has complete path, get the length of the path
  1386.             TCHAR Drive[_MAX_DRIVE];
  1387.             TCHAR Path[_MAX_PATH];
  1388.             _tsplitpath(DropBuffer, Drive, Path, NULL, NULL);
  1389.             FolderLength = _tcslen(Drive) + _tcslen(Path);
  1390.         }
  1391.         else
  1392.         {   // all the rest of the files will drop the path if it
  1393.             // is the same as the first file's path
  1394.             if (DropBuffer.Left(FolderLength) == szDroppedFiles.Left(FolderLength))
  1395.                 DropBuffer.Delete(0, FolderLength);
  1396.             szDroppedFiles += szSeparator;
  1397.         }
  1398.         szDroppedFiles += DropBuffer;
  1399.     }
  1400.     DragFinish(hDropInfo);
  1401.     // notify parent window that a drop occured (thanks Remon)
  1402.     LRESULT result = 0;
  1403.     CWnd *pParent = GetParent();
  1404.     if (IsWindow(pParent))
  1405.     {
  1406.         FEC_NOTIFY notify(this, FEC_NM_DROP);
  1407.         notify.pNewText = &szDroppedFiles;
  1408.         result = pParent->SendMessage(WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&notify);
  1409.     }
  1410.     if (0 == result)
  1411.         SetWindowText(szDroppedFiles);
  1412. }
  1413. /////////////////////////////////////////////////////////////////////////////
  1414. //
  1415. //  CFileEditCtrl::OnEnable  (protected member function)
  1416. //    Handles the WM_ENABLE message
  1417. //    enables or disables the control, and redraws the button to reflect the new state
  1418. //
  1419. //  Parameters :
  1420. //    bEnable [in] - Enabled flag, TRUE to enable, FALSE to disable
  1421. //
  1422. //  Returns :
  1423. //    Nothing
  1424. //
  1425. /////////////////////////////////////////////////////////////////////////////
  1426. void CFileEditCtrl::OnEnable(BOOL bEnable) 
  1427. {
  1428.     CEdit::OnEnable(bEnable);
  1429.     Redraw(TRUE);
  1430.     DrawButton(BTN_UP);
  1431. }
  1432. /////////////////////////////////////////////////////////////////////////////
  1433. //
  1434. //  CFileEditCtrl::OnKeyDown  (protected member function)
  1435. //    Handles the WM_KEYDOWN message
  1436. //    Checks for the <CTRL> + 'period' keystroke, calls ButtonClicked() if found
  1437. //
  1438. //  Parameters :
  1439. //    nChar   [in] - The virtual key code
  1440. //    nRepCnt [in] - not used here, passed on to the base class
  1441. //    nFlags  [in] - not used here, passed on to the base class
  1442. //
  1443. //  Returns :
  1444. //    Nothing
  1445. //
  1446. /////////////////////////////////////////////////////////////////////////////
  1447. void CFileEditCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  1448. {
  1449. #ifndef VK_OEM_PERIOD
  1450. #define VK_OEM_PERIOD 0xBE
  1451. #endif
  1452.     if ((VK_OEM_PERIOD == nChar || VK_DECIMAL == nChar) && GetKeyState(VK_CONTROL) < 0)
  1453.         ButtonClicked();
  1454.     else
  1455.         CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
  1456. }
  1457. /////////////////////////////////////////////////////////////////////////////
  1458. //
  1459. //  CFileEditCtrl::OnKillFocus  (protected member function)
  1460. //    Handles the WM_KILLFOCUS message
  1461. //    Redraws the border on a flat control
  1462. //
  1463. //  Parameters :
  1464. //    pNewWnd [in] - not used here, passed on to the base class
  1465. //
  1466. //  Returns :
  1467. //    Nothing
  1468. //
  1469. /////////////////////////////////////////////////////////////////////////////
  1470. void CFileEditCtrl::OnKillFocus(CWnd *pNewWnd)
  1471. {
  1472.     if (m_bMouseCaptured)
  1473.     {
  1474.         ReleaseCapture();
  1475.         m_bMouseCaptured = FALSE;
  1476.         if (!(m_nButtonState & BTN_UP))
  1477.             DrawButton(BTN_UP);
  1478.     }
  1479.     CEdit::OnKillFocus(pNewWnd);
  1480.     Redraw(TRUE);
  1481. }
  1482. /////////////////////////////////////////////////////////////////////////////
  1483. //
  1484. //  CFileEditCtrl::OnLButtonDown  (protected member function)
  1485. //    Handles the WM_LBUTTONDOWN message
  1486. //    If the user clicks on the button, capture mouse input, set the focus
  1487. //    to this control, and draw the button as pressed
  1488. //
  1489. //  Parameters :
  1490. //    nFlags [in] - not used here, passed on to the base class
  1491. //    point  [in] - the location of the mouse cursor
  1492. //
  1493. //  Returns :
  1494. //    Nothing
  1495. //
  1496. //  Note:
  1497. //    If the FEC_FLAT flag is used, the mouse is captured in the WM_MOUSEMOVE
  1498. //    handler, so we have to use the WM_LBUTTONDOWN message instead of the
  1499. //    WM_NCLBUTTONDOWN message.
  1500. //
  1501. /////////////////////////////////////////////////////////////////////////////
  1502. void CFileEditCtrl::OnLButtonDown(UINT Flags, CPoint point)
  1503. {
  1504.     CEdit::OnLButtonDown(Flags, point);
  1505.     if (GetFlags() & FEC_FLAT && !(m_nButtonState & BTN_DISABLED))
  1506.     {
  1507.         ClientToScreen(&point);
  1508.         if (ScreenPointInButtonRect(point))
  1509.         {
  1510.             SetCapture();  // should already be captured, but just to make sure
  1511.             m_bMouseCaptured = TRUE;
  1512.             DrawButton(BTN_DOWN);
  1513.         }
  1514.     }
  1515. }
  1516. /////////////////////////////////////////////////////////////////////////////
  1517. //
  1518. //  CFileEditCtrl::OnLButtonUp  (protected member function)
  1519. //    Handles the WM_LBUTTONUP message
  1520. //    Release the mouse capture and draw the button as normal. If the
  1521. //    cursor is over the button, call ButtonClicked() 
  1522. //
  1523. //  Parameters :
  1524. //    nFlags [in] - not used here, passed on to the base class
  1525. //    point  [in] - the location of the mouse cursor
  1526. //
  1527. //  Returns :
  1528. //    Nothing
  1529. //
  1530. /////////////////////////////////////////////////////////////////////////////
  1531. void CFileEditCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
  1532. {
  1533.     CEdit::OnLButtonUp(nFlags, point);
  1534.     if (m_bMouseCaptured)
  1535.     {
  1536.         ReleaseCapture();
  1537.         m_bMouseCaptured = FALSE;
  1538.         if (BTN_UP != m_nButtonState)
  1539.             DrawButton(BTN_UP);
  1540.         ClientToScreen(&point);
  1541.         if (ScreenPointInButtonRect(point))
  1542.             ButtonClicked();
  1543.     }
  1544. }
  1545. /////////////////////////////////////////////////////////////////////////////
  1546. //
  1547. //  CFileEditCtrl::OnMouseMove  (protected member function)
  1548. //    Handles the WM_MOUSEMOVE message
  1549. //    If the mouse has been captured, draws the button as up or down
  1550. //    as the mouse moves on or off the button. Also handles drawing the 
  1551. //    flat/raised border as the mouse moves off/over the control
  1552. //
  1553. //  Parameters :
  1554. //    nFlags [in] - not used here, passed on to the base class
  1555. //    point  [in] - The location of the mouse cursor
  1556. //
  1557. //  Returns :
  1558. //    Nothing
  1559. //
  1560. /////////////////////////////////////////////////////////////////////////////
  1561. void CFileEditCtrl::OnMouseMove(UINT nFlags, CPoint point) 
  1562. {
  1563.     CEdit::OnMouseMove(nFlags, point);
  1564.     ClientToScreen(&point);
  1565.     if (m_bMouseCaptured)
  1566.     {
  1567.         if (ScreenPointInButtonRect(point))
  1568.         {
  1569.             if (BTN_DOWN != m_nButtonState)
  1570.                 DrawButton(BTN_DOWN);
  1571.         }
  1572.         else if (BTN_UP != m_nButtonState)
  1573.             DrawButton(BTN_UP);
  1574.     }
  1575.     else if (GetFlags() & FEC_FLAT && this != GetFocus())
  1576.     {
  1577.         if (this != GetCapture())
  1578.         {   // capture the mouse, draw 3D border
  1579.             SetCapture();
  1580.             Redraw(FALSE);
  1581.         }
  1582.         CRect rc;
  1583.         GetWindowRect(&rc);
  1584.         if (!rc.PtInRect(point))
  1585.         {   // mouse moved off control, release mouse, draw flat border
  1586.             ReleaseCapture();
  1587.             Redraw(TRUE);
  1588.         }
  1589.         else
  1590.         {   // set the correct mouse cursor
  1591.             GetClientRect(&rc);
  1592.             ClientToScreen(&rc);
  1593.             if (rc.PtInRect(point))
  1594.                 SetCursor(LoadCursor(NULL, IDC_IBEAM));
  1595.             else
  1596.                 SetCursor(LoadCursor(NULL, IDC_ARROW));
  1597.         }
  1598.     }
  1599. }
  1600. /////////////////////////////////////////////////////////////////////////////
  1601. //
  1602. //  CFileEditCtrl::OnNcCalcSize  (protected member function)
  1603. //    Handles the WM_NCCALCSIZE message
  1604. //    Calculates the size and position of the button and client areas
  1605. //
  1606. //  Parameters :
  1607. //    bCalcValidRects [in] - specifies if the rgrc[1] and rgrc[2] rectangles in the 
  1608. //                           NCCALCSIZE_PARAMS structure are valid
  1609. //    lpncsp          [in] - Pointer to a NCCALCSIZE_PARAMS structure supplied by windows
  1610. //
  1611. //  Returns :
  1612. //    Nothing
  1613. //
  1614. /////////////////////////////////////////////////////////////////////////////
  1615. void CFileEditCtrl::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp) 
  1616. {
  1617.     CEdit::OnNcCalcSize(bCalcValidRects, lpncsp);
  1618.     // if m_nButtonWidth is -1, set the button width to 80% of the control height
  1619.     // else set the button width to m_nButtonWidth
  1620.     int ButtonWidth = (m_nButtonWidth == -1) ? (lpncsp->rgrc[0].bottom - lpncsp->rgrc[0].top) * 8/10 : m_nButtonWidth;
  1621.     
  1622.     // set button area equal to client area of edit control
  1623.     m_rcButtonRect = lpncsp->rgrc[0];
  1624.     
  1625.     if (FEC_BUTTONLEFT == m_bButtonLeft)  // draw the button on the left side of the control
  1626.     {   // shrink left side of client area by the button width
  1627.         lpncsp->rgrc[0].left += ButtonWidth;
  1628.         // shrink the button so its right side is at the left side of client area
  1629.         m_rcButtonRect.right = lpncsp->rgrc[0].left;
  1630.     }
  1631.     else   // draw the button on the right side of the control
  1632.     {   // shrink right side of client area by the button width
  1633.         lpncsp->rgrc[0].right -= ButtonWidth;
  1634.         // shrink the button so its left side is at the right side of client area
  1635.         m_rcButtonRect.left = lpncsp->rgrc[0].right;
  1636.     }
  1637.     if (bCalcValidRects)
  1638.         // convert button coordinates from parent client coordinates to control window coordinates
  1639.         m_rcButtonRect.OffsetRect(-lpncsp->rgrc[1].left, -lpncsp->rgrc[1].top);
  1640.     m_rcButtonRect.NormalizeRect();
  1641.     if (IsWindow(m_ToolTip))
  1642.         m_ToolTip.DestroyWindow();
  1643. }
  1644. /////////////////////////////////////////////////////////////////////////////
  1645. //
  1646. //  CFileEditCtrl::OnNcHitTest  (protected member function)
  1647. //    Handles the WM_NCHITTEST message
  1648. //    Ensures the control gets mouse messages when the mouse cursor is on the button
  1649. //
  1650. //  Parameters :
  1651. //    point [in] - The location of the mouse cursor
  1652. //
  1653. //  Returns :
  1654. //    The HitTest value for the mouse cursor location
  1655. //
  1656. //  Note :
  1657. //    If the mouse is over the button, OnNcHitTest() would normally return
  1658. //    HTNOWHERE, and we would not get any mouse messages. So we return 
  1659. //    HTBORDER to ensure we get them.
  1660. //
  1661. /////////////////////////////////////////////////////////////////////////////
  1662. UINT CFileEditCtrl::OnNcHitTest(CPoint point) 
  1663. {
  1664.     UINT where = CEdit::OnNcHitTest(point);
  1665.     if (HTNOWHERE == where && ScreenPointInButtonRect(point))
  1666.         where = HTBORDER;
  1667.     return where;
  1668. }
  1669. /////////////////////////////////////////////////////////////////////////////
  1670. //
  1671. //  CFileEditCtrl::OnNcLButtonDblClk  (protected member function)
  1672. //    Handles the WM_NCLBUTTONDBLCLK message
  1673. //    Have a double click on the button be treated as two single clicks
  1674. //
  1675. //  Parameters :
  1676. //    nHitTest [in] - not used here, passed on to the base class
  1677. //    point    [in] - the location of the mouse cursor
  1678. //
  1679. //  Returns :
  1680. //    Nothing
  1681. //
  1682. //  Note :
  1683. //    When this control sends a FEC_NM_PREBROWSE notification message to its
  1684. //    parent window, and the parent window returns a nonzero value, the browse
  1685. //    dialogs do not execute. This function makes the button go down and up on
  1686. //    the second click of a double click
  1687. //
  1688. /////////////////////////////////////////////////////////////////////////////
  1689. void CFileEditCtrl::OnNcLButtonDblClk(UINT nHitTest, CPoint point) 
  1690. {
  1691.     if (ScreenPointInButtonRect (point))
  1692.         OnNcLButtonDown(nHitTest, point);
  1693.     else
  1694.         CEdit::OnNcLButtonDblClk(nHitTest, point);
  1695. }
  1696. /////////////////////////////////////////////////////////////////////////////
  1697. //
  1698. //  CFileEditCtrl::OnNcLButtonDown  (protected member function)
  1699. //    Handles the WM_NCLBUTTONDOWN message
  1700. //    If the user clicks on the button, capture mouse input, set the focus
  1701. //    to this control, and draw the button as pressed
  1702. //
  1703. //  Parameters :
  1704. //    nHitTest [in] - not used here, passed on to the base class
  1705. //    point    [in] - the location of the mouse cursor
  1706. //
  1707. //  Returns :
  1708. //    Nothing
  1709. //
  1710. /////////////////////////////////////////////////////////////////////////////
  1711. void CFileEditCtrl::OnNcLButtonDown(UINT nHitTest, CPoint point) 
  1712. {
  1713.     CEdit::OnNcLButtonDown(nHitTest, point);
  1714.     if (ScreenPointInButtonRect(point) && !(m_nButtonState & BTN_DISABLED))
  1715.     {
  1716.         SetFocus();
  1717.         SetCapture();
  1718.         m_bMouseCaptured = TRUE;
  1719.         DrawButton(BTN_DOWN);
  1720.     }
  1721. }
  1722. /////////////////////////////////////////////////////////////////////////////
  1723. //
  1724. //  CFileEditCtrl::OnNcMouseMove  (protected member function)
  1725. //    Handles the WM_NCMOUSEMOVE message
  1726. //    Redraws the flat border as the mouse moves onto the control
  1727. //
  1728. //  Parameters :
  1729. //    nHitTest [in] - not used here, passed on to the base class
  1730. //    point    [in] - the location of the mouse cursor
  1731. //
  1732. //  Returns :
  1733. //    Nothing
  1734. //
  1735. //  Note :
  1736. //    Because the mouse is captured, all subsequent moves are handled by OnMouseMove()
  1737. //
  1738. /////////////////////////////////////////////////////////////////////////////
  1739. void CFileEditCtrl::OnNcMouseMove(UINT nHitTest, CPoint point)
  1740. {
  1741.     CEdit::OnNcMouseMove(nHitTest, point);
  1742.     if (GetFlags() & FEC_FLAT && this != GetFocus())
  1743.     {
  1744.         SetCapture();
  1745.         Redraw(FALSE);
  1746.     }
  1747. }
  1748. void CFileEditCtrl::DrawEdge(void)
  1749. {
  1750. HDC hDC;
  1751. RECT Rect;
  1752. LONG lExStyle, lStyle;
  1753. HANDLE hHandle;
  1754. lStyle = ::GetWindowLong(this->m_hWnd, GWL_STYLE);
  1755. lExStyle = ::GetWindowLong(this->m_hWnd, GWL_EXSTYLE);
  1756. if ((::GetWindowLong(this->m_hWnd, GWL_STYLE) & WS_BORDER) ||
  1757. (lExStyle & WS_EX_CLIENTEDGE) || (lExStyle & WS_EX_STATICEDGE))
  1758. {
  1759. // 由于绘制的东西很少,所以直接绘制而不使用 MEMDCXP 方式
  1760. hDC = ::GetWindowDC(this->m_hWnd);
  1761. // 获取窗口大小
  1762. ::GetWindowRect(this->m_hWnd, &Rect);
  1763. Rect.right -= Rect.left;
  1764. Rect.bottom -= Rect.top;
  1765. Rect.top = Rect.left = 0;
  1766. // 绘制外框
  1767. hHandle = (HANDLE) CreateSolidBrush(
  1768. (lStyle & WS_DISABLED) ? (GetSysColor(COLOR_BTNFACE) - 0x00202020) : 0x00BD9E7B);
  1769. FrameRect(hDC, &Rect, (HBRUSH) hHandle);
  1770. DeleteObject((HGDIOBJ) hHandle);
  1771. // 绘制内框
  1772. if ((lExStyle & WS_EX_CLIENTEDGE) || (lExStyle & WS_EX_STATICEDGE))
  1773. {
  1774. InflateRect(&Rect, -1, -1);
  1775. hHandle = (HANDLE) GetSysColorBrush(
  1776. (lStyle & WS_DISABLED) || (lStyle & ES_READONLY) ? COLOR_BTNFACE : COLOR_WINDOW);
  1777. FrameRect(hDC, &Rect, (HBRUSH) hHandle);
  1778. if ((lExStyle & WS_EX_CLIENTEDGE) && (lExStyle & WS_EX_STATICEDGE))
  1779. {
  1780. InflateRect(&Rect, -1, -1);
  1781. FrameRect(hDC, &Rect, (HBRUSH)hHandle);
  1782. }
  1783. }
  1784. // 释放设备场景
  1785. ::ReleaseDC(this->m_hWnd, hDC);
  1786. }
  1787. }
  1788. /////////////////////////////////////////////////////////////////////////////
  1789. //
  1790. //  CFileEditCtrl::OnNcPaint  (protected member function)
  1791. //    Handles the WM_NCPAINT message
  1792. //    Redraws the control's border as needed
  1793. //
  1794. //  Parameters :
  1795. //    None
  1796. //
  1797. //  Returns :
  1798. //    Nothing
  1799. //
  1800. //  Note:
  1801. //    If the control is flat, we have to draw a COLOR_WINDOW coloured
  1802. //    border around the control
  1803. //
  1804. /////////////////////////////////////////////////////////////////////////////
  1805. void CFileEditCtrl::OnNcPaint() 
  1806. {
  1807. DrawEdge();
  1808.   /*  if (m_nButtonState & BTN_FLAT)
  1809.     {   // draw the flat border
  1810.         CRect WindowRect;
  1811.         GetWindowRect(&WindowRect);
  1812.         CRect ClientRect;
  1813.         GetClientRect(&ClientRect);
  1814.         ClientToScreen(&ClientRect);
  1815.         int Border = ClientRect.top - WindowRect.top;
  1816.             
  1817.         CWindowDC DC(this);
  1818.         int saved = DC.SaveDC();
  1819.         CPen thePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOW));  // border colour
  1820.         DC.SelectObject(&thePen);
  1821.         DC.Rectangle(Border - 1, Border - 1, WindowRect.Width() - Border + 1, WindowRect.Height() - Border + 1);
  1822.         DC.RestoreDC(saved);
  1823.         DeleteObject(thePen);
  1824.     }
  1825.     else
  1826.         CEdit::OnNcPaint();         // draws the 3D border around the control*/
  1827.     DrawButton(m_nButtonState);     // draw the button in its current state
  1828. }
  1829. /////////////////////////////////////////////////////////////////////////////
  1830. //
  1831. //  CFileEditCtrl::OnSetFocus  (protected member function)
  1832. //    Handles the WM_SETFOCUS message
  1833. //    Selects (hilites) all the text in the control
  1834. //
  1835. //  Parameters :
  1836. //    pOldWnd [in] - not used here, passed on to the base class
  1837. //
  1838. //  Returns :
  1839. //    Nothing
  1840. //
  1841. /////////////////////////////////////////////////////////////////////////////
  1842. void CFileEditCtrl::OnSetFocus(CWnd* pOldWnd) 
  1843. {
  1844.     CEdit::OnSetFocus(pOldWnd);
  1845.     Redraw(FALSE);
  1846. m_bIsFocused = TRUE;
  1847. // DrawEdge();
  1848.     SetSel(0, -1);
  1849. }
  1850. /////////////////////////////////////////////////////////////////////////////
  1851. //
  1852. //  CFileEditCtrl::OnSetReadOnly  (protected member function)
  1853. //    Handles the EM_SETREADONLY message
  1854. //
  1855. //  Parameters :
  1856. //    None
  1857. //
  1858. //  Returns :
  1859. //    Whatever the default windows procedure returns
  1860. //
  1861. //  Note :
  1862. //    If the control has the FEC_FLAT flag set, the border must
  1863. //    be redrawn when the readonly state is changed
  1864. //
  1865. /////////////////////////////////////////////////////////////////////////////
  1866. LRESULT CFileEditCtrl::OnSetReadOnly(WPARAM, LPARAM)
  1867. {
  1868.     LRESULT retval = Default();
  1869.     Redraw(TRUE);
  1870.     return retval;
  1871. }
  1872. /////////////////////////////////////////////////////////////////////////////
  1873. //
  1874. //  CFileEditCtrl::OnSetText  (protected member function)
  1875. //    Handles the WM_SETTEXT message
  1876. //    Sets the m_bTextChanged flag
  1877. //
  1878. //  Parameters :
  1879. //    None
  1880. //
  1881. //  Returns :
  1882. //    Whatever the default windows procedure returns
  1883. //
  1884. //  Note :
  1885. //    OnChange() does not seem to get called every time a WM_SETTEXT message
  1886. //    is sent to this control, so I duplicated it's functionality here.
  1887. //
  1888. //    CWnd does not have an OnSetText() handler function, so I called Default()
  1889. //    to ensure this message is properly handled 
  1890. //
  1891. /////////////////////////////////////////////////////////////////////////////
  1892. LRESULT CFileEditCtrl::OnSetText(WPARAM, LPARAM)
  1893. {
  1894.     m_bTextChanged = TRUE;
  1895.     return Default();
  1896. }
  1897. /////////////////////////////////////////////////////////////////////////////
  1898. //
  1899. //  CFileEditCtrl::OnSize  (protected member function)
  1900. //    Handles the WM_SIZE message
  1901. //    Forces a recalculation of the button's and client area's size and position
  1902. //    also recalculates the tooltips bounding rectangles
  1903. //
  1904. //  Parameters :
  1905. //    nType [in] - not used here, passed on to the base class
  1906. //    cx    [in] - not used here, passed on to the base class
  1907. //    cy    [in] - not used here, passed on to the base class
  1908. //
  1909. //  Returns :
  1910. //    Nothing
  1911. //
  1912. /////////////////////////////////////////////////////////////////////////////
  1913. void CFileEditCtrl::OnSize(UINT nType, int cx, int cy) 
  1914. {
  1915.     CEdit::OnSize(nType, cx, cy);
  1916.     SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  1917. }
  1918. /////////////////////////////////////////////////////////////////////////////
  1919. //
  1920. //  CFileEditCtrl::OnTTNNeedText  (protected member function)
  1921. //    Handles the TTN_NEEDTEXT message from the tooltip control
  1922. //    Sets the tooltip text
  1923. //
  1924. //  Parameters :
  1925. //    pTTTStruct [in] - pointer to a TOOLTIPTEXT structure
  1926. //
  1927. //  Returns :
  1928. //    TRUE
  1929. //
  1930. /////////////////////////////////////////////////////////////////////////////
  1931. BOOL CFileEditCtrl::OnTTNNeedText(UINT, NMHDR *pTTTStruct, LRESULT *)
  1932. {
  1933.     DWORD Flags = GetFlags();
  1934.     TOOLTIPTEXT* pTTT = ((TOOLTIPTEXT*)pTTTStruct);
  1935.     if ((Flags & FEC_BUTTONTIP) && ID_BUTTONTIP == pTTT->hdr.idFrom)
  1936.     {
  1937. #if defined FEC_NORESOURCESTRINGS
  1938.         pTTT->lpszText = FEC_IDS_BUTTONTIP;
  1939. #else
  1940.         pTTT->lpszText = MAKEINTRESOURCE(FEC_IDS_BUTTONTIP);
  1941.         pTTT->hinst = AfxGetResourceHandle();
  1942. #endif
  1943.     }
  1944.     if ((Flags & FEC_CLIENTTIP) && ID_CLIENTTIP == pTTT->hdr.idFrom)
  1945.     {
  1946.         pTTT->lpszText = m_szClientTip.GetBuffer(m_szClientTip.GetLength());
  1947.         m_szClientTip.ReleaseBuffer();
  1948.     }
  1949.     return TRUE;
  1950. }
  1951. /////////////////////////////////////////////////////////////////////////////
  1952. //
  1953. //  CFileEditCtrl::PostNcDestroy  (protected member function)
  1954. //    deletes this control object if the m_bAutoDelete flag is set
  1955. //
  1956. //  Parameters :
  1957. //    None
  1958. //
  1959. //  Returns :
  1960. //    Nothing
  1961. //
  1962. /////////////////////////////////////////////////////////////////////////////
  1963. void CFileEditCtrl::PostNcDestroy() 
  1964. {
  1965.     if (m_bAutoDelete)
  1966.         delete this;
  1967. }
  1968. /////////////////////////////////////////////////////////////////////////////
  1969. //
  1970. //  CFileEditCtrl::PreTranslateMessage  (public member function)
  1971. //    Sets up and passes messages to the tooltip control
  1972. //
  1973. //  Parameters :
  1974. //    pMsg [in] - the current windows message
  1975. //
  1976. //  Returns :
  1977. //    whatever CEdit::PreTranslateMessage() returns
  1978. //
  1979. /////////////////////////////////////////////////////////////////////////////
  1980. BOOL CFileEditCtrl::PreTranslateMessage(MSG* pMsg) 
  1981. {   // not using GetFlags() because this is faster
  1982.     if (m_dwFlags & (FEC_BUTTONTIP | FEC_CLIENTTIP))
  1983.     {
  1984.         if (!IsWindow (m_ToolTip))
  1985.         {
  1986.             // create and activate the tooltip control
  1987.             m_ToolTip.Create(this);
  1988.             m_ToolTip.Activate(TRUE);
  1989.             m_ToolTip.SetFont(GetFont());
  1990.             // Setup the button tooltip
  1991.             CRect rc(m_rcButtonRect);
  1992.             CRect wnd;
  1993.             GetWindowRect(&wnd);
  1994.             rc.OffsetRect(wnd.left, wnd.top);
  1995.             ScreenToClient(&rc);
  1996.             m_ToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &rc, ID_BUTTONTIP);
  1997.             // Setup the client area tooltip
  1998.             GetClientRect(&wnd);
  1999.             m_ToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &wnd, ID_CLIENTTIP);
  2000.         }
  2001.         m_ToolTip.RelayEvent(pMsg);
  2002.     }
  2003.     return CEdit::PreTranslateMessage(pMsg);
  2004. }
  2005. /////////////////////////////////////////////////////////////////////////////
  2006. //
  2007. //  CFileEditCtrl::Redraw   (protected member function)
  2008. //    Redraws the control as either flat or 3D
  2009. //
  2010. //  Parameters :
  2011. //    Flat [in] : The control's flat state
  2012. //
  2013. //  Returns :
  2014. //    Nothing
  2015. //
  2016. /////////////////////////////////////////////////////////////////////////////
  2017. void CFileEditCtrl::Redraw(BOOL Flat)
  2018. {
  2019.     if (IsWindow(this) && GetFlags() & FEC_FLAT)
  2020.     {
  2021.         if (Flat && this != GetFocus())
  2022.         {   // draw flat
  2023.             m_nButtonState |= BTN_FLAT;
  2024.             // Get parent window to erase the border
  2025.             CWnd *pParent = GetParent();
  2026.             if (IsWindow(pParent))
  2027.             {
  2028.                 CRect rc;
  2029.                 GetWindowRect(&rc);
  2030.                 pParent->ScreenToClient(&rc);
  2031.                 pParent->RedrawWindow(&rc);
  2032.             }
  2033.         }
  2034.         else
  2035.         {   // draw 3D
  2036.             m_nButtonState &= ~BTN_FLAT;
  2037.             RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW/* | RDW_ERASE*/);
  2038.         }
  2039.     }
  2040. }
  2041. /////////////////////////////////////////////////////////////////////////////
  2042. //
  2043. //  CFileEditCtrl::ScreenPointInButtonRect  (protected member function)
  2044. //    determine if the mouse cursor is on the button
  2045. //
  2046. //  Parameters :
  2047. //    point [in] - The location of the mouse cursor in screen coordinates
  2048. //
  2049. //  Returns :
  2050. //    TRUE if the mouse cursor is on the button
  2051. //    FALSE if it is not
  2052. //
  2053. /////////////////////////////////////////////////////////////////////////////
  2054. BOOL CFileEditCtrl::ScreenPointInButtonRect(CPoint point)
  2055. {
  2056.     CRect ControlRect;
  2057.     GetWindowRect(&ControlRect);
  2058.     // convert point from screen coordinates to window coordinates
  2059.     point.Offset(-ControlRect.left, -ControlRect.top);
  2060.     return m_rcButtonRect.PtInRect(point);
  2061. }
  2062. /////////////////////////////////////////////////////////////////////////////
  2063. //
  2064. //  CFileEditCtrl::SetButtonImage  (public member function)
  2065. //    Set the image to be used on the browse button
  2066. //
  2067. //  Parameters :
  2068. //    hImage      [in] - handle of the image (can be a HBITMAP or HICON)
  2069. //    PJAIFlags   [in] - The image flags (see the note below)
  2070. //    Transparent [in] - the transparent colour, if CLR_DEFAULT is used, the colour
  2071. //                       of the top left pixel is used as the transparent colour
  2072. //
  2073. //  Returns :
  2074. //    TRUE if a new image is set, FALSE if not
  2075. //
  2076. //  Note :
  2077. //    Flags used in the PJAIFlags parameter :
  2078. //      PJAI_ICON        - the image is a HICON
  2079. //      PJAI_BITMAP      - the image is a HBITMAP
  2080. //      PJAI_STRETCHED   - the image will be stretched (or shrunk) to fit on the button
  2081. //      PJAI_TRANSPARENT - the HBITMAP image will be drawn transparently. The transparent 
  2082. //                         colour is specified using the Transparent parameter.
  2083. //      PJAI_AUTODELETE  - the image handle will be deleted and the memory freed when 
  2084. //                         when a new image is set or the CFileEditCtrl is deleted. If
  2085. //                         this flag is not set, the user of this class is responsible
  2086. //                         for deleting the handle.
  2087. //
  2088. //    The PJAImage.h file must be included (see lines 37 to 41 of FileEditCtrl.h) in
  2089. //    order for this function to work.
  2090. //
  2091. /////////////////////////////////////////////////////////////////////////////
  2092. #ifdef AFX_PJAIMAGE_H__F15965B0_B05A_11D4_B625_A1459D96AB20__INCLUDED_
  2093.     BOOL CFileEditCtrl::SetButtonImage(HANDLE hImage, DWORD PJAIFlags, COLORREF Transparent/* = CLR_DEFAULT*/)
  2094.     {
  2095.         BOOL ret = FALSE;
  2096.         if (m_pButtonImage)
  2097.         {
  2098.             delete m_pButtonImage;
  2099.             m_pButtonImage = NULL;
  2100.         }
  2101.         if (hImage)
  2102.         {
  2103.             m_pButtonImage = new CPJAImage();
  2104.             if (m_pButtonImage->SetImage(hImage, PJAIFlags))
  2105.             {
  2106.                 ret = TRUE;
  2107.                 m_dwImageDrawFlags = PJAIFlags;
  2108.                 m_pButtonImage->SetTransparentColour(Transparent);
  2109.                 if (!(m_dwImageDrawFlags & PJAI_STRETCHED))
  2110.                     m_dwImageDrawFlags |= PJAI_CENTERED;
  2111.             }
  2112.         }
  2113.         if (IsWindow(this))
  2114.             RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
  2115.         return ret;
  2116.     }
  2117. #endif
  2118. /////////////////////////////////////////////////////////////////////////////
  2119. //
  2120. //  CFileEditCtrl::SetButtonWidth  (public member function)
  2121. //    Sets the width, in pixels, of the browse button
  2122. //
  2123. //  Parameters :
  2124. //    width [in] - The new width of the button
  2125. //
  2126. //  Returns :
  2127. //    The previous width of the button
  2128. //
  2129. //  Note :
  2130. //    Setting the width to -1 causes the control to use the default width
  2131. //    which is calculated to be 80% of it's height
  2132. //
  2133. /////////////////////////////////////////////////////////////////////////////
  2134. int CFileEditCtrl::SetButtonWidth(int width/* = -1*/)
  2135. {
  2136.     int oldWidth = GetButtonWidth();
  2137.     m_nButtonWidth = width;
  2138.     SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  2139.     return oldWidth;
  2140. }
  2141. /////////////////////////////////////////////////////////////////////////////
  2142. //
  2143. //  CFileEditCtrl::SetClientTipText  (public member function)
  2144. //    Sets the text to be used by the client area tooltip
  2145. //
  2146. //  Parameters :
  2147. //    text [in] - The text to set
  2148. //
  2149. //  Returns :
  2150. //    Nothing
  2151. //
  2152. /////////////////////////////////////////////////////////////////////////////
  2153. void CFileEditCtrl::SetClientTipText(CString text)
  2154. {
  2155.     m_szClientTip = text;
  2156. }
  2157. /////////////////////////////////////////////////////////////////////////////
  2158. //
  2159. //  CFileEditCtrl::SetFlags  (public member function)
  2160. //    Sets all the internal flags
  2161. //    Initializes and sets up the OPENFILENAME or BROWSEINFO structures
  2162. //    Forces the control to be redrawn if the button position changes
  2163. //
  2164. //  Parameters :
  2165. //    dwFlags [in] - The flags to set
  2166. //
  2167. //  Returns :
  2168. //    TRUE if successful
  2169. //    FALSE if not
  2170. //
  2171. //  Note :
  2172. //    See the FileEditCtrl.h file for descriptions of the flags used
  2173. //
  2174. /////////////////////////////////////////////////////////////////////////////
  2175. BOOL CFileEditCtrl::SetFlags(DWORD dwFlags)
  2176. {
  2177.     m_bTextChanged = TRUE;
  2178.     if (dwFlags & FEC_FOLDER)
  2179.     {   // set the control to find folders
  2180.         if (dwFlags & (FEC_FILEOPEN | FEC_FILESAVEAS))
  2181.         {
  2182.             TRACE (_T("CFileEditCtrl::SetFlags() : Can not specify FEC_FILEOPEN or FEC_FILESAVEAS with FEC_FOLDERn"));
  2183.             ASSERT (FALSE);
  2184.             return FALSE;
  2185.         }
  2186.         if (!m_pBROWSEINFO)
  2187.         {   // create the BROWSEINFO structure
  2188.             m_pBROWSEINFO = new BROWSEINFO();
  2189.             if (!m_pBROWSEINFO)
  2190.             {
  2191.                 TRACE (_T("CFileEditCtrl::SetFlags() : Failed to create the BROWSEINFO structuren"));
  2192.                 ASSERT (FALSE);
  2193.                 return FALSE;
  2194.             }
  2195. /*            if (m_pCFileDialog)
  2196.             {
  2197. delete m_pCFileDialog;          // delete the CFileDialog
  2198. m_pCFileDialog = NULL;
  2199. }*/
  2200.             // set up the BROWSEINFO structure used by SHBrowseForFolder()
  2201.             ::ZeroMemory(m_pBROWSEINFO, sizeof(BROWSEINFO));
  2202.             m_pBROWSEINFO->hwndOwner = GetSafeHwnd();
  2203.             m_pBROWSEINFO->lParam = (LPARAM)this;
  2204.             m_pBROWSEINFO->lpfn = FECFolderProc;
  2205.             m_pBROWSEINFO->ulFlags = BIF_RETURNONLYFSDIRS;
  2206.         }
  2207.     }
  2208. else if (dwFlags & (FEC_FILEOPEN | FEC_FILESAVEAS))
  2209. {
  2210. if (m_pBROWSEINFO)
  2211. {
  2212. delete m_pBROWSEINFO;               // delete the BROWSEINFO structure
  2213. m_pBROWSEINFO = NULL;
  2214. }
  2215. }
  2216. /*  else if (dwFlags & (FEC_FILEOPEN | FEC_FILESAVEAS))
  2217.     {   // set the control to find files
  2218. if ((dwFlags & FEC_FILEOPEN) && (dwFlags & FEC_FILESAVEAS))
  2219. {
  2220. TRACE (_T("CFileEditCtrl::SetFlags() : Can not specify FEC_FILEOPEN with FEC_FILESAVEAS"));
  2221. ASSERT (FALSE);
  2222. return FALSE;
  2223. }
  2224.   BOOL bOpen = dwFlags & FEC_FILEOPEN;
  2225.   
  2226.         if (!m_pCFileDialog)
  2227.         {   // create the CFileDialog
  2228. CString szFilter;
  2229. #if defined FEC_NORESOURCESTRINGS
  2230. szFilter = FEC_IDS_ALLFILES;
  2231. #else
  2232. szFilter.LoadString(FEC_IDS_ALLFILES);
  2233. #endif
  2234. m_pCFileDialog = new CFECFileDialog(bOpen,
  2235. NULL,
  2236. NULL,
  2237. OFN_HIDEREADONLY | OFN_NOCHANGEDIR,
  2238. m_strFilter,
  2239. this);
  2240. if (!m_pCFileDialog)
  2241. {
  2242. TRACE (_T("CFileEditCtrl::SetFlags() : Failed to create the CFileDialogn"));
  2243. ASSERT (FALSE);
  2244. return FALSE;
  2245. }
  2246. if (m_pBROWSEINFO)
  2247. {
  2248. delete m_pBROWSEINFO;               // delete the BROWSEINFO structure
  2249. m_pBROWSEINFO = NULL;
  2250. }
  2251.         }
  2252.         
  2253.   m_pCFileDialog->SetOpenSave(bOpen);
  2254.   
  2255. if (bOpen)
  2256.             m_pCFileDialog->m_ofn.Flags |= OFN_FILEMUSTEXIST;
  2257. else
  2258.             m_pCFileDialog->m_ofn.Flags |= OFN_OVERWRITEPROMPT;
  2259.   if (dwFlags & FEC_MULTIPLE)
  2260.   m_pCFileDialog->m_ofn.Flags |= OFN_ALLOWMULTISELECT;
  2261.   else
  2262.   m_pCFileDialog->m_ofn.Flags &= ~OFN_ALLOWMULTISELECT;
  2263.   
  2264. if (dwFlags & FEC_NODEREFERENCELINKS)
  2265. m_pCFileDialog->m_ofn.Flags |= OFN_NODEREFERENCELINKS;
  2266. else
  2267. m_pCFileDialog->m_ofn.Flags &= ~OFN_NODEREFERENCELINKS;
  2268.   m_pCFileDialog->m_ofn.hwndOwner = GetSafeHwnd();
  2269.   #if defined FEC_NORESOURCESTRINGS
  2270.   m_szCaption = FEC_IDS_FILEDIALOGTITLE;
  2271.   #else
  2272.   m_szCaption.LoadString(FEC_IDS_FILEDIALOGTITLE);
  2273.   #endif
  2274.   m_pCFileDialog->m_ofn.lpstrTitle = (LPCTSTR)m_szCaption;
  2275.   }
  2276.   
  2277. else
  2278. {
  2279. TRACE (_T("CFileEditCtrl::SetFlags() : Must specify either FEC_FILEOPEN, FEC_FILESAVEAS or FEC_FOLDER when setting flagsn"));
  2280. ASSERT (FALSE);
  2281. return FALSE;
  2282. }
  2283. */
  2284.     // m_bButtonLeft will be 0xFFFFFFFF the first time SetFlags() is called
  2285.     // (dwFlags & FEC_BUTTONLEFT) will be either 0x00000000 or FEC_BUTTONLEFT
  2286.     if (m_bButtonLeft != (dwFlags & FEC_BUTTONLEFT))
  2287.     {
  2288.         // move the button to the desired side of the control
  2289.         m_bButtonLeft = dwFlags & FEC_BUTTONLEFT;
  2290.         // force a call to OnNcCalcSize to calculate the size and position of the button and client area
  2291.         SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  2292.         if (m_dwFlags & FEC_FLAT)
  2293.             RedrawWindow(); // the text needs to be redrawn if moving the button on a flat control
  2294.     }
  2295.     // check to see if the FEC_FLAT flag has changed
  2296.     // if it has, redraw the control to reflect it's new state
  2297.     if ((dwFlags & FEC_FLAT) != (m_dwFlags & FEC_FLAT))
  2298.     {
  2299.         m_dwFlags |= FEC_FLAT;   // needed to redraw the control's borders 
  2300.         Redraw(dwFlags & FEC_FLAT);
  2301.     }
  2302.     m_dwFlags = dwFlags;
  2303.     return TRUE;
  2304. }
  2305. /////////////////////////////////////////////////////////////////////////////
  2306. // DDV_FileEditCtrl & DDX_FileEditCtrl
  2307. /////////////////////////////////////////////////////////////////////////////
  2308. //
  2309. //  DDV_FileEditCtrl  (Global function)
  2310. //    Verifies that the files or folders entered actually exist
  2311. //
  2312. //  Parameters :
  2313. //    pDX  [in] - Pointer to the CDataExchange object
  2314. //    nIDC [in] - The controls resource ID
  2315. //
  2316. //  Returns :
  2317. //    Nothing
  2318. //
  2319. //  Note :
  2320. //    If the file or folder is invalid, pops up a messagebox informing the user,
  2321. //    then sets the focus to the offending CFileEditCtrl
  2322. //
  2323. /////////////////////////////////////////////////////////////////////////////
  2324. void DDV_FileEditCtrl(CDataExchange *pDX, int nIDC)
  2325. {
  2326.     CWnd *pWnd = pDX->m_pDlgWnd->GetDlgItem(nIDC);
  2327.     ASSERT(pWnd);
  2328.     if (!pWnd->IsKindOf(RUNTIME_CLASS(CFileEditCtrl)))  // is this control a CFileEditCtrl control?
  2329.     {
  2330.         TRACE(_T("Control %d not subclassed to CFileEditCtrl, must first call DDX_FileEditCtrl()"), nIDC);
  2331.         ASSERT(FALSE);
  2332.         AfxThrowNotSupportedException();
  2333.     }
  2334.     if (!pDX->m_bSaveAndValidate)               // not saving data
  2335.         return;
  2336.     CFileEditCtrl *pFEC = (CFileEditCtrl *)pWnd;
  2337.     pDX->PrepareEditCtrl(nIDC);
  2338.     POSITION pos = pFEC->GetStartPosition();
  2339.     if (!pos)
  2340.     { // no name entered
  2341.         AfxMessageBox(FEC_IDS_NOFILE);
  2342.         pDX->Fail();
  2343.     }
  2344.     while (pos)
  2345.     {
  2346.         CString szMessage;
  2347.         CString szFile = pFEC->GetNextPathName(pos);
  2348.         DWORD dwAttribute = GetFileAttributes(szFile);
  2349.         if (0xFFFFFFFF == dwAttribute)          // GetFileAttributes() failed
  2350.         {                                       // does not exist
  2351.             szMessage.Format(FEC_IDS_NOTEXIST, szFile);
  2352.             AfxMessageBox(szMessage);
  2353.             pDX->Fail();
  2354.         }
  2355.         if ((pFEC->GetFlags() & FEC_FOLDER) && !(dwAttribute & FILE_ATTRIBUTE_DIRECTORY))
  2356.         {                                       // not a folder
  2357.             szMessage.Format(FEC_IDS_NOTFOLDER, szFile);
  2358.             AfxMessageBox(szMessage);
  2359.             pDX->Fail();
  2360.         }
  2361.         if ((pFEC->GetFlags() & FEC_FILE) && (dwAttribute & FILE_ATTRIBUTE_DIRECTORY))
  2362.         {                                       // not a file
  2363.             szMessage.Format(FEC_IDS_NOTFILE, szFile);
  2364.             AfxMessageBox(szMessage);
  2365.             pDX->Fail();
  2366.         }
  2367.     }
  2368. }
  2369. /////////////////////////////////////////////////////////////////////////////
  2370. //
  2371. //  DDX_FileEditCtrl (Global function)
  2372. //    Subclasses the control with the given ID
  2373. //    Transfers the data between the control and the supplied CString
  2374. //
  2375. //  Parameters :
  2376. //    pDX     [in] - Pointer to the CDataExchange object
  2377. //    nIDC    [in] - The controls resource ID
  2378. //    rStr    [in] - The CString that contains the initial control text, and receives the text
  2379. //    dwFlags [in] - The flags used to setup this control
  2380. //
  2381. //  Returns :
  2382. //    Nothing
  2383. //
  2384. //  Note :
  2385. //    See the FileEditCtrl.h file for descriptions of the flags used
  2386. //    the FEC_MULTIPLE flag can not be used (how can multiple files be returned in one CString?)
  2387. //
  2388. /////////////////////////////////////////////////////////////////////////////
  2389. void DDX_FileEditCtrl(CDataExchange *pDX, int nIDC, CString& rStr, DWORD dwFlags)
  2390. {
  2391.     CWnd *pWnd = pDX->m_pDlgWnd->GetDlgItem(nIDC);
  2392.     ASSERT(pWnd);
  2393.     if (pDX->m_bSaveAndValidate)                // update string with text from control
  2394.     {
  2395.         // ensure the control is a CFileEditCtrl control
  2396.         ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CFileEditCtrl)));
  2397.         // copy the first file listed in the control to the string
  2398.         rStr.Empty();
  2399.         CFileEditCtrl *pFEC = (CFileEditCtrl *)pWnd;
  2400.         POSITION pos = pFEC->GetStartPosition();
  2401.         if (pos)
  2402.             rStr = pFEC->GetNextPathName(pos);
  2403.     }
  2404.     else                                        // create the control if it is not already created
  2405.     {                                           // set the control text to the text in string
  2406.         CFileEditCtrl *pFEC = NULL;
  2407.         if (!pWnd->IsKindOf(RUNTIME_CLASS(CFileEditCtrl)))    // not subclassed yet
  2408.         {
  2409.             // create then subclass the control to the edit control with the ID nIDC
  2410.             HWND hWnd = pDX->PrepareEditCtrl(nIDC);
  2411.             pFEC = new CFileEditCtrl(TRUE);     // create the control with autodelete
  2412.             if (!pFEC)                          // failed to create control
  2413.             {
  2414.                 ASSERT(FALSE);
  2415.                 AfxThrowNotSupportedException();
  2416.             }
  2417.             if (!pFEC->SubclassWindow(hWnd))
  2418.             {                                   // failed to subclass the edit control
  2419.                 delete pFEC;
  2420.                 ASSERT(FALSE);
  2421.                 AfxThrowNotSupportedException();
  2422.             }
  2423.             // call CFileEditCtrl::SetFlags() to initialize the internal data structures
  2424.             dwFlags &= ~FEC_MULTIPLE;           // can not put multiple files in one CString
  2425.             if (!pFEC->SetFlags(dwFlags))
  2426.             {
  2427.                 delete pFEC;
  2428.                 ASSERT(FALSE);
  2429.                 AfxThrowNotSupportedException();
  2430.             }
  2431.         }
  2432.         else                                    // control already exists
  2433.             pFEC = (CFileEditCtrl *)pWnd;
  2434.         if (pFEC)
  2435.             pFEC->SetWindowText(rStr);          // set the control text
  2436.     }
  2437. }
  2438. /////////////////////////////////////////////////////////////////////////////
  2439. //
  2440. //  DDX_FileEditCtrl (Global function)
  2441. //    Subclasses the control with the given ID
  2442. //    Transfers the data between the control and the supplied CFileEditCtrl
  2443. //
  2444. //  Parameters :
  2445. //    pDX     [in] - Pointer to the CDataExchange object
  2446. //    nIDC    [in] - The controls resource ID
  2447. //    rCFEC   [in] - The CFileEditCtrl object that is to control this window
  2448. //    dwFlags [in] - The flags used to setup this control
  2449. //
  2450. //  Returns :
  2451. //    Nothing
  2452. //
  2453. //  Note :
  2454. //    See the FileEditCtrl.h file for descriptions of the flags used
  2455. //
  2456. /////////////////////////////////////////////////////////////////////////////
  2457. void DDX_FileEditCtrl(CDataExchange *pDX, int nIDC, CFileEditCtrl &rCFEC, DWORD dwFlags)
  2458. {
  2459.     ASSERT(pDX->m_pDlgWnd->GetDlgItem(nIDC));
  2460.     if (NULL == rCFEC.m_hWnd)                   // not yet subclassed
  2461.     {
  2462.         ASSERT(!pDX->m_bSaveAndValidate);
  2463.         // subclass the control to the edit control with the ID nIDC
  2464.         HWND hWnd = pDX->PrepareEditCtrl(nIDC);
  2465.         if (!rCFEC.SubclassWindow(hWnd))
  2466.         {                                       // failed to subclass the edit control
  2467.             ASSERT(FALSE);
  2468.             AfxThrowNotSupportedException();
  2469.         }
  2470.         // call CFileEditCtrl::SetFlags() to initialize the internal data structures
  2471.         if (!rCFEC.SetFlags(dwFlags))
  2472.         {
  2473.             ASSERT(FALSE);
  2474.             AfxThrowNotSupportedException();
  2475.         }
  2476.     }
  2477.     else if (pDX->m_bSaveAndValidate)
  2478.         rCFEC.GetStartPosition();               // updates the data from the edit control
  2479. }
  2480. /////////////////////////////////////////////////////////////////////////////
  2481. // FEC_NOTIFY structure
  2482. /////////////////////////////////////////////////////////////////////////////
  2483. //
  2484. //  FEC_NOTIFY constructor (public member function)
  2485. //    Initializes the FEC_NOTIFY structure used when the CFileEditCtrl sends
  2486. //    a WM_NOTIFY message to it's parent window (in CFileEditCtrl::ButtonClicked())
  2487. //
  2488. //  Parameters :
  2489. //    FEC  [in] - pointer to the CFileEditCtrl sending the message
  2490. //    code [in] - The notification message being sent. (FEC_NM_PREBROWSE,
  2491. //                FEC_NM_POSTBROWSE or FEC_NM_DROP)
  2492. //
  2493. //  Returns :
  2494. //    Nothing
  2495. //
  2496. /////////////////////////////////////////////////////////////////////////////
  2497. tagFEC_NOTIFY::tagFEC_NOTIFY (CFileEditCtrl *FEC, UINT code)
  2498. {
  2499.     pFEC = FEC;
  2500.     hdr.hwndFrom = FEC->GetSafeHwnd();
  2501.     hdr.idFrom = FEC->GetDlgCtrlID();
  2502.     hdr.code = code;
  2503.     pNewText = NULL;
  2504. }
  2505. /////////////////////////////////////////////////////////////////////////////
  2506. /////////////////////////////////////////////////////////////////////////////
  2507. //
  2508. //  End of FileEditCtrl.cpp
  2509. //
  2510. /////////////////////////////////////////////////////////////////////////////