从 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 库功能进行路径操作。
我正在使用以下代码从 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 库功能进行路径操作。