我是不是需要一个包装类来从 user32.dll 中 p/invoke'ing 一些函数

Posted

技术标签:

【中文标题】我是不是需要一个包装类来从 user32.dll 中 p/invoke\'ing 一些函数【英文标题】:Do I need a wrapper class for p/invoke'ing a few functions from user32.dll我是否需要一个包装类来从 user32.dll 中 p/invoke'ing 一些函数 【发布时间】:2016-07-09 20:50:16 【问题描述】:

所以我正在开发一个 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 pii)

起初我将它们与所有主要表单代码一起作为public partial class MainForm 的一部分放在文件中,这一切都有效。然后,当我在 Visual Studio Community 2015 中运行代码分析时,它抱怨说“因为它们是 P/Invoke 方法,它们应该在名为 NativeMethods、SafeNativeMethods 或 UnsafeNativeMethods 的类中定义。

因此,作为一名优秀的程序员,我总是听从他的 IDE 的一时兴起,我立即制作了一个新的类文件并遇到了第一个问题。

包含这些函数的类会是不安全的(它也是非托管的)吗?哪个名字 我应该使用并且应该使用[DebuggerNonUserCode] 属性将类声明为internal static

当我阅读更多内容试图弄清楚这一点时,我不断遇到为代码制作包装类的参考资料,因此我开始研究它。这产生了大量关于 c++ 或 c 的安全性和包装器、原型以及大量其他似乎没有帮助的信息,让我完全迷失了方向。

所以我想我想知道两件事。第一,我需要(或 这样做是否是最佳实践)制作一个包装类来使用这些 方法,如果是这样,我将如何去做?

第二,如果我创建类 Unsafe/SafeNativeMethods 我应该调用它吗 安全还是不安全?所有方法都应该公开吗?还是应该 将方法声明为私有并编写一些 getter/setter,例如:

public IntPtr getGetForegroundWindow()

    return GetForegroundWindow()

public setSendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr, lParam)

    SendMessage(hWnd, Msg, wParam, lParam);

或者我是否需要使用委托或其他东西来代替 setter 和 getter?

很抱歉这个问题有点脑残。每次我认为我找到了答案时,我都会遇到更多问题,所有关于安全/不安全/安全的讨论都让我担心。我不介意谷歌搜索和阅读主题,但只是为了弄清楚要阅读什么的阅读清单越来越大,所以我想我会停下来问这里,看看我是否问对了问题。提前致谢。

【问题讨论】:

【参考方案1】:

我会创建一个静态类。

namespace NativeMethods

    public static class User32
    
        [DllImport("user32.dll")]
        public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, ref RECT lParam);
    

仅在执行某些操作时创建包装器,例如保持参数转换/检查状态。


要包装 pInvokes 的情况

包装 PInvoke 方法的一个例子可能是本地方法分配内存并返回句柄。在这种情况下,您需要创建一个跟踪句柄的包装器。它应该实现IDisposable 来释放非托管资源。

for (pseudo) 示例:(你应该检查 dispose 模式)

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);
        

【讨论】:

应该和MainForm在同一个命名空间吗? 通常你想在多个项目中重用这些类,所以我会把它们放在一个单独的库中。 就我而言,它们永远不会被重复使用,但我想确保我遵循最佳实践。澄清一下,您是在建议我创建一个类库的第二个项目,然后在原始项目中引用这个新的类库? 是的,这样您就可以将该库重用于其他项目。

以上是关于我是不是需要一个包装类来从 user32.dll 中 p/invoke'ing 一些函数的主要内容,如果未能解决你的问题,请参考以下文章

如何从 PHP 进行 Win32 API 调用?

User32.dll:未找到 RegisterHotkey

User32.dll 鼠标事件

使用 user32.dll 获取特定窗口的句柄

我可以从系统服务中检索 user32.dll getlastinputtime

Teamviewer 停止工作 GetWindowText (User32.dll) 功能