【发布时间】: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 的“性质”需要嵌入式系统和这个特定库的安装。
非常感谢
【问题讨论】: