SHGetKnownFolderPath / Environment.GetFolderPath() 返回公共文档的错误值

10

当我尝试解析CommonDocuments目录时,遇到了一个有点奇怪的错误。在使用 Windows Explorer(属性->从上下文菜单中选择路径)将 CommonDocuments 目录重定向/移动到新位置之后,它仍然会解析到错误的目录。

一个最小化的工作代码如下:

namespace CommonDocumentsTest
{
    class Program
    {
        private static readonly Guid CommonDocumentsGuid = new Guid("ED4824AF-DCE4-45A8-81E2-FC7965083634");

        [Flags]
        public enum KnownFolderFlag : uint
        {
            None = 0x0,
            CREATE = 0x8000,
            DONT_VERFIY = 0x4000,
            DONT_UNEXPAND= 0x2000,
            NO_ALIAS = 0x1000,
            INIT = 0x800,
            DEFAULT_PATH = 0x400,
            NOT_PARENT_RELATIVE = 0x200,
            SIMPLE_IDLIST = 0x100,
            ALIAS_ONLY = 0x80000000
        }

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

        static void Main(string[] args)
        {
            KnownFolderFlag[] flags = new KnownFolderFlag[] {
                KnownFolderFlag.None,
                KnownFolderFlag.ALIAS_ONLY | KnownFolderFlag.DONT_VERFIY,
                KnownFolderFlag.DEFAULT_PATH | KnownFolderFlag.NOT_PARENT_RELATIVE,
            };


            foreach (var flag in flags)
            {
                Console.WriteLine(string.Format("{0}; P/Invoke==>{1}", flag, pinvokePath(flag)));
            }
            Console.ReadLine();
        }

        private static string pinvokePath(KnownFolderFlag flags)
        {
            IntPtr pPath;
            SHGetKnownFolderPath(CommonDocumentsGuid, (uint)flags, IntPtr.Zero, out pPath); // public documents

            string path = System.Runtime.InteropServices.Marshal.PtrToStringUni(pPath);
            System.Runtime.InteropServices.Marshal.FreeCoTaskMem(pPath);
            return path;
        }
    }
}

期望的行为:
输出为D:\TestDocuments

实际的行为:
输出为C:\Users\Public\Documents

没有;P/Invoke==>C:\Users\Public\Documents
DONT_VERFIY,ALIAS_ONLY;P/Invoke==>
NOT_PARENT_RELATIVE,DEFAULT_PATH;P/Invoke==>C:\Users\Public\Documents

正确的值存储在Windows注册表中(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Common Documents),但SHGetKnownFolderPath(或Environment.GetFolderPath)没有返回该值。

操作系统:Windows 7 Professional x64
.NET Framework v4.0.30319 应用程序是针对x86 CPU编译的

我尝试过:

  • 重新启动我的应用程序
  • 重新启动计算机
  • 调用Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments);
  • P/Invoke直接调用Win32-API SHGetKnownFolderPath

编辑2 重现步骤:

  1. 在您的计算机上停用UAC [并重新启动!]
  2. 转到C:\Users\Public\
  3. 右键单击“公共文档”文件夹,然后选择 属性
  4. 选择“路径”选项卡
  5. 单击“移动...”并选择一个名为TestDocuments的驱动器D:上的(新)文件夹
  6. 单击“应用”
  7. 同意将所有文件移动到新位置,开始执行上面的最小应用程序

我怀疑重定向/移动操作没有正确执行... 通常这种更改会通过一些组策略来完成... 还有“本地化”方面的问题(真实文件夹名称与显示名称不同),似乎在你的情况下起了作用... - Yahia
1
在你结合 EXPORT_REPOSITORY 和 "\excel2007" 的上面第二行,很可能会给你一个值为 "\excel2007"。至少根据文档,它指出:“如果 path2 包含一个绝对路径,这个方法将返回 path2”。 - Daniel
我可能有所遗漏,为什么你要使用P/Invoke而不是使用Environment.SpecialFolder.CommonDocuments呢? - qJake
@SpikeX 请看一下这个问题的历史。你所建议的是我的第一次尝试,但自那以后我一直在努力找到问题的核心。 - yas4891
从听起来的情况来看,问题不在于这个变量,而是在于用户如何移动他们的文档文件夹。我怀疑某些值或某些注册表项没有得到更新,更不用说C:\Users\结构内的一些文件夹是联接点(不是真正的文件夹),因此移动它们只会移动联接点。 - qJake
显示剩余2条评论
1个回答

5
简短版:这种行为是设计上的,仅在运行针对x86 CPU编译的程序时出现在x64操作系统上。
更详细的解释: Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments)访问Windows注册表的32位集合。 实际文件夹路径存储在64位集合中。 此问题已转发给Windows团队,可能在将来的Windows版本中修复。
若需更多信息,请参见Microsoft connect report 解决方案:创建一个控制台应用程序,使用以下代码并将其编译为任何CPU
static void Main(string[] args)
{
        Console.WriteLine("{0}", Environment.GetFolderPath(System.Environment.SpecialFolder.CommonDocuments));
}

然后从你的主应用程序中调用它:

Process proc = new Process();
ProcessStartInfo info = new ProcessStartInfo("myConsoleApp.exe");

// allow output to be read
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.UseShellExecute = false;
proc.StartInfo = info;

proc.Start(); 
proc.WaitForExit();
string path = proc.StandardOutput.ReadToEnd();

这将启动Any CPU可执行文件,该文件只会将所需路径打印到标准输出。然后在主应用程序中读取输出,从而得到真实路径。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接