Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / October 2005

Tip: Looking for answers? Try searching our database.

PIDL returned from IEnumIdList causes ExecutionEngineException when calling IShellFolder::GetDisplayNameOf on Windows 2000 (C#, Framework 2.0.50215)

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Jim - 03 Oct 2005 09:27 GMT
The problem i've stated in the topic occurs on Windows 2000, while the
code works perfectly on Windows XP.

Basically, what I'm trying to do is to recursively enumerate shell
folders starting at the root desktop. The currentFolder parameter for
the first call is obtained from SHGetDesktopFolder.

Dictionary<string, IntPtr> GetSubFolders(IShellFolder currentFolder) {
  Dictionary<string, IntPtr> result = new Dictionary<string, IntPtr>();
  try {
    IEnumIDList enumIdList = null;
    currentFolder.EnumObjects(
       0,
       (int)(EnumOptions.Folders),
       ref enumIdList
    );
    if (enumIdList != null) {
      IntPtr itemId;
      uint fetched = 0;
      do {
        enumIdList.Next(1, out itemId, ref fetched);
        if (fetched == 1) {
          try {
            STRRET name;

            //The following line fails on win2000 once
            //enumIdList.Next has been called a few times:
            currentFolder.GetDisplayNameOf(
             itemId, SHGDN_FORADDRESSBAR, out name
            );

            result[name.sString] = itemId;
          } finally {
            //the pidls will be released by caller
         //if (itemId != IntPtr.Zero) Marshal.FreeCoTaskMem(itemId);
          }
        }
      } while (fetched == 1);
    }
  } catch {

  }
  return result;
}

My Interface/Interop declarations (which work on windows xp):

    [ComImport(), Guid("000214F2-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IEnumIDList {
        void Next(UInt32 celt, out IntPtr itemId , ref UInt32
pceltFetched);
        void Skip(UInt32 celt);
        void Reset();
        void Clone(ref IEnumIDList ppenum);
    }

    [ComImport(), Guid("000214E6-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IShellFolder {
        void ParseDisplayName(IntPtr hwnd, IntPtr pbc,
[MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, out uint
pchEaten, out IntPtr ppidl, ref uint pdwAttributes);
        void EnumObjects(int hwnd, int grfFlags, ref IEnumIDList
ppenumIDList);
        void BindToObject(IntPtr pidl, IntPtr pbc, ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out IShellFolder /* IntPtr*/ ppv);
        void BindToStorage(IntPtr pidl, IntPtr pbc, ref Guid riid, ref
IntPtr ppv);
        void CompareIDs(int lParam, IntPtr pidl1, IntPtr pidl2);

        [PreserveSig]
        long CreateViewObject(IntPtr hwndOwner, ref Guid riid, out
IntPtr ppv);

        [PreserveSig]
        long GetAttributesOf(uint cidl, IntPtr apidl, ref int rgfInOut);
        void GetUIObjectOf(IntPtr hwndOwner, uint cidl, IntPtr apidl,
ref Guid riid, ref uint rgfReserved, ref IntPtr ppv);
        void GetDisplayNameOf(IntPtr pidl, uint uFlags, out STRRET pName);
        void SetNameOf(IntPtr hwnd, IntPtr pidl, IntPtr pszName, long
uFlags, out IntPtr ppidlOut);
    }

        [DllImport("shell32.dll")]
        private static extern Int32
SHGetDesktopFolder([MarshalAs(UnmanagedType.Interface)] out IShellFolder
ppshf);

        [Flags]
        private enum EnumOptions {
            Folders = 0x0020,   // only want folders enumerated
(SFGAO_FOLDER)
            NonFolders = 0x0040,   // include non folders
            IncludeHidden = 0x0080,   // show items normally hidden
            InitOnFirstNext = 0x0100,   // allow EnumObject() to return
before validating enum
            NetPrinterSrch = 0x0200,   // hint that client is looking
for printers
            Shareable = 0x0400,   // hint that client is looking
sharable resources (remote shares)
            Storage = 0x0800    // include all items with accessible
storage and their ancestors
        }
Mattias Sjögren - 03 Oct 2005 23:37 GMT
Jim,

>             STRRET name;
>
[quoted text clipped - 5 lines]
>
>             result[name.sString] = itemId;

How did you declare STRRET? You should probably use a function like
StrRetToStr to retrieve the string, rather than assuming that it's
returned in a specific format.

Mattias

Signature

Mattias Sjögren [MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.

Jim - 04 Oct 2005 07:44 GMT
> Jim,
>
[quoted text clipped - 13 lines]
>
> Mattias

My declaration is as follows:

    [StructLayout(LayoutKind.Sequential)]
    public struct STRRET {

        public UInt32 uType;

        [MarshalAs(UnmanagedType.LPWStr)]
        public string sString;

    }

If I remember correctly it's from the MSDN article about writing C#
Shell Extensions. I'll take a look at the StrRetToStr function to see if
that fixes the problem.
Jim - 04 Oct 2005 15:27 GMT
I found the problem. Windows XP has no problem with the line
MarshalAs(UnmanagedType.LPWStr) in my STRRET declaration, but Windows
2000 doesn't work since an Ansi string is returned.

I got it working using the StrRetToStr function and STRRET::sString
declared as an IntPtr :)

>> Jim,
>>
[quoted text clipped - 29 lines]
> Shell Extensions. I'll take a look at the StrRetToStr function to see if
> that fixes the problem.
Mattias Sjögren - 04 Oct 2005 16:16 GMT
>My declaration is as follows:
>
[quoted text clipped - 10 lines]
>If I remember correctly it's from the MSDN article about writing C#
>Shell Extensions.

Well unfortunately it's incorrect. That declaration is way too small,
and you risk a buffer overrun by passing it to GetDisplayNameOf.

A declaration I've used in the past, which works nicely if you treat
it as an opaque struct (ie just pass it to StrRetToStr and don't have
to directly access the members), looks like this

[StructLayout(LayoutKind.Sequential, Size=264)]
struct STRRET
{
    int uType;
    /*
        IntPtr pOleStr;
        uint uOffset;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst=260)]
        char[] cStr;
    */
}

The commented union members are there for information purpose only.
The important thing is that the struct has the correct size, 264
bytes.

Mattias

Signature

Mattias Sjögren [MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.