some fun interop between c and sharp
About
I wanted to be better.
Unmanaged Side
Let's create some C library:
#include <stdio.h>
#include <string.h>
void bar(void *b) {
printf("Buffer received at address: %p\n", b);
strcpy(b, "bonjour"); // XXX: yolo buffer overflow.
}
void baz(const char *s) {
printf("string received: %s", s);
}
typedef int (*Operation)(int,int);
int qux(int a, int b, Operation op) {
return op(a,b);
}
void x(char *s) {
s[0] = 'x';
}We can build the libfoo.dylib like this:
cc -shared -o libfoo.dylib -fPIC foo.cManaged Side
Let's write a F# application that calls the C library:
open System
open System.Runtime.InteropServices
module NativeMethods =
[<DllImport("libfoo")>]
extern void bar(void* b);
[<DllImport("libfoo")>]
extern void baz(string s);
type Operation = delegate of int * int -> int
[<DllImport("libfoo")>]
extern int qux(int a, int b, Operation operation)
[<DllImport("libfoo")>]
extern void x(nativeint s)
module Call =
let bar () =
let bytes = "helloworld" |> System.Text.Encoding.UTF8.GetBytes
let ptr = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0)
NativeMethods.bar ptr
// let c = bytes.[0]
printfn $"{bytes |> System.Text.Encoding.UTF8.GetString}"
let baz () =
let s = "foobar"
NativeMethods.baz s
let qux () =
let add (a : int) (b : int) = a + b
let n = NativeMethods.qux(1,2, add)
printfn $"Computed: {n}"
let x () =
let s = "helloworld"
let ptr = Marshal.StringToHGlobalAnsi(s)
NativeMethods.x ptr
let s' = Marshal.PtrToStringAnsi(ptr)
printfn $"x'd: {s'}"
[<EntryPoint>]
let main _ =
Call.bar ()
Call.baz ()
Call.qux ()
Call.x ()
0Output
And for the curious ones! Here is the output.
Buffer received at address: 0x3000b04a0
bonjourld
Computed: 3
x'd: xelloworld
string received: foobar