How to convert out/ref extern parameters to F# - f#

I've got a C# extern declaration that goes like this:
[DllImport("something.dll")]
public static extern ReturnCode GetParent(IntPtr inRef, out IntPtr outParentRef);
How to translate that to F#?

You can try something like the code below. I don't know what ReturnCode is, so the code below expects it is an integer. For any more complex type, you'll need to use [<Struct>] attribute as in the answer referenced by A-Dubb.
type ReturnCode = int
[<System.Runtime.InteropServices.DllImport("something.dll")>]
extern ReturnCode GetParent(System.IntPtr inRef, System.IntPtr& outParentRef);
To call the function, you'd write something like this:
let mutable v = nativeint 10
let n = GetParent(nativeint 0, &v)
BTW: Could you also post a sample C code that implements the function in something.dll? If yes, we could try running the solution before sending an answer...

Maybe this similar question will point you in the right direction. Looks like he used attributes at the parameter level for "in" and "out" F# syntax for P/Invoke signature using MarshalAs

For anyone else trying to use F# with EnvDte via PInvoke this may help:
[<System.Runtime.InteropServices.DllImport("ole32.dll")>]
extern unit CreateBindCtx(System.IntPtr inRef, IBindCtx& outParentRef);
[<System.Runtime.InteropServices.DllImport("ole32.dll")>]
extern unit GetRunningObjectTable(System.IntPtr inRef, IRunningObjectTable& outParentRef);
which apparently is slightly incorrect, but appears to work. the definition should be:
[<System.Runtime.InteropServices.DllImport("ole32.dll")>]
extern int CreateBindCtx(System.IntPtr inRef, IBindCtx& outParentRef);
[<System.Runtime.InteropServices.DllImport("ole32.dll")>]
extern int GetRunningObjectTable(System.IntPtr inRef, IRunningObjectTable& outParentRef);

Related

Platform Invoke F# callback functions

