digitalmars.D.learn - D Bindings for C Opaque Pointers
- Kyle Ingraham (59/59) Dec 02 2020 Hello all. I am new to D and loving the experience so far.
- Paul Backus (11/18) Dec 02 2020 You've dropped a level of indirection here. In the C header,
- Kyle Ingraham (8/30) Dec 02 2020 That did it. The binding works without issue now. Thanks a ton
- bachmeier (6/11) Dec 02 2020 Not an answer to your question, but the "idiomatic" approach is
- Kyle Ingraham (6/19) Dec 02 2020 Thanks for the suggestions here. I had no idea that these tools
Hello all. I am new to D and loving the experience so far. I am trying to make use of a C library from Canon that provides a header and a pre-compiled binary containing implementations of declarations found in the header. I used the excellent guide at https://www.gamedev.net/articles/programming/general-and-gameplay-programming/b nding-d-to-c-r3122/ to get started and so far I can initialize the library and embed it within my D application. So far so great! Where I am running into problems is creating D bindings for this function declaration: // EDSDK.h EdsError EDSAPI EdsGetCameraList(EdsCameraListRef* outCameraListRef); // If accepts a pointer to EdsCameraListRef that is declared as: // EDSDKTypes.h typedef struct __EdsObject* EdsBaseRef; typedef EdsBaseRef EdsCameraListRef; // From my reading I learned that EdsCameraListRef is an alias of an alias for an opaque pointer. It allowed the library writers to declare an object for use that the end-user would not have access to the implementation of. These are the D bindings I created: // edsdk.d struct EdsBaseRef; alias EdsBaseRef EdsCameraListRef; alias uint EdsUInt32; extern (System): EdsError EdsGetCameraList(EdsCameraListRef*); EdsError EdsGetChildCount(EdsBaseRef*, EdsUInt32*); EdsUInt32 EdsRelease(EdsBaseRef*); // Calling the functions using the bindings and the following code results in invalid pointer errors however (reported from the library): // camera_list.d import edsdk; class CameraList { private EdsCameraListRef* list; private EdsUInt32 _count = 0; this() { // Returns EDS_ERR_INVALID_POINTER EdsGetCameraList(list); // Returns EDS_ERR_INVALID_HANDLE EdsGetChildCount(list, &_count); } ~this() { EdsRelease(list); } final uint count() { return cast(uint) _count; } } // What did I do wrong in constructing the bindings? If it helps the library provides a function called EdsRelease for cleaning-up allocated objects. Is the management of pointers between D and C the issue? Please forgive me if I've mangled that concept.
Dec 02 2020
On Thursday, 3 December 2020 at 00:30:06 UTC, Kyle Ingraham wrote:// EDSDKTypes.h typedef struct __EdsObject* EdsBaseRef; typedef EdsBaseRef EdsCameraListRef; //[...]// edsdk.d struct EdsBaseRef; alias EdsBaseRef EdsCameraListRef;You've dropped a level of indirection here. In the C header, EdsBaseRef is a pointer, but in your D code, it is an opaque struct. The correct way to translate these C declarations into D is: struct __EdsObject; alias EdsBaseRef = __EdsObject*; alias EdsCameraListRef = EdsBaseRef; Note that unlike C, D does not allow us to refer to an incomplete type without first declaring it.
Dec 02 2020
On Thursday, 3 December 2020 at 00:58:20 UTC, Paul Backus wrote:On Thursday, 3 December 2020 at 00:30:06 UTC, Kyle Ingraham wrote:That did it. The binding works without issue now. Thanks a ton for the direction. I'll keep that distinction between C and D in mind as I go forward. It's been night and day between D and C++. I struggled for a while getting this work going in C++ but was firmly blocked by CMake. D and dub have been champs for ease of use.// EDSDKTypes.h typedef struct __EdsObject* EdsBaseRef; typedef EdsBaseRef EdsCameraListRef; //[...]// edsdk.d struct EdsBaseRef; alias EdsBaseRef EdsCameraListRef;You've dropped a level of indirection here. In the C header, EdsBaseRef is a pointer, but in your D code, it is an opaque struct. The correct way to translate these C declarations into D is: struct __EdsObject; alias EdsBaseRef = __EdsObject*; alias EdsCameraListRef = EdsBaseRef; Note that unlike C, D does not allow us to refer to an incomplete type without first declaring it.
Dec 02 2020
On Thursday, 3 December 2020 at 00:30:06 UTC, Kyle Ingraham wrote:What did I do wrong in constructing the bindings? If it helps the library provides a function called EdsRelease for cleaning-up allocated objects. Is the management of pointers between D and C the issue? Please forgive me if I've mangled that concept.Not an answer to your question, but the "idiomatic" approach is to not write bindings yourself. dstep generates bindings: https://github.com/jacob-carlborg/dstep dpp lets you include C header files directly: https://github.com/atilaneves/dpp
Dec 02 2020
On Thursday, 3 December 2020 at 01:19:05 UTC, bachmeier wrote:On Thursday, 3 December 2020 at 00:30:06 UTC, Kyle Ingraham wrote:Thanks for the suggestions here. I had no idea that these tools existed. Now that I've gotten my feet wet with doing it manually it'll be interesting to compare results with those from automation. I'm all for it they can take some of the heavy lifting away.What did I do wrong in constructing the bindings? If it helps the library provides a function called EdsRelease for cleaning-up allocated objects. Is the management of pointers between D and C the issue? Please forgive me if I've mangled that concept.Not an answer to your question, but the "idiomatic" approach is to not write bindings yourself. dstep generates bindings: https://github.com/jacob-carlborg/dstep dpp lets you include C header files directly: https://github.com/atilaneves/dpp
Dec 02 2020