从C#调用Windows API函数时,我需要显式释放哪些对象?

时间:2015-02-05 15:01:37

标签: c# winapi pointers marshalling

我使用以下代码从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?

垃圾收集器是自动完成的吗?

如果我确实需要发布,它是如何完成的?

谢谢, 迈克尔。

2 个答案:

答案 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