@nativescript/windows-jsc 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +55 -0
  2. package/framework/__PROJECT_NAME__/App.xaml +13 -0
  3. package/framework/__PROJECT_NAME__/App.xaml.cs +240 -0
  4. package/framework/__PROJECT_NAME__/Assets/SplashScreen.png +0 -0
  5. package/framework/__PROJECT_NAME__/Assets/Square150x150Logo.png +0 -0
  6. package/framework/__PROJECT_NAME__/Assets/Square44x44Logo.png +0 -0
  7. package/framework/__PROJECT_NAME__/Assets/StoreLogo.png +0 -0
  8. package/framework/__PROJECT_NAME__/Assets/Wide310x150Logo.png +0 -0
  9. package/framework/__PROJECT_NAME__/CrashDiagnostics.cs +281 -0
  10. package/framework/__PROJECT_NAME__/Directory.Build.props +15 -0
  11. package/framework/__PROJECT_NAME__/Directory.Build.targets +106 -0
  12. package/framework/__PROJECT_NAME__/Package.appxmanifest +35 -0
  13. package/framework/__PROJECT_NAME__/Program.cs +34 -0
  14. package/framework/__PROJECT_NAME__/Properties/Default.rd.xml +9 -0
  15. package/framework/__PROJECT_NAME__/RuntimeHost.cs +359 -0
  16. package/framework/__PROJECT_NAME__/__PROJECT_NAME__.csproj +263 -0
  17. package/framework/dotnet-bridge/BinaryProtocol.cs +161 -0
  18. package/framework/dotnet-bridge/Bridge.BinaryDispatch.cs +373 -0
  19. package/framework/dotnet-bridge/Bridge.Dispatch.cs +597 -0
  20. package/framework/dotnet-bridge/Bridge.JsDelegate.cs +244 -0
  21. package/framework/dotnet-bridge/Bridge.Proxy.cs +573 -0
  22. package/framework/dotnet-bridge/Bridge.TaskHelper.cs +207 -0
  23. package/framework/dotnet-bridge/Bridge.cs +724 -0
  24. package/framework/dotnet-bridge/DispatchTypes.cs +333 -0
  25. package/framework/dotnet-bridge/DotNetBridge.csproj +30 -0
  26. package/framework/dotnet-bridge/publish_build/DotNetBridge.deps.json +23 -0
  27. package/framework/dotnet-bridge/publish_build/DotNetBridge.dll +0 -0
  28. package/framework/dotnet-bridge/publish_build/DotNetBridge.pdb +0 -0
  29. package/framework/dotnet-bridge/publish_build/DotNetBridge.runtimeconfig.json +14 -0
  30. package/framework/libs/x64/JavaScriptCore.dll +0 -0
  31. package/framework/libs/x64/icudt77.dll +0 -0
  32. package/framework/libs/x64/icuin77.dll +0 -0
  33. package/framework/libs/x64/icuuc77.dll +0 -0
  34. package/framework/libs/x64/nativescript.dll +0 -0
  35. package/framework/tools/ManifestMerger/ManifestMerger.deps.json +24 -0
  36. package/framework/tools/ManifestMerger/ManifestMerger.dll +0 -0
  37. package/framework/tools/ManifestMerger/ManifestMerger.pdb +0 -0
  38. package/framework/tools/dotnet-tool-arm64.exe +0 -0
  39. package/framework/tools/dotnet-tool-x64.exe +0 -0
  40. package/framework/tools/dotnet-tool.exe +0 -0
  41. package/framework/tools/dotnet-typings-gen/dotnet-typings-gen.deps.json +23 -0
  42. package/framework/tools/dotnet-typings-gen/dotnet-typings-gen.dll +0 -0
  43. package/framework/tools/dotnet-typings-gen/dotnet-typings-gen.exe +0 -0
  44. package/framework/tools/dotnet-typings-gen/dotnet-typings-gen.pdb +0 -0
  45. package/framework/tools/dotnet-typings-gen/dotnet-typings-gen.runtimeconfig.json +13 -0
  46. package/framework/tools/sbg-arm64.exe +0 -0
  47. package/framework/tools/sbg-x64.exe +0 -0
  48. package/framework/tools/sbg.exe +0 -0
  49. package/framework/tools/typings-generator-arm64.exe +0 -0
  50. package/framework/tools/typings-generator-x64.exe +0 -0
  51. package/framework/tools/typings-generator.exe +0 -0
  52. package/package.json +43 -0
