2

I am trying to use a DLL file from python with ctypes but get stuck in a problem of

OSError: exception: access violation reading 0x00000000

The code is:

import ctypes as ctypes
NS = ctypes.oledll.LoadLibrary ("D:\\XXX\\nsga2.dll")
NS.Initialise(360,2,2,5,0,5,2)
NS.Randomise()

In DLL file, the function Randomise() is defined as follow:

ADDAPI  void
ADDCALL Randomise(){
randomize();
initialize_pop (parent_pop);
ngen = 0;}

And the function randomize() is defined as:

 # include "rand.h"
   double seed;
   double oldrand[55];
   int jrand;
   void randomize()
   {
       int j1;
       for(j1=0; j1<=54; j1++)
       {
          oldrand[j1] = 0.0;
       }
       jrand=0;
       warmup_random (seed);
       return;
   }

My question is why I get this problem and how can I fix it?

Thank you all!

EDIT 1 as asked

The function Initialise() is defined as:

ADDAPI  void 
ADDCALL Initialise(int populationSize, int objectives, int constraints,  
int realvars, int binvars, int intvars, int nfix)
{
    popsize = populationSize;
    nobj = objectives;
    ncon = constraints;
    nreal = realvars;
    nint = intvars;
    nbin = binvars;
    nfixed = nfix;

    nbits = (int *)malloc(binvars*sizeof(int));
    for (int i = 0 ; i <binvars  ; i++)
        {
            nbits[i]=24 ;
        } 

    nints = (int *)malloc(nint*sizeof(int));
    bints = (int *)malloc(nint*sizeof(int));    

    for (int i = 0 ; i <nfixed/(2*nswitch+1); i++) 
        {
                bints[i*(2*nswitch+1)]=0; 
                nints[i*(2*nswitch+1)]=1; 
                //nints[i*(2*nswitch+1)]=2;

                 for (int j =(2*nswitch+1)*i+1 ; j<(2*nswitch+1)*(i+1); i++) 

                 {
                    bints[j]=0; 
                    nints[j]=TimeLength; 
                    //nints[j]=25;
                }
        }

    min_realvar = (double *)malloc(nreal*sizeof(double));
    max_realvar = (double *)malloc(nreal*sizeof(double));

    intvar = NULL;
    min_binvar = NULL;
    max_binvar = NULL;

    parent_pop = (population *)malloc(sizeof(population));
    child_pop = (population *)malloc(sizeof(population));
    mixed_pop = (population *)malloc(sizeof(population));

     allocate_memory_pop (parent_pop, popsize);
     allocate_memory_pop (child_pop, popsize);
     allocate_memory_pop (mixed_pop, 2*popsize);

     seed = 0.232; // for random functions

     bitlength = 0;
     pcross_bin = 0;
     pcross_int = 0;
     pmut_bin = 0 ;
     pmut_int = 0;
     eta_c = 50 ; // distribution index for crossover
     eta_m = 100 ; // distrubution index for mutations
     nbits = 0 ;
     nints = 0;

     fitness_func = NULL;
 }
ZZG
  • 31
  • 1
  • 4
  • Which function throws the error? Please also post *Initialise* – CristiFati Jan 25 '19 at 08:37
  • The function throws the error is NS.Randomise() where I try to call Ranmosie() function in the DLL. – ZZG Jan 25 '19 at 10:16
  • Initialise is also posted above – ZZG Jan 25 '19 at 10:23
  • That's ***InitialiseRandomiseWithFile***. But anyway, the problem became clear, it's *argtypes* (and *restype*) definitions for the imported functions. *Initialise* is the function that fails. It's the same problem as https://stackoverflow.com/questions/52268294/python-ctypes-cdll-loadlibrary-instantiate-an-object-execute-its-method-priva/52272969#52272969, or https://stackoverflow.com/questions/53182796/python-ctypes-issue-on-different-oses/53185316#53185316. I will mark this question as a dup of the one of others. – CristiFati Jan 25 '19 at 10:33
  • Possible duplicate of [python ctypes issue on different OSes](https://stackoverflow.com/questions/53182796/python-ctypes-issue-on-different-oses) – CristiFati Jan 25 '19 at 10:48
  • `oledll` is used for functions that return `HRESULT`. You probably need `cdll`, at least. – Mark Tolonen Jan 26 '19 at 02:22
  • Hi Cristi, thank you for your reply. Sadly I found that it is not _Initialise_ that fails because I tried to get the number of population with another function in DLL called _GetPopulationSize_ and I got exactly the number of population(in this case, 360 as the first parameter for _Initalise_). And I have also tried to clarify argtypes and restype as you recommended, but I still get the same error... – ZZG Jan 28 '19 at 04:16

1 Answers1

0

The implementation of Initialise isn't important, but the declaration is, including what ADDAPI and ADDCALL are defined as. Assuming ADDAPI is something like __declspec(dllexport) and ADDCALL is __cdecl (or empty), then use:

import ctypes
NS = ctypes.CDLL("D:\\XXX\\nsga2.dll")
NS.Initialise(360,2,2,5,0,5,2)
NS.Randomise()

Use ctypes.WinDLL if ADDCALL is __stdcall.

Ideally, define argtypes and restype, but integer parameters are the default anyway, e.g.:

NS.Initialise.argtypes = ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int
NS.Initialise.restype = None
NS.Randomise.argtypes = ()
NS.Randomise.restype = None
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • Hi Mark, thanks for your reply. I think for this case, it should use _ctypes.WinDLL_ . And I have also added those types clarifications as you mentioned above, but sadly I still get the same error when I call _Randomise()_... – ZZG Jan 28 '19 at 06:50
  • @ZZG With only integer parameters, the only thing that can really mess up is the calling convention. Are you using 32-bit Python? WinDLL/CDLL don't make a difference on 64-bit, but on 32-bit you must use the right one or crashes like you are seeing can occur. Did you try CDLL? What do ADDCALL and ADDAPI resolve to? – Mark Tolonen Jan 28 '19 at 08:17