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

Which objects do I need to explicitly release when calling Windows API functions from C#?

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

或者垃圾收集器会自动完成吗?

如果我确实需要释放,它是如何完成的?

谢谢, 迈克尔.

这个特定的 WinAPI 函数是一个棘手的函数。返回指针指向输入缓冲区。这意味着它没有被分配,不应该被你释放。此外,如果代码有效,你就很幸运了,因为你需要输入缓冲区一直存在,直到 PtrToStringAuto 将其内容复制到托管字符串。

您真的需要调用这个特定的 WinAPI 函数吗?您可以在 .NET Framework 库的 System.IO.Path class 中找到相同的函数。

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

了解如何为互操作处理内存的唯一方法是阅读文档。

在这种情况下,文档有点薄弱,没有明确说明发生了什么。发生的事情是函数 returns 指向您提供的缓冲区中的某个点的指针。这意味着您传递给函数的缓冲区必须在函数 returns 之后有效,您才能从中读取。当您使用 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 库功能进行路径操作。