Add A Favorites Function to Your Menu

Environment: VC6 SP5,Win98 & Win2k

Do you want your program to read the users' Favorites/Bookmarks? Here is a simple and easy way to add a "Read my Favorites" function to your program based on CMenu class. After using CodeGuru.com almost everyday to help me learn C++ while designing JoeSwammi MLB (www.joeswammi.com), this is my small contibution.

  1. Insert a new menu IDR_FAVORITES_POPUP and make first topic ID_BOGUS

  2. Create your "Favorites" menu item in your IDR_MAINFRAME, in properties check mark it as a Pop-Up.

  3. Add
    #include <wininet.h>
    #include <shellapi.h>
    
    to MAINFRM.CPP

  4. Add
    CStringArray m_astrFavoriteURLs; 
    
    as a public variable in MAINFM.H

  5. Add this function to CMainFrame named:
    int CMainFrame::BuildFavoritesMenu(LPCTSTR pszPath, 
                                       int nStartPos, 
                                       CMenu *pMenu)
    {
      CString         strPath(pszPath);
      CString         strPath2;
      CString         str;
      WIN32_FIND_DATA wfd;
      HANDLE          h;
      int             nPos;
      int             nEndPos;
      int             nNewEndPos;
      int             nLastDir;
      TCHAR           buf[INTERNET_MAX_PATH_LENGTH];
      CStringArray    astrFavorites;
      CStringArray    astrDirs;
      CMenu*          pSubMenu;
    
      // make sure there's a trailing backslash
      if(strPath[strPath.GetLength() - 1] != _T('\\'))
        strPath += _T('\\');
      strPath2 = strPath;
      strPath += "*.*";
    
      // now scan the directory, first for .URL 
      // files and then for subdirectories
      // that may also contain .URL files
      h = FindFirstFile(strPath, &wfd);
      if(h != INVALID_HANDLE_VALUE)
      {
        nEndPos = nStartPos;
        do
        {
          if((wfd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|
                  FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))==0)
          {
            str = wfd.cFileName;
            if(str.Right(4) == _T(".url"))
            {
              // an .URL file is formatted just like an .INI file,
              // so we can use GetPrivateProfileString() to get 
              // the information we want
              ::GetPrivateProfileString(_T("InternetShortcut"),
                                        _T("URL"),
                                        _T(""),
                                        buf,
                                        INTERNET_MAX_PATH_LENGTH,
                                        strPath2 + str);
              str = str.Left(str.GetLength() - 4);
    
              // scan through the array and perform an insertion
              // sort to make sure the menu ends up in alphabetic
              // order
              for(nPos = nStartPos ; nPos < nEndPos ; ++nPos)
              {
                if(str.CompareNoCase(astrFavorites[nPos]) < 0)
                  break;
              }
              astrFavorites.InsertAt(nPos, str);
              m_astrFavoriteURLs.InsertAt(nPos, buf);
              ++nEndPos;
            }
          }
        } while(FindNextFile(h, &wfd));
        FindClose(h);
        // Now add these items to the menu
        for(nPos = nStartPos ; nPos < nEndPos ; ++nPos)
        {
          pMenu->AppendMenu(MF_STRING | MF_ENABLED,
                            0xe00 + nPos,
                            astrFavorites[nPos]);
        }
    
        // now that we've got all the .URL files, check 
        // the subdirectories for more
        nLastDir = 0;
        h = FindFirstFile(strPath, &wfd);
        ASSERT(h != INVALID_HANDLE_VALUE);
        do
        {
          if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
          {
            // ignore the current and parent directory entries
            if(lstrcmp(wfd.cFileName, 
    _T(".")) == 0 || lstrcmp(wfd.cFileName, _T("..")) == 0)
              continue;
    
            for(nPos = 0 ; nPos < nLastDir ; ++nPos)
            {
              if(astrDirs[nPos].CompareNoCase(wfd.cFileName) > 0)
                break;
            }
            pSubMenu = new CMenu;
            pSubMenu->CreatePopupMenu();
    
            // call this function recursively.
            nNewEndPos = BuildFavoritesMenu(strPath2 + wfd.cFileName,
                                            nEndPos,
                                            pSubMenu);
            if(nNewEndPos != nEndPos)
            {
              // only intert a submenu if there are in 
              // fact .URL files in the subdirectory
              nEndPos = nNewEndPos;
              pMenu->InsertMenu(nPos, 
                         MF_BYPOSITION | MF_POPUP | MF_STRING,
                         (UINT)pSubMenu->m_hMenu,
                         wfd.cFileName);
              pSubMenu->Detach();
              astrDirs.InsertAt(nPos, wfd.cFileName);
              ++nLastDir;
            }
            delete pSubMenu;
          }
        } while(FindNextFile(h, &wfd));
        FindClose(h);
      }
      return nEndPos;
    }
    
  6. Add this member function to CMainFrame named:
    void CMainFrame::OnFavorite(UINT nID)
    {
      ShellExecute(m_hWnd,
                   "open",
                   m_astrFavoriteURLs[nID-0xe00],
                   NULL,
                   NULL,
                   SW_SHOWDEFAULT);
    }
  7. In the ONCREATE function of CMainFrame, just before ending "return 0;", Add:
    // set up Favorites menu
      TCHAR           sz[MAX_PATH];
      TCHAR           szPath[MAX_PATH];
      HKEY            hKey;
      DWORD           dwSize;
      CMenu*          pMenu;
    
      // first get rid of bogus submenu items.
      pMenu = GetMenu()->GetSubMenu(3); //change three to what 
                        // ever position "Favorites" is from left - 1
      while(pMenu->DeleteMenu(0, MF_BYPOSITION));
    
      // find out from the registry where the favorites are located.
      if(RegOpenKey(HKEY_CURRENT_USER,
    _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User 
    Shell Folders"),
         &hKey) != ERROR_SUCCESS)
      {
        TRACE0("Favorites folder not found\n");
        return 0;
      }
      dwSize = sizeof(sz);
      RegQueryValueEx(hKey, _T("Favorites"), NULL, NULL, (LPBYTE)sz, &dwSize);
      ExpandEnvironmentStrings(sz, szPath, MAX_PATH);
      RegCloseKey(hKey);
    
      BuildFavoritesMenu(szPath, 0, pMenu);
  8. lastly, in the "BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)"add this line just above "END_MESSAGE_MAP()":
    ON_COMMAND_RANGE(0xe00, 0xfff, OnFavorite)
  9. Build and Run and should work.

