/*
   ----------------------------------------------------------------
   Filename.....: apifolders.cc
   ClassName....: apifolders
   Purpose......: object to hold operating system folders.
   Programmer...: Rick Miller
   Date.........: February 06, 2002.
   Notes........: See Notes below.
   Written for..: dB2K 0.1 and newer.
   Rev. History.: See Revisions below.
   Dependencies.: None.
   Calls........: None.
   Called by....: Any.
   Usage........: set procedure to apifolders.cc additive
   Example......: See Example below.
   ----------------------------------------------------------------
   Example:
   ----------------------------------------------------------------
      oRef = new apifolders()
      inspect(oRef) //  to view properties
      oRef.release()
      oRef  := null
      close procedure apifolders.cc
   ----------------------------------------------------------------
   Properties:
   ----------------------------------------------------------------
      // common folders.
      commonfiles             programfiles\Common Files
      current                 current folder
      fonts                   windows\Fonts
      programfiles            boot root\Program Files
      system                  windows system folder
      temp                    tmp or temp in that order
      windows                 windows folder

      // all user folders.
      allappdata              All Users\Application Data
      alldesktop              All Users\Desktop
      alldocuments            All Users\My Documents
      allfavorites            All Users\Favorites
      allmusic                All Users\My Documents\My Music
      allpictures             All Users\My Documents\My Pictures
      allprograms             All Users\Start Menu\Programs
      allstartup              All Users\Start Menu\Programs\Startup
      alltemplates            All Users\Templates

      // user specific folders.
      appdata                 User\Application Data
      appdatalocal            User\Local Settings\Application Data
      cookies                 User\Cookies
      desktop                 User\Desktop
      favorites               User\Favorites
      history                 User\Local Settings\History
      mydocuments             User\My Documents or User\Personal
      mymusic                 User\My Documents\My Music
      mypictures              User\My Documents\My Pictures
      programs                User\Start Menu\Programs
      recent                  User\Recent
      sendto                  User\Start Menu\Sendto
      startup                 User\Start Menu\Programs\StartUp
      templates               User\Templates
   ----------------------------------------------------------------
   Methods:
   ----------------------------------------------------------------
      close          calls release.
      getLongPath    returns long path for a passed parameter.
      release        release object from memory.
   ----------------------------------------------------------------
   Notes:
   ----------------------------------------------------------------
      1) shfolder.dll is distributed with IE 5 and newer.
      2) The constants in the header were derived from shlobj.h.
         They were renamed to avoid conflicts.
      3) You may want to copy and paste the portion of the
            header from #ifndef to #endif into rmmshfolder.h.
            rmmshfolder.h can then be used with an #include
            where ever needed.
      4) properties do NOT have a trailing backslash ("\")
            testing done on WinXP, Win2000, Win98, Win95.
   ----------------------------------------------------------------
   Revisions:
   ----------------------------------------------------------------
      October 30, 2006
         1) fix for bug in x_Find method.
         2) correction for appdata property.
         3) correction for desktop property.
         4) added appdatalocal property.
         5) changed code to use constants.
      -------------------------------------------------------------
      April 21, 2005    -  cleaned code.
      -------------------------------------------------------------
      February 10, 2005 -  renamed all external functions.
      -------------------------------------------------------------
      January 01, 2005  -  verify externs, revisited all methods.
      -------------------------------------------------------------
      September 10,2003 -  now compatible with Win95.
      -------------------------------------------------------------
      August 07, 2003   -  revised for win 95.
      -------------------------------------------------------------
      May 09, 2003      -  added getLongPath call.
      -------------------------------------------------------------
      March 31, 2003    -  revised release method.
      -------------------------------------------------------------
      April 03, 2002    -  added shgetfolderpath from
                           newsgroup posting
                           by Christopher F. Neumann.
      -------------------------------------------------------------
      February 19, 2002 -  documentation.
   ----------------------------------------------------------------
   */
