An error occurred while loading the file. Please try again.
-
Julien Wadel authored
Reorder freeing memory when Marshalling on Native Windows ID Add import grammar for CS
42618957
/*
LinphoneWrapper.cs
Copyright (C) 2017 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
#if __IOS__
using ObjCRuntime;
#endif
namespace Linphone
{
#region Wrapper specifics
/// <summary>
/// Only contains the LIB_NAME value that represents the library in which all DllImport are made
/// </summary>
public class LinphoneWrapper
{
public const string VERSION = "{{version}}";
#if __IOS__
public const string LIB_NAME = "linphone.framework/linphone";
#elif WINDOWS_UWP
public const string LIB_NAME = "liblinphone"; // With this, it automatically finds liblinphone.dll
#else
public const string LIB_NAME = "linphone"; // With this, it automatically finds liblinphone.so
#endif
#if WINDOWS_UWP
public const string BELLE_SIP_LIB_NAME = "bellesip";
public const string BCTOOLBOX_LIB_NAME = "bctoolbox";
#else
public const string BELLE_SIP_LIB_NAME = LIB_NAME;
public const string BCTOOLBOX_LIB_NAME = LIB_NAME;
#endif
/// https://docs.microsoft.com/fr-fr/xamarin/cross-platform/app-fundamentals/building-cross-platform-applications/platform-divergence-abstraction-divergent-implementation#android
#if __ANDROID__
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern void setAndroidLogHandler();
#endif
#if __IOS__
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern void linphone_iphone_enable_logs();
#endif
/// <summary>
/// Registers the native log handler in Linphone.
/// </summary>
public static void setNativeLogHandler()
{
#if __ANDROID__
setAndroidLogHandler();
#elif __IOS__
linphone_iphone_enable_logs();
#endif
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
}
}
/// <summary>
/// All methods that returns a LinphoneStatus with a value != 0 as an error code in C are translated in C# by throwing a LinphoneException
/// </summary>
#if WINDOWS_UWP
public class LinphoneException : System.Exception
{
public LinphoneException() : base() { }
public LinphoneException(string message) : base(message) { }
public LinphoneException(string message, System.Exception inner) : base(message, inner) { }
}
#else
[Serializable()]
public class LinphoneException : System.Exception
{
public LinphoneException() : base() { }
public LinphoneException(string message) : base(message) { }
public LinphoneException(string message, System.Exception inner) : base(message, inner) { }
protected LinphoneException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
}
#endif
[StructLayout(LayoutKind.Sequential)]
/// <summary>
/// Parent class for a Linphone public objects
/// </summary>
public class LinphoneObject
{
internal IntPtr nativePtr;
internal GCHandle handle;
internal List<IntPtr> string_ptr_list;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void OnLinphoneObjectDataDestroyed(IntPtr data);
[DllImport(LinphoneWrapper.BELLE_SIP_LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
#if WINDOWS_UWP
static extern int belle_sip_object_data_set(IntPtr ptr, string name, IntPtr data, IntPtr cb);
#else
static extern int belle_sip_object_data_set(IntPtr ptr, string name, IntPtr data, OnLinphoneObjectDataDestroyed cb);
#endif
[DllImport(LinphoneWrapper.BELLE_SIP_LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr belle_sip_object_data_get(IntPtr ptr, string name);
[DllImport(LinphoneWrapper.BELLE_SIP_LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr belle_sip_object_ref(IntPtr ptr);
[DllImport(LinphoneWrapper.BELLE_SIP_LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern void belle_sip_object_unref(IntPtr ptr);
[DllImport(LinphoneWrapper.BELLE_SIP_LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern void belle_sip_object_data_remove(IntPtr ptr, string name);
[DllImport(LinphoneWrapper.BCTOOLBOX_LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr bctbx_list_next(IntPtr ptr);
[DllImport(LinphoneWrapper.BCTOOLBOX_LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr bctbx_list_get_data(IntPtr ptr);
[DllImport(LinphoneWrapper.BCTOOLBOX_LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr bctbx_list_append(IntPtr elem, IntPtr data);
~LinphoneObject()
{
//Console.WriteLine("Destroying " + this.ToString());
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
if (nativePtr != IntPtr.Zero) {
//Console.WriteLine("Unreffing " + this.ToString());
belle_sip_object_data_remove(nativePtr, "cs_obj");
belle_sip_object_unref(nativePtr);
handle.Free();
}
}
internal static T fromNativePtr<T>(IntPtr ptr, bool takeRef=true) where T : LinphoneObject, new()
{
if (ptr == IntPtr.Zero) return null;
IntPtr objPtr = belle_sip_object_data_get(ptr, "cs_obj");
if (objPtr != IntPtr.Zero)
{
T obj = null;
GCHandle handle = GCHandle.FromIntPtr(objPtr);
if (handle.IsAllocated)
{
obj = (T)handle.Target;
}
if (obj == null)
{
//Console.WriteLine("Handle target is null " + handle.Target);
objPtr = IntPtr.Zero;
}
else
{
//Console.WriteLine("Using existing " + obj.ToString());
return obj;
}
}
if (objPtr == IntPtr.Zero)
{
T obj = new T();
//Console.WriteLine("Creating " + obj.ToString());
if (takeRef)
{
ptr = belle_sip_object_ref(ptr);
//Console.WriteLine("Reffing " + obj.ToString());
}
obj.nativePtr = ptr;
obj.handle = GCHandle.Alloc(obj, GCHandleType.WeakTrackResurrection);
objPtr = GCHandle.ToIntPtr(obj.handle);
#if WINDOWS_UWP
belle_sip_object_data_set(ptr, "cs_obj", objPtr, IntPtr.Zero);
#else
belle_sip_object_data_set(ptr, "cs_obj", objPtr, null);
#endif
return obj;
}
return null;
}
internal static IEnumerable<string> MarshalStringArray(IntPtr listPtr)
{
if (listPtr != IntPtr.Zero)
{
IntPtr ptr = listPtr;
while (ptr != IntPtr.Zero)
{
IntPtr dataPtr = bctbx_list_get_data(ptr);
if (dataPtr == IntPtr.Zero)
{
break;
}
string key = Marshal.PtrToStringAnsi(dataPtr);
yield return key;
ptr = bctbx_list_next(ptr);
}
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
}
}
internal static IEnumerable<T> MarshalBctbxList<T>(IntPtr listPtr) where T : LinphoneObject, new()
{
if (listPtr != IntPtr.Zero)
{
IntPtr ptr = listPtr;
while (ptr != IntPtr.Zero)
{
IntPtr dataPtr = bctbx_list_get_data(ptr);
if (dataPtr == IntPtr.Zero)
{
break;
}
T obj = fromNativePtr<T>(dataPtr);
yield return obj;
ptr = bctbx_list_next(ptr);
}
}
}
internal protected IntPtr StringArrayToBctbxList(IEnumerable<string> stringlist)
{
IntPtr bctbx_list = IntPtr.Zero;
string_ptr_list = new List<IntPtr>();
foreach (string s in stringlist)
{
IntPtr string_ptr = Marshal.StringToHGlobalAnsi(s);
bctbx_list = bctbx_list_append(bctbx_list, string_ptr);
string_ptr_list.Add(string_ptr);
}
return bctbx_list;
}
internal protected void CleanStringArrayPtrs()
{
foreach (IntPtr string_ptr in string_ptr_list)
{
Marshal.FreeHGlobal(string_ptr);
}
}
internal static IntPtr ObjectArrayToBctbxList<T>(IEnumerable<T> objlist) where T : LinphoneObject, new()
{
IntPtr bctbx_list = IntPtr.Zero;
foreach (T ptr in objlist)
{
bctbx_list = bctbx_list_append(bctbx_list, ptr.nativePtr);
}
return bctbx_list;
}
}
public class MediastreamerFactory
{
public IntPtr nativePtr;
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern int ms_factory_enable_filter_from_name(IntPtr nativePtr, string name, char enabled);
public void enableFilterFromName(string name, bool enabled)
{
ms_factory_enable_filter_from_name(nativePtr, name, enabled ? (char)1 : (char)0);
}
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern void ms_devices_info_add(IntPtr devices_info, string manufacturer, string model, string platform, uint flags, int delay, int recommended_rate);
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
static extern IntPtr ms_factory_get_devices_info(IntPtr factory);
public void addDevicesInfo(string manufacturer, string model, string platform, uint flags, int delay, int recommended_rate)
{
ms_devices_info_add(ms_factory_get_devices_info(nativePtr), manufacturer, model, platform, flags, delay, recommended_rate);
}
}
#endregion
#region Enums
{{#enums}}
{{#enum}}
{{#doc}}
{{#lines}}
/// {{{line}}}
{{/lines}}
{{/doc}}{{#isFlag}}[Flags]{{/isFlag}}
public enum {{enumName}}
{
{{#values}}
{{#doc}}
{{#lines}}
/// {{{line}}}
{{/lines}}
{{/doc}}
{{name}} = {{{value}}},
{{/values}}
}
{{/enum}}
{{/enums}}
#endregion
#region Listeners
{{#interfaces}}
{{#interface}}
[StructLayout(LayoutKind.Sequential)]
public class {{interfaceName}} : LinphoneObject
{
~{{interfaceName}}()
{
unregister();
}
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern void {{set_user_data_name}}(IntPtr thiz, IntPtr listener);
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr {{get_user_data_name}}(IntPtr thiz);
{{#methods}}
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
{{#cb_setter}}
#if WINDOWS_UWP
static extern void {{name}}(IntPtr thiz, IntPtr cb);
#else
static extern void {{name}}(IntPtr thiz, {{name_private}} cb);
#endif
{{/cb_setter}}
{{#delegate}}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void {{name_private}}({{params_private}});
public delegate void {{name_public}}({{{params_public}}});
private {{name_private}} {{var_private}};
private {{name_public}} {{var_public}};
#if __IOS__
[MonoPInvokeCallback(typeof({{name_private}}))]
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
#endif
private static void {{cb_name}}({{params_private}})
{
{{interfaceClassName}} thiz = fromNativePtr<{{interfaceClassName}}>({{first_param}});
{{interfaceName}} current_listener = thiz.CurrentCallbacks;
if (current_listener != null)
{
current_listener.{{var_public}}?.Invoke({{{params}}});
}
}
public {{name_public}} {{name}}
{
get
{
return {{var_public}};
}
set
{
{{var_public}} = value;
#if WINDOWS_UWP
{{var_private}} = {{cb_name}};
IntPtr cb = Marshal.GetFunctionPointerForDelegate({{var_private}});
{{c_name_setter}}(nativePtr, cb);
#else
{{c_name_setter}}(nativePtr, {{cb_name}});
#endif
}
}
{{/delegate}}
{{/methods}}
internal void register() {
IntPtr listener = {{get_user_data_name}}(nativePtr);
if (listener == IntPtr.Zero)
{
GCHandle _handle = GCHandle.Alloc(this, GCHandleType.Normal);
listener = GCHandle.ToIntPtr(_handle);
} else
{
GCHandle _handle = GCHandle.FromIntPtr(listener);
if (_handle.Target == this)
{
return;
} else
{
_handle.Free();
_handle = GCHandle.Alloc(this, GCHandleType.Normal);
listener = GCHandle.ToIntPtr(_handle);
}
}
{{set_user_data_name}}(nativePtr, listener);
}
internal void unregister() {
IntPtr listener = {{get_user_data_name}}(nativePtr);
{{set_user_data_name}}(nativePtr, IntPtr.Zero);
if (listener != IntPtr.Zero)
{
GCHandle.FromIntPtr(listener).Free();
}
}
}
{{/interface}}
{{/interfaces}}
#endregion
#region Classes
{{#classes}}
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
{{#_class}}
{{#doc}}
{{#lines}}
/// {{{line}}}
{{/lines}}
{{/doc}}
[StructLayout(LayoutKind.Sequential)]
public class {{className}} : LinphoneObject
{
{{#isLinphoneFactory}}
#if __ANDROID__
static Factory()
{
Java.Lang.JavaSystem.LoadLibrary("c++_shared");
Java.Lang.JavaSystem.LoadLibrary("bctoolbox");
Java.Lang.JavaSystem.LoadLibrary("ortp");
Java.Lang.JavaSystem.LoadLibrary("mediastreamer");
Java.Lang.JavaSystem.LoadLibrary("linphone");
}
#endif
{{/isLinphoneFactory}}
{{#isLinphoneCall}}
/// Get the native window handle of the video window, casted as an unsigned long.
public string NativeVideoWindowIdString
{
get
{
return Marshal.PtrToStringUni(linphone_call_get_native_video_window_id(nativePtr));
}
set
{
IntPtr string_ptr_to_remove = linphone_call_get_native_video_window_id(nativePtr);
IntPtr string_ptr = Marshal.StringToHGlobalUni(value);
linphone_call_set_native_video_window_id(nativePtr, string_ptr);
if(string_ptr_to_remove != IntPtr.Zero)
Marshal.FreeHGlobal(string_ptr_to_remove);
}
}
{{/isLinphoneCall}}
{{#isLinphoneCore}}
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr linphone_core_get_ms_factory(IntPtr thiz);
public MediastreamerFactory MsFactory {
get
{
IntPtr ptr = linphone_core_get_ms_factory(nativePtr);
MediastreamerFactory factory = new MediastreamerFactory();
factory.nativePtr = ptr;
return factory;
}
}
/// Get the native window handle of the video window.
public string NativeVideoWindowIdString
{
get
{
return Marshal.PtrToStringUni(linphone_core_get_native_video_window_id(nativePtr));
}
set
{
IntPtr string_ptr_to_remove = linphone_core_get_native_video_window_id(nativePtr);
if(string_ptr_to_remove != IntPtr.Zero)
Marshal.FreeHGlobal(string_ptr_to_remove);
IntPtr string_ptr = Marshal.StringToHGlobalUni(value);
linphone_core_set_native_video_window_id(nativePtr, string_ptr);
}
}
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
/// Get the native window handle of the video preview window.
public string NativePreviewWindowIdString
{
get
{
return Marshal.PtrToStringUni(linphone_core_get_native_preview_window_id(nativePtr));
}
set
{
IntPtr string_ptr_to_remove = linphone_core_get_native_preview_window_id(nativePtr);
if(string_ptr_to_remove != IntPtr.Zero)
Marshal.FreeHGlobal(string_ptr_to_remove);
IntPtr string_ptr = Marshal.StringToHGlobalUni(value);
linphone_core_set_native_preview_window_id(nativePtr, string_ptr);
}
}
{{/isLinphoneCore}}
{{#listener}}
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr linphone_factory_create_{{listener_constructor}}_cbs(IntPtr factory);
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr linphone_{{listener_constructor}}_add_callbacks(IntPtr thiz, IntPtr cbs);
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr linphone_{{listener_constructor}}_remove_callbacks(IntPtr thiz, IntPtr cbs);
~{{className}}()
{
if (listener != null)
{
linphone_{{listener_constructor}}_remove_callbacks(nativePtr, listener.nativePtr);
}
}
private {{interfaceName}} listener;
public {{interfaceName}} Listener
{
get {
if (listener == null)
{
IntPtr nativeListener = linphone_factory_create_{{listener_constructor}}_cbs(IntPtr.Zero);
listener = fromNativePtr<{{interfaceName}}>(nativeListener, false);
linphone_{{listener_constructor}}_add_callbacks(nativePtr, nativeListener);
listener.register();
}
return listener;
}
}
{{/listener}}
{{#dllImports}}
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
{{{prototype}}}
{{#has_second_prototype}}
[DllImport(LinphoneWrapper.LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
{{second_prototype}}
{{/has_second_prototype}}
{{#has_property}}
{{#doc}}
{{#lines}}
/// {{{line}}}
{{/lines}}
{{/doc}}
{{property_static}}public {{{property_return}}} {{property_name}}
{
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
{{#has_getter}}
get
{
{{#is_string}}
IntPtr stringPtr = {{getter_c_name}}({{getter_nativePtr}});
return Marshal.PtrToStringAnsi(stringPtr);
{{/is_string}}
{{#is_bool}}
return {{getter_c_name}}({{getter_nativePtr}}) != 0;
{{/is_bool}}
{{#is_class}}
IntPtr ptr = {{getter_c_name}}({{getter_nativePtr}});
{{{property_return}}} obj = fromNativePtr<{{return}}>(ptr, {{takeRef}});
return obj;
{{/is_class}}
{{#is_enum}}
return {{getter_c_name}}({{getter_nativePtr}});
{{/is_enum}}
{{#is_generic}}
return {{getter_c_name}}({{getter_nativePtr}});
{{/is_generic}}
{{#is_string_list}}
return MarshalStringArray({{getter_c_name}}({{getter_nativePtr}}));
{{/is_string_list}}
{{#is_class_list}}
return MarshalBctbxList<{{{list_type}}}>({{getter_c_name}}({{getter_nativePtr}}));
{{/is_class_list}}
}
{{/has_getter}}
{{#has_setter}}
set
{
{{#is_string}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value);
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_string}}
{{#is_bool}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value ? (char)1 : (char)0);
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_bool}}
{{#is_class}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value.nativePtr);
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_class}}
{{#is_enum}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}(int)value);
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_enum}}
{{#is_generic}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value);
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_generic}}
{{#is_string_list}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}StringArrayToBctbxList(value));
CleanStringArrayPtrs();
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_string_list}}
{{#is_class_list}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}ObjectArrayToBctbxList<{{{list_type}}}>(value));
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_class_list}}
}
{{/has_setter}}
}
{{/has_property}}
{{#has_impl}}
{{#impl}}
{{#doc}}
{{#lines}}
/// {{{line}}}
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
{{/lines}}
{{/doc}}
public {{static}}{{override}}{{{type}}} {{name}}({{{args}}})
{
{{#is_string}}
IntPtr stringPtr = {{c_name}}({{nativePtr}}{{{c_args}}});
string returnVal = Marshal.PtrToStringAnsi(stringPtr);
{{/is_string}}
{{#is_bool}}
{{#hasReturn}}bool returnVal = {{/hasReturn}}{{c_name}}({{nativePtr}}{{{c_args}}}) == (char)0 ? false : true;
{{/is_bool}}
{{#is_class}}
IntPtr ptr = {{c_name}}({{nativePtr}}{{{c_args}}});
{{type}} returnVal = fromNativePtr<{{type}}>(ptr, {{takeRef}});
{{/is_class}}
{{#is_enum}}
{{#exception}}int exception_result = {{/exception}}{{#hasReturn}}{{{type}}} returnVal = {{/hasReturn}}{{c_name}}({{nativePtr}}{{{c_args}}});
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{name}} returned value " + exception_result);{{/exception}}
{{/is_enum}}
{{#is_generic}}
{{#exception}}int exception_result = {{/exception}}{{#hasReturn}}{{{type}}} returnVal = {{/hasReturn}}{{c_name}}({{nativePtr}}{{{c_args}}});
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{name}} returned value" + exception_result);{{/exception}}
{{/is_generic}}
{{#is_string_list}}
IEnumerable<string> returnVal = MarshalStringArray({{c_name}}({{nativePtr}}{{{c_args}}}));
{{/is_string_list}}
{{#is_class_list}}
IEnumerable<{{{list_type}}}> returnVal = MarshalBctbxList<{{{list_type}}}>({{c_name}}({{nativePtr}}{{{c_args}}}));
{{/is_class_list}}
{{#clean_string_list_ptrs}}CleanStringArrayPtrs();{{/clean_string_list_ptrs}}
{{#hasReturn}}return returnVal;{{/hasReturn}}
}
{{/impl}}
{{/has_impl}}
{{/dllImports}}
}
{{/_class}}
{{/classes}}
#endregion
}