NOTE: I am sure there are other features I am missing. For example, icons to go with the pop-ups next to the bookmarks, like folders and html icon, more like MS IE. If you develope this code, Please add your code to the comments for others to use also. Thanks.

Downloads

Download demo project - 22.7 Kb
Download source - All Source on this page (Cut & Paste)


Comments

  • How do you implement Add to favorites in MFC?

    Posted by Legacy on 09/14/2003 12:00am

    Originally posted by: Mike Hardy

    I am writting a Webbrowser in VC++ 6.0 standard Edition using MFC and I have already implemented View your Favorites I would like to know how I can call the Add to Favorites dialog where the user can Add a Site to the favorites menu. Can anyone help me please. if so email me or reply here my email is scoobyto@fidnet.com any one that can help will recieve the Source Code to my Webbrowser. Thanks sincerely, Mike Hardy
    

    Reply
  • bugs in Visual C++.net

    Posted by Legacy on 11/19/2002 12:00am

    Originally posted by: Richard H

    Try building this in Visual C++ .net.......
    
    

    I'm having problems with the .exe file which balks on memory problems.

    Any ideas?

    Reply
  • MFCIE?

    Posted by Legacy on 05/13/2002 12:00am

    Originally posted by: Allen

    Isn't that the code from MFCIE from MSDN?

    http://msdn.microsoft.com/code/default.asp?url=/msdn-files/026/001/497/Source%20Files/MainFrm_cpp.asp

    Reply
  • Thanks

    Posted by Legacy on 03/17/2002 12:00am

    Originally posted by: Bug Alert

    Thanks again

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • The proliferation of cloud computing options has begun to change the way storage is thought about, procured, and used. IT managers and departments need to think through how cloud options might fit into and complement their onsite data infrastructures. This white paper explains cloud storage and backup, providing advice about the tools and best practices for its implementation and use. Read this white paper for some useful takeaways about how to take advantage of cloud storage for high availability, backup and …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds