Convert managed C++ DLL project to unmanaged C++ - python

I got VS2008 project written in managed C++ that produces a utility DLL.
CLR Support: Common Language Runtime Support, Old Syntax (/clr:oldSyntax)
The resulting DLL exports a bunch of functions and complex types based on managed types like System::String, System::Byte and so on.
The DLL must be consumed (linked to) by a Python application. It seems that Python cannot use managed types/classes/structs.
Is it possible to convert the project so that it produces an "unmanaged" interface. That is, instead of working with System::String, I should somehow convert the types to std::string so that the Python app can work with?
The only "good news" is that the Python app that tries to consume the DLL needs to access only ONE exported function.
Additional question: if I only change the signature of that very function so that all the types of in/out parameters are unmanaged C++ would that work? The other exported functions will still work through managed types, but they won't be called at all.

Related

Boost.Python: Converters unavailable from standalone python script

The title may not be as explicit as I wish it would be but here is what I am trying to achieve:
Using Boost.Python, I expose a set of class/functions to Python in the typical BOOST_PYTHON_MODULE(MyPythonModule) macro from C++ that produces MyPythonModule.pyd after compilation. I can now invoke a python script from C++ and play around with MyPythonModule without any issue (eg. create objects, call methods and use my registered converters). FYI: the converter I'm refering to is a numpy.ndarray to cv::Mat converter.
This works fine, but when I try to write a standalone Python script that uses MyPythonModule, my converters are not available. I tried to expose the C++ method that performs the converter registration to Python without any luck.
If my explanation isn't clear enough, don't hesitate to ask questions in the comments.
Thanks a lot for your help / suggestions.
I found the problem... The prototype of my C++ function was taking cv::Mat& as argument and the converter was registered for cv::Mat without reference.
That was silly.

Python+Numpy modules in free pascal

Developing a module (.pyd) for Python in free pascal is fairly easy, see Developing Python Modules with Pascal. But if I want to interface with numpy, this is not that easy.
When using C to interface with numpy, you have to add #include <numpy/arrayobject.h> to the code, and also call import_array(); in the initialization function.
Is there a way to interface with numpy in pascal?
EDIT1
As mentioned in the comments under #wilberforce answer, the import_array function which is defined in the header files just imports multiarray.pyd module into the current interpreter and does some checking. It is easily translated into pascal and it works.
The numpy C-API functions are not present initially in pythonXX.dll, so they can't be linked statically. Static or dynamic linking with multiarray.pyd is not working for me.
So the updated question is: Is there a way to access the C-API functions embedded in multiarray.pyd from code which is not C?
Treat the numpy library like any other C library from Pascal's point of view - you need to include the header and declare import_array as an external cdecl function.
This guide covers the details.
You already need to have done some of this in order to have written a Python extension module so your Pascal code can use the Python API functions to interact with Python objects. You can see this in the cdecl; external PythonLib; modifiers in the example you link to. It's possible this wasn't clear while you were doing it.

Can one author a library API – one accessible outside Python – using Cython?

I know Cython's purpose is to create Python extensions modules, but can the compiled libraries made with Cython be loaded by non-python programs? If not, why?
I doubt that you can load them directly on a non-python program; looking at the C code generated by the simplest Cython script it's apparent that you need all the Python scaffolding to make it work. That said, you can do it indirectly for example from C++. In C++ I use boost.python to embed the Python interpreter and load some of my modules and scripts. This may seem convoluted, but allows you to quickly use whatever extensions you already have written in Python from C++, provided that you build the appropriate gluing code (see the boost.python wiki).
The disadvantage of this approach is that you are really loading a full Python interpreter just to be able to use some extension. This wasn't an issue for me since I already had the python extension and was embedding Python in my application to provide basic scripting ability, but I would not use this approach to write new libraries.
There are two mechanisms by which you can make cdef’ed Cython structures available externally:
Use a cdef public declaration – and/or also
Use the api keyword.
Here’s one of the examples of both mechanisms, from the aforelinked pages:
cdef public struct Vehicle:
int speed
float power
cdef api void activate(Vehicle *v):
if v.speed >= 88 and v.power >= 1.21:
print "Time travel achieved"
Each of these methods will instruct the Cython compiler to generate a header (“.h”) file that you can then integrate with your orthogonal C/C++ project.
A cdef public declaration yields a file named modulename.h; using the structures in this file will require you to link with the compiled Cython extension module.
An api declaration (which may be used simultaneously with cdef public, if you so desire) yields a modulename_api.h file; code consuming an api-based header will not need to link to the extension module – but it will need to call the cdef’d function import_modulename() before any of the API code can be used (a tactic the Cython-inclined users of NumPy will find familiar).
In my personal experience, it takes little effort to expose and subsequently employ encythoned structures as an external API in this fashion, provided that the struct layouts dovetail well with the consuming code, and that you’re willing to contend with manually managing the GIL in your C/C++ code in order to make things work.

Is wrapping C++ library with ctypes a bad idea?

I read through the following two threads on wrapping C library and C++ library, I am not sure I get it yet. The C++ library I am working with does use class and template, but not in any over-sophisticated way. What are issues or caveats of wrapping it with ctypes (besides the point that you can do so in pure python etc)?
PyCXX , Cython and boost::python are three other choices people mentioned, is there any consensus which one is more suitable for C++?
Thanks
Oliver
In defence of boost::python, given Alexander's answer on ctypes:
Boost python provides a very "c++" interface between c++ and python code - even doing things like allowed python subclasses of c++ classes to override virtual methods is relatively straightforward. Here's a potted list of good features:
Allow virtual methods of C++ classes to be overridden by python subclasses.
Bridge between std::vector<>, std::map<> instances and python lists and dictionaries (using vector_indexing_suite and map_indexing_suite)
Automatic sharing of reference counts in smart pointers (boost::shared_ptr, etc) with python reference counts (and you can extend this to any smart pointer).
Fine grained control of ownership when passing arguments and returning values from functions.
Basically, if you have a design where you want to expose a c++ interface in a way faithful to the language, then boost::python is probably the best way to do it.
The only downsides are increased compile time (boost::python makes extensive use of templates), and sometimes opaque error messages if you don't get things quite right.
For C++ a library to be accessible from Python it must use C export names, which basically means that a function named foo will be accessible from ctypes as foo.
This can be achieved only by enclosing the public interface with export C {}, which in turn disallows function overloading and templates therein (only the public interface of the library to be wrapped is relevant, the inner workings are not and may use any C++ features they like).
Reason for this is that C++ compilers use a mechanism called name mangling to generate unique names for overloaded or templated symbols. While ctypes would still find a function provided you knew its mangled name, the mangling scheme depends on the compiler/linker being used and is nothing you can rely on. In short: do not use ctypes to wrap libraries that use C++ features in their public interface.
Cython takes a different approach. It aids you at building a C extension module that does the interfacing with the original library. Therefore, linking to the C++ library is done by the regular C++ linkage mechanism, thus avoiding the aforementioned problem. The trouble with Cython is that C extension libraries need to to be recompiled for every platform, but anyway, this applies to the C++ library to be wrapped as well.
Personally, I'd say that in most cases the time to fire up Cython is a time that is well-spent and will eventually pay off in comparison to ctypes (with an exception for really simple Cish interfaces).
I don't have any experience with boost.python, so I can't comment on it (however, I don't have the impression that it is very popular either).

Running unexported .dll functions with python

This may seem like a weird question, but I would like to know how I can run a function in a .dll from a memory 'signature'. I don't understand much about how it actually works, but I needed it badly. Its a way of running unexported functions from within a .dll, if you know the memory signature and adress of it.
For example, I have these:
respawn_f "_ZN9CCSPlayer12RoundRespawnEv"
respawn_sig "568BF18B06FF90B80400008B86E80D00"
respawn_mask "xxxxx?xxx??xxxx?"
And using some pretty nifty C++ code you can use this to run functions from within a .dll.
Here is a well explained article on it:
http://wiki.alliedmods.net/Signature_Scanning
So, is it possible using Ctypes or any other way to do this inside python?
If you can already run them using C++ then you can try using SWIG to generate python wrappers for the C++ code you've written making it callable from python.
http://www.swig.org/
Some caveats that I've found using SWIG:
Swig looks up types based on a string value. For example
an integer type in Python (int) will look to make sure
that the cpp type is "int" otherwise swig will complain
about type mismatches. There is no automatic conversion.
Swig copies source code verbatim therefore even objects in the same namespace
will need to be fully qualified so that the cxx file will compile properly.
Hope that helps.
You said you were trying to call a function that was not exported; as far as I know, that's not possible from Python. However, your problem seems to be merely that the name is mangled.
You can invoke an arbitrary export using ctypes. Since the name is mangled, and isn't a valid Python identifier, you can use getattr().
Another approach if you have the right information is to find the export by ordinal, which you'd have to do if there was no name exported at all. One way to get the ordinal would be using dumpbin.exe, included in many Windows compiled languages. It's actually a front-end to the linker, so if you have the MS LinK.exe, you can also use that with appropriate commandline switches.
To get the function reference (which is a "function-pointer" object bound to the address of it), you can use something like:
import ctypes
func = getattr(ctypes.windll.msvcrt, "##myfunc")
retval = func(None)
Naturally, you'd replace the 'msvcrt' with the dll you specifically want to call.
What I don't show here is how to unmangle the name to derive the calling signature, and thus the arguments necessary. Doing that would require a demangler, and those are very specific to the brand AND VERSION of C++ compiler used to create the DLL.
There is a certain amount of error checking if the function is stdcall, so you can sometimes fiddle with things till you get them right. But if the function is cdecl, then there's no way to automatically check. Likewise you have to remember to include the extra this parameter if appropriate.

Categories