PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/animeplugin3/MyAnimePlugin3/ShellItem.cs

https://bitbucket.org/gibwar/jmm-test
C# | 2334 lines | 2317 code | 7 blank | 10 comment | 90 complexity | 9b807895a5af4736537348782ed636b8 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * This class is converted VB.Net from the CScItem
  3. * from http://www.codeproject.com/KB/cpp/VbNetExpTree.aspx
  4. */
  5. using System.IO;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using System;
  9. using System.Collections;
  10. using System.Windows.Forms;
  11. using System.Diagnostics;
  12. using System.Management;
  13. public class ShellItem : IDisposable, IComparable
  14. {
  15.    
  16.     #region " Shared Private Fields"
  17.     //This class has occasion to refer to the TypeName as reported by
  18.     // ShellDll.SHGetFileInfo. It needs to compare this to the string
  19.     // (in English) "System Folder"
  20.     //on non-English systems, we do not know, in the general case,
  21.     // what the equivalent string is to compare against
  22.     //The following variable is set by Sub New() to the string that
  23.     // corresponds to "System Folder" on the current machine
  24.     // Sub New() depends on the existance of My Computer(ShellDll.CSIDL.DRIVES),
  25.     // to determine what the equivalent string is
  26.     private static string m_strSystemFolder;
  27.    
  28.     //My Computer is also commonly used (though not internally),
  29.     // so save & expose its name on the current machine
  30.     private static string m_strMyComputer;
  31.    
  32.     //To get My Documents sorted first, we need to know the Locale
  33.     //specific name of that folder.
  34.     private static string m_strMyDocuments;
  35.    
  36.     // The DesktopBase is set up via Sub New() (one time only) and
  37.     // disposed of only when DesktopBase is finally disposed of
  38.     private static ShellItem DesktopBase;
  39.    
  40.     //We can avoid an extra ShellDll.SHGetFileInfo call once this is set up
  41.     private static int OpenFolderIconIndex = -1;
  42.    
  43.     // It is also useful to know if the OS is XP or above.
  44.     // Set up in Sub New() to avoid multiple calls to find this info
  45.     private static bool XPorAbove;
  46.     // Likewise if OS is Win2K or Above
  47.     private static bool Win2KOrAbove;
  48.    
  49.     // DragDrop, possibly among others, needs to know the Path of
  50.     // the DeskTopDirectory in addition to the Desktop itself
  51.     // Also need the actual ShellItem for the DeskTopDirectory, so get it
  52.     private static ShellItem m_DeskTopDirectory;
  53.    
  54.    
  55.     #endregion
  56.    
  57.     #region " Instance Private Fields"
  58.     //m_Folder and m_Pidl must be released/freed at Dispose time
  59.     private ShellDll.IShellFolder m_Folder;
  60.     //if item is a folder, contains the Folder interface for this instance
  61.     private IntPtr m_Pidl;
  62.     //The Absolute PIDL for this item (not retained for files)
  63.     private string m_DisplayName = "";
  64.     private string m_Path;
  65.     private string m_TypeName;
  66.     private ShellItem m_Parent;
  67.     //= Nothing
  68.     private int m_IconIndexNormal;
  69.     //index into the System Image list for Normal icon
  70.     private int m_IconIndexOpen;
  71.     //index into the SystemImage list for Open icon
  72.     private bool m_IsBrowsable;
  73.     private bool m_IsFileSystem;
  74.     private bool m_IsFolder;
  75.     private bool m_HasSubFolders;
  76.     private bool m_IsLink;
  77.     private bool m_IsDisk;
  78.     private bool m_IsShared;
  79.     private bool m_IsHidden;
  80.     private bool m_IsNetWorkDrive;
  81.     //= False
  82.     private bool m_IsRemovable;
  83.     //= False
  84.     private bool m_IsReadOnly;
  85.     //= False
  86.     //Properties of interest to Drag Operations
  87.     private bool m_CanMove;
  88.     //= False
  89.     private bool m_CanCopy;
  90.     //= False
  91.     private bool m_CanDelete;
  92.     //= False
  93.     private bool m_CanLink;
  94.     //= False
  95.     private bool m_IsDropTarget;
  96.     //= False
  97.     private ShellDll.SFGAO m_Attributes;
  98.     //the original, returned from GetAttributesOf
  99.    
  100.     private int m_SortFlag;
  101.     //= 0 'Used in comparisons
  102.    
  103.     private ArrayList m_Directories;
  104.    
  105.     //The following elements are only filled in on demand
  106.     private bool m_XtrInfo;
  107.     //= False
  108.     private DateTime m_LastWriteTime;
  109.     private DateTime m_CreationTime;
  110.     private DateTime m_LastAccessTime;
  111.     private long m_Length;
  112.    
  113.     //Indicates whether DisplayName, TypeName, SortFlag have been set up
  114.     private bool m_HasDispType;
  115.     //= False
  116.    
  117.     //Indicates whether IsReadOnly has been set up
  118.     private bool m_IsReadOnlySetup;
  119.     //= False
  120.    
  121.     //Holds a byte() representation of m_PIDL -- filled when needed
  122.     private cPidl m_cPidl;
  123.    
  124.     //Flags for Dispose state
  125.     private bool m_Disposed;
  126.    
  127.     #endregion
  128.    
  129.     #region " Destructor"
  130.     /// <summary>
  131.     /// Summary of Dispose.
  132.     /// </summary>
  133.     ///
  134.     public void Dispose()
  135.     {
  136.         Dispose(true);
  137.         // Take yourself off of the finalization queue
  138.         // to prevent finalization code for this object
  139.         // from executing a second time.
  140.         GC.SuppressFinalize(this);
  141.     }
  142.     /// <summary>
  143.     /// Deallocates CoTaskMem contianing m_Pidl and removes reference to m_Folder
  144.     /// </summary>
  145.     /// <param name="disposing"></param>
  146.     ///
  147.     protected virtual void Dispose(bool disposing)
  148.     {
  149.         // Allow your Dispose method to be called multiple times,
  150.         // but throw an exception if the object has been disposed.
  151.         // Whenever you do something with this class,
  152.         // check to see if it has been disposed.
  153.         if (!(m_Disposed)) {
  154.             // If disposing equals true, dispose all managed
  155.             // and unmanaged resources.
  156.             m_Disposed = true;
  157.             if ((disposing)) {
  158.             }
  159.             // Release unmanaged resources. If disposing is false,
  160.             // only the following code is executed.
  161.             if ((m_Folder != null)) {
  162.                 Marshal.ReleaseComObject(m_Folder);
  163.             }
  164.             if (!m_Pidl.Equals(IntPtr.Zero)) {
  165.                 Marshal.FreeCoTaskMem(m_Pidl);
  166.             }
  167.         }
  168.         else {
  169.             throw new Exception("ShellItem Disposed more than once");
  170.         }
  171.     }
  172.    
  173.     // This Finalize method will run only if the
  174.     // Dispose method does not get called.
  175.     // By default, methods are NotOverridable.
  176.     // This prevents a derived class from overriding this method.
  177.     /// <summary>
  178.     /// Summary of Finalize.
  179.     /// </summary>
  180.     ///
  181.     ~ShellItem()
  182.     {
  183.         // Do not re-create Dispose clean-up code here.
  184.         // Calling Dispose(false) is optimal in terms of
  185.         // readability and maintainability.
  186.         Dispose(false);
  187.     }
  188.    
  189.     #endregion
  190.    
  191.     #region " Constructors"
  192.    
  193.     #region " Private Sub New(ByVal folder As ShellDll.IShellFolder, ByVal pidl As IntPtr, ByVal parent As ShellItem)"
  194.     /// <summary>
  195.     /// Private Constructor, creates new ShellItem from the item's parent folder and
  196.     /// the item's PIDL relative to that folder.</summary>
  197.     /// <param name="folder">the folder interface of the parent</param>
  198.     /// <param name="pidl">the Relative PIDL of this item</param>
  199.     /// <param name="parent">the CShitem of the parent</param>
  200.     ///
  201.     private ShellItem(ShellDll.IShellFolder folder, IntPtr pidl, ShellItem parent)
  202.     {
  203.         if ((DesktopBase == null)) {
  204.                 //This initializes the Desktop folder
  205.             DesktopBase = new ShellItem();
  206.         }
  207.         m_Parent = parent;
  208.         m_Pidl = concatPidls(parent.PIDL, pidl);
  209.        
  210.         //Get some attributes
  211.         SetUpAttributes(folder, pidl);
  212.        
  213.         //Set unfetched value for IconIndex....
  214.         m_IconIndexNormal = -1;
  215.         m_IconIndexOpen = -1;
  216.         //finally, set up my Folder
  217.         if (m_IsFolder) {
  218.             int HR = 0;
  219.             HR = folder.BindToObject(pidl, IntPtr.Zero, ref ShellDll.IID_IShellFolder, ref m_Folder);
  220.             if (HR != ShellDll.NOERROR) {
  221.                 Marshal.ThrowExceptionForHR(HR);
  222.             }
  223.         }
  224.     }
  225.     #endregion
  226.    
  227.     #region " Sub New()"
  228.     /// <summary>
  229.     /// Private Constructor. Creates ShellItem of the Desktop
  230.     /// </summary>
  231.     ///
  232.     private ShellItem()
  233.     {
  234.         //only used when desktopfolder has not been intialized
  235.         if ((DesktopBase != null)) {
  236.             throw new Exception("Attempt to initialize ShellItem for second time");
  237.         }
  238.        
  239.         int HR = 0;
  240.         //firstly determine what the local machine calls a "System Folder" and "My Computer"
  241.         IntPtr tmpPidl = default(IntPtr);
  242.         HR = ShellDll.SHGetSpecialFolderLocation(0, (int)ShellDll.CSIDL.DRIVES, ref tmpPidl);
  243.         ShellDll.SHFILEINFO shfi = new ShellDll.SHFILEINFO();
  244.         int dwflag = (int)(ShellDll.SHGFI.DISPLAYNAME | ShellDll.SHGFI.TYPENAME | ShellDll.SHGFI.PIDL);
  245.         int dwAttr = 0;
  246. ShellDll.SHGetFileInfo(tmpPidl, dwAttr, ref shfi, (int)ShellDll.cbFileInfo, dwflag);
  247.         m_strSystemFolder = shfi.szTypeName;
  248.         m_strMyComputer = shfi.szDisplayName;
  249.         Marshal.FreeCoTaskMem(tmpPidl);
  250.         //set OS version info
  251.         XPorAbove = ShellDll.IsXpOrAbove();
  252.         Win2KOrAbove = ShellDll.Is2KOrAbove();
  253.        
  254.         //With That done, now set up Desktop ShellItem
  255. m_Path = "::{" + ShellDll.DesktopGUID.ToString() + "}";
  256.         m_IsFolder = true;
  257.         m_HasSubFolders = true;
  258.         m_IsBrowsable = false;
  259. HR = ShellDll.SHGetDesktopFolder(ref m_Folder);
  260. m_Pidl = ShellDll.GetSpecialFolderLocation(IntPtr.Zero, (int)ShellDll.CSIDL.DESKTOP);
  261.         dwflag = (int)(ShellDll.SHGFI.DISPLAYNAME | ShellDll.SHGFI.TYPENAME | ShellDll.SHGFI.SYSICONINDEX | ShellDll.SHGFI.PIDL);
  262.         dwAttr = 0;
  263. IntPtr H = ShellDll.SHGetFileInfo(m_Pidl, dwAttr, ref shfi, (int)ShellDll.cbFileInfo, dwflag);
  264.         m_DisplayName = shfi.szDisplayName;
  265.         m_TypeName = strSystemFolder;
  266.         //not returned correctly by ShellDll.SHGetFileInfo
  267.         m_IconIndexNormal = shfi.iIcon;
  268.         m_IconIndexOpen = shfi.iIcon;
  269.         m_HasDispType = true;
  270.         m_IsDropTarget = true;
  271.         m_IsReadOnly = false;
  272.         m_IsReadOnlySetup = true;
  273.        
  274.         //also get local name for "My Documents"
  275.         int pchEaten = 0;
  276.         tmpPidl = IntPtr.Zero;
  277. int tmp = 0;
  278.         HR = m_Folder.ParseDisplayName(0, IntPtr.Zero, "::{450d8fba-ad25-11d0-98a8-0800361b1103}", ref pchEaten, ref tmpPidl, ref tmp);
  279.         shfi = new ShellDll.SHFILEINFO();
  280.         dwflag = (int)(ShellDll.SHGFI.DISPLAYNAME | ShellDll.SHGFI.TYPENAME | ShellDll.SHGFI.PIDL);
  281.         dwAttr = 0;
  282. ShellDll.SHGetFileInfo(tmpPidl, dwAttr, ref shfi, ShellDll.cbFileInfo, dwflag);
  283.         m_strMyDocuments = shfi.szDisplayName;
  284.         Marshal.FreeCoTaskMem(tmpPidl);
  285.         //this must be done after getting "My Documents" string
  286.         m_SortFlag = ComputeSortFlag();
  287.         //Set DesktopBase
  288.         DesktopBase = this;
  289.         // Lastly, get the Path and ShellItem of the DesktopDirectory -- useful for DragDrop
  290.         m_DeskTopDirectory = new ShellItem(ShellDll.CSIDL.DESKTOPDIRECTORY);
  291.     }
  292.     #endregion
  293.    
  294.     #region " New(ByVal ID As ShellDll.CSIDL)"
  295.     /// <summary>Create instance based on a non-desktop ShellDll.CSIDL.
  296.     /// Will create based on any ShellDll.CSIDL Except the DeskTop ShellDll.CSIDL</summary>
  297.     /// <param name="ID">Value from ShellDll.CSIDL enumeration denoting the folder to create this ShellItem of.</param>
  298.     ///
  299.     public ShellItem(ShellDll.CSIDL ID)
  300.     {
  301.         if ((DesktopBase == null)) {
  302.                 //This initializes the Desktop folder
  303.             DesktopBase = new ShellItem();
  304.         }
  305.         int HR = 0;
  306.         if (ID == ShellDll.CSIDL.MYDOCUMENTS) {
  307.             int pchEaten = 0;
  308. int tmp = 0;
  309.             HR = DesktopBase.m_Folder.ParseDisplayName(0, IntPtr.Zero, "::{450d8fba-ad25-11d0-98a8-0800361b1103}", ref pchEaten, ref m_Pidl, ref tmp);
  310.         }
  311.         else {
  312.             HR = ShellDll.SHGetSpecialFolderLocation(0, (int)ID, ref m_Pidl);
  313.         }
  314.         if (HR == ShellDll.NOERROR) {
  315.             ShellDll.IShellFolder pParent = default(ShellDll.IShellFolder);
  316.             IntPtr relPidl = IntPtr.Zero;
  317. pParent = GetParentOf(m_Pidl, ref relPidl);
  318.             //Get the Attributes
  319.             SetUpAttributes(pParent, relPidl);
  320.             //Set unfetched value for IconIndex....
  321.             m_IconIndexNormal = -1;
  322.             m_IconIndexOpen = -1;
  323.             //finally, set up my Folder
  324.             if (m_IsFolder) {
  325.                 HR = pParent.BindToObject(relPidl, IntPtr.Zero, ref ShellDll.IID_IShellFolder, ref m_Folder);
  326.                 if (HR != ShellDll.NOERROR) {
  327.                     Marshal.ThrowExceptionForHR(HR);
  328.                 }
  329.             }
  330.             Marshal.ReleaseComObject(pParent);
  331.             //if PidlCount(m_Pidl) = 1 then relPidl is same as m_Pidl, don't release
  332.             if (PidlCount(m_Pidl) > 1) Marshal.FreeCoTaskMem(relPidl);
  333.         }
  334.         else {
  335.             Marshal.ThrowExceptionForHR(HR);
  336.         }
  337.     }
  338.     #endregion
  339.    
  340.     #region " New(ByVal path As String)"
  341.     /// <summary>Create a new ShellItem based on a Path Must be a valid FileSystem Path</summary>
  342.     /// <param name="path"></param>
  343.     ///
  344.     public ShellItem(string path)
  345.     {
  346.         if ((DesktopBase == null)) {
  347.                 //This initializes the Desktop folder
  348.             DesktopBase = new ShellItem();
  349.         }
  350.         //Removal of following code allows Path(GUID) of Special FOlders to serve
  351.         // as a valid Path for ShellItem creation (part of Calum's refresh code needs this
  352.         //If Not Directory.Exists(path) AndAlso Not File.Exists(path) Then
  353.         // Throw New Exception("ShellItem -- Invalid Path specified")
  354.         //End If
  355.         int HR = 0;
  356. int tmp1 = 0, tmp2 = 0;
  357.         HR = DesktopBase.m_Folder.ParseDisplayName(0, IntPtr.Zero, path, ref tmp1, ref m_Pidl, ref tmp2);
  358.         if (!(HR == ShellDll.NOERROR)) Marshal.ThrowExceptionForHR(HR);
  359.         ShellDll.IShellFolder pParent = default(ShellDll.IShellFolder);
  360.         IntPtr relPidl = IntPtr.Zero;
  361.        
  362.         pParent = GetParentOf(m_Pidl, ref relPidl);
  363.        
  364.         //Get the Attributes
  365.         SetUpAttributes(pParent, relPidl);
  366.         //Set unfetched value for IconIndex....
  367.         m_IconIndexNormal = -1;
  368.         m_IconIndexOpen = -1;
  369.         //finally, set up my Folder
  370.         if (m_IsFolder) {
  371.             HR = pParent.BindToObject(relPidl, IntPtr.Zero, ref ShellDll.IID_IShellFolder, ref m_Folder);
  372.             if (HR != ShellDll.NOERROR) {
  373.                 Marshal.ThrowExceptionForHR(HR);
  374.             }
  375.         }
  376.         Marshal.ReleaseComObject(pParent);
  377.         //if PidlCount(m_Pidl) = 1 then relPidl is same as m_Pidl, don't release
  378.         if (PidlCount(m_Pidl) > 1) {
  379.             Marshal.FreeCoTaskMem(relPidl);
  380.         }
  381.     }
  382.     #endregion
  383. #region " ShellItem(byte[] FoldBytes, byte[] ItemBytes)"
  384. ///<Summary>Given a Byte() containing the Pidl of the parent
  385. /// folder and another Byte() containing the Pidl of the Item,
  386. /// relative to the Folder, Create a ShellItem for the Item.
  387. /// This is of primary use in dealing with "Shell IDList Array"
  388. /// formatted info passed in a Drag Operation
  389. /// </Summary>
  390. public ShellItem(byte[] FoldBytes, byte[] ItemBytes)
  391. {
  392.         if ((DesktopBase == null)) {
  393.                 //This initializes the Desktop folder
  394.             DesktopBase = new ShellItem();
  395.         }
  396.         ShellDll.IShellFolder pParent = MakeFolderFromBytes(FoldBytes);
  397.        IntPtr ipParent = cPidl.BytesToPidl(FoldBytes);
  398.         IntPtr ipItem = cPidl.BytesToPidl(ItemBytes);
  399.       if ((pParent == null)) {
  400.                 //m_PIDL will = IntPtr.Zero for really bad CShitem
  401.             goto XIT;
  402.         }
  403.         if (ipParent.Equals(IntPtr.Zero) | ipItem.Equals(IntPtr.Zero)) {
  404.             goto XIT;
  405.         }
  406.         // Now process just like sub new(folder,pidl,parent) version
  407.         m_Pidl = concatPidls(ipParent, ipItem);
  408.        
  409.         //Get some attributes
  410.         SetUpAttributes(pParent, ipItem);
  411.        
  412.         //Set unfetched value for IconIndex....
  413.         m_IconIndexNormal = -1;
  414.         m_IconIndexOpen = -1;
  415.         //finally, set up my Folder
  416.         if (m_IsFolder) {
  417.             int HR = 0;
  418.             HR = pParent.BindToObject(ipItem, IntPtr.Zero, ref ShellDll.IID_IShellFolder, ref m_Folder);
  419.             #if Debug
  420.             if (HR != NOERROR) {
  421.                 Marshal.ThrowExceptionForHR(HR);
  422.             }
  423.             #endif
  424.         }
  425.         XIT:
  426.         //On any kind of exit, free the allocated memory
  427.         #if Debug
  428.         if (m_Pidl.Equals(IntPtr.Zero)) {
  429.             Debug.WriteLine("CShItem.New(FoldBytes,ItemBytes) Failed");
  430.         }
  431.         else {
  432.             Debug.WriteLine("CShItem.New(FoldBytes,ItemBytes) Created " + this.Path);
  433.         }
  434.         #endif
  435.         if (!ipParent.Equals(IntPtr.Zero)) {
  436.             Marshal.FreeCoTaskMem(ipParent);
  437.         }
  438.         if (!ipItem.Equals(IntPtr.Zero)) {
  439.             Marshal.FreeCoTaskMem(ipItem);
  440.         }
  441. }
  442. #endregion
  443.    
  444.     #region " Utility functions used in Constructors"
  445.    
  446.     #region " IsValidPidl"
  447.     ///<Summary>It is impossible to validate a PIDL completely since its contents
  448.     /// are arbitrarily defined by the creating Shell Namespace. However, it
  449.     /// is possible to validate the structure of a PIDL.</Summary>
  450.     public static bool IsValidPidl(byte[] b)
  451.     {
  452.         bool IsValidPidl = false;
  453.         //assume failure
  454.         int bMax = b.Length - 1;
  455.         //max value that index can have
  456. if (bMax < 1) return IsValidPidl;
  457.         //min Size is 2 bytes
  458.         int cb = b[0] + (b[1] * 256);
  459.         int indx = 0;
  460.         while (cb > 0) {
  461. if ((indx + cb + 1) > bMax) return IsValidPidl;
  462.             //an error
  463.             indx += cb;
  464.             cb = b[indx] + (b[indx + 1] * 256);
  465.         }
  466.             // on fall thru, it is ok as far as we can check
  467.         return true;
  468.     }
  469.     #endregion
  470.    
  471.     #region " MakeFolderFromBytes"
  472.     public static ShellDll.IShellFolder MakeFolderFromBytes(byte[] b)
  473.     {
  474.         ShellDll.IShellFolder functionReturnValue = default(ShellDll.IShellFolder);
  475.         functionReturnValue = null;
  476.         //get rid of VS2005 warning
  477.         if (!IsValidPidl(b)) return null;
  478.         if (b.Length == 2 && ((b[0] == 0) & (b[1] == 0))) {
  479.             //this is the desktop
  480.             return DesktopBase.Folder;
  481.         }
  482.         else if (b.Length == 0) {
  483.             //Also indicates the desktop
  484.             return DesktopBase.Folder;
  485.         }
  486.         else {
  487.             IntPtr ptr = Marshal.AllocCoTaskMem(b.Length);
  488.             if (ptr.Equals(IntPtr.Zero)) return null;
  489.             Marshal.Copy(b, 0, ptr, b.Length);
  490.             //the next statement assigns a IshellFolder object to the function return, or has an error
  491. int hr = DesktopBase.Folder.BindToObject(ptr, IntPtr.Zero, ref ShellDll.IID_IShellFolder, ref functionReturnValue);
  492.             if (hr != 0) functionReturnValue = null;
  493.             Marshal.FreeCoTaskMem(ptr);
  494.         }
  495.         return functionReturnValue;
  496.     }
  497.     #endregion
  498.    
  499.     #region " GetParentOf"
  500.    
  501.     ///<Summary>Returns both the ShellDll.IShellFolder interface of the parent folder
  502.     /// and the relative pidl of the input PIDL</Summary>
  503.     ///<remarks>Several internal functions need this information and do not have
  504.     /// it readily available. GetParentOf serves those functions</remarks>
  505.     private static ShellDll.IShellFolder GetParentOf(IntPtr pidl, ref IntPtr relPidl)
  506.     {
  507.         ShellDll.IShellFolder functionReturnValue = default(ShellDll.IShellFolder);
  508.         functionReturnValue = null;
  509.         //avoid VB2005 warning
  510.         int HR = 0;
  511.         int itemCnt = PidlCount(pidl);
  512.         if (itemCnt == 1) {
  513.             //parent is desktop
  514. HR = ShellDll.SHGetDesktopFolder(ref functionReturnValue);
  515.             relPidl = pidl;
  516.         }
  517.         else {
  518.             IntPtr tmpPidl = default(IntPtr);
  519.             tmpPidl = TrimPidl(pidl, ref relPidl);
  520.             HR = DesktopBase.m_Folder.BindToObject(tmpPidl, IntPtr.Zero, ref ShellDll.IID_IShellFolder, ref functionReturnValue);
  521.             Marshal.FreeCoTaskMem(tmpPidl);
  522.         }
  523.         if (!(HR == ShellDll.NOERROR)) Marshal.ThrowExceptionForHR(HR);
  524.         return functionReturnValue;
  525.     }
  526.     #endregion
  527.    
  528.     #region " SetUpAttributes"
  529.     /// <summary>Get the base attributes of the folder/file that this ShellItem represents</summary>
  530.     /// <param name="folder">Parent Folder of this Item</param>
  531.     /// <param name="pidl">Relative Pidl of this Item.</param>
  532.     ///
  533.     private void SetUpAttributes(ShellDll.IShellFolder folder, IntPtr pidl)
  534.     {
  535.         ShellDll.SFGAO attrFlag = default(ShellDll.SFGAO);
  536.         attrFlag = ShellDll.SFGAO.BROWSABLE;
  537.         attrFlag = attrFlag | ShellDll.SFGAO.FILESYSTEM;
  538.         attrFlag = attrFlag | ShellDll.SFGAO.HASSUBFOLDER;
  539.         attrFlag = attrFlag | ShellDll.SFGAO.FOLDER;
  540.         attrFlag = attrFlag | ShellDll.SFGAO.LINK;
  541.         attrFlag = attrFlag | ShellDll.SFGAO.SHARE;
  542.         attrFlag = attrFlag | ShellDll.SFGAO.HIDDEN;
  543.         attrFlag = attrFlag | ShellDll.SFGAO.REMOVABLE;
  544.         //attrFlag = attrFlag Or ShellDll.SFGAO.RDONLY 'made into an on-demand attribute
  545.         attrFlag = attrFlag | ShellDll.SFGAO.CANCOPY;
  546.         attrFlag = attrFlag | ShellDll.SFGAO.CANDELETE;
  547.         attrFlag = attrFlag | ShellDll.SFGAO.CANLINK;
  548.         attrFlag = attrFlag | ShellDll.SFGAO.CANMOVE;
  549.         attrFlag = attrFlag | ShellDll.SFGAO.DROPTARGET;
  550.         //Note: for GetAttributesOf, we must provide an array, in all cases with 1 element
  551.         IntPtr[] aPidl = new IntPtr[1];
  552.         aPidl[0] = pidl;
  553.         folder.GetAttributesOf(1, aPidl, ref attrFlag);
  554.         m_Attributes = attrFlag;
  555.         m_IsBrowsable = ((attrFlag & ShellDll.SFGAO.BROWSABLE) != 0);
  556.         m_IsFileSystem = ((attrFlag & ShellDll.SFGAO.FILESYSTEM) != 0);
  557.         m_HasSubFolders = ((attrFlag & ShellDll.SFGAO.HASSUBFOLDER) != 0);
  558.         m_IsFolder = ((attrFlag & ShellDll.SFGAO.FOLDER) != 0);
  559.         m_IsLink = ((attrFlag & ShellDll.SFGAO.LINK) != 0);
  560.         m_IsShared = ((attrFlag & ShellDll.SFGAO.SHARE) != 0);
  561.         m_IsHidden = ((attrFlag & ShellDll.SFGAO.HIDDEN) != 0);
  562.         m_IsRemovable = ((attrFlag & ShellDll.SFGAO.REMOVABLE) != 0);
  563.         //m_IsReadOnly = CBool(attrFlag And ShellDll.SFGAO.RDONLY) 'made into an on-demand attribute
  564.         m_CanCopy = ((attrFlag & ShellDll.SFGAO.CANCOPY) != 0);
  565.         m_CanDelete = ((attrFlag & ShellDll.SFGAO.CANDELETE) != 0);
  566.         m_CanLink = ((attrFlag & ShellDll.SFGAO.CANLINK) != 0);
  567.         m_CanMove = ((attrFlag & ShellDll.SFGAO.CANMOVE) != 0);
  568. m_IsDropTarget = ((attrFlag & ShellDll.SFGAO.DROPTARGET) != 0);
  569.        
  570.         //Get the Path
  571.         IntPtr strr = Marshal.AllocCoTaskMem(ShellDll.MAX_PATH * 2 + 4);
  572.         Marshal.WriteInt32(strr, 0, 0);
  573.         StringBuilder buf = new StringBuilder(ShellDll.MAX_PATH);
  574.         ShellDll.SHGDN itemflags = ShellDll.SHGDN.FORPARSING;
  575.         folder.GetDisplayNameOf(pidl, itemflags, strr);
  576.         int HR = ShellDll.StrRetToBuf(strr, pidl, buf, ShellDll.MAX_PATH);
  577.         Marshal.FreeCoTaskMem(strr);
  578.         //now done with it
  579.         if (HR == ShellDll.NOERROR) {
  580.             m_Path = buf.ToString();
  581.             //check for zip file = folder on xp, leave it a file
  582.             if (m_IsFolder && m_IsFileSystem && XPorAbove) {
  583.                 //Note:meaning of ShellDll.SFGAO.STREAM changed between win2k and winXP
  584.                 //Version 20 code
  585.                 //If File.Exists(m_Path) Then
  586.                 // m_IsFolder = False
  587.                 //End If
  588.                 //Version 21 code
  589.                 aPidl[0] = pidl;
  590.                 attrFlag = ShellDll.SFGAO.STREAM;
  591.                 folder.GetAttributesOf(1, aPidl, ref attrFlag);
  592.                 if ((attrFlag & ShellDll.SFGAO.STREAM) != 0) {
  593.                     m_IsFolder = false;
  594.                 }
  595.             }
  596.             if (m_Path.Length == 3 && m_Path.Substring(1).Equals(":\\")) {
  597.                 m_IsDisk = true;
  598.             }
  599.         }
  600.         else {
  601.             Marshal.ThrowExceptionForHR(HR);
  602.         }
  603.     }
  604.    
  605.     #endregion
  606.    
  607.     #endregion
  608.    
  609.     #region " Public Shared Function GetCShItem(ByVal path As String) As ShellItem"
  610.     public static ShellItem GetCShItem(string path)
  611.     {
  612.         ShellItem functionReturnValue = default(ShellItem);
  613.         functionReturnValue = null;
  614.         //assume failure
  615.         int HR = 0;
  616.         IntPtr tmpPidl = default(IntPtr);
  617. int tmp1 = 0, tmp2 = 0;
  618.         HR = GetDeskTop().Folder.ParseDisplayName(0, IntPtr.Zero, path, ref tmp1, ref tmpPidl, ref tmp2);
  619.         if (HR == 0) {
  620.             functionReturnValue = FindCShItem(tmpPidl);
  621. if ((functionReturnValue == null))
  622. {
  623.                 try {
  624.                     functionReturnValue = new ShellItem(path);
  625.                 }
  626.                 catch {
  627.                     functionReturnValue = null;
  628.                 }
  629.             }
  630.         }
  631.         if (!tmpPidl.Equals(IntPtr.Zero)) {
  632.             Marshal.FreeCoTaskMem(tmpPidl);
  633.         }
  634.         return functionReturnValue;
  635.     }
  636.     #endregion
  637.    
  638.     #region " Public Shared Function GetCShItem(ByVal ID As ShellDll.CSIDL) As ShellItem"
  639.     public static ShellItem GetCShItem(ShellDll.CSIDL ID)
  640.     {
  641.         ShellItem functionReturnValue = default(ShellItem);
  642.         functionReturnValue = null;
  643.         //avoid VB2005 Warning
  644.         if (ID == ShellDll.CSIDL.DESKTOP) {
  645.             return GetDeskTop();
  646.         }
  647.         int HR = 0;
  648.         IntPtr tmpPidl = default(IntPtr);
  649.         if (ID == ShellDll.CSIDL.MYDOCUMENTS) {
  650.             int pchEaten = 0;
  651. int tmp = 0;
  652.             HR = GetDeskTop().Folder.ParseDisplayName(0, IntPtr.Zero, "::{450d8fba-ad25-11d0-98a8-0800361b1103}", ref pchEaten, ref tmpPidl, ref tmp);
  653.         }
  654.         else {
  655.             HR = ShellDll.SHGetSpecialFolderLocation(0, (int)ID, ref tmpPidl);
  656.         }
  657.         if (HR == ShellDll.NOERROR) {
  658.             functionReturnValue = FindCShItem(tmpPidl);
  659. if ((functionReturnValue == null))
  660. {
  661.                 try {
  662.                     functionReturnValue = new ShellItem(ID);
  663.                 }
  664.                 catch {
  665.                     functionReturnValue = null;
  666.                 }
  667.             }
  668.         }
  669.         if (!tmpPidl.Equals(IntPtr.Zero)) {
  670.             Marshal.FreeCoTaskMem(tmpPidl);
  671.         }
  672.         return functionReturnValue;
  673.     }
  674.     #endregion
  675.    
  676.     #region " Public Shared Function GetCShItem(ByVal FoldBytes() As Byte, ByVal ItemBytes() As Byte) As ShellItem"
  677.     public static ShellItem GetCShItem(byte[] FoldBytes, byte[] ItemBytes)
  678.     {
  679.         ShellItem functionReturnValue = default(ShellItem);
  680.         functionReturnValue = null;
  681.         //assume failure
  682.         byte[] b = cPidl.JoinPidlBytes(FoldBytes, ItemBytes);
  683.         if ((b == null)) return functionReturnValue;
  684.         //can do no more with invalid pidls
  685.         //otherwise do like below, skipping unnecessary validation check
  686.         IntPtr thisPidl = Marshal.AllocCoTaskMem(b.Length);
  687.         if (thisPidl.Equals(IntPtr.Zero)) return null;
  688.         Marshal.Copy(b, 0, thisPidl, b.Length);
  689.         functionReturnValue = FindCShItem(thisPidl);
  690.         Marshal.FreeCoTaskMem(thisPidl);
  691. if ((functionReturnValue == null))
  692. {
  693.             //didn't find it, make new
  694.             try {
  695.                 functionReturnValue = new ShellItem(FoldBytes, ItemBytes);
  696.             }
  697.             catch {
  698.                
  699.             }
  700.         }
  701.         if (functionReturnValue.PIDL.Equals(IntPtr.Zero)) functionReturnValue = null;
  702.         return functionReturnValue;
  703.     }
  704.     #endregion
  705.    
  706.     #region " Public Shared Function FindCShItem(ByVal b() As Byte) As ShellItem"
  707.     public static ShellItem FindCShItem(byte[] b)
  708.     {
  709.         ShellItem functionReturnValue = default(ShellItem);
  710.         if (!IsValidPidl(b)) return null;
  711.         IntPtr thisPidl = Marshal.AllocCoTaskMem(b.Length);
  712.         if (thisPidl.Equals(IntPtr.Zero)) return null;
  713.         Marshal.Copy(b, 0, thisPidl, b.Length);
  714.         functionReturnValue = FindCShItem(thisPidl);
  715.         Marshal.FreeCoTaskMem(thisPidl);
  716.         return functionReturnValue;
  717.     }
  718.     #endregion
  719.    
  720.     #region " Public Shared Function FindCShItem(ByVal ptr As IntPtr) As ShellItem"
  721.     public static ShellItem FindCShItem(IntPtr ptr)
  722.     {
  723.         ShellItem functionReturnValue = default(ShellItem);
  724.         functionReturnValue = null;
  725.         //avoid VB2005 Warning
  726.         ShellItem BaseItem = ShellItem.GetDeskTop();
  727.         //ShellItem CSI = default(ShellItem);
  728.         bool FoundIt = false;
  729.         //True if we found item or an ancestor
  730.         while (!(FoundIt)) {
  731.             foreach (var obj in BaseItem.GetDirectories(true)) {
  732. ShellItem CSI = obj as ShellItem;
  733.                 if (IsAncestorOf(CSI.PIDL, ptr, false)) {
  734.                     if (ShellItem.IsEqual(CSI.PIDL, ptr)) {
  735.                         //we found the desired item
  736.                         return CSI;
  737.                     }
  738.                     else {
  739.                         BaseItem = CSI;
  740.                         FoundIt = true;
  741.                         break; // TODO: might not be correct. Was : Exit For
  742.                     }
  743.                 }
  744.             }
  745.             if (!FoundIt) return null;
  746.             //didn't find an ancestor
  747.             //The complication is that the desired item may not be a directory
  748.             if (!IsAncestorOf(BaseItem.PIDL, ptr, true)) {
  749.                 //Don't have immediate ancestor
  750.                     //go around again
  751.                 FoundIt = false;
  752.             }
  753.             else {
  754.                 foreach (var obj in BaseItem.GetItems()) {
  755. ShellItem CSI = obj as ShellItem;
  756. if (ShellItem.IsEqual(CSI.PIDL, ptr))
  757. {
  758.                         return CSI;
  759.                     }
  760.                 }
  761.                 //fall thru here means it doesn't exist or we can't find it because of funny PIDL from SHParseDisplayName
  762.                 return null;
  763.             }
  764.         }
  765.         return functionReturnValue;
  766.     }
  767.     #endregion
  768.    
  769.     #endregion
  770.    
  771.     #region " Icomparable -- for default Sorting"
  772.    
  773.     /// <summary>Computes the Sort key of this ShellItem, based on its attributes</summary>
  774.     ///
  775.     private int ComputeSortFlag()
  776.     {
  777.         int rVal = 0;
  778.         if (m_IsDisk) rVal = 0x100000;
  779.         if (m_TypeName.Equals(strSystemFolder)) {
  780.             if (!m_IsBrowsable) {
  781.                 rVal = rVal | 0x10000;
  782.                 if (m_strMyDocuments.Equals(m_DisplayName)) {
  783.                     rVal = rVal | 0x1;
  784.                 }
  785.             }
  786.             else {
  787.                 rVal = rVal | 0x1000;
  788.             }
  789.         }
  790.         if (m_IsFolder) rVal = rVal | 0x100;
  791.         return rVal;
  792.     }
  793.    
  794.     ///<Summary> CompareTo(obj as object)
  795.     /// Compares obj to this instance based on SortFlag-- obj must be a ShellItem</Summary>
  796.     ///<SortOrder> (low)Disks,non-browsable System Folders,
  797.     /// browsable System Folders,
  798.     /// Directories, Files, Nothing (high)</SortOrder>
  799.     public virtual int CompareTo(object obj)
  800.     {
  801.         ShellItem Other = obj as ShellItem;
  802.         if ((Other == null)) return 1;
  803.         //non-existant is always low
  804.         if (!m_HasDispType) SetDispType();
  805.         int cmp = Other.SortFlag - m_SortFlag;
  806.         //Note the reversal
  807.         if (cmp != 0) {
  808.             return cmp;
  809.         }
  810.         else {
  811.             if (m_IsDisk) {
  812.                 //implies that both are
  813.                 return string.Compare(m_Path, Other.Path);
  814.             }
  815.             else {
  816.                 return string.Compare(m_DisplayName, Other.DisplayName);
  817.             }
  818.         }
  819.     }
  820.     #endregion
  821.    
  822.     #region " Properties"
  823.    
  824.     #region " Shared Properties"
  825.     public static string strMyComputer {
  826.         get { return m_strMyComputer; }
  827.     }
  828.    
  829.     public static string strSystemFolder {
  830.         get { return m_strSystemFolder; }
  831.     }
  832.    
  833.     public static string DesktopDirectoryPath {
  834.         get { return m_DeskTopDirectory.Path; }
  835.     }
  836.    
  837.     #endregion
  838.    
  839.     #region " Normal Properties"
  840.     public IntPtr PIDL {
  841.         get { return m_Pidl; }
  842.     }
  843.    
  844.     public ShellDll.IShellFolder Folder {
  845.         get { return m_Folder; }
  846.     }
  847.    
  848.     public string Path {
  849.         get { return m_Path; }
  850.     }
  851.     public ShellItem Parent {
  852.         get { return m_Parent; }
  853.     }
  854.    
  855.     public ShellDll.SFGAO Attributes {
  856.         get { return m_Attributes; }
  857.     }
  858.     public bool IsBrowsable {
  859.         get { return m_IsBrowsable; }
  860.     }
  861.     public bool IsFileSystem {
  862.         get { return m_IsFileSystem; }
  863.     }
  864.     public bool IsFolder {
  865.         get { return m_IsFolder; }
  866.     }
  867.     public bool HasSubFolders {
  868.         get { return m_HasSubFolders; }
  869.     }
  870.     public bool IsDisk {
  871.         get { return m_IsDisk; }
  872.     }
  873.     public bool IsLink {
  874.         get { return m_IsLink; }
  875.     }
  876.     public bool IsShared {
  877.         get { return m_IsShared; }
  878.     }
  879.     public bool IsHidden {
  880.         get { return m_IsHidden; }
  881.     }
  882.     public bool IsRemovable {
  883.         get { return m_IsRemovable; }
  884.     }
  885.    
  886.     #region " Drag Ops Properties"
  887.     public bool CanMove {
  888.         get { return m_CanMove; }
  889.     }
  890.     public bool CanCopy {
  891.         get { return m_CanCopy; }
  892.     }
  893.     public bool CanDelete {
  894.         get { return m_CanDelete; }
  895.     }
  896.     public bool CanLink {
  897.         get { return m_CanLink; }
  898.     }
  899.     public bool IsDropTarget {
  900.         get { return m_IsDropTarget; }
  901.     }
  902.     #endregion
  903.    
  904.     #endregion
  905.    
  906.     #region " Filled on Demand Properties"
  907.    
  908.     #region " Filled based on m_HasDispType"
  909.     /// <summary>
  910.     /// Set DisplayName, TypeName, and SortFlag when actually needed
  911.     /// </summary>
  912.     ///
  913.     private void SetDispType()
  914.     {
  915.         //Get Displayname, TypeName
  916.         ShellDll.SHFILEINFO shfi = new ShellDll.SHFILEINFO();
  917.         int dwflag = (int)(ShellDll.SHGFI.DISPLAYNAME | ShellDll.SHGFI.TYPENAME | ShellDll.SHGFI.PIDL);
  918.         int dwAttr = 0;
  919.         if (m_IsFileSystem & !m_IsFolder) {
  920.             dwflag = dwflag | (int)ShellDll.SHGFI.USEFILEATTRIBUTES;
  921. dwAttr = (int)ShellDll.FILE_ATTRIBUTE_NORMAL;
  922.         }
  923. IntPtr H = ShellDll.SHGetFileInfo(m_Pidl, dwAttr, ref shfi, ShellDll.cbFileInfo, dwflag);
  924.         m_DisplayName = shfi.szDisplayName;
  925.         m_TypeName = shfi.szTypeName;
  926.         //fix DisplayName
  927.         if (m_DisplayName.Equals("")) {
  928.             m_DisplayName = m_Path;
  929.         }
  930.         //Fix TypeName
  931.         //If m_IsFolder And m_TypeName.Equals("File") Then
  932.         // m_TypeName = "File Folder"
  933.         //End If
  934.         m_SortFlag = ComputeSortFlag();
  935.         m_HasDispType = true;
  936.     }
  937.    
  938.     public string DisplayName {
  939.         get {
  940.             if (!m_HasDispType) SetDispType();
  941.             return m_DisplayName;
  942.         }
  943.     }
  944.    
  945.     private int SortFlag {
  946.         get {
  947.             if (!m_HasDispType) SetDispType();
  948.             return m_SortFlag;
  949.         }
  950.     }
  951.    
  952.     public string TypeName {
  953.         get {
  954.             if (!m_HasDispType) SetDispType();
  955.             return m_TypeName;
  956.         }
  957.     }
  958.     #endregion
  959.    
  960.     #region " IconIndex properties"
  961.     public int IconIndexNormal {
  962.         get {
  963.             if (m_IconIndexNormal < 0) {
  964.                 if (!m_HasDispType) SetDispType();
  965.                 ShellDll.SHFILEINFO shfi = new ShellDll.SHFILEINFO();
  966.                 int dwflag = (int)(ShellDll.SHGFI.PIDL | ShellDll.SHGFI.SYSICONINDEX);
  967.                 int dwAttr = 0;
  968.                 if (m_IsFileSystem & !m_IsFolder) {
  969.                     dwflag = dwflag | (int)ShellDll.SHGFI.USEFILEATTRIBUTES;
  970.                     dwAttr = (int)ShellDll.FILE_ATTRIBUTE_NORMAL;
  971.                 }
  972.                 IntPtr H = ShellDll.SHGetFileInfo(m_Pidl, dwAttr, ref shfi, ShellDll.cbFileInfo, dwflag);
  973.                 m_IconIndexNormal = shfi.iIcon;
  974.             }
  975.             return m_IconIndexNormal;
  976.         }
  977.     }
  978.     // IconIndexOpen is Filled on demand
  979.     public int IconIndexOpen {
  980.         get {
  981.             if (m_IconIndexOpen < 0) {
  982.                 if (!m_HasDispType) SetDispType();
  983.                 if (!m_IsDisk & m_IsFileSystem & m_IsFolder) {
  984.                     if (OpenFolderIconIndex < 0) {
  985.                         int dwflag = (int)(ShellDll.SHGFI.SYSICONINDEX | ShellDll.SHGFI.PIDL);
  986.                         ShellDll.SHFILEINFO shfi = new ShellDll.SHFILEINFO();
  987.                         IntPtr H = ShellDll.SHGetFileInfo(m_Pidl, 0, ref shfi, ShellDll.cbFileInfo, dwflag | (int)ShellDll.SHGFI.OPENICON);
  988.                         m_IconIndexOpen = shfi.iIcon;
  989.                     }
  990.                     else {
  991.                         //If m_TypeName.Equals("File Folder") Then
  992.                         // OpenFolderIconIndex = shfi.iIcon
  993.                         //End If
  994.                         m_IconIndexOpen = OpenFolderIconIndex;
  995.                     }
  996.                 }
  997.                 else {
  998.                     m_IconIndexOpen = m_IconIndexNormal;
  999.                 }
  1000.             }
  1001.             return m_IconIndexOpen;
  1002.         }
  1003.     }
  1004.     #endregion
  1005.    
  1006.     #region " FileInfo type Information"
  1007.    
  1008.     /// <summary>
  1009.     /// Obtains information available from FileInfo.
  1010.     /// </summary>
  1011.     ///
  1012.     private void FillDemandInfo()
  1013.     {
  1014.         if (m_IsDisk) {
  1015.             try {
  1016.                 //See if this is a network drive
  1017.                 //NoRoot = 1
  1018.                 //Removable = 2
  1019.                 //LocalDisk = 3
  1020.                 //Network = 4
  1021.                 //CD = 5
  1022.                 //RAMDrive = 6
  1023.                 System.Management.ManagementObject disk = new System.Management.ManagementObject("win32_logicaldisk.deviceid=\"" + m_Path.Substring(0, 2) + "\"");
  1024.                 m_Length = (long)(UInt64)disk["Size"];
  1025.                 if ((UInt32)disk["DriveType"] == 4) {
  1026.                     m_IsNetWorkDrive = true;
  1027.                 }
  1028.             }
  1029.             catch (Exception) {
  1030.                 //Disconnected Network Drives etc. will generate
  1031.                 //an error here, just assume that it is a network
  1032.                 //drive
  1033.                 m_IsNetWorkDrive = true;
  1034.             }
  1035.             finally {
  1036.                 m_XtrInfo = true;
  1037.             }
  1038.         }
  1039.         else if (!m_IsDisk & m_IsFileSystem & !m_IsFolder) {
  1040.             //in this case, it's a file
  1041.             if (File.Exists(m_Path)) {
  1042.                 FileInfo fi = new FileInfo(m_Path);
  1043.                 m_LastWriteTime = fi.LastWriteTime;
  1044.                 m_LastAccessTime = fi.LastAccessTime;
  1045.                 m_CreationTime = fi.CreationTime;
  1046.                 m_Length = fi.Length;
  1047.                 m_XtrInfo = true;
  1048.             }
  1049.         }
  1050.         else {
  1051.             if (m_IsFileSystem & m_IsFolder) {
  1052.                 if (Directory.Exists(m_Path)) {
  1053.                     DirectoryInfo di = new DirectoryInfo(m_Path);
  1054.                     m_LastWriteTime = di.LastWriteTime;
  1055.                     m_LastAccessTime = di.LastAccessTime;
  1056.                     m_CreationTime = di.CreationTime;
  1057.                     m_XtrInfo = true;
  1058.                 }
  1059.             }
  1060.         }
  1061.     }
  1062.    
  1063.     public DateTime LastWriteTime {
  1064.         get {
  1065.             if (!m_XtrInfo) {
  1066.                 FillDemandInfo();
  1067.             }
  1068.             return m_LastWriteTime;
  1069.         }
  1070.     }
  1071.     public DateTime LastAccessTime {
  1072.         get {
  1073.             if (!m_XtrInfo) {
  1074.                 FillDemandInfo();
  1075.             }
  1076.             return m_LastAccessTime;
  1077.         }
  1078.     }
  1079.     public DateTime CreationTime {
  1080.         get {
  1081.             if (!m_XtrInfo) {
  1082.                 FillDemandInfo();
  1083.             }
  1084.             return m_CreationTime;
  1085.         }
  1086.     }
  1087.     public long Length {
  1088.         get {
  1089.             if (!m_XtrInfo) {
  1090.                 FillDemandInfo();
  1091.             }
  1092.             return m_Length;
  1093.         }
  1094.     }
  1095.     public bool IsNetworkDrive {
  1096.         get {
  1097.             if (!m_XtrInfo) {
  1098.                 FillDemandInfo();
  1099.             }
  1100.             return m_IsNetWorkDrive;
  1101.         }
  1102.     }
  1103.     #endregion
  1104.    
  1105.     #region " cPidl information"
  1106.     public cPidl clsPidl {
  1107.         get {
  1108.             if ((m_cPidl == null)) {
  1109.                 m_cPidl = new cPidl(m_Pidl);
  1110.             }
  1111.             return m_cPidl;
  1112.         }
  1113.     }
  1114.     #endregion
  1115.    
  1116.     #region " IsReadOnly and IsSystem"
  1117.     ///<Summary>The IsReadOnly attribute causes an annoying access to any floppy drives
  1118.     /// on the system. To postpone this (or avoid, depending on user action),
  1119.     /// the attribute is only queried when asked for</Summary>
  1120.     public bool IsReadOnly {
  1121.         get {
  1122.             if (m_IsReadOnlySetup) {
  1123.                 return m_IsReadOnly;
  1124.             }
  1125.             else {
  1126.                 ShellDll.SHFILEINFO shfi = new ShellDll.SHFILEINFO();
  1127.                 shfi.dwAttributes = (int)ShellDll.SFGAO.RDONLY;
  1128.                 int dwflag = (int)(ShellDll.SHGFI.PIDL | ShellDll.SHGFI.ATTRIBUTES | ShellDll.SHGFI.ATTR_SPECIFIED);
  1129.                 int dwAttr = 0;
  1130.                 IntPtr H = ShellDll.SHGetFileInfo(m_Pidl, dwAttr, ref shfi, ShellDll.cbFileInfo, dwflag);
  1131.                 if (H.ToInt32() != ShellDll.NOERROR && H.ToInt32() != 1) {
  1132.                     Marshal.ThrowExceptionForHR(H.ToInt32());
  1133.                 }
  1134.                 m_IsReadOnly = ((shfi.dwAttributes & (int)ShellDll.SFGAO.RDONLY) != 0);
  1135.                 //If m_IsReadOnly Then Debug.WriteLine("IsReadOnly -- " & m_Path)
  1136.                 m_IsReadOnlySetup = true;
  1137.                 return m_IsReadOnly;
  1138.             }
  1139.         }
  1140.         //If Not m_XtrInfo Then
  1141.         // FillDemandInfo()
  1142.         //End If
  1143.         //Return m_Attributes And FileAttributes.ReadOnly = FileAttributes.ReadOnly
  1144.     }
  1145.     ///<Summary>The IsSystem attribute is seldom used, but required by DragDrop operations.
  1146.     /// Since there is no way of getting ONLY the System attribute without getting
  1147.     /// the RO attribute (which forces a reference to the floppy drive), we pay
  1148.     /// the price of getting its own File/DirectoryInfo for this purpose alone.
  1149.     ///</Summary>
  1150.     public bool IsSystem {
  1151.         get {
  1152.             //true once we have gotten this attr
  1153.             //the value of this attr once we have it
  1154.             if (!static_IsSystem_HaveSysInfo) {
  1155.                 try {
  1156.                     static_IsSystem_m_IsSystem = (File.GetAttributes(m_Path) & FileAttributes.System) == FileAttributes.System;
  1157.                     static_IsSystem_HaveSysInfo = true;
  1158.                 }
  1159.                 catch (Exception) {
  1160.                     static_IsSystem_HaveSysInfo = true;
  1161.                 }
  1162.             }
  1163. Debug.WriteLine("In IsSystem -- Path = " + m_Path + " IsSystem = " + static_IsSystem_m_IsSystem);
  1164.             return static_IsSystem_m_IsSystem;
  1165.         }
  1166.     }
  1167.     static bool static_IsSystem_m_IsSystem = false;
  1168.     static bool static_IsSystem_HaveSysInfo = false;
  1169.    
  1170.     #endregion
  1171.    
  1172.     #endregion
  1173.    
  1174.     #endregion
  1175.    
  1176.     #region " Public Methods"
  1177.    
  1178.     #region " Shared Public Methods"
  1179.    
  1180.     #region " GetDeskTop"
  1181.     /// <summary>
  1182.     /// If not initialized, then build DesktopBase
  1183.     /// once done, or if initialized already,
  1184.     /// </summary>
  1185.     ///<returns>The DesktopBase ShellItem representing the desktop</returns>
  1186.     ///
  1187.     public static ShellItem GetDeskTop()
  1188.     {
  1189.         if ((DesktopBase == null)) {
  1190.             DesktopBase = new ShellItem();
  1191.         }
  1192.         return DesktopBase;
  1193.     }
  1194.     #endregion
  1195.    
  1196.     #region " IsAncestorOf"
  1197.     ///<Summary>IsAncestorOf returns True if ShellItem ancestor is an ancestor of ShellItem current
  1198.     /// if OS is Win2K or above, uses the ILIsParent API, otherwise uses the
  1199.     /// cPidl function StartsWith. This is necessary since ILIsParent in only available
  1200.     /// in Win2K or above systems AND StartsWith fails on some folders on XP systems (most
  1201.     /// obviously some Network Folder Shortcuts, but also Control Panel. Note, StartsWith
  1202.     /// always works on systems prior to XP.
  1203.     /// NOTE: if ancestor and current reference the same Item, both
  1204.     /// methods return True</Summary>
  1205.     public static bool IsAncestorOf(ShellItem ancestor, ShellItem current, [System.Runtime.InteropServices.OptionalAttribute, System.Runtime.InteropServices.DefaultParameterValueAttribute(false)] // ERROR: Optional parameters aren't supported in C#
  1206. bool fParent)
  1207.     {
  1208.         return IsAncestorOf(ancestor.PIDL, current.PIDL, fParent);
  1209.     }
  1210.     ///<Summary> Compares a candidate Ancestor PIDL with a Child PIDL and
  1211.     /// returns True if Ancestor is an ancestor of the child.
  1212.     /// if fParent is True, then only return True if Ancestor is the immediate
  1213.     /// parent of the Child</Summary>
  1214.     public static bool IsAncestorOf(IntPtr AncestorPidl, IntPtr ChildPidl, [System.Runtime.InteropServices.OptionalAttribute, System.Runtime.InteropServices.DefaultParameterValueAttribute(false)] // ERROR: Optional parameters aren't supported in C#
  1215. bool fParent)
  1216.     {
  1217.         bool functionReturnValue = false;
  1218.         if (ShellDll.Is2KOrAbove()) {
  1219.             return ShellDll.ILIsParent(AncestorPidl, ChildPidl, fParent);
  1220.         }
  1221.         else {
  1222.             cPidl Child = new cPidl(ChildPidl);
  1223.             cPidl Ancestor = new cPidl(AncestorPidl);
  1224.             functionReturnValue = Child.StartsWith(Ancestor);
  1225.             if (!functionReturnValue) return functionReturnValue;
  1226.             if (fParent) {
  1227.                 // check for immediate ancestor, if desired
  1228.                 object[] oAncBytes = Ancestor.Decompose();
  1229.                 object[] oChildBytes = Child.Decompose();
  1230.                 if (oAncBytes.Length != (oChildBytes.Length - 1)) {
  1231.                     functionReturnValue = false;
  1232.                 }
  1233.             }
  1234.         }
  1235.         return functionReturnValue;
  1236.     }
  1237.     #endregion
  1238.    
  1239.     #region " AllFolderWalk"
  1240.     ///<Summary>The WalkAllCallBack delegate defines the signature of
  1241.     /// the routine to be passed to DirWalker
  1242.     /// Usage: dim d1 as new CshItem.WalkAllCallBack(addressof yourroutine)
  1243.     /// Callback function receives a ShellItem for each file and Directory in
  1244.     /// Starting Directory and each sub-directory of this directory and
  1245.     /// each sub-dir of each sub-dir ....
  1246.     ///</Summary>
  1247.     public delegate bool WalkAllCallBack(ShellItem info, int UserLevel, int Tag);
  1248.     ///<Summary>
  1249.     /// AllFolderWalk recursively walks down directories from cStart, calling its
  1250.     /// callback routine, WalkAllCallBack, for each Directory and File encountered, including those in
  1251.     /// cStart. UserLevel is incremented by 1 for each level of dirs that DirWalker
  1252.     /// recurses thru. Tag in an Integer that is simply passed, unmodified to the
  1253.     /// callback, with each ShellItem encountered, both File and Directory CShItems.
  1254.     /// </Summary>
  1255.     /// <param name="cStart"></param>
  1256.     /// <param name="cback"></param>
  1257.     /// <param name="UserLevel"></param>
  1258.     /// <param name="Tag"></param>
  1259.     ///
  1260.     public static bool AllFolderWalk(ShellItem cStart, WalkAllCallBack cback, int UserLevel, int Tag)
  1261.     {
  1262.         if ((cStart != null) && cStart.IsFolder) {
  1263.             //ShellItem cItem = default(ShellItem);
  1264.             //first processes all files in this directory
  1265.             foreach (var obj in cStart.GetFiles()) {
  1266. ShellItem cItem = obj as ShellItem;
  1267.                 if (!cback(cItem, UserLevel, Tag)) {
  1268.                         //user said stop
  1269.                     return false;
  1270.                 }
  1271.             }
  1272.             //then process all dirs in this directory, recursively
  1273.             foreach (var obj in cStart.GetDirectories(true)) {
  1274. ShellItem cItem = obj as ShellItem;
  1275.                 if (!cback(cItem, UserLevel + 1, Tag)) {
  1276.                         //user said stop
  1277.                     return false;
  1278.                 }
  1279.                 else {
  1280.                     if (!AllFolderWalk(cItem, cback, UserLevel + 1, Tag)) {
  1281.                         return false;
  1282.                     }
  1283.                 }
  1284.             }
  1285.             return true;
  1286.         }
  1287.         else {
  1288.             //Invalid call
  1289.             throw new ApplicationException("AllFolderWalk -- Invalid Start Directory");
  1290.         }
  1291.     }
  1292.     #endregion
  1293.    
  1294.     #endregion
  1295.    
  1296.     #region " Public Instance Methods"
  1297.    
  1298.     #region " Equals"
  1299.     public bool Equals(ShellItem other)
  1300.     {
  1301.         return this.Path.Equals(other.Path);
  1302.     }
  1303.     #endregion
  1304.    
  1305.     #region " GetDirectories"
  1306.     /// <summary>
  1307.     /// Returns the Directories of this sub-folder as an ArrayList of CShitems
  1308.     /// </summary>
  1309.     /// <param name="doRefresh">Optional, default=True, Refresh the directories</param>
  1310.     /// <returns>An ArrayList of CShItems. May return an empty ArrayList if there are none.</returns>
  1311.     /// <remarks>revised to alway return an up-to-date list unless
  1312.     /// specifically instructed not to (useful in constructs like:
  1313.     //…

Large files files are truncated, but you can click here to view the full file