I need to create a dynamic .NET delegate with specially marshalled parameters (e.g. [MarshalAs(UnamangedType.LPWStr)]) at runtime using System.Reflection.Emit. This requires me to create a type inheriting MulticastDelegate (no problems so far), an appropriate constructor, and the Invoke-method with the specially marshalled parameters.
My C# code so far:
TypeBuilder type_builder = ...;
MethodBuilder method_builder = type_builder.DefineMethod(
"Invoke",
MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.Public,
CallingConventions.Standard,
typeof(int),
new[] { typeof(string) } // only an example - this array could hold any number of parameter types
);
ParameterBuilder parameter_1 = invoke.DefineParameter(1, ParameterAttributes.HasFieldMarshal, "arg0");
parameter_1.SetCustomAttribute(new CustomAttributeBuilder(
typeof(MarshalAsAttribute).GetConstructor(new[] { typeof(UnmanagedType) }),
new object[] { UnmanagedType.LPWStr }
));
// ...
type_builder.CreateType();
I can generate the dynamic assembly, however the application crashes upon invocation of the 'Invoke'-method due to invalid IL instructions.
After a closer inspection using the peverify and ildasm-tools I detect, that my code above emits the following IL:
.method public hidebysig newslot virtual instance int32 Invoke (
string arg0
) runtime managed
{
.param [1]
.custom instance void [System.Private.CoreLib]System.Runtime.InteropServices.MarshalAsAttribute::.ctor(
class [System.Private.CoreLib]System.Runtime.InteropServices.UnmanagedType) = (
01 00 15 00 00 00 05 00 53 08 0c 41 72 72 61 79 /* ...huge binary blob... */ 00 00 00 00
)
// ...
}
Whereas the following should be the correct IL code:
.method public hidebysig newslot virtual instance int32 Invoke (
string marshal(lpwstr) arg0
) runtime managed
{
// ...
}
(Namely the marshal(lpwstr)-modifier on arg0!)
My Question
How do I have to change the code above to emit the correct marshalling information?
The MSDN documentation is not helping, as it always refers to the obsolete method MethodBuilder.SetMarshal(UnmanagedMarshal). Furthermore, the documentation only tells me to "emit the MarshalAs custom attribute instead" - which is pretty unhelpful, because this is exactly what I am doing.
Note: I am using .NET Core 5
EDIT:
Creating the IL code for a delegate is not a problem. I've tested it and it works flawlessly. The only trouble I have is correctly implementing marshal(...).