summaryrefslogtreecommitdiff
path: root/tests/src/Interop/NativeCallable/NativeCallableTest.cs
blob: 0dcc184b4a65d2fd9eec237c12cb9d9cdc76408e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Threading;

public class Program
{
    public static class NativeMethods
    {
        [DllImport("NativeCallableDll")]
        public static extern int CallManagedAdd(IntPtr callbackProc, int n);
    }

    private delegate int IntNativeMethodInvoker();    
    private delegate void NativeMethodInvoker();

    public static int Main()
    {
        int ret;
        //NegativeTest_NonBlittable();
        ret = TestNativeCallableValid();
        if (ret != 100)
            return ret;
        //NegativeTest_ViaDelegate();
        //NegativeTest_ViaLdftn();
        return 100;
    }

    public static int TestNativeCallableValid()
    {
        /*
           void TestNativeCallable()
           {
                   .locals init ([0] native int ptr)
                   IL_0000:  nop  
                   IL_0002:  ldftn      int32 CallbackMethod(int32)

                   IL_0012:  stloc.0
                   IL_0013:  ldloc.0
                   IL_0014:  ldc.i4     100
                   IL_0019:  call       bool NativeMethods::CallNativeAdd(native int, int)
                   IL_001e:  pop
                   IL_001f:  ret
             }
           */
        DynamicMethod testNativeCallable = new DynamicMethod("TestNativeCallable", typeof(int), null, typeof(Program).Module);
        ILGenerator il = testNativeCallable.GetILGenerator();
        il.DeclareLocal(typeof(IntPtr));
        il.Emit(OpCodes.Nop);

        // Get native function pointer of the callback
        il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod("ManagedAddCallback"));
        il.Emit(OpCodes.Stloc_0);
        il.Emit(OpCodes.Ldloc_0);

        // return 111+100
        il.Emit(OpCodes.Ldc_I4, 111);
        il.Emit(OpCodes.Call, typeof(NativeMethods).GetMethod("CallManagedAdd"));
        il.Emit(OpCodes.Ret);
        IntNativeMethodInvoker testNativeMethod = (IntNativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(IntNativeMethodInvoker));
        if (testNativeMethod() != 211)
            return 0;
        return 100;
    }

    public static void NegativeTest_ViaDelegate()
    {
        // Try invoking method directly 
        try
        {
            Func<int, int> invoker = ManagedAddCallback;
            invoker(0);
        }
        catch (Exception)
        {

        }
    }

    public static void NegativeTest_NonBlittable()
    {
        // Try invoking method directly 
        try
        {
            Func<bool, int> invoker = CallbackMethodNonBlitabble;
            invoker(true);
        }
        catch (Exception)
        {
            Console.WriteLine(":bla");
        }
    }


    public static void NegativeTest_ViaLdftn()
    {
        /*
           .locals init (native int V_0)
           IL_0000:  nop
           IL_0001:  ldftn      void ConsoleApplication1.Program::callback(int32)
           IL_0007:  stloc.0
           IL_0008:  ldc.i4.s   12
           IL_000a:  ldloc.0
           IL_000b:  calli      void(int32)
           IL_0010:  nop
           IL_0011:  ret
       */
        DynamicMethod testNativeCallable = new DynamicMethod("TestNativeCallableLdftn", null, null, typeof(Program).Module);
        ILGenerator il = testNativeCallable.GetILGenerator();
        il.DeclareLocal(typeof(IntPtr));
        il.Emit(OpCodes.Nop);
        il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod("LdftnCallback"));
        il.Emit(OpCodes.Stloc_0);
        il.Emit(OpCodes.Ldc_I4,12);
        il.Emit(OpCodes.Ldloc_0);

        SignatureHelper sig =  SignatureHelper.GetMethodSigHelper(typeof(Program).Module, null, new Type[] { typeof(int) });
        sig.AddArgument(typeof(int));

        // il.EmitCalli is not available  and the below is not correct
        il.Emit(OpCodes.Calli,sig);
        il.Emit(OpCodes.Nop);
        il.Emit(OpCodes.Ret);

        NativeMethodInvoker testNativeMethod = (NativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(NativeMethodInvoker));
        testNativeMethod();

    }

    #region callbacks
    [NativeCallable]
    public static void LdftnCallback(int val)
    {
    }

    [NativeCallable]
    public static int ManagedAddCallback(int n)
    {
        return n + 100;
    }

    [NativeCallable]
    public static int CallbackMethodGeneric<T>(IntPtr hWnd, IntPtr lParam)
    {
        return 1;
    }

    [NativeCallable]
    public static int CallbackMethodNonBlitabble(bool x1)
    {
        return 1;
    }
    #endregion //callbacks

}