How can I pass a Perl 6 object through a Nativecall callback? - raku

I'm working with the NativeCall interface.
The library is going to call my callback function a bunch of times.
That works fine. I can just declare my callback with the right
signature, pass it in as &callback and the library calls the sub just
fine.
It also has the capability to set a payload void *pointer to anything
I want, and it will include that in the call to my callback function.
Can I hide a Perl Str, for example, in the payload and successfully round trip it?
sub set_userdata(Pointer) returns int32 is native { ... }
sub set_callback(&callback(Pointer $userdata --> int32)) returns int32 is native { ... }
sub callback(Pointer $userdata) returns int32 {
my Str $mystring = ???
...
}
my Str $my-userdata-string;
set_userdata(???);
set_callback(&callback);
It seems like it could work with some incantation of binding, "is rw", nativecast() and/or .deref.

You can only use a native representation in such a case (such as CStruct, CArray, and CPointer), or alternatively a Blob. You are also responsible for ensuring that you keep a reference to the thing you pass as userdata alive from Perl 6's perspective also, so the GC doesn't reclaim the memory that was passed to the C function.
Memory management is the reason you can't pass any old Perl 6 object off to a C function: there's no way for the GC to know whether the object is still reachable through some C data structure it can't introspect. In a VM like MoarVM objects are moved around in memory over time as part of the garbage collection process also, meaning that the C code could end up with an out-dated pointer.
An alternative strategy is not not pass a pointer at all, but instead pass an integer and use that to index into an array of objects. (That's how the libuv binding inside of MoarVM tracks down the VM-level callbacks, fwiw.)

I got around this by just ignoring the userdata and making a new closure referencing the Perl object directly for every callback function. Since there is a new closure created every time I set the callback, I think this will leak memory over time.

Related

How to avoid the error "staticCFunction must take an unbound..." in Kotlin Native when a Kotlin callback function is called from C?

This is a general question about callback functions, defined in Kotlin Native, called by C functions.
For argument's sake, let's say I'm trying to walk a directory in a filesystem recursively, using https://linux.die.net/man/3/nftw in Kotlin Native.
(I know there are other ways to do this, using other C functions, but that is not the core of this question.)
nftw() takes a function as a callback:
val directory = "//some/directory"
val callback = kotlinx.cinterop.staticCFunction {
file: CPointer<ByteVar>?,
stat: CPointer<stat>?,
typeFlag: Int,
b: CPointer<FTW>? ->
val fileName = file?.toKString()
println(fileName)
val result = 0
result
}
val depth = 10
val flags = 0
platform.posix.nftw(directory, callback, depth, flags)
This works for listing files via "println()", but as as soon as the lambda contains any captured value, I get the following compiler error:
"kotlinx.cinterop.staticCFunction must take an unbound, non-capturing function or lambda".
My question is: is there any recommended approach on how to
access any non-global state from such a callback?
I did come up with a nasty workaround using a global variable, so that's not what I'm looking for primarily. If there is a commonly accepted solution using #ThreadLocal or something else, please discuss.
For native callbacks in general (not specific to nftw). The C function should accept a void* userData parameter and pass it to the callback when it is called. This allows you to pass local data to the callback, instead of global data.
This is the case even in C/C++.
For this particular case (regardless of language) there isn't really a way to do this without some global data (or JIT but let's not think about it). So any workaround would have to be nasty.
Using #ThreadLocal is a "reasonable nasty" solution.
nftw is just not a well designed C interface.

VB.NET Interfacing with external DLL to obtain USB names from function

