所以我正在开发一个 c# Windows 窗体应用程序,我的部分代码使用 user32.dll 中的一些方法。下面列出了它们。
- public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
- public static extern bool ReleaseCapture();
- public static extern IntPtr GetForegroundWindow();
- public static extern int GetWindowText(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpString, int nMaxCount);
- public static extern uint GetWindowThreadProcessId
- public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii)
起初,我将它们与所有主要表单代码一起放在文件中,作为public partial class MainForm
的一部分,这一切都有效。然后,当我在Visual Studio Community 2015中运行代码分析时,它抱怨说:"因为它们是P/Invoke方法,所以应该在名为NativeMethods,SafeNativeMethods或UnsafeNativeMethods的类中定义。
因此,作为一个优秀的程序员,我总是服从他的IDE的突发奇想,我立即制作一个新的类文件并遇到第一个问题。
包含这些函数的类是否不安全(是否也是非托管的)?哪个名字 我应该使用并且应该使用
[DebuggerNonUserCode]
属性将类声明为internal static
?
当我做更多的阅读试图弄清楚这一点时,我不断遇到为代码制作包装类的引用,所以我开始研究它。这产生了大量关于安全性的东西和 c++ 或 c 的包装器、原型以及大量其他似乎没有帮助的信息,让我自己完全迷失了方向。
所以我想我想知道的是两件事。 第一,我需要(或 这样做是最好的做法)制作一个包装类来使用这些 方法,如果是这样,我将如何去做?
2nd,如果我使类不安全/安全本机方法,我应该调用它 安全还是不安全?所有方法都应该公开吗?还是应该做 将方法声明为私有并编写一些getter/setter,例如:
public IntPtr getGetForegroundWindow()
{
return GetForegroundWindow()
}
或
public setSendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr, lParam)
{
SendMessage(hWnd, Msg, wParam, lParam);
}
还是我需要使用委托或其他东西来代替二传手和获取者?
很抱歉这个问题有点脑残。每次我认为我找到了答案时,我最终都会提出更多的问题,所有关于安全/不安全/安全的讨论都让我担心。我不介意谷歌搜索和阅读主题,但只是为了弄清楚要阅读什么的阅读清单变得越来越大,所以我想我会停下来问这里,看看我是否问了正确的问题。提前谢谢。
我会创建一个静态类。
namespace NativeMethods
{
public static class User32
{
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, ref RECT lParam);
}
}
仅在执行某些操作时创建包装器,例如保持参数转换/检查状态。
要包装 pInvoke 的情况
包装 PInvoke 方法的一个示例可能是本机方法分配内存并返回句柄。在这种情况下,您需要创建一个跟踪句柄的包装器。它应实现释放非托管资源的IDisposable
。
对于(伪)示例:(您应该检查释放模式)
public class MyWrapper : IDisposable
{
[DllImport("MyLibrary.dll")]
private static extern IntPtr DoAllocSomeMemory(int size);
[DllImport("MyLibrary.dll")]
private static extern void ReleaseMe(IntPtr handle);
private IntPtr _handle;
public MyWrapper()
{
_handle = DoAllocSomeMemory(8000);
}
public void Dispose()
{
ReleaseMe(_handle);
}
}