我对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
谢谢!
答案 0 :(得分: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\\");
答案 1 :(得分:2)
尝试使用此代码。很抱歉这个长度,但是所有这些都需要正确地启动这个特定的功能。它是一个简单的控制台应用程序,包括函数的定义和SHGetKnownFolderPath的示例用法。
我继续前进,包括KNOWN_FOLDER_FLAG的定义以及文件夹ID的一些定义。所有文件夹Id实际上只是GUID。可以在%ProgramFiles%\ Windows SDK \ v6.0A \ Include \ KnownFolders.h中找到所有可能的ID,并以与我在示例中添加的方式相同的方式添加。
我包含了几个包装函数,它们隐藏了调用特定函数的所有邪恶的marashal'ing细节。
如果您有任何特定的文件夹ID或说明,请添加评论,我会更新示例。
编辑纠正了SHSetKnownFolderPath编组中的错误。我没有向String值添加MarshalAs标记,它默认为ANSI字符串。 API需要unicode。 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
答案 2 :(得分:0)
这将是宣言:
[DllImport("shell32.dll")]
static extern int SHSetFolderPath(int csidl, IntPtr hToken, uint dwFlags, StringBuilder path)
你需要创建一个StringBuilder,将最大路径260传递给构造函数(对于Vista / XP来说也是如此。)这是一个stringbuilder,它将为你正在尝试的文件夹提供新目录。设置,所以将您的文本附加到StringBuilder中以获取新位置。但是,实现的最大问题是csidl参数与Windows中指定的Guid不同。这些值实际上是shlobj.h中声明的值。按照链接查看最常传入的值.hToken应始终为IntPtr.Zero,除非您有指向特定用户的指针,而您正尝试更改此值。 IntPtr.Zero将使用当前用户。 dwFlags应始终设置为0.