我使用以下代码从C#调用winapi函数。
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr PathFindFileName(string p);
IntPtr pStr = PathFindFileName("Test");
string str = Marshal.PtrToStringAuto(pStr)
我想知道如何区分需要在完成后释放的对象和不需要释放的对象。
例如:在上面的代码中,我是否需要发布pStr?
垃圾收集器是自动完成的吗?
如果我确实需要发布,它是如何完成的?
谢谢, 迈克尔。
答案 0 :(得分:4)
了解如何处理内存的唯一方法是阅读文档。
在这种情况下,文档有点弱,并没有明确说明发生了什么。发生了什么是函数返回的指针指向您提供的缓冲区中的某个点。这意味着在函数返回后,传递给函数的缓冲区必须有效,以便能够从中读取。当您使用string
参数的自动编组编写p / invoke时,传递给非托管函数的缓冲区将超出您的控制范围。您的代码可能在某些时候似乎有效,但它肯定会被破坏,并且可能会因为相当讨厌的运行时错误而失败。
您需要手动编组字符串,以便控制所提供缓冲区的生命周期。
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr PathFindFileName(IntPtr pPath);
....
string path = ...;
IntPtr pPath = Marshal.StringToHGlobalUni(path);
try
{
IntPtr pFileName = PathFindFileName(pPath);
string fileName = Marshal.PtrToStringUni(pFileName);
}
finally
{
Marshal.FreeHGlobal(pPath);
}
这就是你提出的问题的答案。但是,解决问题的最佳方法是避免互操作并使用内置的.net库功能进行路径操作。
答案 1 :(得分:2)
这个特殊的WinAPI功能非常棘手。返回指针指向输入缓冲区。这意味着它没有分配,不应该由你发布。此外,如果代码有效,您很幸运,因为您需要输入缓冲区才能生效,直到PtrToStringAuto
将其内容复制到托管字符串。
你真的需要调用这个特定的WinAPI函数吗?您可以在System.IO.Path
.NET Framework库中找到相同的函数。
https://msdn.microsoft.com/en-us/library/system.io.path.aspx
您可能需要Path.GetFileName
https://msdn.microsoft.com/en-us/library/system.io.path.getfilename.aspx