I am trying to interface with a USB device that provides an external C++ dll file and have read a myriad of articles surrounding delegates, marshalling, pointers and I generally get the idea of what is happening. Unfortunately, my practical experience in this area is letting me down in obtaining the final solution.
I have connected to the device in order to create a session successfully but there is a function called EnumDevices which supposedly enumerates the device list for specific future calls. The function has a function within itself that lists the devices and it is this part I am struggling with.
The enumdevices call in the API looks like this:
EnumDevices(INTERFACE,FoundDevice,NULL);
bool __stdcall FoundDevice(long data, const char *DeviceName)
{
printf("device name %s\n", DeviceName)
Return True
}
and according to the documentation, FoundDevice is a call back method called for each found device.
In VB.Net, what I have done is as follows:
Created a delegate function
Delegate Function FoundDeviceDelegate(data as integer, DeviceName as PInvoker.Marshal.ByteArrayPtr) as Boolean
Then I created a local function with the same signature
Private Function FoundDevice(data as integer, DeviceName as PInvoker.Marshal.ByteArrayPtr) as Boolean
Msgbox(DeviceName.ToString)
Return True
End Function
In my main code, I make the following declarations and calls
dim devhandler as assembly.FoundDeviceHandler = AddressOf FoundDevice
dim device as new assembly.FoundDevice(devhandler)
assembly.EnumDevices(INTERFACE,device,vbNull)
('assembly' is the reference to the external dll, 'INTERFACE' is a constant and 'device' expects a function with the two parameters - user and devicename)
I thought that the EnumDevices call would then pass back to the device reference which in turns calls the DeviceHandler which references the delegated function which would then output the device name.
What I have got is a pointer value on 'device' but I am struggling referencing this back to a device name. It is never executing the FoundDevice function to show the messagebox.
I have read so much that I think I have read too much surrounding delegates and marshalling etc that I am now struggling to get to the end which feels so close given that I have the pointer reference when I debug it.
If anyone can make sense of the above and provide any useful assistance, it would be very much appreciated.

Tracking down the source of E_POINTER in IMFMediaSource::ReadSample

I'm getting an E_POINTER error from the ReadSample call, and as far as I can tell, none of the pointers are invalid. See snippet below (note, it's a C++/CLI app):
IMFSample* sample = NULL;
pin_ptr<IMFSample*> pinnedSample = &sample;
LONGLONG timeStamp;
HRESULT hr = mSourceReader->ReadSample(
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0,
NULL,
NULL,
&timeStamp,
pinnedSample
);
I suspect the problem lies in the construction of the mSourceReader (an IMFSourceReader instance, created from an IMFMediaSource). But, alas, I've no idea how to backtrack and find the source, as all the COM calls in the chain of commands that created mSourceReader returned S_OK.
Much thanks for any tips.
You don't need pin_ptr when taking the address of a local variable, since the garbage collector never moves local variables around anyway.
I'd guess that one of the other three parameters you're passing NULL to is non-optional, but I need to see what function you're calling to know for sure.
Did you create the IMFSourceReader in synchronous or asynchronous mode? The docs say:
This method can complete synchronously or asynchronously. If you provide a callback pointer when you create the source reader, the method is asynchronous. Otherwise, the method is synchronous.
I think this is your problem:
In synchronous mode:
The pdwStreamFlags and ppSample parameters cannot be NULL. Otherwise, the method returns E_POINTER.
You've passed NULL for pdwStreamFlags, which is not allowed.
Doc link: http://msdn.microsoft.com/en-us/library/dd374665.aspx

Declare native types inside a cli class?

I have a
public ref class Test
inside this class, I have:
int frameWidth;
int frameHeight;
int frameStride;
When I try to compile this, I get the error:
error C2664: 'GetImageSize' : cannot convert parameter 1 from 'cli::interior_ptr<Type>' to 'int *'
GetImageSize is a native function and it works only if I move the declaration of the 3 ints above to outside the class or inside the block that calls GetImageSize.
How can I solve this?
Those 3 ints needs to be accessible by more than one function within the class, right now I made it work because I moved them to outside the class, but it's not the right thing to do I believe since they become global.
According to this post, the reason you are seeing this is because the ints are inside a ref class which can be moved around the heap by the garbage collector at will, the address of the ints could change and you wouldn't be told.
To overcome this, you need to tell the GC not to move the objects while you are using them. To do this you need to use
pin_ptr<int*> pinnedFrameWidth = &frameWidth;
then pass pinnedFrameWidth into GetImageSize. The pin_ptr will be automatically cast to int* when passed into the method.
You need to be careful when using pin_ptr. Because the GC can't move the instance of Test class around during a collection, the managed heap can become fragmented and, eventually, performance can suffer. Ideally pin as few objects for the least amount of time possible.
There is a brief discussion of pin pointers in this .Net Rocks show.

