Help calling a function from dylib

Ok, so an update on this - The frame grabber manufacturer provided me with the C++ source code for a Windows DLL they made for another customer. I have had someone port this to mac (it was 98% generic C++ with very little OS-specific stuff), and I’m now trying to get his .dylib file into Xojo to test.

I did this once before on Windows, as I mentioned in that other post, but that was on RealBasic and the zip file with my source code for that project very helpfully corrupted itself sometime in the last 8 years.

I am trying to sanity check that I have the basic Xojo code right. Here’s a function from the Windows DLL that should tell me how many frame grabber boards are installed.

// return the amount of board found in the system
// 0 = no board found
COAX_GRABBER_API int32_t GetBoardCount(uint32_t * count);

How would I call this from Xojo?

Refer to the documentation at Declare - Xojo Documentation

Declare Function GetBoardCount Lib <dylib_name> (byref count as UInt32) as Integer

Thanks. So that runs just fine, but I guess what I’m not really understanding here is where the return value from GetBoardCount in the dylib now lives in Xojo. How do I access that? I’ve put a break in after the declare function but see nothing in the debugger that seems to contain the return value from the dylib.

I’m sure I’m missing something really elementary here. I wish there were more examples of non-OS dylib calls in the documentation, because for some reason I’m having a hard time wrapping my head around this one.

The Declare just tells Xojo how to call it. It doesn’t actually call it. You would do that with something like

dim success, count as integer
success = GetBoardCount(count)

I am assuming that the return value from the function is a success/failure indicator and that the count is returned in the parameter you pass to it, based on the C declaration.

1 Like

Ok, so I added that code and I’m getting this when I run it:

Could not load GetBoardCount from <path-to-library>.dylib.

I don’t know if this is because there’s an issue with the dylib, or if it’s something to do with how I’m calling that function.

The person who ported it for me gave me two files:

libCoaxLinkGrabber.dylib
libegrabber.dylib

And he said:

Here’s a first pass build of the library. I’m not clear on how Xojo handles dependencies between libraries, so I included the ‘libegrabber.dylib’ library, and I’m hopeful that if it’s in the same directory as ‘libCoaxLinkGrabber.dylib’ Xojo will do the right thing

I think the best approach might be to import ‘libegrabber.dylib’ first, then ‘libCoaxLinkGrabber.dylib’. If that doesn’t work and Xojo or the Console gives an error importing either library, let me know and we can take it from there.

My understanding is that you don’t import a whole library and just have access to it wholesale, as you would in C/C++. Instead you declare each function you want to use, separately. So his suggestion to import the two libraries might be based on an incorrect assumption about how Xojo is handling this, correct?

Be aware that when you press Run in the IDE, it actually creates a subdirectory where it builds the executable, so your dylibs need to be copied in if you’re running from the IDE rather than building the executable. You can add a build step to copy them in when you run, or run paused and copy them before you resume.

1 Like

I am copying the files into the resources folder with a build copy step. I can see that they’re in the same folder as rbframework.dylib. However, I’m still getting the error above:

Could not load GetBoardCount from libCoaxLinkGrabber.dylib.

Here’s the code:

#If TargetMacOS Then
  Declare Function GetBoardCount Lib "libCoaxLinkGrabber.dylib"  (byref count as UInt32) as Integer
  dim success, count as UInt32
  success = GetBoardCount(count)
  break
#EndIf

it fails at success = GetBoardCount(count)

So at this point, the remaining question is: Can Xojo resolve dependencies between libraries when you call something via declare, because he has this split into two dylib files? I haven’t seen the source code so I don’t know for sure what’s inside the two. My guess is that he may be porting the structure of the DLL as-is, which contains two C++ files: CoaxLinkGrabber.cpp and dllmain.cpp. Is it possible that the issue here is that Xojo needs the two dylibs to be merged into one or something like that?

I dont believe it can resolve which dylib. Make 100% certain that thepath to the dylib is correct in your declare. Make a working, simple example that you can declare and test against to ensure you have the path correct. After that is behind you, you will need to make sure you’re calling it correctly - that your declaration matches the dylib function’s signature otherwise you’ll get this error for either oone of those.

I’ll see what I can do. creating the dylib is a beyond my area of expertise so I’ll need to either locate a working one or have someone make one for me. If you’re aware of any that I can easily download to test with, I’d love to try it.

