1

編集: Scotty2012 と David Morton の回答がうまくいかないので、この質問に報奨金を出しました。文字列を渡す前に、文字列の型を別のものに変更する必要があると思います。

私は P/Invoke の警官ではなく、SHSetKnownFolderPathの宣言と呼び出しに苦労しています。私は VB9 を使用していますが、誰かが C# で答えを出したら、翻訳できるはずです。

SHGetKnowFolderPath が機能しています。これが私のコードです。

VB で

Imports System.Runtime.InteropServices

Public Class Form1
    <DllImport("shell32.dll")> _
    Private Shared Function SHGetKnownFolderPath(<MarshalAs(UnmanagedType.LPStruct)> ByVal rfid As Guid, ByVal dwFlags As UInteger, ByVal hToken As IntPtr, ByRef pszPath As IntPtr) As Integer
    End Function

    <DllImport("shell32.dll")> _
    Private Shared Function SHSetKnownFolderPath(<MarshalAs(UnmanagedType.LPStruct)> ByVal rfid As Guid, ByVal dwFlags As UInteger, ByVal hToken As IntPtr, ByRef pszPath As IntPtr) As Integer
    End Function

    Public Shared ReadOnly Documents As New Guid("FDD39AD0-238F-46AF-ADB4-6C85480369C7")


    Private Sub ButtonSetDocumentsPath_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSetDocumentsPath.Click
        Dim pPath As IntPtr = Marshal.StringToCoTaskMemUni(TextBoxPath.Text)
        If SHSetKnownFolderPath(Documents, 0, IntPtr.Zero, pPath) = 0 Then
            MsgBox("Set Sucessfully")
        End If

    End Sub

    Private Sub ButtonGetDocumentsPath_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonGetDocumentsPath.Click
        Dim pPath As IntPtr
        If SHGetKnownFolderPath(Documents, 0, IntPtr.Zero, pPath) = 0 Then
            Dim s As String = Marshal.PtrToStringUni(pPath)
            Marshal.FreeCoTaskMem(pPath)
            TextBoxPath.Text = s
        End If

    End Sub
End Class

ありがとう!

4

3 に答える 3

3

このコードを試してください。長々と申し訳ありませんが、この特定の関数を適切に PInvoke するために必要なことはすべてです。これは、両方の関数の定義と SHGetKnownFolderPath の使用例を含む単純なコンソール アプリケーションです。

先に進み、KNOWN_FOLDER_FLAG の定義と、フォルダー ID のいくつかの定義を含めました。すべてのフォルダ ID は、実際には単なる GUID です。考えられる ID はすべて %ProgramFiles%\Windows SDK\v6.0A\Include\KnownFolders.h にあり、サンプルで追加したのと同じ方法で追加できます。

特定の関数を呼び出すための邪悪な marashal'ing の詳細をすべて隠すラッパー関数をいくつか含めました。

必要な特定のフォルダー ID または説明がある場合は、コメントを追加してください。サンプルを更新します。

編集SHSetKnownFolderPath のマーシャリングの誤りを修正しました。MarshalAs タグを String 値に追加しなかったため、デフォルトで ANSI 文字列になっていました。API にはユニコードが必要でした。SHSetFolderFunction が機能するようになりました (RecentFolder で確認済み)

Imports System.Runtime.InteropServices



