Proposal: C# should provide better interop with unmanaged function pointers. #80
-
Ported from dotnet/roslyn#13240 Issue While there are a couple of mechanisms designed to work with and call unmanaged function pointers, these mechanisms may:
Workaround [UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void _D();
public struct S
{
private IntPtr pD;
public void D()
{
var funcptr = Marshal.GetDelegateForFunctionPointer<_D>(pD);
funcptr();
}
}
public static class C
{
[DllImport("SomeBinary.dll")]
public static extern void CreateS(out S pS);
} -or- Declare a managed delegate and rely on the marshalling behavior to convert as appropriate. Such As: [UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void _D();
public struct S
{
[MarshalAs(UnmanagedType.FunctionPtr)]
public _D D;
}
public static class C
{
[DllImport("SomeBinary.dll")]
public static extern void CreateS(out S pS);
} Proposal unsafe public struct S
{
public void (*D)();
} The compilation should fail if Advantages The compiler could provide some level of type safety when invoking the function pointer (ensuring the arguments passed in match the types required). This would allow better interop with unmanaged languages and types that use function pointers. This would allow a user to more readily implement VTBLs for unmanaged interop when required. |
Beta Was this translation helpful? Give feedback.
Replies: 18 comments 4 replies
-
FYI. @jaredpar, who had some thoughts on how this could be implemented in a safe-manner. |
Beta Was this translation helpful? Give feedback.
-
The idea I had was for a more general purpose C# feature: static delegates. static delegate int Func(); A
This adds a nice general purpose, light weight, call back capability to the C# language. This can be used in a variety of scenarios, including PInvoke. Attributes could be used on top of the declarations to support calling conventions very similar to the original proposal. |
Beta Was this translation helpful? Give feedback.
-
Would a special attribute also be used to track the signature of the |
Beta Was this translation helpful? Give feedback.
-
The signature needs to be tracked in metadata. I wouldn't use an attribute though because that's generally a poor way of tracking certain kinds of types: generic type parameters for instance. Instead I'd prefer to generate a method on the struct that had the signature. |
Beta Was this translation helpful? Give feedback.
-
Makes sense 😄 |
Beta Was this translation helpful? Give feedback.
-
I like this suggestion. There are several areas where interaction with native environments is restrictive and this is definitely one. |
Beta Was this translation helpful? Give feedback.
-
@jaredpar, we talked about it a bit already, but would you be willing to champion this if I submit a formal proposal against the repo? |
Beta Was this translation helpful? Give feedback.
-
Yes. Need to buy a cape though. Feel weird being a champion without a better outfit. |
Beta Was this translation helpful? Give feedback.
-
@jaredpar would that be usable even in safe code? eg if I had:
Would that be possible? Would that be allowed without usage (ignoring disposal impl best practices):
|
Beta Was this translation helpful? Give feedback.
-
@bbarry it would be allowed in safe code. It's just another delegate type that just also happens to be very usable in interop scenarios. |
Beta Was this translation helpful? Give feedback.
-
I opened an official proposal for this, taking into account @jaredpar's "safe" version 😄 |
Beta Was this translation helpful? Give feedback.
-
From the current version of the proposal:
I think the name should be exactly the same as what the source code contains. The user declared a type named This is important for reflection and for at least limited support of interop with languages that don't support the feature themselves. Though maybe I'm missing something: @tannergooding, what is the reason why "
I think that name should be |
Beta Was this translation helpful? Give feedback.
-
I think that is the point here, we generate a field called
This makes sense, provided we hook up the method to basically just be the |
Beta Was this translation helpful? Give feedback.
-
I'm confused, what field? I thought this proposal is about declaring a type, not a field. To make it more concrete, consider this code: static delegate void Func();
static void Nop() {}
void Call(Func f) => f();
void Main() => Call(Nop); I think this should generate something like (hopefully my syntax for IL instructions not directly available in C# is obvious): struct Func
{
public IntPtr Function;
public void Invoke();
}
static void Nop() {}
void Call(Func f) => calli f.Function;
void Main() => Call(new Func { Function = ldftn Nop }); There is no field called I also noticed that the |
Beta Was this translation helpful? Give feedback.
-
I have one question... Suppose the static delegate value comes from native code... How would we verify that the value is valid? And by valid, I mean not null... Can we get a method for determining that? |
Beta Was this translation helpful? Give feedback.
-
Or, perhaps I should be asking if we could get a method to find out if the delegate is |
Beta Was this translation helpful? Give feedback.
-
This discussion is no longer needed as C# has shipped function pointer support. |
Beta Was this translation helpful? Give feedback.
-
What does external variable work? Like we missed Adobe Flash Player has also passing external variable like this:
Like in C++/C
Old AS3 - I know because I miss my past time with AS3:
Do you think C# can access UnmanagedVariable from nativelibrary? |
Beta Was this translation helpful? Give feedback.
This discussion is no longer needed as C# has shipped function pointer support.