views:

642

answers:

2

I'm attempting to write a C# managed class to wrap SHGetKnownFolderPath, so far it works on Vista, but crashes on XP due to not finding the proper function in shell32.dll, as expected.

I want to have it set so I can fallback on a (admittedly hacky) solution using System.Environment.GetFolderPath if using XP. (Or, even better, if it can't find the funciton in shell32.)

Is there any way to do this other then conditional compilation?

My current code looks like:

public abstract class KnownFolders
    {
        [DllImport("shell32.dll")]
        private static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr pszPath);

        // Trim properties to get various Guids.

        public static string GetKnownFolderPath(Guid guid)
        {
            IntPtr pPath;
            int result = SHGetKnownFolderPath(guid, 0, IntPtr.Zero, out pPath);
            if (result == 0)
            {
                string s = Marshal.PtrToStringUni(pPath);
                Marshal.FreeCoTaskMem(pPath);
                return s;
            }
            else
                throw new System.ComponentModel.Win32Exception(result);
        }
    }
+5  A: 

Wrap your call to SHGetKnownFolderPath in a try-catch block. Catch the System.DllNotFoundException and then try your alternative solution:

public static string GetKnownFolderPath(Guid guid)
{
  try
  {
    IntPtr pPath;
    int result = SHGetKnownFolderPath(guid, 0, IntPtr.Zero, out pPath);
    if (result == 0)
    {
        string s = Marshal.PtrToStringUni(pPath);
        Marshal.FreeCoTaskMem(pPath);
        return s;
    }
    else
        throw new System.ComponentModel.Win32Exception(result);
  }
  catch(EntryPointNotFoundException ex)
  {
    DoAlternativeSolution();
  }
}
heavyd
Okay, this works, but with one small change. I had to catch a EntryPointNotFoundException, not a DllNotFoundException. Seeing as the function is from shell32.dll, it isn't unlikely to be missing on a functional Windows platform.
MiffTheFox
Yes, that is correct, I'll update my response to reflect the actual exception.
heavyd
+2  A: 

You can check the OS version using the Environment.OSVersion property. I believe if you do

int osVersion = Environment.OSVersion.Version.Major

on XP that will be 5, and on Vista that will be 6. So from there just to a simple check.

if(osVersion == 5)
{
   //do XP way
}
else if(osVersion == 6)
{
   //P/Invoke it
}
BFree