【问题标题】:SHGetKnownFolderPath / Environment.GetFolderPath() returning wrong value for public documentsSHGetKnownFolderPath / Environment.GetFolderPath() 返回公共文档的错误值
【发布时间】:2011-11-04 06:24:31
【问题描述】:

我在尝试解析CommonDocuments 目录时遇到了一个奇怪的错误。 在使用 Windows 资源管理器(属性->上下文菜单中的路径)将 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/调用==>
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 框架 v4.0.30319 应用程序针对 x86 CPU

编译

到目前为止我尝试了什么:

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

编辑 2 重现步骤:

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

【问题讨论】:

  • 我怀疑重定向/移动它没有正确完成......通常这样的改变会通过一些组策略来完成......而且还有“本地化”方面(真正的文件夹的名称与显示的名称不同)这似乎在您的情况下起作用...
  • 上面的第二行将 EXPORT_REPOSITORY 和 "\\excel2007" 组合在一起,很可能会给你一个 "\excel2007" 的值。至少根据说明“如果 path2 包含绝对路径,此方法返回 path2”的文档。
  • @Daniel 感谢您指出这一点。根据版本控制系统,我一定是在本地系统上引入了该错误。
  • 我在这里遗漏了什么吗?你为什么要 P/Invoking 而不是使用Environment.SpecialFolder.CommonDocuments

标签: c# winapi windows-7 .net-4.0 known-folders


【解决方案1】:

tl;dr: 行为是设计使然,仅当您在 x64 操作系统上运行为 x86 CPU 编译的程序集时才会出现


更长的版本:
Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments) 访问 Windows 注册表的 32 位配置单元。
文件夹的实际路径存储在 64 位配置单元中。 该问题已转发给 Windows 团队,可能会在未来的 Windows 版本中得到修复。

有关更多信息,请参阅the Microsoft connect report


解决方法 使用以下代码创建一个控制台应用程序并为 ANY 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 可执行文件,它只打印出所需的标准输出路径。然后在主应用程序中读取输出并获得真实路径。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-26
    • 2013-11-15
    • 2012-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多