GetLongPathName API Function Emulation

Environment: Windows 95/NT

The GetLongPathName API call is only available on Windows 98/ME and Windows 2000/XP. It is not available on Windows 95 & NT. This code example emulates the function for use on 95 & NT and will work on the other systems as well.

This example uses MFC and CString, but could be easily adapted to use null terminated character strings as well. The algorithm recursively strips off path components, then reassembles them with their long name equivalents.

DWORD GetLongPathName(CString  strShortPath,
                      CString& strLongPath  )
{
  int iFound = strShortPath.ReverseFind('\\');
  if (iFound > 1)
  {
    // recurse to peel off components
    //
    if (GetLongPathName(strShortPath.Left(iFound),
                        strLongPath) > 0)
    {
      strLongPath += '\\';

      if (strShortPath.Right(1) != "\\")
      {
        WIN32_FIND_DATA findData;

        // append the long component name to the path
        //
        if (INVALID_HANDLE_VALUE != ::FindFirstFile
           (strShortPath, &findData))
        {
          strLongPath += findData.cFileName;
        }
        else
        {
          // if FindFirstFile fails, return the error code
          //
          strLongPath.Empty();
          return 0;
        }
      }
    }
  }
  else
  {
    strLongPath = strShortPath;
  }

  return strLongPath.GetLength();
}


Comments

  • Error CloseHandle for

    Posted by Fthr on 10/24/2011 02:45am

    "When the search handle is no longer needed, close it by using the FindClose function, not CloseHandle." As you can see on link http://msdn.microsoft.com/en-us/library/windows/desktop/aa364418(v=vs.85).aspx

    Reply
  • Thanks for your idea! I tweaked your code a bit.

    Posted by n0gsg on 06/06/2006 08:58pm

    Randall,
    
    Thanks for your code tip, very nicely done! I added two minor fixes:
    
    1) Changed the code so that it will correctly parse long filenames on network shares (for example, the name "\\server_name\share\myfile.txt" will fail to parse in the original code since "\\server_name" won't successfully pass the ::FindFirstFile() call.
    2) Added HANDLE variable 'h' so that the resulting file handle can be closed to prevent a leak.
    
    Tom
    
    
    
    /////////////////////////////////////////////////////////////////////////////
    //
    // DWORD GetLongPathName(CString strShortPath, CString& strLongPath)
    //
    // Stupid Microsoft bandaid - allows GetLongPathName emulation under W95. Needed
    //                            since XP transmits filenames in short form, while
    //                            95/98/2000/NT don't, but function not available to
    //                            fix problem under 95.
    //
    // From: http://www.codeguru.com/cpp/w-p/files/article.php/c4461/
    // Author: Randall Garacci
    //
    // Parameters: [in] strShortPath -- The mangled short pathname to the file
    //             [out] strLongPath -- The calculated long pathname
    //
    // Returns: 0 on failure, or the length of the calculated long pathname
    //
    // Revision history:
    //
    // 06/06/2006 -- Wheeler, T: Added code to correct HANDLE leak & modified
    //               (iFound >1) test to allow parsing a file on a network share.
    //
    /////////////////////////////////////////////////////////////////////////////
    
    DWORD GetLongPathName(CString  strShortPath,
                          CString& strLongPath  )
    {
    HANDLE h;
    
    int iFound = strShortPath.ReverseFind('\\');
    
      if ((iFound > 1) && (strShortPath.Left(2) != "\\\\")) // Added 06/6/2006
      {
        // recurse to peel off components
        //
        if (GetLongPathName(strShortPath.Left(iFound),
                            strLongPath) > 0)
        {
          strLongPath += '\\';
    
          if (strShortPath.Right(1) != "\\")
          {
          WIN32_FIND_DATA findData;
    
          // append the long component name to the path
          //
            if (INVALID_HANDLE_VALUE != (h=::FindFirstFile(strShortPath, &findData)) )
    			{
    			::CloseHandle(h);
    			strLongPath += findData.cFileName;
    			}
    		else
    			{
    			// if FindFirstFile fails, return the error code
    			//
    			strLongPath.Empty();
    			return 0;
    			}
          }
        }
    
      }
      else
      {
        strLongPath = strShortPath;
      }
    
      return strLongPath.GetLength();
    }

    Reply
  • An alternative method which is also suitable for all flavours of Windows

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

    Originally posted by: Jase Jennings

    BOOL ShortToLongPath(CString &sShortPath, CString &sLongPath) 
    
    {
    USES_CONVERSION;

    LPSHELLFOLDER psfDesktop = NULL;
    ULONG chEaten = 0;
    LPITEMIDLIST pidlShellItem = NULL;
    WCHAR szLongPath[_MAX_PATH] = { 0 };
    BOOL bResult = TRUE;

    // Get the Desktop's shell folder interface
    HRESULT hr = SHGetDesktopFolder(&psfDesktop);

    LPCTSTR lpsz = (LPCTSTR)sShortPath;
    LPWSTR lpwShortPath = A2W(lpsz);

    // Request an ID list (relative to the desktop) for the short pathname
    hr = psfDesktop->ParseDisplayName(NULL, NULL, lpwShortPath, &chEaten, &pidlShellItem, NULL);
    psfDesktop->Release(); // Release the desktop's IShellFolder

    if(FAILED(hr))
    {
    // If we couldn't get an ID list for short pathname, it must not exist.
    sLongPath.Empty();
    bResult = FALSE;
    }
    else
    {
    // We did get an ID list, convert it to a long pathname
    SHGetPathFromIDListW(pidlShellItem, szLongPath);

    // Free the ID list allocated by ParseDisplayName
    LPMALLOC pMalloc = NULL;
    SHGetMalloc(&pMalloc);
    pMalloc->Free(pidlShellItem);
    pMalloc->Release();
    sLongPath = W2A(szLongPath);
    }

    return bResult;
    }

    Reply
  • Thanks...

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

    Originally posted by: Paul Selormey

    Just tested it, it works!

    Thanks for the contribution.

    Best regards,
    Paul.

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

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Webinar on September 23, 2014, 2 p.m. ET / 11 a.m. PT Mobile commerce presents an array of opportunities for any business -- from connecting with your customers through mobile apps to enriching operations with mobile enterprise solutions. Join guest speaker, Michael Facemire, Forrester Research, Inc. Principal Analyst, as he discusses the new demands of mobile engagement and how application program interfaces (APIs) play a crucial role. Check out this upcoming webinar to learn about the new set of …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds