feat: finish basic function of BMapSharp.
- fix weird C sharp behavior about calling FreeNativeData without calling ManagedToNative, which cause segment fault. - disable unhandled exception handler in debug mode for BMap. - change all associated code involving these issues.
This commit is contained in:
parent
3566efa36a
commit
b319e0fcb6
@ -55,7 +55,7 @@ bool BMInit() {
|
|||||||
if (CheckInited()) return false;
|
if (CheckInited()) return false;
|
||||||
|
|
||||||
// register exception handler if we are in Windows.
|
// register exception handler if we are in Windows.
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
#if defined(LIBCMO_BUILD_RELEASE) && (YYCC_OS == YYCC_OS_WINDOWS)
|
||||||
YYCC::ExceptionHelper::Register();
|
YYCC::ExceptionHelper::Register();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ bool BMDispose() {
|
|||||||
LibCmo::CK2::CKShutdown();
|
LibCmo::CK2::CKShutdown();
|
||||||
|
|
||||||
// unregister exception handler if we are in Windows
|
// unregister exception handler if we are in Windows
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
#if defined(LIBCMO_BUILD_RELEASE) && (YYCC_OS == YYCC_OS_WINDOWS)
|
||||||
YYCC::ExceptionHelper::Unregister();
|
YYCC::ExceptionHelper::Unregister();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -19,10 +19,6 @@ namespace BMapSharp {
|
|||||||
|
|
||||||
public static class BMap {
|
public static class BMap {
|
||||||
|
|
||||||
/// <summary>The callback function of BMap.</summary>
|
|
||||||
/// <param name="msg">The message content need to be printed.</param>
|
|
||||||
public delegate void OutputCallback([In, MarshalAs(UnmanagedType.LPUTF8Str)] string msg);
|
|
||||||
|
|
||||||
#region Custom Marshalers
|
#region Custom Marshalers
|
||||||
|
|
||||||
// References:
|
// References:
|
||||||
@ -33,24 +29,38 @@ namespace BMapSharp {
|
|||||||
// Because my binding do not have In, Out parameter. All parameters are In OR Out.
|
// Because my binding do not have In, Out parameter. All parameters are In OR Out.
|
||||||
// So there is no reason to keep that member.
|
// So there is no reason to keep that member.
|
||||||
|
|
||||||
|
// IDK why Microsoft try to call ICustomMarshaler.CleanUpNativeData without calling ICustomMarshaler.MarshalManagedToNative.
|
||||||
|
// It is trying to free the pointer managed by LibCmo self (for example, it will try to free we got string when getting object name)!
|
||||||
|
// So as the compromise, we use "cookie" feature to explicit specify the marshaler In/Out behavior when getting it.
|
||||||
|
[Flags]
|
||||||
|
internal enum MarshalerType {
|
||||||
|
None = 0b0,
|
||||||
|
In = 0b1,
|
||||||
|
Out = 0b10
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>The custom marshaler for BMap string array.</summary>
|
/// <summary>The custom marshaler for BMap string array.</summary>
|
||||||
public class BMStringArrayMarshaler : ICustomMarshaler {
|
public class BMStringArrayMarshaler : ICustomMarshaler {
|
||||||
private static readonly BMStringArrayMarshaler g_Instance = new BMStringArrayMarshaler();
|
private static readonly BMStringArrayMarshaler g_InInstance = new BMStringArrayMarshaler(MarshalerType.In);
|
||||||
public static ICustomMarshaler GetInstance(string pstrCookie) => g_Instance;
|
private static readonly BMStringArrayMarshaler g_OutInstance = new BMStringArrayMarshaler(MarshalerType.Out);
|
||||||
|
public static ICustomMarshaler GetInstance(string pstrCookie) {
|
||||||
|
if (pstrCookie == "In") return g_InInstance;
|
||||||
|
else if (pstrCookie == "Out") return g_OutInstance;
|
||||||
|
else throw new MarshalDirectiveException("Not supported cookie string for BMStringArrayMarshaler.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly MarshalerType m_MarshalerType;
|
||||||
|
private BMStringArrayMarshaler(MarshalerType marshaler_type) {
|
||||||
|
m_MarshalerType = marshaler_type;
|
||||||
|
}
|
||||||
|
|
||||||
// For respecting the standard of BMap,
|
// For respecting the standard of BMap,
|
||||||
// the native memory we created is a simple array and each item is a pointer to a NULL-terminated UTF8 string.
|
// the native memory we created is a simple array and each item is a pointer to a NULL-terminated UTF8 string.
|
||||||
// Please note the array self is not NULL-terminated because its length is provided by another argument in function calling.
|
// Please note the array self is also NULL-terminated otherwise we don't know its length.
|
||||||
// However, this memory layout is not good for our marshaling.
|
|
||||||
// We can not know the size of array we created. Because we need iterate it when freeing or fetching data.
|
|
||||||
// We also can not know the size of string we created because we need read them when parsing them to C# string.
|
|
||||||
//
|
|
||||||
// So the solution we made is adding an uint32_t header before the array to indicate the size of array.
|
|
||||||
// And also add an uint32_t header for each string to indicate the length of string (in bytes, NULL exclusive).
|
|
||||||
// So the pointer put in array is not the address we allocated, it has an offset.
|
|
||||||
// Also we return native pointer is not the address we allocated, it also has an offset.
|
|
||||||
|
|
||||||
public nint MarshalManagedToNative(object ManagedObj) {
|
public nint MarshalManagedToNative(object ManagedObj) {
|
||||||
|
// Check marshaler type
|
||||||
|
if (!m_MarshalerType.HasFlag(MarshalerType.In)) return nint.Zero;
|
||||||
// Check nullptr object.
|
// Check nullptr object.
|
||||||
if (ManagedObj is null) return nint.Zero;
|
if (ManagedObj is null) return nint.Zero;
|
||||||
// Check argument type.
|
// Check argument type.
|
||||||
@ -72,7 +82,7 @@ namespace BMapSharp {
|
|||||||
// Allocate array pointer now.
|
// Allocate array pointer now.
|
||||||
nint pArray = Marshal.AllocHGlobal(szArrayItemSize * (szArrayItemCount + 1));
|
nint pArray = Marshal.AllocHGlobal(szArrayItemSize * (szArrayItemCount + 1));
|
||||||
// Copy string pointer data
|
// Copy string pointer data
|
||||||
Marshal.Copy(apString, 0, pArray, szArrayItemSize * szArrayItemCount);
|
Marshal.Copy(apString, 0, pArray, szArrayItemCount);
|
||||||
// Setup NULL ternimal
|
// Setup NULL ternimal
|
||||||
Marshal.WriteIntPtr(pArray + (szArrayItemSize * szArrayItemCount), nint.Zero);
|
Marshal.WriteIntPtr(pArray + (szArrayItemSize * szArrayItemCount), nint.Zero);
|
||||||
|
|
||||||
@ -81,6 +91,8 @@ namespace BMapSharp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public object MarshalNativeToManaged(nint pNativeData) {
|
public object MarshalNativeToManaged(nint pNativeData) {
|
||||||
|
// Check marshaler type
|
||||||
|
if (!m_MarshalerType.HasFlag(MarshalerType.Out)) return null;
|
||||||
// Check nullptr
|
// Check nullptr
|
||||||
if (pNativeData == nint.Zero) return null;
|
if (pNativeData == nint.Zero) return null;
|
||||||
|
|
||||||
@ -89,7 +101,7 @@ namespace BMapSharp {
|
|||||||
int szArrayItemSize = Marshal.SizeOf<nint>();
|
int szArrayItemSize = Marshal.SizeOf<nint>();
|
||||||
// Prepare array cache and read it.
|
// Prepare array cache and read it.
|
||||||
nint[] apString = new nint[szArrayItemCount];
|
nint[] apString = new nint[szArrayItemCount];
|
||||||
Marshal.Copy(pNativeData, apString, 0, szArrayItemSize * szArrayItemCount);
|
Marshal.Copy(pNativeData, apString, 0, szArrayItemCount);
|
||||||
|
|
||||||
// Iterate the array and process each string one by one.
|
// Iterate the array and process each string one by one.
|
||||||
string[] ret = new string[szArrayItemCount];
|
string[] ret = new string[szArrayItemCount];
|
||||||
@ -109,6 +121,8 @@ namespace BMapSharp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void CleanUpNativeData(nint pNativeData) {
|
public void CleanUpNativeData(nint pNativeData) {
|
||||||
|
// Check marshaler type
|
||||||
|
if (!m_MarshalerType.HasFlag(MarshalerType.In)) return;
|
||||||
// Check nullptr
|
// Check nullptr
|
||||||
if (pNativeData == nint.Zero) return;
|
if (pNativeData == nint.Zero) return;
|
||||||
|
|
||||||
@ -117,7 +131,7 @@ namespace BMapSharp {
|
|||||||
int szArrayItemSize = Marshal.SizeOf<nint>();
|
int szArrayItemSize = Marshal.SizeOf<nint>();
|
||||||
// Prepare array cache and read it.
|
// Prepare array cache and read it.
|
||||||
nint[] apString = new nint[szArrayItemCount];
|
nint[] apString = new nint[szArrayItemCount];
|
||||||
Marshal.Copy(pNativeData, apString, 0, szArrayItemSize * szArrayItemCount);
|
Marshal.Copy(pNativeData, apString, 0, szArrayItemCount);
|
||||||
// Free array self
|
// Free array self
|
||||||
Marshal.FreeHGlobal(pNativeData);
|
Marshal.FreeHGlobal(pNativeData);
|
||||||
|
|
||||||
@ -154,10 +168,22 @@ namespace BMapSharp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class BMStringMarshaler : ICustomMarshaler {
|
public class BMStringMarshaler : ICustomMarshaler {
|
||||||
private static readonly BMStringMarshaler g_Instance = new BMStringMarshaler();
|
private static readonly BMStringMarshaler g_InInstance = new BMStringMarshaler(MarshalerType.In);
|
||||||
public static ICustomMarshaler GetInstance(string pstrCookie) => g_Instance;
|
private static readonly BMStringMarshaler g_OutInstance = new BMStringMarshaler(MarshalerType.Out);
|
||||||
|
public static ICustomMarshaler GetInstance(string pstrCookie) {
|
||||||
|
if (pstrCookie == "In") return g_InInstance;
|
||||||
|
else if (pstrCookie == "Out") return g_OutInstance;
|
||||||
|
else throw new MarshalDirectiveException("Not supported cookie string for BMStringMarshaler.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly MarshalerType m_MarshalerType;
|
||||||
|
private BMStringMarshaler(MarshalerType marshaler_type) {
|
||||||
|
m_MarshalerType = marshaler_type;
|
||||||
|
}
|
||||||
|
|
||||||
public nint MarshalManagedToNative(object ManagedObj) {
|
public nint MarshalManagedToNative(object ManagedObj) {
|
||||||
|
// Check marshaler type
|
||||||
|
if (!m_MarshalerType.HasFlag(MarshalerType.In)) return nint.Zero;
|
||||||
// Check requirements.
|
// Check requirements.
|
||||||
if (ManagedObj is null) return nint.Zero;
|
if (ManagedObj is null) return nint.Zero;
|
||||||
string castManagedObj = ManagedObj as string;
|
string castManagedObj = ManagedObj as string;
|
||||||
@ -168,6 +194,8 @@ namespace BMapSharp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public object MarshalNativeToManaged(nint pNativeData) {
|
public object MarshalNativeToManaged(nint pNativeData) {
|
||||||
|
// Check marshaler type
|
||||||
|
if (!m_MarshalerType.HasFlag(MarshalerType.Out)) return null;
|
||||||
// Check nullptr
|
// Check nullptr
|
||||||
if (pNativeData == nint.Zero) return null;
|
if (pNativeData == nint.Zero) return null;
|
||||||
// Call self
|
// Call self
|
||||||
@ -175,6 +203,8 @@ namespace BMapSharp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void CleanUpNativeData(nint pNativeData) {
|
public void CleanUpNativeData(nint pNativeData) {
|
||||||
|
// Check marshaler type
|
||||||
|
if (!m_MarshalerType.HasFlag(MarshalerType.In)) return;
|
||||||
// Check nullptr
|
// Check nullptr
|
||||||
if (pNativeData == nint.Zero) return;
|
if (pNativeData == nint.Zero) return;
|
||||||
// Free native pointer
|
// Free native pointer
|
||||||
@ -218,7 +248,7 @@ namespace BMapSharp {
|
|||||||
int szStringItemSize = Marshal.SizeOf<byte>();
|
int szStringItemSize = Marshal.SizeOf<byte>();
|
||||||
nint pString = Marshal.AllocHGlobal(szStringItemSize * (szStringItemCount + 1));
|
nint pString = Marshal.AllocHGlobal(szStringItemSize * (szStringItemCount + 1));
|
||||||
// Copy encoded string data
|
// Copy encoded string data
|
||||||
Marshal.Copy(encString, 0, pString, szStringItemSize * szStringItemCount);
|
Marshal.Copy(encString, 0, pString, szStringItemCount);
|
||||||
// Setup NUL
|
// Setup NUL
|
||||||
Marshal.WriteByte(pString + (szStringItemSize * szStringItemCount), (byte)0);
|
Marshal.WriteByte(pString + (szStringItemSize * szStringItemCount), (byte)0);
|
||||||
// Return value
|
// Return value
|
||||||
@ -236,7 +266,7 @@ namespace BMapSharp {
|
|||||||
int szStringItemSize = Marshal.SizeOf<byte>();
|
int szStringItemSize = Marshal.SizeOf<byte>();
|
||||||
// Prepare cache and copy string data
|
// Prepare cache and copy string data
|
||||||
byte[] encString = new byte[szStringItemCount];
|
byte[] encString = new byte[szStringItemCount];
|
||||||
Marshal.Copy(ptr, encString, 0, szStringItemSize * szStringItemCount);
|
Marshal.Copy(ptr, encString, 0, szStringItemCount);
|
||||||
// Decode string and return
|
// Decode string and return
|
||||||
return Encoding.UTF8.GetString(encString);
|
return Encoding.UTF8.GetString(encString);
|
||||||
}
|
}
|
||||||
@ -244,6 +274,10 @@ namespace BMapSharp {
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>The callback function of BMap.</summary>
|
||||||
|
/// <param name="msg">The message content need to be printed.</param>
|
||||||
|
internal delegate void OutputCallback([In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler))] string msg);
|
||||||
|
|
||||||
// Decide the file name of loaded DLL.
|
// Decide the file name of loaded DLL.
|
||||||
|
|
||||||
#if BMAP_OS_WINDOWS
|
#if BMAP_OS_WINDOWS
|
||||||
@ -281,7 +315,7 @@ namespace BMapSharp {
|
|||||||
/// <returns>True if no error, otherwise False.</returns>
|
/// <returns>True if no error, otherwise False.</returns>
|
||||||
[DllImport(g_DllName, EntryPoint = "BMFile_Load", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
[DllImport(g_DllName, EntryPoint = "BMFile_Load", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static extern bool BMFile_Load([In, MarshalAs(UnmanagedType.LPUTF8Str)] string file_name, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string temp_folder, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string texture_folder, [In, MarshalAs(UnmanagedType.FunctionPtr)] OutputCallback raw_callback, [In, MarshalAs(UnmanagedType.U4)] uint encoding_count, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringArrayMarshaler))] string[] encodings, [Out, MarshalAs(UnmanagedType.SysInt)] out IntPtr out_file);
|
internal static extern bool BMFile_Load([In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "In")] string file_name, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "In")] string temp_folder, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "In")] string texture_folder, [In, MarshalAs(UnmanagedType.FunctionPtr)] OutputCallback raw_callback, [In, MarshalAs(UnmanagedType.U4)] uint encoding_count, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringArrayMarshaler), MarshalCookie = "In")] string[] encodings, [Out, MarshalAs(UnmanagedType.SysInt)] out IntPtr out_file);
|
||||||
/// <summary>BMFile_Create</summary>
|
/// <summary>BMFile_Create</summary>
|
||||||
/// <param name="temp_folder">Type: LibCmo::CKSTRING. </param>
|
/// <param name="temp_folder">Type: LibCmo::CKSTRING. </param>
|
||||||
/// <param name="texture_folder">Type: LibCmo::CKSTRING. </param>
|
/// <param name="texture_folder">Type: LibCmo::CKSTRING. </param>
|
||||||
@ -292,7 +326,7 @@ namespace BMapSharp {
|
|||||||
/// <returns>True if no error, otherwise False.</returns>
|
/// <returns>True if no error, otherwise False.</returns>
|
||||||
[DllImport(g_DllName, EntryPoint = "BMFile_Create", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
[DllImport(g_DllName, EntryPoint = "BMFile_Create", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static extern bool BMFile_Create([In, MarshalAs(UnmanagedType.LPUTF8Str)] string temp_folder, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string texture_folder, [In, MarshalAs(UnmanagedType.FunctionPtr)] OutputCallback raw_callback, [In, MarshalAs(UnmanagedType.U4)] uint encoding_count, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringArrayMarshaler))] string[] encodings, [Out, MarshalAs(UnmanagedType.SysInt)] out IntPtr out_file);
|
internal static extern bool BMFile_Create([In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "In")] string temp_folder, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "In")] string texture_folder, [In, MarshalAs(UnmanagedType.FunctionPtr)] OutputCallback raw_callback, [In, MarshalAs(UnmanagedType.U4)] uint encoding_count, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringArrayMarshaler), MarshalCookie = "In")] string[] encodings, [Out, MarshalAs(UnmanagedType.SysInt)] out IntPtr out_file);
|
||||||
/// <summary>BMFile_Save</summary>
|
/// <summary>BMFile_Save</summary>
|
||||||
/// <param name="map_file">Type: BMap::BMFile*. </param>
|
/// <param name="map_file">Type: BMap::BMFile*. </param>
|
||||||
/// <param name="file_name">Type: LibCmo::CKSTRING. </param>
|
/// <param name="file_name">Type: LibCmo::CKSTRING. </param>
|
||||||
@ -302,7 +336,7 @@ namespace BMapSharp {
|
|||||||
/// <returns>True if no error, otherwise False.</returns>
|
/// <returns>True if no error, otherwise False.</returns>
|
||||||
[DllImport(g_DllName, EntryPoint = "BMFile_Save", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
[DllImport(g_DllName, EntryPoint = "BMFile_Save", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static extern bool BMFile_Save([In, MarshalAs(UnmanagedType.SysInt)] IntPtr map_file, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string file_name, [In, MarshalAs(UnmanagedType.U4)] uint texture_save_opt, [In, MarshalAs(UnmanagedType.U1)] bool use_compress, [In, MarshalAs(UnmanagedType.I4)] int compreess_level);
|
internal static extern bool BMFile_Save([In, MarshalAs(UnmanagedType.SysInt)] IntPtr map_file, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "In")] string file_name, [In, MarshalAs(UnmanagedType.U4)] uint texture_save_opt, [In, MarshalAs(UnmanagedType.U1)] bool use_compress, [In, MarshalAs(UnmanagedType.I4)] int compreess_level);
|
||||||
/// <summary>BMFile_Free</summary>
|
/// <summary>BMFile_Free</summary>
|
||||||
/// <param name="map_file">Type: BMap::BMFile*. </param>
|
/// <param name="map_file">Type: BMap::BMFile*. </param>
|
||||||
/// <returns>True if no error, otherwise False.</returns>
|
/// <returns>True if no error, otherwise False.</returns>
|
||||||
@ -537,7 +571,7 @@ namespace BMapSharp {
|
|||||||
/// <returns>True if no error, otherwise False.</returns>
|
/// <returns>True if no error, otherwise False.</returns>
|
||||||
[DllImport(g_DllName, EntryPoint = "BMObject_GetName", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
[DllImport(g_DllName, EntryPoint = "BMObject_GetName", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static extern bool BMObject_GetName([In, MarshalAs(UnmanagedType.SysInt)] IntPtr bmfile, [In, MarshalAs(UnmanagedType.U4)] uint objid, [Out, MarshalAs(UnmanagedType.LPUTF8Str)] out string out_name);
|
internal static extern bool BMObject_GetName([In, MarshalAs(UnmanagedType.SysInt)] IntPtr bmfile, [In, MarshalAs(UnmanagedType.U4)] uint objid, [Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "Out")] out string out_name);
|
||||||
/// <summary>BMObject_SetName</summary>
|
/// <summary>BMObject_SetName</summary>
|
||||||
/// <param name="bmfile">Type: BMap::BMFile*. The pointer to corresponding BMFile.</param>
|
/// <param name="bmfile">Type: BMap::BMFile*. The pointer to corresponding BMFile.</param>
|
||||||
/// <param name="objid">Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.</param>
|
/// <param name="objid">Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.</param>
|
||||||
@ -545,7 +579,7 @@ namespace BMapSharp {
|
|||||||
/// <returns>True if no error, otherwise False.</returns>
|
/// <returns>True if no error, otherwise False.</returns>
|
||||||
[DllImport(g_DllName, EntryPoint = "BMObject_SetName", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
[DllImport(g_DllName, EntryPoint = "BMObject_SetName", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static extern bool BMObject_SetName([In, MarshalAs(UnmanagedType.SysInt)] IntPtr bmfile, [In, MarshalAs(UnmanagedType.U4)] uint objid, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string name);
|
internal static extern bool BMObject_SetName([In, MarshalAs(UnmanagedType.SysInt)] IntPtr bmfile, [In, MarshalAs(UnmanagedType.U4)] uint objid, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "In")] string name);
|
||||||
/// <summary>BMGroup_AddObject</summary>
|
/// <summary>BMGroup_AddObject</summary>
|
||||||
/// <param name="bmfile">Type: BMap::BMFile*. The pointer to corresponding BMFile.</param>
|
/// <param name="bmfile">Type: BMap::BMFile*. The pointer to corresponding BMFile.</param>
|
||||||
/// <param name="objid">Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.</param>
|
/// <param name="objid">Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.</param>
|
||||||
@ -578,7 +612,7 @@ namespace BMapSharp {
|
|||||||
/// <returns>True if no error, otherwise False.</returns>
|
/// <returns>True if no error, otherwise False.</returns>
|
||||||
[DllImport(g_DllName, EntryPoint = "BMTexture_GetFileName", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
[DllImport(g_DllName, EntryPoint = "BMTexture_GetFileName", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static extern bool BMTexture_GetFileName([In, MarshalAs(UnmanagedType.SysInt)] IntPtr bmfile, [In, MarshalAs(UnmanagedType.U4)] uint objid, [Out, MarshalAs(UnmanagedType.LPUTF8Str)] out string out_filename);
|
internal static extern bool BMTexture_GetFileName([In, MarshalAs(UnmanagedType.SysInt)] IntPtr bmfile, [In, MarshalAs(UnmanagedType.U4)] uint objid, [Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "Out")] out string out_filename);
|
||||||
/// <summary>BMTexture_LoadImage</summary>
|
/// <summary>BMTexture_LoadImage</summary>
|
||||||
/// <param name="bmfile">Type: BMap::BMFile*. The pointer to corresponding BMFile.</param>
|
/// <param name="bmfile">Type: BMap::BMFile*. The pointer to corresponding BMFile.</param>
|
||||||
/// <param name="objid">Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.</param>
|
/// <param name="objid">Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.</param>
|
||||||
@ -586,7 +620,7 @@ namespace BMapSharp {
|
|||||||
/// <returns>True if no error, otherwise False.</returns>
|
/// <returns>True if no error, otherwise False.</returns>
|
||||||
[DllImport(g_DllName, EntryPoint = "BMTexture_LoadImage", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
[DllImport(g_DllName, EntryPoint = "BMTexture_LoadImage", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static extern bool BMTexture_LoadImage([In, MarshalAs(UnmanagedType.SysInt)] IntPtr bmfile, [In, MarshalAs(UnmanagedType.U4)] uint objid, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string filename);
|
internal static extern bool BMTexture_LoadImage([In, MarshalAs(UnmanagedType.SysInt)] IntPtr bmfile, [In, MarshalAs(UnmanagedType.U4)] uint objid, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "In")] string filename);
|
||||||
/// <summary>BMTexture_SaveImage</summary>
|
/// <summary>BMTexture_SaveImage</summary>
|
||||||
/// <param name="bmfile">Type: BMap::BMFile*. The pointer to corresponding BMFile.</param>
|
/// <param name="bmfile">Type: BMap::BMFile*. The pointer to corresponding BMFile.</param>
|
||||||
/// <param name="objid">Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.</param>
|
/// <param name="objid">Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.</param>
|
||||||
@ -594,7 +628,7 @@ namespace BMapSharp {
|
|||||||
/// <returns>True if no error, otherwise False.</returns>
|
/// <returns>True if no error, otherwise False.</returns>
|
||||||
[DllImport(g_DllName, EntryPoint = "BMTexture_SaveImage", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
[DllImport(g_DllName, EntryPoint = "BMTexture_SaveImage", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static extern bool BMTexture_SaveImage([In, MarshalAs(UnmanagedType.SysInt)] IntPtr bmfile, [In, MarshalAs(UnmanagedType.U4)] uint objid, [In, MarshalAs(UnmanagedType.LPUTF8Str)] string filename);
|
internal static extern bool BMTexture_SaveImage([In, MarshalAs(UnmanagedType.SysInt)] IntPtr bmfile, [In, MarshalAs(UnmanagedType.U4)] uint objid, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = "In")] string filename);
|
||||||
/// <summary>BMTexture_GetSaveOptions</summary>
|
/// <summary>BMTexture_GetSaveOptions</summary>
|
||||||
/// <param name="bmfile">Type: BMap::BMFile*. The pointer to corresponding BMFile.</param>
|
/// <param name="bmfile">Type: BMap::BMFile*. The pointer to corresponding BMFile.</param>
|
||||||
/// <param name="objid">Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.</param>
|
/// <param name="objid">Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.</param>
|
||||||
|
@ -229,7 +229,7 @@ namespace BMapSharp.BMapWrapper {
|
|||||||
BMapException.ThrowIfFailed(BMap.BMFile_GetMeshCount(this.getPointer(), out uint out_count));
|
BMapException.ThrowIfFailed(BMap.BMFile_GetMeshCount(this.getPointer(), out uint out_count));
|
||||||
return out_count;
|
return out_count;
|
||||||
}
|
}
|
||||||
public IEnumerable<BMMesh> GetMeshs() {
|
public IEnumerable<BMMesh> GetMeshes() {
|
||||||
uint count = GetMeshCount();
|
uint count = GetMeshCount();
|
||||||
for (uint i = 0; i < count; ++i) {
|
for (uint i = 0; i < count; ++i) {
|
||||||
BMapException.ThrowIfFailed(BMap.BMFile_GetMesh(this.getPointer(), i, out uint out_id));
|
BMapException.ThrowIfFailed(BMap.BMFile_GetMesh(this.getPointer(), i, out uint out_id));
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\BMapSharp\BMapSharp.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
@ -1,12 +1,58 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace BMapSharpTestbench {
|
||||||
|
internal class Program {
|
||||||
|
static void Main(string[] args) {
|
||||||
|
// Check environment
|
||||||
|
Console.OutputEncoding = Encoding.UTF8;
|
||||||
|
if (!BMapSharp.BMapWrapper.Utils.IsBMapAvailable()) {
|
||||||
|
Console.WriteLine("Fail to initialize native BMap.");
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Waiting debugger
|
||||||
|
int pid = System.Diagnostics.Process.GetCurrentProcess().Id;
|
||||||
|
Console.WriteLine($"C# PID is {pid}. Waiting debugger, press any key to continue...");
|
||||||
|
Console.ReadKey(true);
|
||||||
|
|
||||||
|
// Start testbench
|
||||||
|
string file_name = "Level_02.NMO";
|
||||||
|
string temp_folder = "Temp";
|
||||||
|
string texture_folder = "F:\\Ballance\\Ballance\\Textures";
|
||||||
|
string[] encodings = ["cp1252", "gb2312"];
|
||||||
|
|
||||||
|
using (var reader = new BMapSharp.BMapWrapper.BMFileReader(file_name, temp_folder, texture_folder, encodings)) {
|
||||||
|
Console.WriteLine("===== Groups =====");
|
||||||
|
foreach (var gp in reader.GetGroups()) {
|
||||||
|
Console.WriteLine(gp.GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("===== 3dObjects =====");
|
||||||
|
foreach (var obj in reader.Get3dObjects()) {
|
||||||
|
Console.WriteLine(obj.GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("===== Meshes =====");
|
||||||
|
foreach (var mesh in reader.GetMeshes()) {
|
||||||
|
Console.WriteLine(mesh.GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("===== Materials =====");
|
||||||
|
foreach (var mtl in reader.GetMaterials()) {
|
||||||
|
Console.WriteLine(mtl.GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("===== Textures =====");
|
||||||
|
foreach (var tex in reader.GetTextures()) {
|
||||||
|
Console.WriteLine(tex.GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("===== Done =====");
|
||||||
|
Console.ReadKey(true);
|
||||||
|
|
||||||
namespace BMapSharpTestbench // Note: actual namespace depends on the project name.
|
|
||||||
{
|
|
||||||
internal class Program
|
|
||||||
{
|
|
||||||
static void Main(string[] args)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Hello World!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ def main() -> None:
|
|||||||
for gp in reader.get_groups():
|
for gp in reader.get_groups():
|
||||||
print(gp.get_name())
|
print(gp.get_name())
|
||||||
|
|
||||||
print('===== Objects =====')
|
print('===== 3dObjects =====')
|
||||||
for obj in reader.get_3dobjects():
|
for obj in reader.get_3dobjects():
|
||||||
print(obj.get_name())
|
print(obj.get_name())
|
||||||
|
|
||||||
|
@ -45,14 +45,22 @@ public class CSharpWriter {
|
|||||||
// use "switch" to check variable type
|
// use "switch" to check variable type
|
||||||
switch (vt_base_type) {
|
switch (vt_base_type) {
|
||||||
case "CKSTRING":
|
case "CKSTRING":
|
||||||
|
// decide direction cookies
|
||||||
|
String direction_cookie = "";
|
||||||
|
if (paramdecl.mIsInput) {
|
||||||
|
direction_cookie = "In";
|
||||||
|
} else {
|
||||||
|
direction_cookie = "Out";
|
||||||
|
}
|
||||||
// only allow 0 and 1 pointer level for string.
|
// only allow 0 and 1 pointer level for string.
|
||||||
switch (vt_pointer_level) {
|
switch (vt_pointer_level) {
|
||||||
case 0:
|
case 0:
|
||||||
ret.mMarshalAs = "UnmanagedType.LPUTF8Str";
|
ret.mMarshalAs = "UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = \"" + direction_cookie + "\"";
|
||||||
|
// ret.mMarshalAs = "UnmanagedType.LPUTF8Str";
|
||||||
ret.mCsType = "string";
|
ret.mCsType = "string";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
ret.mMarshalAs = "UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringArrayMarshaler)";
|
ret.mMarshalAs = "UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringArrayMarshaler), MarshalCookie = \"" + direction_cookie + "\"";
|
||||||
ret.mCsType = "string[]";
|
ret.mCsType = "string[]";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user