@@ -0,0 +1,373 @@
1
+ using System;
2
+ using System.Buffers;
3
+ using System.Collections.Generic;
4
+ using System.Linq;
5
+ using System.Reflection;
6
+ using System.Runtime.InteropServices;
7
+
8
+ namespace NativeScriptBridge;
9
+
10
+ public static partial class Bridge
11
+ {
12
+ // Safe to reuse per thread: the response is copied to unmanaged memory
13
+ // before InvokeBinary returns.
14
+ [ThreadStatic]
15
+ private static ArrayBufferWriter<byte>? t_responseWriter;
16
+
17
+ [UnmanagedCallersOnly(EntryPoint = "InvokeBinary",
18
+ CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])]
19
+ public static unsafe int InvokeBinary(
20
+ byte* requestPtr, int requestLen,
21
+ byte** responsePtr, int* responseLenPtr)
22
+ {
23
+ try
24
+ {
25
+ var r = new BinReader(new ReadOnlySpan<byte>(requestPtr, requestLen));
26
+ var res = DispatchBin(ref r);
27
+ var buf = t_responseWriter ??= new ArrayBufferWriter<byte>(256);
28
+ buf.ResetWrittenCount();
29
+ res.WriteAsBin(buf);
30
+ WriteUnmanaged(buf.WrittenSpan, responsePtr, responseLenPtr);
31
+ }
32
+ catch (Exception ex)
33
+ {
34
+ WriteBinError(Unwrap(ex).Message, responsePtr, responseLenPtr);
35
+ }
36
+ return 0;
37
+ }
38
+
39
+ internal static DispatchResult DispatchBin(ref BinReader r)
40
+ {
41
+ var op = r.ReadByte();
42
+
43
+ if (op == 0x04) // release
44
+ {
45
+ var handleToRemove = r.ReadI32();
46
+ s_handles.TryRemove(handleToRemove, out _);
47
+ if (s_nativePtrs.TryRemove(handleToRemove, out var nativePtr))
48
+ {
49
+ RemoveNativePtr(handleToRemove, nativePtr);
50
+ try
51
+ {
52
+ Marshal.Release(nativePtr);
53
+ }
54
+ catch
55
+ {
56
+ }
57
+ }
58
+ return DispatchResult.Void;
59
+ }
60
+
61
+ if (op == 0x05) // members by handle
62
+ {
63
+ var h = r.ReadI32();
64
+ if (!s_handles.TryGetValue(h, out var obj))
65
+ throw new KeyNotFoundException($"Invalid handle {h}");
66
+ return BuildMembersResult(
67
+ obj?.GetType() ?? throw new InvalidOperationException("Handle is null"));
68
+ }
69
+
70
+ if (op == 0x06) // members by type
71
+ {
72
+ var typeName = r.ReadString16();
73
+ var assembly = r.ReadString16();
74
+ var type = ResolveType(NullIfEmpty(assembly), typeName)
75
+ ?? throw new TypeLoadException($"Type not found: {typeName} (assembly: {assembly})");
76
+ return BuildMembersResult(type);
77
+ }
78
+
79
+ if (op == 0x01) // instance call
80
+ {
81
+ var handle = r.ReadI32();
82
+ if (!s_handles.TryGetValue(handle, out var target))
83
+ throw new KeyNotFoundException($"Invalid handle {handle}");
84
+ var type = target?.GetType() ?? throw new InvalidOperationException("Handle is null");
85
+ var method = r.ReadString16();
86
+ var args = r.ReadArgs();
87
+
88
+ if (method == "__dotnet_await__" && args.Length == 2
89
+ && args[0] is int resolveId && args[1] is int rejectId)
90
+ {
91
+ ScheduleTaskContinuation(handle, resolveId, rejectId);
92
+ return DispatchResult.Void;
93
+ }
94
+
95
+ return DispatchCallBin(target, type, method, args, isStatic: false);
96
+ }
97
+
98
+ if (op == 0x09) // create JS delegate
99
+ {
100
+ var delTypeName = r.ReadString16(); // "" → System.Action
101
+ var callbackId = r.ReadI32();
102
+ return CreateJsDelegate(delTypeName, callbackId);
103
+ }
104
+
105
+ if (op == 0x0A) // create JS-backed subclass instance
106
+ {
107
+ var assembly = r.ReadString16();
108
+ var typeName = r.ReadString16();
109
+
110
+ var interfaceCount = r.ReadI32();
111
+ var interfaceNames = interfaceCount > 0 ? new string[interfaceCount] : [];
112
+ for (int i = 0; i < interfaceCount; i++) interfaceNames[i] = r.ReadString16();
113
+
114
+ var memberCount = r.ReadI32();
115
+ var memberNames = memberCount > 0 ? new string[memberCount] : [];
116
+ for (int i = 0; i < memberCount; i++) memberNames[i] = r.ReadString16();
117
+
118
+ var callbackId = r.ReadI32();
119
+ return CreateJsSubclass(NullIfEmpty(assembly), typeName, callbackId, interfaceNames, memberNames);
120
+ }
121
+
122
+ if (op == 0x0B) // get CLR-only property by raw IInspectable ptr (CLR reflection fallback)
123
+ {
124
+ var instancePtr = new IntPtr(r.ReadI64());
125
+ var propName = r.ReadString16();
126
+ return ClrGetProperty(instancePtr, propName);
127
+ }
128
+
129
+ // Static ops: 0x02 = call, 0x03 = constructor
130
+ var typeNameS = r.ReadString16();
131
+ var assemblyS = r.ReadString16();
132
+ var typeS = ResolveType(NullIfEmpty(assemblyS), typeNameS)
133
+ ?? throw new TypeLoadException($"Type not found: {typeNameS} (assembly: {assemblyS})");
134
+
135
+ if (op == 0x03) // constructor
136
+ {
137
+ var args = r.ReadArgs();
138
+ var entry = GetCachedCtor(typeS, args.Length);
139
+ if (entry.Ctor is null)
140
+ throw new MissingMethodException(
141
+ $"No public ctor on {typeS.FullName} for {args.Length} args");
142
+ // ConstructorInfo.Invoke requires exact arg count — build a precise array.
143
+ var ctorArgs = BuildArgsBinExact(args, entry.Parameters);
144
+ return Box(entry.Ctor.Invoke(ctorArgs));
145
+ }
146
+
147
+ // op == 0x02: static call
148
+ var methodS = r.ReadString16();
149
+ var argsS = r.ReadArgs();
150
+ return DispatchCallBin(null, typeS, methodS, argsS, isStatic: true);
151
+ }
152
+
153
+ private static DispatchResult DispatchCallBin(
154
+ object? target, Type type, string method, object?[] args, bool isStatic)
155
+ {
156
+ var flags = (isStatic ? BindingFlags.Static : BindingFlags.Instance) | BindingFlags.Public;
157
+
158
+
159
+
160
+ if (method.Length > 4
161
+ && method[0] == 'g' && method[1] == 'e' && method[2] == 't' && method[3] == '_')
162
+ {
163
+ var prop = GetCachedProp(type, method, 4, flags);
164
+ if (prop is not null) return Box(prop.GetValue(target));
165
+ }
166
+
167
+ if (method.Length > 4
168
+ && method[0] == 's' && method[1] == 'e' && method[2] == 't' && method[3] == '_'
169
+ && args.Length == 1)
170
+ {
171
+ var prop = GetCachedProp(type, method, 4, flags);
172
+ if (prop is not null)
173
+ {
174
+ prop.SetValue(target, CoerceBin(args[0], prop.PropertyType));
175
+ return DispatchResult.Void;
176
+ }
177
+ }
178
+
179
+ var entry = GetCachedMethod(type, method, args.Length, flags);
180
+ if (entry.Invoke is null)
181
+ {
182
+ var candidates = type.GetMethods(flags).Where(m => m.Name == method && !m.IsSpecialName);
183
+ foreach (var m in candidates)
184
+ {
185
+ var parameters = m.GetParameters();
186
+ var built = BuildArgsBin(args, parameters);
187
+ try
188
+ {
189
+ var res = AwaitIfTask(m.Invoke(target, built));
190
+ return Box(res);
191
+ }
192
+ catch (TargetInvocationException tie) when (IsMarshaledForDifferentThread(tie.InnerException))
193
+ {
194
+ if (Bridge.IsLogToConsole()) Console.Error.WriteLine($"[Bridge] Detected wrong-thread COM error; retrying {type.FullName}.{m.Name} on UI thread");
195
+ try
196
+ {
197
+ var res = InvokeOnUIThread(() => AwaitIfTask(m.Invoke(target, built)));
198
+ return Box(res);
199
+ }
200
+ catch { /* retry failed — try next candidate */ }
201
+ }
202
+ catch (System.Runtime.InteropServices.COMException ce) when (IsMarshaledForDifferentThread(ce))
203
+ {
204
+ if (Bridge.IsLogToConsole()) Console.Error.WriteLine($"[Bridge] Detected COMException wrong-thread; retrying {type.FullName}.{m.Name} on UI thread");
205
+ try
206
+ {
207
+ var res = InvokeOnUIThread(() => AwaitIfTask(m.Invoke(target, built)));
208
+ return Box(res);
209
+ }
210
+ catch { /* retry failed — try next candidate */ }
211
+ }
212
+ finally { if (built.Length > 0) ReturnArgs(built); }
213
+ }
214
+ throw new MissingMethodException(
215
+ $"Method '{method}' ({args.Length} args) not found on {type.FullName}");
216
+ }
217
+
218
+ var builtArgs = BuildArgsBin(args, entry.Parameters);
219
+ try {
220
+ try
221
+ {
222
+ var res = AwaitIfTask(entry.Invoke(target, builtArgs));
223
+ return Box(res);
224
+ }
225
+ catch (TargetInvocationException tie) when (IsMarshaledForDifferentThread(tie.InnerException))
226
+ {
227
+ if (Bridge.IsLogToConsole()) Console.Error.WriteLine($"[Bridge] Detected wrong-thread COM error; retrying {type.FullName}.{method} on UI thread");
228
+ var res = InvokeOnUIThread(() => AwaitIfTask(entry.Invoke(target, builtArgs)));
229
+ return Box(res);
230
+ }
231
+ catch (System.Runtime.InteropServices.COMException ce) when (IsMarshaledForDifferentThread(ce))
232
+ {
233
+ if (Bridge.IsLogToConsole()) Console.Error.WriteLine($"[Bridge] Detected COMException wrong-thread; retrying {type.FullName}.{method} on UI thread");
234
+ var res = InvokeOnUIThread(() => AwaitIfTask(entry.Invoke(target, builtArgs)));
235
+ return Box(res);
236
+ }
237
+ }
238
+ finally { if (builtArgs.Length > 0) ReturnArgs(builtArgs); }
239
+ }
240
+
241
+ private static object?[] BuildArgsBin(object?[] binArgs, ParameterInfo[] parameters)
242
+ {
243
+ if (parameters.Length == 0) return [];
244
+ var result = ArrayPool<object?>.Shared.Rent(parameters.Length);
245
+ for (int i = 0; i < parameters.Length && i < binArgs.Length; i++)
246
+ result[i] = CoerceBin(binArgs[i], parameters[i].ParameterType);
247
+ return result;
248
+ }
249
+
250
+ private static object?[] BuildArgsBinExact(object?[] binArgs, ParameterInfo[] parameters)
251
+ {
252
+ if (parameters.Length == 0) return [];
253
+ var result = new object?[parameters.Length];
254
+ for (int i = 0; i < parameters.Length && i < binArgs.Length; i++)
255
+ result[i] = CoerceBin(binArgs[i], parameters[i].ParameterType);
256
+ return result;
257
+ }
258
+
259
+ private static object? CoerceBin(object? value, Type targetType)
260
+ {
261
+ if (value is null) return null;
262
+ if (value is HandleRef hr)
263
+ {
264
+ s_handles.TryGetValue(hr.Id, out var obj);
265
+ return obj;
266
+ }
267
+ if (value is WinRtRef wr)
268
+ {
269
+ if (wr.Ptr == 0) return null;
270
+ var nativePtr = new IntPtr((long)wr.Ptr);
271
+ // If this native pointer is one that we previously exported (stored
272
+ // in s_nativePtrs), prefer returning the original managed object
273
+ // to preserve identity and avoid creating a new RCW which can
274
+ // fail for CCW pointers. This addresses cases where the runtime
275
+ // round-trips a managed object's canonical IUnknown pointer.
276
+ if (s_nativePtrsReverse.TryGetValue(nativePtr, out var ownerHandle)
277
+ && s_handles.TryGetValue(ownerHandle, out var original))
278
+ {
279
+ return original;
280
+ }
281
+ // 1. Typed QI first: works for COM/CsWinRT interface types that carry a
282
+ // [Guid] attribute. More precise than a generic RCW for strongly-typed
283
+ // parameters such as Windows.UI.Xaml.UIElement.
284
+ if (targetType != typeof(object) && targetType.GUID != Guid.Empty)
285
+ {
286
+ try
287
+ {
288
+ return Marshal.GetTypedObjectForIUnknown(nativePtr, targetType);
289
+ }
290
+ catch (Exception ex)
291
+ {
292
+ if (Bridge.IsLogToConsole())
293
+ {
294
+ try { Console.Error.WriteLine($"[Bridge] GetTypedObjectForIUnknown failed ptr=0x{nativePtr.ToInt64():x} targetType={targetType.FullName}: {ex}"); } catch { }
295
+ }
296
+ }
297
+ }
298
+
299
+ try
300
+ {
301
+ return Marshal.GetObjectForIUnknown(nativePtr);
302
+ }
303
+ catch (Exception ex)
304
+ {
305
+ if (Bridge.IsLogToConsole())
306
+ {
307
+ try
308
+ {
309
+ Console.Error.WriteLine($"[Bridge] GetObjectForIUnknown failed ptr=0x{nativePtr.ToInt64():x} targetType={targetType.FullName} ({targetType.GUID}): {ex}");
310
+ try
311
+ {
312
+ var found = s_nativePtrs.FirstOrDefault(kvp => kvp.Value == nativePtr);
313
+ Console.Error.WriteLine($"[Bridge] s_nativePtrs match: key={found.Key} ptr=0x{found.Value.ToInt64():x}");
314
+ }
315
+ catch { }
316
+ }
317
+ catch { }
318
+ }
319
+ throw;
320
+ }
321
+ }
322
+ if (value.GetType() == targetType) return value;
323
+ try { return Convert.ChangeType(value, targetType); }
324
+ catch { return value; }
325
+ }
326
+
327
+ // CLR reflection fallback for properties that exist only in managed code and are
328
+ // therefore invisible to the WinRT metadata layer (e.g. App.MainWindow on a class
329
+ // that derives from Microsoft.UI.Xaml.Application but adds CLR-only members).
330
+ // Called by binary opcode 0x0B from the Rust runtime's property interceptor.
331
+ // Throws MissingMemberException when the property doesn't exist so the Rust side
332
+ // can distinguish "not found" (0xFF error → kNo) from "found but null" (0x00 → JS null).
333
+ private static DispatchResult ClrGetProperty(IntPtr instancePtr, string propName)
334
+ {
335
+ if (instancePtr == IntPtr.Zero)
336
+ throw new ArgumentException("Null instance pointer");
337
+
338
+ object? target;
339
+ // Prefer the existing managed wrapper (CCW/RCW identity) over creating a new RCW.
340
+ if (s_nativePtrsReverse.TryGetValue(instancePtr, out var ownerHandle)
341
+ && s_handles.TryGetValue(ownerHandle, out target))
342
+ { /* use cached */ }
343
+ else
344
+ {
345
+ try { target = Marshal.GetObjectForIUnknown(instancePtr); }
346
+ catch (Exception e) { throw new InvalidOperationException($"GetObjectForIUnknown failed: {e.Message}"); }
347
+ }
348
+
349
+ if (target is null)
350
+ throw new InvalidOperationException("Instance resolved to null");
351
+
352
+ var type = target.GetType();
353
+ var flags = BindingFlags.Public | BindingFlags.Instance;
354
+ var prop = GetCachedProp(type, propName, 0, flags);
355
+
356
+ if (prop is null)
357
+ throw new MissingMemberException($"CLR property '{propName}' not found on {type.FullName}");
358
+
359
+ return Box(prop.GetValue(target));
360
+ }
361
+
362
+ private static string? NullIfEmpty(string s) => s.Length == 0 ? null : s;
363
+
364
+ private static unsafe void WriteBinError(string msg, byte** outPtr, int* outLen)
365
+ {
366
+ var msgBytes = System.Text.Encoding.UTF8.GetByteCount(msg);
367
+ var buf = new ArrayBufferWriter<byte>(5 + msgBytes);
368
+ var w = new BinWriter(buf);
369
+ w.WriteByte(0xFF);
370
+ w.WriteString32(msg);
371
+ WriteUnmanaged(buf.WrittenSpan, outPtr, outLen);
372
+ }
373
+ }