Python Load windows library C# conversion

453 Views Asked by At

I have a C# application that call a windows dll (fbwflib.dll). From this dll is called a function (FbwfIsFilterEnabled) that require two parameter passed by reference.

In C# my code is:

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

Now I need to convert this code in Python code.

I have tried:

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

but I have an error: ctypes.ArgumentError: argument 1: :wrong type

I have tried other parametrizations but without any good result.

What is the correct way to load a library with parameters by reference?

Other function without parameter work well:

@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()

that work fine without any error.

A small description of the function that give me some trouble is here: https://www.pinvoke.net/default.aspx/fbwflib.FbwfIsFilterEnabled

EDIT:

changing with ctypes.pointer as suggested from Luke (thanks) now I had a different error:

Procedure called with not enough arguments (8 bytes missing) or wrong calling convention

referred to line:

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

changing the line as:

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

I receive the error: Type error: must be ctypes type

that let me know that byref calling was the right way probably.

changing considering bool type as done on my c# 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)

I receive the same error: Procedure called with not enough arguments (8 bytes missing) or wrong calling convention

I think that the solution is near but it seams that there is some detail missing

SOLUTION:

The solution finally come starting from

ctypes.windll.LoadLibrary

as suggested from Luke. I have removed argtypes and restype for now and after receiving c_long value that can be 0 or 1 a have obtained boolean condition.

The simple (I can say this now) code is:

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

I hope that it can be usefull for others in order to not loose so many time like me around the solution that is near the initial code but that require hours to be fixed also because of the "nature" of this dll that required an embedded system and the installation of this particular library.

Many thanks

1

There are 1 best solutions below

5
On

Try replacing the line

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

with

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

I also note that the function is defined to return a UIntPtr, so you might also want to try replacing the line

    dllObject.FbwfIsFilterEnabled.restype = None

with

    dllObject.FbwfIsFilterEnabled.restype = c_void_p

However, I don't have a copy of that DLL so I can't test that this change works.