I am using F# on a Raspberry Pi 2 (ARM 7 & thus mono). I am currently trying to use the WiringPi library, written in C. I have successfully managed to use some of the functions using P/Invoke.
Now I am trying to use interrupts (see http://wiringpi.com/reference/priority-interrupts-and-threads/) but I am stumped by this function with the following C signature
int wiringPiISR (int pin, int edgeType, void (*function)(void));
Which has been translated (see https://github.com/danriches/WiringPi.Net/blob/master/WiringPi/WrapperClass.cs) by Daniel Riches into a C# library like this
//This is the C# equivelant to "void (*function)(void))" required by wiringPi to define a callback method
public delegate void ISRCallback();
[DllImport("libwiringPi.so", EntryPoint = "wiringPiISR")]
public static extern int wiringPiISR(int pin, int mode, ISRCallback method);
How on earth would I do this in F#? I guess DllImport line looks like this ("method" is reserved in F#)
[<DllImport("libwiringPi.so", EntryPoint = "wiringPiISR")>]
extern int wiringPiISR(int pin, int mode, ISRCallback callBack);
What does the type definition for ISRCallback look like?
Note: this is not just "a" function pointer but a void one, with void arguments.
The delegate definition would look something like this:
type ISRCallback = delegate of unit -> unit
And the platform invoke signature would look like this:
[<DllImport("libwiringPi.so", EntryPoint = "wiringPiISR")>]
extern int wiringPiISR(int pin, int mode, [<MarshalAs(UnmanagedType.FunctionPtr)>]ISRCallback callBack);
An example usage of the function:
let callback : ISRCallback = ISRCallback(fun () -> (*do something interesting here*) ())
let result = wiringPiISR(1, 1, callback)
You should keep in mind that delegates in .NET are subject to garbage collection. It is the responsibility of the developer to ensure that the delegate doesn't "go out of scope" until your native library no longer needs the function callback.

Why does the F# compiler give an error for one case but not the other?

I'm working on a platform invoke call from F#, and I am getting a compiler error I really can't make that much sense out of. First, let me show the C signature of what I am doing:
int Foo(
ULONG_PTR *phHandle,
DWORD flags
);
In F#, I think the correct way to invoke this natively is as so:
[<DllImport("somedll.dll")>]
static extern int APlatformInvokeCall
(
[<Out>]nativeint& phHandle,
uint32 flags
)
If I try to call this in a class, I get a compilation error when calling it like so:
type Class1() =
[<DllImport("somedll.dll")>]
static extern int APlatformInvokeCall
(
nativeint& phHandle,
uint32 flags
)
member this.Foo() =
let mutable thing = nativeint 0
APlatformInvokeCall(&thing, 0u) |> ignore
thing
The error is:
A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
Weirdly, when I do this all in a module, the compilation errors go away:
module Module1 =
[<DllImport("somedll.dll")>]
extern int APlatformInvokeCall
(
nativeint& phHandle,
uint32 flags
)
let Foo() =
let mutable thing = nativeint 0
APlatformInvokeCall(&thing, 0u) |> ignore
thing
Why does this compile as a module, but not as a class?
I don't think it's valid to define an extern method within a class in F#.
If you pull up the F# 3.0 language specification and search for DllImport, near the bottom is a table listing some special attributes and how they can be used. The text for [<DllImport>] says:
When applied to a function definition in a module, causes the F# compiler to ignore the implementation of the definition, and instead compile it as a CLI P/Invoke stub declaration.
That seems to indicate that it's only valid to declare extern methods (that use [<DllImport>]) on functions defined in a module; it doesn't say anything about class members though.
I think you're running into a compiler bug. Please submit this code to fsbugs#microsoft.com so they can fix the error message emitted by the compiler -- it should really be giving you an error about defining an extern method in a class since that's not allowed by the language spec.
Whether this is a bug not withstanding, maybe this is what's going on: If APlatformInvokeCall were considered a static member function, that member have a single argument of tuple type. Tuples are compiled into objects of generic type (see here, at the bottom, or 5.1.3 in the spec). In this case that tuple is
System.Tuple<nativeint&, uint32>
But ECMA 335 II.9.4 says you can't instantiate generic types at byref types. This explains the error reported.
This explanation fits the fact mentioned above that Class1 works (well, compiles) if you modify the extern declaration and call to take instead a single argument. It also fits the fact that the module version works, since in that version there is no considering APlatFormInvokeCall a member function.
The simple solution is to check the spec, here is the class definition grammar:
type type-name pat_opt as-defn)opt =
class
class-inherits-decl_opt
class-function-or-value-defns_opt
type-defn-elements
end
then we have
class-function-or-value-defn :
attributes_opt staticopt let rec_opt function-or-value-defns
attributes_opt staticopt do expr
which doesn't allow extern.
and
type-defn-element :
member-defn
interface-impl
interface-signature
which isn't what you want either.
As a result, we can see that using extern as you are trying to use it can't be done inside a class.

Refactoring many identical DllImport declarations

I have a module which contains an interface to a native DLL; it looks like this:
// nvtt.dll binding module
module private NvTextureTools =
type NvttInputOptions = IntPtr
[<DllImport("nvtt", CallingConvention = CallingConvention.Cdecl)>]
extern NvttInputOptions nvttCreateInputOptions()
[<DllImport("nvtt", CallingConvention = CallingConvention.Cdecl)>]
extern void nvttDestroyInputOptions(NvttInputOptions)
[<DllImport("nvtt", CallingConvention = CallingConvention.Cdecl)>]
extern void nvttSetInputOptionsAlphaMode(NvttInputOptions, AlphaMode alphaMode)
[<DllImport("nvtt", CallingConvention = CallingConvention.Cdecl)>]
extern void nvttSetInputOptionsGamma(NvttInputOptions, float inputGamma, float outputGamma)
[<DllImport("nvtt", CallingConvention = CallingConvention.Cdecl)>]
extern void nvttSetInputOptionsWrapMode(NvttInputOptions, WrapMode mode)
(there are 5x more functions, but this should give the general idea).
Is there any way to specify the DllImport parameters just once? As far as I understand, I can't inherit from DllImport (it's sealed, and anyway I don't think it would work if it was not), and I can't use reflection to add the necessary attributes because I need them at compilation time.
I could make a brand new class with P/Invoke methods using reflection, but this will make calling them cumbersome.
Any thoughts?
I don't know about F#, but in C# you can do something like:
static const string DllName = "nvtt";
[DllImport(DllName, other params...)]
some function signature
[DllImport(DllName, other params...)=
some function signature
So that way the actual string is only declared once - the DllImport attributes themselves all still look a lot alike, but it makes changing things easier. I think you could do the same with CallingConvention, but I've never tried it with an enum.
Just in case you are using Visual Studio - it is possible to create a T4 template and generate all those nasty attributes. This is not an F# or VS specific solution however, any code generating tool would work.

P/Invoke Function Overloading

I'm attempting to P/Invoke a C library from F#, and have encountered a peculiar issue. I have a module containing all my extern functions. The underlying C library has two functions with the same name, but different arguments. This, of course, is not allowed in an F# module.
module C =
open System.Runtime.InteropServices
[<DllImport("libc", CallingConvention = CallingConvention.Cdecl)>]
extern int setValue(nativeint source, int value)
[<DllImport("libc", CallingConvention = CallingConvention.Cdecl)>]
extern int setValue(nativeint source, string value)
// the previous function declaration cause the following compile-time error:
// Duplicate definition of value 'setValue'
Is there some special way to work around this? I can not alter the C library.
The EntryPoint attribute should work (e.g. with an ordinal), if MSDN can be trusted (haven't tested in F#). Name your imported functions e.g. setValueInt() and setValueString().

Mimicking typedef in ActionScript?

I'm working on some ActionScript code that needs to juggle a bunch of similar-but-not-interchangeable types (eg, position-in-pixels, internal-position, row-and-column-position) and I'm trying to come up with a naming scheme to minimize the complexity.
Additionally, I don't yet know what the best format for the "internal position" is – using int, uint and Number all have advantages and disadvantages.
Normally I'd solve this with a typedef:
typedef float pixelPos;
typedef int internalPos;
typedef int rowColPos;
Is there any way of getting similar functionality in ActionScript?
If you're using Flex or another command-line compiler to build your project, you could add a pass from an external preprocessor to your build process.
Doesn't get the type-safety, but otherwise appears to do what you want.
I have found an article titled Typedefs in ActionScript 3, which suggests using:
const pixelPos:Class = int;
But that doesn't work – the compiler complains that "Type was not found or was not a compile-time constant: pixelPos" (note: this also happens when I use Object instead of int).
Here is an example of code which doesn't compile:
const pixelPos:Class = int;
function add3(p:pixelPos):void { // <-- type not found on this line
return p + 3;
}
Just make it static const and you can register your own class. Like this:
static const MyClass:Class = int;
And you can't make a variable with this type:
var ert:MyClass; //error
private function ert2():MyClass {}; //error
But you can make an instance:
var ert:* = new MyClass();

Resources