public void CompileProgram(Device[] devices, string options, Tuple <Program, string>[] headers, Action <Program, object> notify, object user_data) { unsafe { var devices_length = devices == null ? 0 : devices.Length; var device_list = stackalloc IntPtr[devices_length]; for (int i = 0; i < devices_length; ++i) { device_list[i] = devices[i].Handle; } device_list = devices_length == 0 ? null : device_list; int length = options == null ? 0 : Encoding.ASCII.GetByteCount(options); byte *chars = stackalloc byte[length + 1]; if (options != null) { fixed(char *options_ptr = options) { Encoding.ASCII.GetBytes(options_ptr, options.Length, chars, length); } chars[length] = 0; //null terminator } else { chars = null; } var num_headers = headers == null ? 0 : headers.Length; IntPtr *input_headers = stackalloc IntPtr[num_headers]; byte ** header_include_names = stackalloc byte *[num_headers]; for (int i = 0; i < num_headers; ++i) { input_headers[i] = headers[i].Item1.Handle; var name = headers[i].Item2; var header_length = Encoding.ASCII.GetByteCount(name); byte *header_chars = (byte *)Marshal.AllocHGlobal(length + 1).ToPointer(); fixed(char *name_ptr = name) { Encoding.ASCII.GetBytes(name_ptr, name.Length, header_chars, header_length); } header_chars[header_length] = 0; //null terminator header_include_names[i] = header_chars; } if (headers == null) { input_headers = null; header_include_names = null; } var function_ptr = IntPtr.Zero; var data_ptr = new GCHandle(); if (notify != null) { var data = Tuple.Create(notify, user_data); data_ptr = GCHandle.Alloc(data); function_ptr = Marshal.GetFunctionPointerForDelegate(new CallbackDelegate(Callback)); } try { ClHelper.GetError(Cl.CompileProgram(Handle, (uint)devices_length, device_list, chars, (uint)num_headers, input_headers, header_include_names, function_ptr, GCHandle.ToIntPtr(data_ptr).ToPointer())); } catch (Exception) { data_ptr.Free(); throw; } finally { for (int i = 0; i < num_headers; ++i) { Marshal.FreeHGlobal(new IntPtr(header_include_names[i])); } } } }