C
C#2y ago
blue λ

❔ Loading arbitrary values onto a ILGenerator stack

hey! i'm new to c# and i have a question/issue regarding the ILGenerator. I am trying to use a function from JS to subscribe to an event handler. What I came up with was extracting the correct argument types using Reflection (from the target event's Invoke function) and then creating a DynamicMethod to call the JS function, using ILGenerator.EmitCall. After hours of trying to do this, I noticed something: calling the JS function requires 3 arguments (first one being null), but I only have 2. Is there a way to load a null value to Ldarg_0 without messing with the arguments of the dynamic method? I took a look at the Opcodes class (not everything obv) and couldn't find any load operations related to that. any suggestions are appreciated because I really don't know what to do now 🙃
36 Replies
Dusty
Dusty2y ago
What exactly are you trying to solve? This seems very over engineered if you just wanna call a js method Can you not use IJSRuntime? Or JsImport/JsExport
blue λ
blue λOP2y ago
I'm trying to load JS files and allow them to register for events using a normal syntax, something like
registerEvent('input.buttonPressed', () => log('a button got pressed'))
registerEvent('input.buttonPressed', () => log('a button got pressed'))
Using Reflection, I can get the event by "walking" the path provided just fine. However, registering the function is the complicated part. I was following a Microsoft tutorial which involved creating an Assembly at runtime, which I judged an overkill and decided to make it a dynamic method instead. However the fact that the signature of the JS function doesn't match CSharp's is stopping me, because there's an argument missing when I use EmitCall. I could just make the first argument an enum, however that'd require a HUGE switch/case mess because there are a lot of events. Also, by doing this, I could also allow reloading those functions by storing the callback and removing it using RemoveEventHandler whenever I need. I am not familiar with those. Are they from Jint? Currently I'm using normal modules and providing a C# class so the script can interact with the rest of the program using higher level code (a.k.a. no interacting directly with c# built-in classes and functions)
Dusty
Dusty2y ago
This Stuff Can you not use it?
blue λ
blue λOP2y ago
does it work with .net core 5.0?
Dusty
Dusty2y ago
.net 7 i think
blue λ
blue λOP2y ago
it's very EOL but I'm stuck to it
Dusty
Dusty2y ago
Hmmm
blue λ
blue λOP2y ago
yeah, can't then
Dusty
Dusty2y ago
So whats the first arg of ur js function?
blue λ
blue λOP2y ago
the javascript function looks like this
const handler = (sender, args) => {}
const handler = (sender, args) => {}
where sender is the event sender and args are the actual data. However, to call it from C#, it's this:
function.Call(null, a, b);
function.Call(null, a, b);
where null is a JS object (don't need it) and a b are JsValue params (C# types get automatically converted to it unless using the ILGen has some weird effect or something)
Dusty
Dusty2y ago
Got it but what's the problem now? Why can you not just keep using null?
blue λ
blue λOP2y ago
this is what the code looks like
blue λ
blue λOP2y ago
and this is what I get
blue λ
blue λOP2y ago
oops accidentally cut the lines but 78 is the CreateDelegate one the most obvious issue here is the fact that the Call method I've got at methodOverload has 3 arguments, while I've only got 2 loaded on my IL stack
Dusty
Dusty2y ago
If not I'd just create a simple method with 3 params like urs and call the method from another one. Then go to sharplab and see what the IL code is
Aaron
Aaron2y ago
the error isnt because you emitted something wrong you're trying to create a delegate that doesnt have the same signature as the dynamic method what is the event handler type, and what arguments does your dynamic method take/what does it return
blue λ
blue λOP2y ago
the dynamic method takes types extracted from the event Invoke function, which would be object for the sender and ButtonPressedArgs for the arg btw the sender is null (not sure if this usual or not) thats useful! thank u so much, its going to save me from implementing a method just for that however as @Windows10CE still doesn't work. the stack thing was going to be an issue but not anymore cant bind to the target method because its signature is not compatible with that of the delegate type
Aaron
Aaron2y ago
could you send the entire method as text you can use $paste if its long
MODiX
MODiX2y ago
If your code is too long, you can post to https://paste.mod.gg/ and copy the link into chat for others to see your shared code!
blue λ
blue λOP2y ago
BlazeBin - adjbcyxauzhs
A tool for sharing your source code with the world!
Aaron
Aaron2y ago
oh i see now you have a typeof(JsVelvet) on the end of your DynamicMethod constructor pretty sure that shouldnt be there actually that seems to not matter nevermind
blue λ
blue λOP2y ago
lemme try taking it out, it's from stuff i was trying out earlier
Aaron
Aaron2y ago
actually why do you have _modEntry on the CreateDelegate yeah thats what it is
blue λ
blue λOP2y ago
it's the target doesn't work without it too if i recall correctly lemme try it
Aaron
Aaron2y ago
adding it to my testing gets me the same exception as you
blue λ
blue λOP2y ago
oh ok, did this before now it says the object does not match the target type when attaching the event handler. thats because of the _modEntry in the AddEventHandler. but setting it to null creates another error, saying the target can only be set as null if the method is static iirc let me try it again yeah, non-static method requires a target
Aaron
Aaron2y ago
what complains about that AddEventHandler or CreateDelegate
blue λ
blue λOP2y ago
the addeventhandler
Aaron
Aaron2y ago
AddEventHandler needs an instance of ev.DeclaringType whatever that happens to be
blue λ
blue λOP2y ago
lemme try with it
Aaron
Aaron2y ago
like if i have
class A
{
event Action TestEvent;
}
class A
{
event Action TestEvent;
}
for TestEvent, you need an instance of A to pass to AddEventHandler
blue λ
blue λOP2y ago
ohhh ok i tried ev.DeclaringType literally lol that worked im cryinggggggg just some il errors now because of the generator thank you so muchhh these have been some interesting 72h of using c# 😭
canton7
canton72y ago
Note, dynamically generating code by building a System.Linq.Expressions.Expression and then .Compile()ing it is a lot easier than doing IL generation. The end result is the same, but it works at a higher level
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server