У меня есть приложение С#, которое вызывает dll windows (fbwflib.dll). Из этой DLL вызывается функция (FbwfIsFilterEnabled), для которой требуется два параметра, переданных по ссылке.
В С# мой код:
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
РЕДАКТИРОВАТЬ:
меняя с помощью ctypes.pointer, как предложил Luke (спасибо), теперь у меня была другая ошибка:
Вызывается процедура с недостаточным количеством аргументов (отсутствует 8 байтов) или неправильным соглашением о вызове
относится к строке:
dllObject.FbwfIsFilterEnabled(ctypes.byref(current, 0), ctypes.byref(next, 0))
меняя линию следующим образом:
dllObject.FbwfIsFilterEnabled(ctypes.POINTER(current), ctypes.POINTER(next))
Я получаю сообщение об ошибке: Ошибка типа: должен быть тип ctypes
что дайте мне знать, что, по-видимому, правильное обращение было правильным.
изменяя рассматривая тип bool как сделано на моем С# code:
@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 на данный момент и после получения значения c_long, которое может быть 0 или 1 a, получили логическое условие.
Простой (я могу сказать это сейчас) код:
@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)))
Я надеюсь, что это может быть полезно для других, чтобы не потерять так много времени, как я, вокруг решения, которое находится рядом с исходным кодом, но для этого требуются часы для исправления также из-за "природы" этой библиотеки, требующей встроенной системы и установка этой конкретной библиотеки.
Большое спасибо
Попробуйте заменить линию
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, поэтому я не могу проверить, что это изменение работает.
UIntPtr
функция возвращает что-то (UIntPtr
по ссылке). Однако вы установили егоrestype
наNone
. Поможет ли вам изменить тип возврата в соответствии с моим отредактированным вопросом?