diff --git a/RimeSharp/Rime.cs b/RimeSharp/Rime.cs index 093df8a..1d2cb82 100644 --- a/RimeSharp/Rime.cs +++ b/RimeSharp/Rime.cs @@ -342,14 +342,22 @@ public RimeCandidate[] GetCandidates(RimeSessionId sessionId, int start = 0, int { var iterator = new RimeCandidateListIterator(); if (!_api.CandidateListFromIndex(sessionId, ref iterator, start)) return []; + var candidates = new List(); - var i = 0; - while (i < count && _api.CandidateListNext(ref iterator)) + try + { + var i = 0; + while (i < count && _api.CandidateListNext(ref iterator)) + { + candidates.Add(iterator.Candidate); + ++i; + } + } + finally { - candidates.Add(iterator.Candidate); - ++i; + _api.CandidateListEnd(ref iterator); } - _api.CandidateListEnd(ref iterator); + return [.. candidates]; } diff --git a/RimeSharp/RimeCustomSettings.cs b/RimeSharp/RimeCustomSettings.cs index 83a57c6..6dfdcb1 100644 --- a/RimeSharp/RimeCustomSettings.cs +++ b/RimeSharp/RimeCustomSettings.cs @@ -28,15 +28,22 @@ public class RimeSwitcherSettings() : RimeCustomSettings(s_api.SwitcherSettingsI private RimeSchemaListItem[] GetSchemaList(SchemaListAccess access) { if (!access(handle, out var list)) return []; - var size = Marshal.SizeOf(); - var items = new RimeSchemaListItem[(int)list.Size]; - for (var i = 0; i < (int)list.Size; ++i) + + try + { + var size = Marshal.SizeOf(); + var items = new RimeSchemaListItem[(int)list.Size]; + for (var i = 0; i < (int)list.Size; ++i) + { + var ptr = IntPtr.Add(list.List, i * size); + items[i] = Marshal.PtrToStructure(ptr); + } + return items; + } + finally { - var ptr = IntPtr.Add(list.List, i * size); - items[i] = Marshal.PtrToStructure(ptr); + s_api.SchemaListDestroy(ref list); } - s_api.SchemaListDestroy(ref list); - return items; } public RimeSchemaListItem[] GetAvailableSchemaList() @@ -47,4 +54,4 @@ public RimeSchemaListItem[] GetSelectedSchemaList() public bool SelectSchemas(string[] schemaIdList) => s_api.SelectSchemas(handle, schemaIdList, schemaIdList.Length); -} \ No newline at end of file +} diff --git a/RimeSharp/RimeLevers.cs b/RimeSharp/RimeLevers.cs index b800ff0..6dd8384 100644 --- a/RimeSharp/RimeLevers.cs +++ b/RimeSharp/RimeLevers.cs @@ -57,7 +57,7 @@ internal bool GetAvailableSchemaList(IntPtr ptr, out RimeSchemaList list) => _levers.GetAvailableSchemaList(ptr, out list); internal bool GetSelectedSchemaList(IntPtr ptr, out RimeSchemaList list) - => _levers.GetAvailableSchemaList(ptr, out list); + => _levers.GetSelectedSchemaList(ptr, out list); internal void SchemaListDestroy(ref RimeSchemaList list) => _levers.SchemaListDestroy(ref list); diff --git a/RimeSharp/RimeStructs.cs b/RimeSharp/RimeStructs.cs index 3792982..009d14c 100644 --- a/RimeSharp/RimeStructs.cs +++ b/RimeSharp/RimeStructs.cs @@ -214,9 +214,29 @@ public struct RimeCandidateListIterator { public UIntPtr Ptr; public int Index; + // librime owns these pointers and replaces them during iteration. + private NativeRimeCandidate _candidate; - [MarshalAs(UnmanagedType.Struct)] - public RimeCandidate Candidate; + public readonly RimeCandidate Candidate => _candidate.ToManaged(); + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NativeRimeCandidate + { + internal IntPtr Text; + internal IntPtr Comment; + private readonly IntPtr _reserved; + + internal readonly RimeCandidate ToManaged() + { + return new RimeCandidate + { + Text = UTF8Marshal.PtrToStringUTF8(Text), + Comment = Comment == IntPtr.Zero + ? null + : UTF8Marshal.PtrToStringUTF8(Comment), + }; + } } [StructLayout(LayoutKind.Sequential)]