Callback with StdCall on a Background Thread?

I am assisting another user in trying to access his microscope USB camera, and after first successes I am out of ideas:

The camera is a ToupTek ToupCam which comes with drivers and documentation – we are trying a macOS version where the API is a dylib. The camera sends its replies via background threads, and yes I know these are not officially supported but there are workarounds that currently do work.

There is a hotPlug method which triggers a callback method each time a camera is connected or disconnected:

typedef void (*PTOUPCAM_HOTPLUG)(void* pCallbackCtx); toupcam_ports(void) Toupcam_HotPlug(PTOUPCAM_HOTPLUG pHotPlugCallback, void* pCallbackCtx);

With an external method

Private Sub Toupcam_HotPlug(Callback as ptr, context as ptr)

and an instance method

Private Sub InsertHotPlug() If Mid <> 0 Then Dim id As UInteger = Me.ID Toupcam_HotPlug AddressOf HotPlugCallBack, ptr(id) InstanceDictionary.Value(Mid) = xojo.core.WeakRef.Create(Me) xojo.core.timer.CallLater 0, WeakAddressOf Raiseconnected End If End Sub

I can register the shared method

Private Shared Sub HotPlugCallBack(context as Ptr) #Pragma BackgroundTasks False #Pragma StackOverflowChecking False Dim instance As ToupCam.Camera = GetInstance(context) If instance <> Nil Then CallDelegateOnMainThreadMBS AddressOf instance.RaiseCamerasChanged End If End Sub

which uses

Private Shared Function GetInstance(context as ptr) as ToupCam.Camera #Pragma BackgroundTasks False #Pragma StackOverflowChecking False Dim uid As UInt32 = Integer(context) Dim w As Xojo.Core.WeakRef = InstanceDictionary.Lookup(uid, Nil) If w <> Nil And w.Value <> Nil Then return toupcam.Camera(w.Value) End If End Function

to retrieve the instance. I am using the user customisable ptr “context” to register the id of the camera which is an Unsigned in C terms.
The code above works nicely although using plugins is not advised when trying to cope with a background thread, but I hoped that this part of Christian’s plugins would be thread savvy (else it wouldn’t make much sense) and it very much looks like that.

Now for the problem: There is another callback that is called when a variety of events occur which must be registered too:

typedef void (__stdcall* PTOUPCAM_EVENT_CALLBACK)(unsigned nEvent, void* pCallbackCtx); toupcam_ports(HRESULT) Toupcam_StartPullModeWithCallback(HToupCam h, PTOUPCAM_EVENT_CALLBACK pEventCallback, void* pCallbackContext);

HResult is

#ifndef HRESULT #define HRESULT int #endif

Obviously, the differences are that the handle of the camera is passed to the StartPullMode… method (the UInt32/unsigned I mentioned above), and that the callback method has two input parameters: an unsigned/UInt32 for the event definition and the custom ptr like above. And this method uses the stdCall calling convention. So here is the code:

Private Function Toupcam_StartPullModeWithCallback(id as uint32, callback as Ptr, context as ptr) as Int32

Public Function StartPullMode() as HResult Dim id As UInteger = Me.ID Return hresult(Toupcam_StartPullModeWithCallback (Mid, AddressOf EventCallBack, ptr(id))) End Function

[code]Private Shared Sub EventCallBack(eventID as Uint32, context as Ptr)
#Pragma BackgroundTasks False
#Pragma StackOverflowChecking False
#Pragma X86CallingConvention StdCall

System.DebugLog “Event Callback start”

Dim instance As ToupCam.Camera = GetInstance(context)
If instance <> Nil Then
System.DebugLog “Instance <> Nil”
System.DebugLog "eventid: "+eventid.ToText

Select Case eventID
Case 1 // TOUPCAM_EVENT_EXPOSURE
  CallDelegateOnMainThreadMBS addressof instance.RaiseexposureChanged
Case 2 // TOUPCAM_EVENT_TEMPTINT
  CallDelegateOnMainThreadMBS AddressOf instance.RaiseTempTintModeChanged
Case 3 // TOUPCAM_EVENT_CHROME
  System.DebugLog "Chrome eventID"
Case 4 // TOUPCAM_EVENT_IMAGE  
  CallDelegateOnMainThreadMBS AddressOf instance.RaiseImageArrived
Case 5 // TOUPCAM_EVENT_STILLIMAGE
  CallDelegateOnMainThreadMBS AddressOf instance.RaiseStillimageArrived
Case 6 // TOUPCAM_EVENT_WBGAIN 
  CallDelegateOnMainThreadMBS AddressOf instance.RaiseRBGGainChanged
Case 128 // TOUPCAM_EVENT_ERROR
  CallDelegateOnMainThreadMBS AddressOf instance.RaiseError
Case 129 // TOUPCAM_EVENT_DISCONNECTED
  CallDelegateOnMainThreadMBS AddressOf instance.RaiseDisconnected
Else
  System.DebugLog "Unknown eventID"
End Select

Else
System.DebugLog “Instance is Nil”
End If
End Sub[/code]

But calling StartPullMode always results in a segmentation error, the “Event Callback start” does not appear in the debug log.
Any ideas what I have wrong (except for trying to catch a background thread in Xojo at all)?

Sorry for the length of this entry, and thank you for reading it!

for such callback, you need a plugin or put it in your own DLL.
For Xojo it will eventually always crash.

Too bad! Thank you!
Such a DLL shouldn’t be too hard I guess, but I’ve never done so.
There isn’t by chance a MBSCallBackBlock I might have not found yet?

for that I would need to know the parameter, e.g. which to just pass on and which to copy.