#ifndef _RMMSHFOLDER_H_
#define  _RMMSHFOLDER_H_
#define  RMMCSIDL_FLAG_MASK                  0xFF00   // mask for all possible flag values
// custom constants.
#define  RMMCSIDL_CURRENT                    0xFF01   // current directory (custom).
#define  RMMCSIDL_TEMP                       0xFF02   // tmp/temp directory (custom).
#define  RMMCSIDL_TMP                        RMMCSIDL_TEMP  // tmp/temp directory (custom).
// end of custom constants.
// Note: not all folders are guaranteed to exist.
#define  RMMCSIDL_DESKTOP                    0x0000   // <desktop>
#define  RMMCSIDL_INTERNET                   0x0001   // Internet Explorer (icon on desktop)
#define  RMMCSIDL_PROGRAMS                   0x0002   // Start Menu\Programs
#define  RMMCSIDL_CONTROLS                   0x0003   // My Computer\Control Panel
#define  RMMCSIDL_PRINTERS                   0x0004   // My Computer\Printers
#define  RMMCSIDL_PERSONAL                   0x0005   // My Documents
#define  RMMCSIDL_FAVORITES                  0x0006   // <user name>\Favorites
#define  RMMCSIDL_STARTUP                    0x0007   // Start Menu\Programs\Startup
#define  RMMCSIDL_RECENT                     0x0008   // <user name>\Recent
#define  RMMCSIDL_SENDTO                     0x0009   // <user name>\SendTo
#define  RMMCSIDL_BITBUCKET                  0x000a   // <desktop>\Recycle Bin
#define  RMMCSIDL_STARTMENU                  0x000b   // <user name>\Start Menu
// Note: using PERSONAL for MYDOCUMENTS is correct here.
#define  RMMCSIDL_MYDOCUMENTS                RMMCSIDL_PERSONAL // 0x000c is for the PIDL of the "My Documents" desktop icon
#define  RMMCSIDL_MYMUSIC                    0x000d   // "My Music" folder
#define  RMMCSIDL_MYVIDEO                    0x000e   // "My Videos" folder
#define  RMMCSIDL_DESKTOPDIRECTORY           0x0010   // <user name>\Desktop
#define  RMMCSIDL_DRIVES                     0x0011   // My Computer
#define  RMMCSIDL_NETWORK                    0x0012   // Network Neighborhood (My Network Places)
#define  RMMCSIDL_NETHOOD                    0x0013   // <user name>\nethood
#define  RMMCSIDL_FONTS                      0x0014   // windows\fonts
#define  RMMCSIDL_TEMPLATES                  0x0015   // <user name>\Templates
#define  RMMCSIDL_COMMON_STARTMENU           0x0016   // All Users\Start Menu
#define  RMMCSIDL_COMMON_PROGRAMS            0X0017   // All Users\Start Menu\Programs
#define  RMMCSIDL_COMMON_STARTUP             0x0018   // All Users\Startup
#define  RMMCSIDL_COMMON_DESKTOPDIRECTORY    0x0019   // All Users\Desktop
#define  RMMCSIDL_APPDATA                    0x001a   // <user name>\Application Data
#define  RMMCSIDL_PRINTHOOD                  0x001b   // <user name>\PrintHood
#define  RMMCSIDL_LOCAL_APPDATA              0x001c   // <user name>\Local Settings\Application Data (non roaming)
#define  RMMCSIDL_ALTSTARTUP                 0x001d   // non localized startup
#define  RMMCSIDL_COMMON_ALTSTARTUP          0x001e   // All Users\Start Menu\Programs\startup
#define  RMMCSIDL_COMMON_FAVORITES           0x001f   // All Users\Start Menu\Favorites
#define  RMMCSIDL_INTERNET_CACHE             0x0020   // <user name>\Local Settings\Temporary Internet Files
#define  RMMCSIDL_COOKIES                    0x0021   // <user name>\Cookies
#define  RMMCSIDL_HISTORY                    0x0022   // <user name>\Local Settings\History
#define  RMMCSIDL_COMMON_APPDATA             0x0023   // All Users\Application Data
#define  RMMCSIDL_WINDOWS                    0x0024   // GetWindowsDirectory()
#define  RMMCSIDL_SYSTEM                     0x0025   // GetSystemDirectory()
#define  RMMCSIDL_PROGRAM_FILES              0x0026   // C:\Program Files
#define  RMMCSIDL_MYPICTURES                 0x0027   // "My Pictures" folder
#define  RMMCSIDL_PROFILE                    0x0028   // <user name> %USERPROFILE%
#define  RMMCSIDL_SYSTEMX86                  0x0029   // x86 system directory on RISC
#define  RMMCSIDL_PROGRAM_FILESX86           0x002a   // x86 C:\Program Files on RISC
#define  RMMCSIDL_PROGRAM_FILES_COMMON       0x002b   // C:\Program Files\Common
#define  RMMCSIDL_PROGRAM_FILES_COMMONX86    0x002c   // x86 Program Files\Common on RISC
#define  RMMCSIDL_COMMON_TEMPLATES           0x002d   // All Users\Templates
#define  RMMCSIDL_COMMON_DOCUMENTS           0x002e   // All Users\Documents
#define  RMMCSIDL_COMMON_ADMINTOOLS          0x002f   // All Users\Start Menu\Programs\Administrative Tools
#define  RMMCSIDL_ADMINTOOLS                 0x0030   // <user name>\Start Menu\Programs\Administrative Tools
#define  RMMCSIDL_CONNECTIONS                0x0031   // Network and Dial-up Connections
#define  RMMCSIDL_COMMON_MUSIC               0x0035   // All Users\Documents\My Music
#define  RMMCSIDL_COMMON_PICTURES            0x0036   // All Users\Documents\My Pictures
#define  RMMCSIDL_COMMON_VIDEO               0x0037   // All Users\Documents\My Video
#define  RMMCSIDL_RESOURCES                  0x0038   // windows\Resource
#define  RMMCSIDL_RESOURCES_LOCALIZED        0x0039   // Localized Resource Direcotry
#define  RMMCSIDL_COMMON_OEM_LINKS           0x003a   // Links to All Users OEM specific apps
#define  RMMCSIDL_CDBURN_AREA                0x003b   // <user name>\Local Settings\Application Data\Microsoft\CD Burning
#endif   // endif for _RMMSHFOLDER_H_

