10

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)によって返されません。

OS: Windows 7 Professional x64
.NET Framework v4.0.30319 アプリケーションはx86 CPU用にコンパイルされています

私がこれまでに試したこと:

  • アプリケーションの再起動
  • コンピュータの再起動
  • 呼び出しEnvironment.GetFolderPath(Environment.SpecialFolder.CommonDocuments);
  • Win32-API SHGetKnownFolderPath への直接呼び出し

再現するための編集2ステップ:

  1. コンピューターで UAC を無効にする [そして再起動する!]
  2. C:\Users\Public\ に移動します
  3. 「Public Documents」フォルダを右クリックして選択します Properties
  4. 「パス」タブを選択します
  5. 「移動...」をクリックし、ドライブ上の(新しい)フォルダを選択しD:ますTestDocuments
  6. 「適用」をクリック
  7. すべてのファイルを新しい場所に移動することを受け入れる 上記の最小限のアプリケーションを開始する
4

1 に答える 1

5

tl; dr:動作は仕様によるものであり、x64OSでx86CPU用にコンパイルされたアセンブリを実行している場合にのみ表示されます


長いバージョン:
Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments) Windowsレジストリの32ビットハイブにアクセスします。
フォルダへの実際のパスは64ビットハイブに保存されます。この問題はWindowsチームに転送されており、Windowsの将来のバージョンで修正される可能性があります。

詳細については、Microsoft接続レポートを参照してください。


回避策次のコードを使用してコンソールアプリケーションを作成し、任意の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();

これにより、任意のCPU実行可能ファイルが起動し、必要なパスのみが標準出力に出力されます。次に、出力がメインアプリケーションで読み取られ、実際のパスが取得されます。

于 2011-09-13T14:44:04.463 に答える