Ctypes can not load dll in which some struct has constructor or destructor

I wrote a c file like this:

/* test.c */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#include <stdio.h>
#include <stdlib.h>

bool bEnable = false;

struct GlobalData {
    GlobalData() {
        bEnable = true;
        printf("Enter utest.\n");
    }
    ~GlobalData() {
        bEnable = false;
        printf("Exist utest.\n");
    }
};

struct GlobalData g;

int test_func()
{
    printf("test.\n");
    return 0;
}

#ifdef __cplusplus
}
#endif /* __cplusplus */

and compile it by g++ on windows like this:

g++ -shared -o test.dll test.c

then, I wrote a python script like this:

import ctypes
test_dll = ctypes.cdll.LoadLibrary('./test.dll')
test_dll.test_func()

Finally, I got errors:

D:/WorkSpace/test-ctypes-cplusplus $ python test.py
Traceback (most recent call last):
  File "xxxxx\test.py", line 2, in <module>
    test_dll = ctypes.cdll.LoadLibrary('./test.dll')
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "xxxxx\Python\Python312\Lib\ctypes\__init__.py", line 460, in LoadLibrary
    return self._dlltype(name)
           ^^^^^^^^^^^^^^^^^^^
  File "xxxxx\Python\Python312\Lib\ctypes\__init__.py", line 379, in __init__
    self._handle = _dlopen(self._name, mode)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: Could not find module 'D:\WorkSpace\test-ctypes-cplusplus\test.dll' (or one of its dependencies). Try using the full path with constructor syntax.

And, if I delete the line struct GlobalData g;, it can run successfully, but info in constructor and destructor can not be print.

Has someone know the reason?

the version information:
OS: win11
g++ --version :
g++ (x86_64-win32-seh-rev1, Built by MinGW-Builds project) 13.2.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
python --version :
Python 3.12.4

You are not writing C code, you are writing C++ code.
ctypes allows you to interface to C, but C++ is a lot harder.

Suggest you write C functions as entry points that you call from python’s ctypes.

Alternatively write a python extension, recommend that you use a library to help with this like PyCXX, bind11, etc. Using the Python C API directly is made easier by these libraries.

Hello,

note that you have not defined the true and false variables in your code. You have to do this explicitly.

You may do so by:

#include <stdbool.h>  // used for the 'bEnable` variable below
 
#define false 0
#define true 1

If your variables are not defined, and you attempt to use them, an error will be generated. You also have to include the stdbool.h library otherwise you can’t make use of the bool keyword.

Note that a struct in C is a grouping of items potentially each being a different data type. A print statement is NOT allowed since it is not itself a data type. What you can do is something like this:

struct GlobalData{
    bool bEnable;
    char msg[14];  // Increase value if message requires more characters
};

// Create two variables of type 'GlobalData' and initialize their variables.
struct GlobalData g1 = {.bEnable = false, .msg = "Exit utest.\n"};
struct GlobalData g2 = {.bEnable = true, .msg = "Enter utest.\n"};

Conversely, create ONLY one variable and change its values.

If you don’t already have a C editor compiler installed, you can use the one online here to test your C code.:

See if that helps.

It looks like OP is compiling this code as C++, not C (note that they’re invoking g++ instead gcc, not to mention the fact that they define a class with a constructor and destructor). What you said about needing to define true and false applies to old editions of C, but not C++ or modern C (C23+).

In C++, true and false are keywords, not variables or macros. In fact, defining a macro named true or false like you suggest would be UB in C++ (16.4.5.3.3/2).

Even if OP switches to C, they still shouldn’t need to worry about defining true or false, since the version of GCC they’re using (13.2.0) supports C23 bool constants.

To be clear, in C++, struct defines a class. There’s nothing syntactically wrong with the OP’s code (the print statements are inside member functions, which is a-ok). Though using printf instead of std::print or I/O streams is a bit odd in C++.

1 Like