Click here to Skip to main content
15,793,546 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi all,

I have a 32bit VB6 DLL which has two functions. I want to access those functions from my 32bit version of python. First issue is that I can't seem to see the functions when I load the dll:

from ctypes import *
dll = WinDLL("ARB_Library.dll")

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python_32bit\lib\ctypes\", line 387, in __getattr__
    func = self.__getitem__(name)
  File "C:\Python_32bit\lib\ctypes\", line 392, in __getitem__
    func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'ARB_Value' not found

I know that the function is in the DLL by inspecting OLE/COM Object Viewer:

// Generated .IDL file (by the OLE/COM Object Viewer)
// typelib filename: ARB_Library.dll

  custom(50867B00-BB69-11D0-A8FF-00A0C9110059, 8964)
library ARB_Library
    // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    // Forward declare all types defined in this typelib
    interface _clsARB_Library;
    interface _clsARB_Library : IDispatch {
        [id(0x68030001), propget]
        HRESULT ARB_Value(
                        [in, out] double* PdblListedP, 
                        [in, out] double* PdblNewP, 
                        [in, out] DATE* PdateValDate, 
                        [in, out] DATE* PdatePastDate, 
                        [in, out] short* PintTripNumber, 
                        [in, out] VARIANT_BOOL* PbolPayment, 
                        [out, retval] double* );

I understand that you can access the function by using the ordinal and so I tried the following:

func = dll[0x68030001]
<_FuncPtr object at 0x035129C8>

This gives a pointer to *a* function (the function?) ... so I am hoping that I am on the right path. But I am unable to see anything in this function to confirm whether it is the ARB_Value function that I am after.

The next step is to then try to call the function, but despite using various combinations of inputs including pointers (only one example given below), I cannot get anything back other than "nan". So I suspect that the function is not the one that I am after.

prototype = WINFUNCTYPE(
    c_double,  # return type; rest are parameters 1 to ...
    POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_short), POINTER(VARIANT_BOOL))

paramflags = (1, "PdblListedP", 0), (1, "PdblNewP", 0), (1, "PdateValDate", 0), (1, "PdatePastDate", 0), (1, "PintTripNumber", 0), (1, "PbolPayment", 0))

# map the call to the function in the dll to a python name

dll_api = prototype((1745027073, dll), paramflags)

PdblListedP       = c_double(28)
PdblNewP          = c_double(27.02)
PdateValDate      = c_double(41052)
PdatePastDate     = c_double(42147)
PintTripNumber    = c_short(1)
PbolPayment       = VARIANT_BOOL(0)

answer = dll_api(byref(PdblListedP), byref(PdblNewP), byref(PdateValDate), byref(PdatePastDate), byref(PintTripNumber), byref(PbolPayment))

Any suggestions as to how I can access the ARB_value function in this DLL, and then how to pass the correct variables to it so that it returns a value?


What I have tried:

Using comtypes to generate the code for me, but this did not help in accessing the function.
Updated 26-Sep-22 6:04am
Maciej Los 8-Jun-21 3:28am    
Does "ARB_Library.dll" is registered on system?
I'd suggest to read this: ctypes — A foreign function library for Python — Python 3.9.5 documentation[^]
MrG_ 8-Jun-21 3:38am    
Yep, registered as a 32bit DLL via SysWOW64\regsvr32.exe.

I've spent a few days reading about ctypes including that link but just cannot get it right. The function just returns nan and so it is not clear where I am going wrong. Or that I even have the right function to start with.
Maciej Los 8-Jun-21 3:52am    
MrG_ 8-Jun-21 10:33am    
Have tried that too. Worked through all of the examples on that page but couldn't come right.

And using the comtypes approach I tried
CreateObject(clsARB_Library._reg_clsid_, interface=_clsARB_Library)
which gives me a pointer to the two functions, but still cannot see to get the arguments right.

1 solution

For what it is worth, I managed to resolve this. Extracts of the relevant code:

from comtypes import c_double, c_short, client
from ctypes.wintypes import VARIANT_BOOL
from comtypes.automation import _midlSAFEARRAY

my_dll = client.GetModule('C:/foldername/ARB_Library.dll')
dll_object = client.CreateObject(my_dll.clsARB_Library)   # the functions are in this class

PdblPrice      = c_double(28)
PdateDate      = c_double(41052)
PintFlag       = c_short(1)
PbolSomething  = VARIANT_BOOL(0)
t              = _midlSAFEARRAY(c_double)
PdblScale      = t.from_param([0, 0.5, 0.5, 0.75, 1.0, 0, 0, 0.5,1, 1])
return_value   = c_double(0)

# call this method with the return_value as an argument

dll_object.__clsARB_Library__com__get_ARB_Value(PdblPrice, PdateDate, PintFlag, 
                  PbolSomething, PdblScale, return_value) # this method is what I was missing

print("The value is: ", return_value.value)
Share this answer

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900