#define  MAXPATH                    (260)
#define  APIFOLDERS_PUBLISHERINFO   "Rick Miller"
#define  APIFOLDERS_VERSIONINFO     "6.1030"
//---------------------------------------------------------------//
//          apifolders constructor.
//---------------------------------------------------------------//
class apifolders

   // protected methods
   protect  x_Assign, x_Backslashtest, x_Find, x_Get,;
            x_InitExterns, x_Special, x_SpecialFolders

   class::x_InitExterns()  // initialize externs.
   class::x_Assign()       // assign properties.
   this.versioninfo  =  APIFOLDERS_VERSIONINFO
   this.publishinfo  =  APIFOLDERS_PUBLISHERINFO
   //------------------------------------------------------------//
   //       end of constructor   -  methods below.
   //------------------------------------------------------------//
   // un-protected method  -  call to release.
   function close
      this.release()
   return

   //------------------------------------------------------------//
   // un-protected method  -  return the long path for cPath.
   function getLongPath(cPath)
      Local cRet, n
      n  =  0
      cRet  =  ""
      if type("RMM_GetLongPathName") == "FP"
         n  := MAXPATH
         cRet  := space(n)
         // next line returns number of chars
         // placed into cRet not counting the chr(0) terminator.
         n  := RMM_GetLongPathName(cPath, cRet, n)
      endif
   return   iif(n == 0, "" + cPath, left(cRet, n))

   //------------------------------------------------------------//
   // un-protected method  -  release object from memory.
   function release
      // NOTE: PLUS 2.01 or newer may raise an exception on
      //       release object so the method is wrapped in a
      //       try/endtry construct.
      try
         release object this
      catch(exception e)
      endtry
   return   true

   //------------------------------------------------------------//
   // protected method  -  assign properties.
   function x_Assign
      this.current   =  class::getLongPath( ;
                        class::x_Get(RMMCSIDL_CURRENT))
      this.system    =  class::getLongPath( ;
                        class::x_Get(RMMCSIDL_SYSTEM))
      this.temp      =  class::getLongPath( ;
                        class::x_Get(RMMCSIDL_TEMP))
      this.windows   =  class::getLongPath( ;
                        class::x_Get(RMMCSIDL_WINDOWS))
      if file(this.system + "\shfolder.dll")
         // shfolder.dll comes with Internet Explorer 5.01 or newer.
         if not type("RMM_SHGetFolderPath") == "FP"
            extern CLONG RMM_SHGetFolderPath( ;
               CHANDLE, CINT, CHANDLE, CULONG, CSTRING) ;
               shfolder.dll from "SHGetFolderPathA"
         endif
      endif
      if type("RMM_SHGetFolderPath") == "FP"
         class::x_SpecialFolders()
      else
         class::x_Special()
      endif
      this.tempapp   =  "" + this.temp
   return   true

   //------------------------------------------------------------//
   // protected method  -  remove any trailing backslash
   function x_Backslashtest(cPath)
      if cPath.right(1) == "\"
         // remove trailing backslash.
         cPath := cPath.left(cPath.length - 1)
      endif
   return   "" + cPath

   //------------------------------------------------------------//
   // protected method  -  return the path for nFold.
   function x_Find(nFold)
      Local cRet, n
      n  =  MAXPATH
      cRet  =  space(n)
      // next line returns 0 for success.
      n  := RMM_SHGetFolderPath(null, nFold, 0, null, cRet)
      if n == 0
         // cRet holds the folder in a long name.
      else
         cRet  := ""
      endif
   return   "" + cRet

   //------------------------------------------------------------//
   // protected method  -  return the path for nFold.
   function x_Get(nFold)
      Local cRet, n
      n  =  MAXPATH
      cRet  =  space(n)
      if nFold == RMMCSIDL_CURRENT
         n  := RMM_GetCurrentDirectory(n, cRet)
      elseif nFold == RMMCSIDL_SYSTEM
         n  := RMM_GetSystemDirectory(cRet, n)
      elseif nFold == RMMCSIDL_TEMP
         n  := RMM_GetTempPath(n, cRet)
      elseif nFold == RMMCSIDL_WINDOWS
         n  := RMM_GetWindowsDirectory(cRet, n)
      else
         n  := 0
      endif
      // cRet holds the folder in a short name.
   return   iif(n > 0, class::x_Backslashtest(cRet.left(n)), "")

   //------------------------------------------------------------//
   // protected method  -  declare functions external to dBASE.
   function x_InitExterns
      if not type("RMM_GetCurrentDirectory") == "FP"
         extern CULONG RMM_GetCurrentDirectory(CULONG, CSTRING) ;
            kernel32 from "GetCurrentDirectoryA"
      endif
      if not type("RMM_GetLongPathName")   == "FP"
         try
            // requires win98 or winNT 4.0 SP3 and above.
            extern CULONG RMM_GetLongPathName( ;
               CSTRING, CSTRING, CULONG) ;
               kernel32 from "GetLongPathNameA"
         catch(exception e)
         endtry
      endif
      if not type("RMM_GetSystemDirectory") == "FP"
         extern CUINT RMM_GetSystemDirectory(CSTRING, CUINT) ;
            kernel32 from "GetSystemDirectoryA"
      endif
      if not type("RMM_GetTempPath") == "FP"
         extern CULONG RMM_GetTempPath(CULONG, CSTRING) ;
            kernel32 from "GetTempPathA"
      endif
      if not type("RMM_GetWindowsDirectory") == "FP"
         extern CUINT RMM_GetWindowsDirectory(CSTRING, CUINT) ;
            kernel32 from "GetWindowsDirectoryA"
      endif
   return   true

   //------------------------------------------------------------//
   // protected method  -  assign special folders for win95.
   // Note: these folders are for Windows English version.
   function x_Special
      Local cAll, cRoot, cWin
      cWin  =  (this.windows)
      cRoot =  cWin.left(cWin.indexof("\"))
      cAll  =  cWin + "\All Users"
      this.appdata      =  (cWin + "\Application Data")
      this.appdatalocal =  (cWin + "\Application Data")
      this.commonfiles  =  (cRoot + "\Program Files\Common Files")
      this.cookies      =  ""
      this.desktop      =  (cWin + "\Desktop")
      this.favorites    =  (cWin + "\Favorites")
      this.fonts        =  (cWin + "\Fonts")
      this.history      =  (cWin + "\History")
      this.mydocuments  =  (cRoot + "\My Documents")
      this.mymusic      =  (cRoot + "\My Documents\My Music")
      this.mypictures   =  (cRoot + "\My Documents\My Pictures")
      this.programfiles =  (cRoot + "\Program Files")
      this.programs     =  (cWin + "\Start Menu\Programs")
      this.recent       =  (cWin + "\Recent")
      // this.recycle        = this.x_Find(10)  // may not work
      this.sendto       =  (cWin + "\SendTo")
      this.startup      =  (cWin + "\Start Menu\Programs\Startup")
      this.templates    =  ""
      this.allappdata   =  (cAll + "\Application Data")
      this.alldesktop   =  (cWin + "\Desktop")
      this.alldocuments =  (cRoot + "\My Documents")
      this.allfavorites =  (cWin + "\Favorites")
      this.allmusic     =  (cRoot + "\My Documents\My Music")
      this.allpictures  =  (cRoot + "\My Documents\My Pictures")
      this.allprograms  =  (cWin + "\Start Menu\Programs")
      this.allstartup   =  (cWin + "\Start Menu\Programs\Startup")
      this.alltemplates =  ""
   return

   //------------------------------------------------------------//
   // protected method  -  assign special folders.
   function x_SpecialFolders

      // not user specific folders.
      this.commonfiles  =  class::x_Find(RMMCSIDL_PROGRAM_FILES_COMMON)
      this.fonts        =  class::x_Find(RMMCSIDL_FONTS)
      this.programfiles =  class::x_Find(RMMCSIDL_PROGRAM_FILES)

      // user (userprofile) folders.
      this.appdata      =  class::x_Find(RMMCSIDL_APPDATA)
      this.appdatalocal =  class::x_Find(RMMCSIDL_LOCAL_APPDATA)
      this.cookies      =  class::x_Find(RMMCSIDL_COOKIES)
      this.desktop      =  class::x_Find(RMMCSIDL_DESKTOPDIRECTORY)
      this.favorites    =  class::x_Find(RMMCSIDL_FAVORITES)
      this.history      =  class::x_Find(RMMCSIDL_HISTORY)
      this.mydocuments  =  class::x_Find(RMMCSIDL_PERSONAL)
      this.mymusic      =  class::x_Find(RMMCSIDL_MYMUSIC)
      this.mypictures   =  class::x_Find(RMMCSIDL_MYPICTURES)
      this.programs     =  class::x_Find(RMMCSIDL_PROGRAMS)
      this.recent       =  class::x_Find(RMMCSIDL_RECENT)
      // this.recycle        = this.x_Find(RMMCSIDL_BITBUCKET)  // may not work
      this.sendto       =  class::x_Find(RMMCSIDL_SENDTO)
      this.startup      =  class::x_Find(RMMCSIDL_STARTUP)
      this.templates    =  class::x_Find(RMMCSIDL_TEMPLATES)

      // all user folders.
      Local cVal
      cVal  =  class::x_Find(RMMCSIDL_COMMON_APPDATA)
      this.allappdata   =  iif(empty(cVal), this.appdata, cVal)
      cVal  =  class::x_Find(RMMCSIDL_COMMON_DESKTOPDIRECTORY)
      this.alldesktop   =  iif(empty(cVal), this.desktop, cVal)
      cVal  =  class::x_Find(RMMCSIDL_COMMON_DOCUMENTS)
      this.alldocuments =  iif(empty(cVal), this.mydocuments, cVal)
      cVal  =  class::x_Find(RMMCSIDL_COMMON_FAVORITES)
      this.allfavorites =  iif(empty(cVal), this.favorites, cVal)
      cVal  =  class::x_Find(RMMCSIDL_COMMON_MUSIC)
      this.allmusic     =  iif(empty(cVal), this.mymusic, cVal)
      cVal  =  class::x_Find(RMMCSIDL_COMMON_PICTURES)
      this.allpictures  =  iif(empty(cVal), this.mypictures, cVal)
      cVal  =  class::x_Find(RMMCSIDL_COMMON_PROGRAMS)
      this.allprograms  =  iif(empty(cVal), this.programfiles, cVal)
      cVal  =  class::x_Find(RMMCSIDL_COMMON_STARTUP)
      this.allstartup   =  iif(empty(cVal), this.startup, cVal)
      cVal  =  class::x_Find(RMMCSIDL_COMMON_TEMPLATES)
      this.alltemplates =  iif(empty(cVal), this.templates, cVal)
   return

endclass
//---------------------------------------------------------------//
//          end of apifolders.
//---------------------------------------------------------------//