【问题标题】:Python Load windows library C# conversionPython 加载 windows 库 C# 转换
【发布时间】:2018-09-20 11:49:57
【问题描述】:

我有一个调用 Windows dll (fbwflib.dll) 的 C# 应用程序。 从这个 dll 中调用了一个函数(FbwfIsFilterEnabled),它需要通过引用传递两个参数。

在 C# 中,我的代码是:

public class FBWF_Utilities
{
    [DllImport("fbwflib.dll", SetLastError = true)]
    static extern UIntPtr FbwfIsFilterEnabled(
       [MarshalAs(UnmanagedType.U1)]
       ref bool currentSession,
       [MarshalAs(UnmanagedType.U1)]
       ref bool nextSession
    );
    [DllImport("fbwflib.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.U4)]
    static extern uint FbwfEnableFilter();

    [DllImport("fbwflib.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.U4)]
    static extern uint FbwfDisableFilter();


    public static bool IsEnabledCurrent()
    {
        bool xCurrent = false;
        bool xNext = false;

        if (IsInstalled())
        {
            try
            {
                FbwfIsFilterEnabled(ref xCurrent, ref xNext);
            }
        catch (Exception ex)
            {
                MessageBox.Show("FBWF IsEnabledCurrent exception:\n\n" + ex.Message);
                return false;
            }
        }

        return xCurrent;
    }

现在我需要将此代码转换为 Python 代码。

我试过了:

@staticmethod
def IsEnabled():
    dllObject = ctypes.cdll.LoadLibrary(r'C:\Windows\System32\fbwflib.dll')
    dllObject.FbwfIsFilterEnabled.argtypes = [ctypes.c_int, ctypes.c_int]
    dllObject.FbwfIsFilterEnabled.restype = None

    current = ctypes.c_int(0)
    next = ctypes.c_int(0)

    dllObject.FbwfIsFilterEnabled(ctypes.byref(current, 0), ctypes.byref(next, 0))
    messagebox.showinfo("", "Current: " + current + "\n" + "Next: " + next)

但我有一个错误: ctypes.ArgumentError:参数 1::错误类型

我尝试了其他参数化,但没有任何好的结果。

通过引用加载带有参数的库的正确方法是什么?

其他不带参数的功能也很好用:

@staticmethod
def EnableFilter():
    dllObject = ctypes.cdll.LoadLibrary(r'C:\Windows\System32\fbwflib.dll')
    dllObject.FbwfEnableFilter()

@staticmethod
def DisableFilter():
    dllObject = ctypes.cdll.LoadLibrary(r'C:\Windows\System32\fbwflib.dll')
    dllObject.FbwfDisableFilter()

工作正常,没有任何错误。

给我一​​些麻烦的功能的小描述在这里: https://www.pinvoke.net/default.aspx/fbwflib.FbwfIsFilterEnabled

编辑:

按照 Luke 的建议更改 ctypes.pointer(谢谢),现在我遇到了不同的错误:

调用的过程没有足够的参数(缺少 8 个字节)或错误的调用约定

参考线:

dllObject.FbwfIsFilterEnabled(ctypes.byref(current, 0), ctypes.byref(next, 0))

将行改为:

dllObject.FbwfIsFilterEnabled(ctypes.POINTER(current), ctypes.POINTER(next))

我收到错误: 类型错误:必须是ctypes类型

这让我知道 byref 调用可能是正确的方式。

在我的 c# 代码中考虑 bool 类型进行更改:

@staticmethod
def IsEnabled():
    dllObject = ctypes.cdll.LoadLibrary(r'C:\Windows\System32\fbwflib.dll')
    dllObject.FbwfIsFilterEnabled.argtypes = [ctypes.POINTER(ctypes.c_bool), ctypes.POINTER(ctypes.c_bool)]
    dllObject.FbwfIsFilterEnabled.restype = None

    current = ctypes.c_bool()
    next = ctypes.c_bool()

    dllObject.FbwfIsFilterEnabled(ctypes.byref(current), ctypes.byref(next))
    messagebox.showinfo("", "Current: " + current + "\n" + "Next: " + next)

我收到同样的错误: 调用的过程没有足够的参数(缺少 8 个字节)或错误的调用约定

我认为解决方案就在附近,但似乎缺少一些细节

解决方案:

解决方案终于从

开始
ctypes.windll.LoadLibrary

正如卢克所建议的那样。 我现在已经删除了 argtypes 和 restype,在收到可以为 0 或 1 的 c_long 值之后,我已经获得了布尔条件。

简单的(我现在可以这么说)代码是:

@staticmethod
def IsEnabled():
    dllObject = ctypes.windll.LoadLibrary(r'C:\Windows\System32\fbwflib.dll')
    c = ctypes.c_int()
    # dllObject.FbwfIsFilterEnabled.argtypes = [ctypes.pointer(ctypes.c_int), ctypes.pointer(ctypes.c_int)]
    # dllObject.FbwfIsFilterEnabled.restype = ctypes.c_void_p

    current = ctypes.c_int()
    next = ctypes.c_int()

    dllObject.FbwfIsFilterEnabled(ctypes.byref(current), ctypes.byref(next))
    messagebox.showinfo("", "Current: " + str(bool(current)) + "\n" + "Next: " + str(bool(next)))

我希望它对其他人有用,以免像我一样在接近初始代码但需要数小时才能修复的解决方案上浪费太多时间,因为这个 dll 的“性质”需要嵌入式系统和这个特定库的安装。

非常感谢

【问题讨论】:

    标签: python ctypes byref


    【解决方案1】:

    换行试试

        dllObject.FbwfIsFilterEnabled.argtypes = [ctypes.c_int, ctypes.c_int]
    

        dllObject.FbwfIsFilterEnabled.argtypes = [POINTER(ctypes.c_int), POINTER(ctypes.c_int)]
    

    我还注意到该函数被定义为返回UIntPtr,因此您可能还想尝试替换该行

        dllObject.FbwfIsFilterEnabled.restype = None
    

        dllObject.FbwfIsFilterEnabled.restype = c_void_p
    

    但是,我没有该 DLL 的副本,因此我无法测试此更改是否有效。

    【讨论】:

    • 非常感谢您的回答。根据您的建议,我已经用其他测试编辑了我的问题。我可以说它不起作用,但我认为解决方案比以前更接近。是的,这个 dll 不是一个常见的 dll,但在嵌入式系统上通常可用,特别是在 Windows 的 POS 版本上。我也对具有通过引用调用的函数的其他 dll 的示例感兴趣,以便测试如何在另一个 dll 上获得正确的调用。在这种情况下,您是否知道可以用作初步测试的 windows dll 上的一些功能?非常感谢
    • 您正在调用的函数返回一些东西(根据链接,UIntPtr)。但是,您已将其 restype 设置为 None。如果您根据我编辑的问题更改返回类型是否有帮助?
    • 错误是一样的:过程调用时没有足够的参数(缺少 8 个字节)或错误的调用约定,即使返回类型为 ctypes.POINTER(ctypes.c_int),错误也是一样的。使用 ctypes.POINTER(c) 其中 c 在上面声明为: c = ctypes.c_int() 错误是 Type error: must be a ctypes type 因为是指向数据的指针而不是数据类型的指针。
    • 我唯一的其他建议是尝试用ctypes.windll.LoadLibrary 替换ctypes.cdll.LoadLibraryThis answer 建议 stdcall 是 P/Invoke 代码的默认调用约定,并且要将 stdcallctypes 一起使用,您必须使用 ctypes.windll 而不是 ctypes.cdll (docs.python.org/3.6/library/…)。
    • 有趣。再次感谢,我会努力的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多