That you ask for the actual code raises doubts in my mind; however, to save time: ``` using System; using System.Runtime.InteropServices; using System.Text; namespace ConsoleApp1 { class Program { [DllImport("sqlite3.dll", EntryPoint = "sqlite3_exec", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] static extern int sqlite3_exec(IntPtr dbHandle, byte[] sql, Callback callback, string args, out IntPtr errmsg); [DllImport("sqlite3.dll", EntryPoint = "sqlite3_open", CallingConvention = CallingConvention.Cdecl)] static extern int sqlite3_open(string filename, out IntPtr dbPtr); //[MarshalAs(UnmanagedType.LPTStr)] [DllImport("sqlite3.dll", EntryPoint = "sqlite3_close_v2", CallingConvention = CallingConvention.Cdecl)] static extern int sqlite3_close_v2(IntPtr dbHandle);// int sqlite3_close_v2(sqlite3*); internal delegate int Callback(IntPtr p, int n, [In] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 1)] string[] names, [In][MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 1)] string[] values); static void Main(string[] args) { Callback IR = new Callback(IterateResults); IntPtr dbHandle; IntPtr errMsg = IntPtr.Zero; if (0 == sqlite3_open(@"d:\sqlite32\db\chinook.db", out dbHandle)) { int rc = sqlite3_exec(dbHandle, Encoding.Default.GetBytes(@"select * from employees;"), IR, "First Argument of callback", out errMsg); // CAllback on previous line failes!!! } else { Console.WriteLine("failed to open database"); } } public static int IterateResults(IntPtr unused, int n, string[] values, string[] names) { for (int i = 0; i < n; i++) { Console.WriteLine($"{names[i]}={values[i]}"); } return 0; } } } ``` This is a Console Application; using Visual Studio 2017, tested the build with framework 4.7.2, Platform target <i>Any CPU</i> and <i>Prefer 32-bit</i> enabled. If you need to know how to reference SQLite3.DLL version 3.34, [see thread [3] here](https://sqlite.org/forum/forumpost/f5e7f7f368?t=h).