What is the equivalent of a C pointer in VB.NET?

What is the most similar thing in VB.NET to a pointer, meaning like C pointers?
I have a TreeView within a class. I need to expose some specific nodes (or leaves) that can be modified by external objects.
C#, and I also believe VB.Net, will work on the concept of references. Essentially, it means when you say
A a = new A()
the 'a' is a reference, and not the actual object.
So if I go
B b = a
b is another reference to the same underlying object.
When you want to expose any internal objects, you can simply do so by exposing 'properties'. Make sure, that you do not provide setters for the properties, or that if you do, there is code to check if the value is legal.
ByRef is used when you want to pass the object as a parameter, and when you want the called method to be able to change the reference (as opposed to the object).
As mentioned above, if you post some code, it will be easier to explain.
Nathan W has already suggested the IntPtr structure which can represent a pointer or handle, however, whilst this structure is part and parcel of the .NET framework, .NET really doesn't have pointers per-say, and certainly not like C pointers.
This is primarily because the .NET Framework is a "managed" platform and memory is managed, assigned, allocated and deallocated by the CLR without you, the developer, having to worry about it (i.e. no malloc commands!) It's mostly because of this memory management that you don't really have access to direct memory addresses.
The closest thing within the .NET Framework that can be thought of as a "pointer" (but really isn't one) is the delegate. You can think of a delegate as a "function pointer", however, it's not really a pointer in the strictest sense. Delegates add type-safety to calling functions, allowing code that "invokes" a delegate instance to ensure that it is calling the correct method with the correct parameters. This is unlike "traditional" pointers as they are not type-safe, and merely reference a memory address.
Delegates are everywhere in the .NET Framework, and whenever you use an event, or respond to an event, you're using delegates.
If you want to use C# rather than VB.NET, you can write code that is marked as "unsafe". This allows code within the unsafe block to run outside of the protection of the CLR. This, in turn, allows usage of "real" pointers, just like C, however, they still do have some limitations (such as what can be at the memory address that is pointed to).
Best way to do it is to just allocate everything manually:
You can move up OR down each Stack at free will without Pushing or Popping.
Dim Stack(4095) as Byte 'for 8bit - 1 bytes each entry
Dim Stack(4095) as Integer 'for 16bit - 2 bytes each entry
Dim Stack(4095) as Long 'for 32bit - 4 bytes each entry
Dim Stack(4095) as Double 'for 64 bit - 8 bytes each entry
Dim i as integer 'Where i is your Stack Pointer(0 through 4095)
Dim int as integer 'Byte Integer Long or Double (8, 16, 32, 64 bit)
for i = 0 to 4095
int = i
Stack(i) = int/256 'For 8bit Byte
Stack(i) = int 'For 16bit Integer
Stack(i) = Microsoft.VisualBasic.MKL$(int) 'For 32bit Long
Stack(i) = Microsoft.VisualBasic.MKD$(int) 'For 64bit Double
MsgBox(Microsoft.VisualBasic.HEX$(Stack(i))) 'To See Bitwise Length Per Entry
next i
If you're looking to pass something back from a subroutine you can pass it by reference - as in "ByRef myParamter as Object".
Best answer depends, to some degree, on what you're trying to do.
If you are using VB the only thing that is really close to a pointer is a IntPtr. If you have access to C# you can use unsafe C# code to do pointer work.