Accessing errno generated by an external C library?

I’ve got libmodbus working in my Xojo project to talk to an external Motion control unit over ModbusTCP. I am testing this now using a Windows-based Modbus slave simulator and so far so good. The one thing I can’t quite wrap my head around is how to catch any errors that libmodbus generates.

Most of the functions I’m using return an integer value, to indicate success or failure. if there’s a failure, you can get the text of the error using the errno variable. Libmodbus includes the standard C errno.h header, so if I have the errno variable, I can pass that to another libmodbus function to retrieve the actual error text.

Maybe this is a dumb question, but how do I access errno from within Xojo in order to call the libmodbus modbus_strerror() function?

Here’s the documentation for modbus_strerror().

For Windows, try this:

Declare Function _get_errno Lib "msvcrt" (ByRef Error As Integer) As Integer
Dim errno As Integer
Call _get_errno(errno)

Unless I’m not reading that correctly, this code is letting me look up the text of an error using a known error number, correct?

The problem is that I don’t know the errno that limbodbus is generating when one of its functions returns a failure.

The list of functions in libmodbus is not especially long, but I can’t find one that fetches the last error. I think the assumption is that if you’re using the library you’re coding in C and maybe then you have access to errno, which appears to be a global variable in C. but because I’m calling discrete functions from the library as needed, from Xojo, wouldn’t I need an explicit function in libmodbus to fetch the most recent error? Or maybe I’m just completely misunderstanding how this works.

No, it looks up the integer value of the last error number that was set.

Ahh, I see. I’ll give that a try after lunch. Thanks!

Actually - do you know what the equivalent lib would be on Mac? I’m testing on mac, but running my modbus simulator on a Windows machine on the network.

I have this method for Windows/Linux/Mac, but I’ve only ever tested the Windows and Linux sides:

Function get_errno() As Integer
  Dim err As Integer
  Dim mb As MemoryBlock
  #If TargetWin32 Then
    Declare Function _get_errno Lib "msvcrt" (ByRef Error As Integer) As Integer
    Dim e As Integer = _get_errno(err)
    If e <> 0 Then err = e
  #elseif TargetLinux
    Declare Function __errno_location Lib "libc.so" () As Ptr
    mb = __errno_location()
  #elseif TargetMacOS
    Declare Function __error Lib "System" () As Ptr
    mb = __error()
  #endif
  If mb <> Nil Then err = mb.Int32Value(0)
  Return err
  
End Function
1 Like

Well at least on my mac that works perfectly. Thanks!

As the underlying int errno should follow the OS bitness, the code should not follow it? Something as

Dim err As Integer
Dim mb As MemoryBlock
#If TargetWindows Then
  Declare Function _get_errno Lib "msvcrt" (ByRef Error As Integer) As Integer
  Dim e As Integer = _get_errno(err)
  If e <> 0 Then err = e
#elseif TargetLinux
  Declare Function __errno_location Lib "libc.so" () As Ptr
  mb = __errno_location()
#elseif TargetMacOS
  Declare Function __error Lib "System" () As Ptr
  mb = __error()
#endif
#if Target64Bit Then
  If mb <> Nil Then err = mb.Int64Value(0)
#else
  If mb <> Nil Then err = mb.Int32Value(0)
#EndIf
Return err