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

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • Learn How A Global Entertainment Company Saw a 448% ROI Every business today uses software to manage systems, deliver products, and empower employees to do their jobs. But software inevitably breaks, and when it does, businesses lose money -- in the form of dissatisfied customers, missed SLAs or lost productivity. PagerDuty, an operations performance platform, solves this problem by helping operations engineers and developers more effectively manage and resolve incidents across a company's global operations. …

Most Popular Programming Stories

More for Developers

RSS Feeds