In the mean time I’m waiting to hear back from the person who ported this for me that the function calls remain the same as they were in the Windows DLL. If those changed, then that’s another possible point of failure.

Ok, he sent me a simple hello world dylib that returns an integer value and it works perfectly. It’s being imported in exactly the same way as the other libs. So now I’ve tossed it back to him to look into what’s up because I’ve clearly getting the code into Xojo.

The person making the dylib created a simple command line app to test it. He’s able to call any of the functions within the library and get the expected results from that. However, I’m still getting the same error.

He thinks Xojo might be changing the paths used to reference the second dylib, which is why we’re not seeing any entries in the system Console app related to this. So he built a version that has the second dylib at a fixed location in /usr/local/lib and this now appears to be working.

As this is an in-house application and not something we’re selling commercially, I’m fine with this.

Just a quick followup on this: We got the library working, but it wasn’t communicating with the driver. The frame grabber manufacturer got that all straightened out (error on the installation of the driver), and my app is now communicating with the frame grabber.

Let’s hope today’s post-covid vaccine brain fog doesn’t get too much in the way, or i might be back here asking dumb questions shortly!

So now that we have the driver and the library situated, I’m running into another issue. In the call to GetBoardCount, and many others, the parameters are of type uint32_t or int32_t or similar. I’m getting errors on these functions (segmentation faults, actually), when I send them uint32 or int32 values, respectively.

What’s the correct integer type in xojo for this situation?

Based on this explanation,

C/C++ has very loose definitions on its basic integer data types (char, short, int, long, and long long). The language guarantees that they can represent at least some range of values, but any particular platform (compiler, operating system, hardware) might be larger than that.

A good example is long. On one machine, it might be 32 bits (the minimum required by C). On another, it’s 64 bits. What do you do if you want an integer type that’s precisely 32 bits long? That’s where int32_t comes in: it’s an alias for whatever integer type your particular system has that is exactly 32 bits.

unit32_t is a UInt32
int32_t is a Int32

Don’t use Integer, as it will be either 32 or 64 bits, depending on your compile settings.

ok, well integer, int32 and uint32 aren’t working here, so I think there’s something deeper going on. Throwing this back to the frame grabber manufacturer and the person who ported the original Windows DLL.

Functions that don’t require any parameters are working as expected. But according to the frame grabber manufacturer, the issue with the segmentation fault is likely that I need to be passing a pointer to the count variable, not the value of count.

So I take it this means I need to set up a memory block, then pass a pointer to that memory block to the function? Something like this?

// return the amount of board found in the system
// 0 = no board found
// COAX_GRABBER_API int32_t GetBoardCount(uint32_t * count);
Declare Function GetBoardCount Lib "libCoaxLinkGrabber.dylib" ( count as Ptr) as int32

var boardCount as Int32
var count as uint32
Var mb As New MemoryBlock(-1)
mb.UInt32Value = count
boardCount = GetBoardCount( mb.Ptr )

But this gives me the following compile errors:

App.libCoaxLinkGrabber, line 171
There is more than one method with this name but this does not match any of the available signatures.
mb.UInt32Value = count

App.libCoaxLinkGrabber, line 172
There is more than one method with this name but this does not match any of the available signatures.
boardCount = GetBoardCount( mb.Ptr )

App.libCoaxLinkGrabber, line 172
Parameter "count" expects type Ptr, but this is type Int32.
boardCount = GetBoardCount( mb.Ptr )

Clearly I’m not doing something right here!

For passing a pointer I believe you need to add byref:

Declare Function GetBoardCount Lib "libCoaxLinkGrabber.dylib" (byref count as uint32) as int32
1 Like

The uint32_t * count means a pointer to a uint32. Byref does that. See my original post.

Make sure that the person working on your dylib hasn’t done the same thing, so you’re not passing a pointer to a pointer into the grabber.

Thanks everyone for pointing out what should have been obvious to me. There’s a lesson here: when you get your covid vaccine, take the next day off!

I’ve set it up to pass the function a pointer, and that worked. So now I’ll start testing the rest of the library and hopefully sign off on this port later today.

2 Likes
Forum for Xojo Programming Language and IDE. Copyright © 2021 Xojo, Inc.