Module NativeMethods

    Public Enum KNOWN_FOLDER_FLAG

        '''KF_FLAG_CREATE -> 0x00008000
        KF_FLAG_CREATE = 32768

        '''KF_FLAG_DONT_VERIFY -> 0x00004000
        KF_FLAG_DONT_VERIFY = 16384

        '''KF_FLAG_DONT_UNEXPAND -> 0x00002000
        KF_FLAG_DONT_UNEXPAND = 8192

        '''KF_FLAG_NO_ALIAS -> 0x00001000
        KF_FLAG_NO_ALIAS = 4096

        '''KF_FLAG_INIT -> 0x00000800
        KF_FLAG_INIT = 2048

        '''KF_FLAG_DEFAULT_PATH -> 0x00000400
        KF_FLAG_DEFAULT_PATH = 1024

        '''KF_FLAG_NOT_PARENT_RELATIVE -> 0x00000200
        KF_FLAG_NOT_PARENT_RELATIVE = 512

        '''KF_FLAG_SIMPLE_IDLIST -> 0x00000100
        KF_FLAG_SIMPLE_IDLIST = 256

        '''KF_FLAG_ALIAS_ONLY -> 0x80000000
        KF_FLAG_ALIAS_ONLY = &H80000000
    End Enum


    Public ComputerFolder As Guid = New Guid("0AC0837C-BBF8-452A-850D-79D08E667CA7")
    Public DesktopFolder As Guid = New Guid("B4BFCC3A-DB2C-424C-B029-7FE99A87C641")
    Public DocumentsFolder As Guid = New Guid("FDD39AD0-238F-46AF-ADB4-6C85480369C7")


    <DllImport("shell32.dll")> _
    Public Function SHGetKnownFolderPath( _
        ByRef folderId As Guid, _
        ByVal flags As UInteger, _
        ByVal token As IntPtr, _
        <Out()> ByRef pathPtr As IntPtr) As Integer

    End Function

    <DllImport("shell32.dll")> _
    Public Function SHSetKnownFolderPath( _
        ByRef folderId As Guid, _
        ByVal flags As UInteger, _
        ByVal token As IntPtr, _
        <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal path As String) As Integer

    End Function

    Public Function SHGetKnownFolderPathWrapper(ByVal folderId As Guid) As String
        Return SHGetKnownFolderPathWrapper(folderId, 0)
    End Function

    Public Function SHGetKnownFolderPathWrapper( _
        ByVal folderId As Guid, _
        ByVal flags As KNOWN_FOLDER_FLAG) As String

        Dim ptr = IntPtr.Zero
        Dim path = String.Empty
        Try
            Dim ret = SHGetKnownFolderPath(folderId, CUInt(flags), IntPtr.Zero, ptr)
            If ret <> 0 Then
                Throw Marshal.GetExceptionForHR(ret)
            End If
            path = Marshal.PtrToStringUni(ptr)
        Finally
            Marshal.FreeCoTaskMem(ptr)
        End Try
        Return path
    End Function

    Public Sub SHSetKnownFolderPathWrapper( _
        ByVal folderId As Guid, _
        ByVal path As String)

        SHSetKnownFolderPathWrapper(folderId, 0, path)
    End Sub

    Public Sub SHSetKnownFolderPathWrapper( _
        ByVal folderId As Guid, _
        ByVal flags As KNOWN_FOLDER_FLAG, _
        ByVal path As String)

        Dim ret = SHSetKnownFolderPath(folderId, CUInt(flags), IntPtr.Zero, path)
        If ret <> 0 Then
            Throw Marshal.GetExceptionForHR(ret)
        End If
    End Sub

End Module

Module Module1

    Sub Main()
        Dim path = SHGetKnownFolderPathWrapper(NativeMethods.DesktopFolder)
        Console.WriteLine(path)
    End Sub

End Module
于 2009-02-01T21:59:02.977 に答える
2

これは C# で動作するはずだと思います (ここでは vista を実行していないため、確認できません)。

[DllImport("shell32.dll")]
private static int SHSetKnownFolderPath(ref Guid guid, int flags, IntPtr hToken, string newPath);

このように呼び出すことができます

SHSetKnownFolderPath(ref Documents, 0, IntPtr.Zero, "c:\\my new path\\");
于 2009-01-27T17:29:33.450 に答える
0

これは宣言になります:

[DllImport("shell32.dll")]
static extern int SHSetFolderPath(int csidl, IntPtr hToken, uint dwFlags, StringBuilder path)

コンストラクターに 260 の最大パスを渡す StringBuilder を作成する必要があります (これは Vista/XP に当てはまります)。これは、設定しようとしているフォルダーの新しいディレクトリを持つ stringbuilder です。新しい場所の StringBuilder にテキストを追加します。ただし、実装の最大の問題は、 csidl パラメーターが Windows で指定された Guid と同じではないことです。これらの値は、実際にはshlobj.hで宣言されている値です。リンクをたどって、渡されるトップの値を確認してください。これを変更しようとしている特定のユーザーへのポインターがない限り、hToken は常に IntPtr.Zero である必要があります。IntPtr.Zero は現在のユーザーを使用します。dwFlags は常に 0 に設定する必要があります。

于 2009-01-27T17:30:37.270 に答える