@nativescript/windows 0.1.0-alpha.76 → 0.1.0-alpha.78

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.
@@ -6,7 +6,7 @@
6
6
  easily overridden per-app or via MSBuild /p: properties. -->
7
7
 
8
8
  <!-- Inline merge task: will merge App_Resources/Windows/Package.appxmanifest or Package.appxmanifest.partial.xml into the generated Package.appxmanifest -->
9
- <UsingTask TaskName="MergeAppxManifest" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
9
+ <UsingTask TaskName="MergeAppxManifest" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" Condition="'$(MSBuildRuntimeType)' != 'Core'">
10
10
  <ParameterGroup>
11
11
  <SourceManifest ParameterType="System.String" Required="true" />
12
12
  <TargetManifest ParameterType="System.String" Required="true" />
@@ -85,7 +85,7 @@
85
85
  </Task>
86
86
  </UsingTask>
87
87
 
88
- <Target Name="MergeAppResourcesManifest" AfterTargets="ApplyManifestOverrides" Condition="Exists('$(MSBuildProjectDirectory)\Package.appxmanifest')">
88
+ <Target Name="MergeAppResourcesManifest" AfterTargets="ApplyManifestOverrides" Condition="Exists('$(MSBuildProjectDirectory)\Package.appxmanifest') and '$(MSBuildRuntimeType)' != 'Core'">
89
89
  <PropertyGroup>
90
90
  <_AppResourcesManifest>$(MSBuildProjectDirectory)\App_Resources\Windows\Package.appxmanifest</_AppResourcesManifest>
91
91
  <!-- Allow CLI or callers to override the source manifest via MSBuild property 'AppResourcesManifestPath' -->
@@ -33,11 +33,23 @@ public static partial class Bridge
33
33
  {
34
34
  var op = r.ReadByte();
35
35
 
36
- if (op == 0x04) // release
37
- {
38
- s_handles.TryRemove(r.ReadI32(), out _);
39
- return DispatchResult.Void;
40
- }
36
+ if (op == 0x04) // release
37
+ {
38
+ var handleToRemove = r.ReadI32();
39
+ s_handles.TryRemove(handleToRemove, out _);
40
+ if (s_nativePtrs.TryRemove(handleToRemove, out var nativePtr))
41
+ {
42
+ try
43
+ {
44
+ Marshal.Release(new IntPtr(nativePtr));
45
+ }
46
+ catch
47
+ {
48
+ // best-effort
49
+ }
50
+ }
51
+ return DispatchResult.Void;
52
+ }
41
53
 
42
54
  if (op == 0x05) // members by handle
43
55
  {
@@ -18,11 +18,24 @@ public static partial class Bridge
18
18
  {
19
19
  var method = req.Method ?? throw new ArgumentException("Method is required");
20
20
 
21
- if (method == "__release" && req.Handle.HasValue)
22
- {
23
- s_handles.TryRemove(req.Handle.Value, out _);
24
- return DispatchResult.Void;
25
- }
21
+ if (method == "__release" && req.Handle.HasValue)
22
+ {
23
+ var id = req.Handle.Value;
24
+ s_handles.TryRemove(id, out _);
25
+ if (s_nativePtrs.TryRemove(id, out var nativePtr))
26
+ {
27
+ try
28
+ {
29
+ Marshal.Release(new IntPtr(nativePtr));
30
+ }
31
+ catch
32
+ {
33
+ // swallow - best-effort release
34
+ }
35
+ }
36
+
37
+ return DispatchResult.Void;
38
+ }
26
39
 
27
40
  object? target = null;
28
41
  Type type;
@@ -244,8 +257,28 @@ public static partial class Bridge
244
257
  catch { }
245
258
  }
246
259
 
247
- var id = Interlocked.Increment(ref s_nextHandle);
248
- s_handles[id] = value;
260
+ var id = Interlocked.Increment(ref s_nextHandle);
261
+ s_handles[id] = value;
262
+
263
+ // Try to obtain a canonical IUnknown pointer for COM/WinRT objects so the
264
+ // runtime can call native vtable methods directly. We addref via
265
+ // Marshal.GetIUnknownForObject and store the raw pointer; it will be
266
+ // released on __release.
267
+ try
268
+ {
269
+ if (value != null)
270
+ {
271
+ var p = Marshal.GetIUnknownForObject(value);
272
+ if (p != IntPtr.Zero)
273
+ {
274
+ s_nativePtrs[id] = p.ToInt64();
275
+ }
276
+ }
277
+ }
278
+ catch
279
+ {
280
+ // Not a COM object or failed to obtain native pointer; ignore.
281
+ }
249
282
  var typeName = t.FullName ?? t.Name;
250
283
  return IsAwaitable(value, t)
251
284
  ? DispatchResult.TaskHandle(id, typeName)
@@ -48,9 +48,15 @@ public static partial class Bridge
48
48
  s_propCache.Clear();
49
49
  s_ctorCache.Clear();
50
50
  s_handles.Clear();
51
+ s_nativePtrs.Clear();
51
52
  s_nextHandle = 0;
52
53
  }
53
54
 
55
+ // Optional mapping from exported handle id -> native IUnknown pointer (Int64)
56
+ // Populated when a managed object can yield a native COM pointer via
57
+ // Marshal.GetIUnknownForObject. Cleared and released on __release.
58
+ internal static readonly ConcurrentDictionary<int, long> s_nativePtrs = new();
59
+
54
60
  // Returns a JSON object mapping top-level namespace roots (e.g. "NativeScript")
55
61
  // to the assembly simple-name that most likely contains that namespace's types.
56
62
  // Reuses s_assemblySearchDirs so plugin and NuGet assemblies are included.
@@ -326,6 +332,132 @@ public static partial class Bridge
326
332
  return 0;
327
333
  }
328
334
 
335
+ // Callback id registered by the runtime/JS that should receive unhandled
336
+ // managed exceptions and unobserved task exceptions.
337
+ private static int s_unhandledExceptionCallbackId = -1;
338
+
339
+ // Called from JS/Rust to request that managed unhandled exceptions be
340
+ // forwarded to the registered JS callback id. The callback id must have
341
+ // been created on the Rust side and point to a JS function stored in the
342
+ // runtime's `DOTNET_JS_CALLBACKS` map.
343
+ public static int RegisterUnhandledExceptionCallback(int callbackId)
344
+ {
345
+ s_unhandledExceptionCallbackId = callbackId;
346
+
347
+ // Subscribe once (idempotent).
348
+ try
349
+ {
350
+ AppDomain.CurrentDomain.UnhandledException -= OnAppDomainUnhandledException;
351
+ AppDomain.CurrentDomain.UnhandledException += OnAppDomainUnhandledException;
352
+
353
+ TaskScheduler.UnobservedTaskException -= OnUnobservedTaskException;
354
+ TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
355
+
356
+ // Try to subscribe to Windows.CoreApplication.UnhandledErrorDetected if available
357
+ foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
358
+ {
359
+ var coreAppType = asm.GetType("Windows.ApplicationModel.Core.CoreApplication");
360
+ if (coreAppType == null) continue;
361
+ var ev = coreAppType.GetEvent("UnhandledErrorDetected");
362
+ if (ev == null) continue;
363
+ try
364
+ {
365
+ var handlerType = ev.EventHandlerType;
366
+ var method = typeof(Bridge).GetMethod(nameof(CoreApplicationUnhandledErrorHandler), BindingFlags.NonPublic | BindingFlags.Static);
367
+ if (method != null)
368
+ {
369
+ var del = Delegate.CreateDelegate(handlerType, method);
370
+ ev.AddEventHandler(null, del);
371
+ }
372
+ }
373
+ catch { }
374
+ }
375
+ }
376
+ catch { }
377
+
378
+ return 0;
379
+ }
380
+
381
+ // Return a canonical native pointer (IUnknown / IInspectable) for an
382
+ // exported handle id. Returns 0 when no pointer is available. If a
383
+ // pointer isn't already cached in `s_nativePtrs`, attempt to obtain one
384
+ // via `Marshal.GetIUnknownForObject` and cache it for subsequent calls.
385
+ public static long GetNativePtrForHandle(int handleId)
386
+ {
387
+ if (handleId <= 0) return 0;
388
+ if (s_nativePtrs.TryGetValue(handleId, out var p)) return p;
389
+
390
+ if (!s_handles.TryGetValue(handleId, out var obj) || obj == null)
391
+ return 0;
392
+
393
+ try
394
+ {
395
+ var ip = Marshal.GetIUnknownForObject(obj);
396
+ if (ip != IntPtr.Zero)
397
+ {
398
+ var val = ip.ToInt64();
399
+ s_nativePtrs[handleId] = val;
400
+ return val;
401
+ }
402
+ }
403
+ catch
404
+ {
405
+ // best-effort: not a COM object or failed to obtain native ptr
406
+ }
407
+
408
+ return 0;
409
+ }
410
+
411
+ private static void OnAppDomainUnhandledException(object? sender, UnhandledExceptionEventArgs e)
412
+ {
413
+ try
414
+ {
415
+ var ex = e.ExceptionObject as Exception;
416
+ var msg = ex?.ToString() ?? e.ExceptionObject?.ToString() ?? "(unknown)";
417
+ SendUnhandledToJs("unhandled", msg);
418
+ }
419
+ catch { }
420
+ }
421
+
422
+ private static void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
423
+ {
424
+ try
425
+ {
426
+ var msg = e.Exception?.ToString() ?? "(unobserved task exception)";
427
+ SendUnhandledToJs("unobservedTask", msg);
428
+ }
429
+ catch { }
430
+ }
431
+
432
+ // Fallback handler for platform-specific CoreApplication unhandled events.
433
+ private static void CoreApplicationUnhandledErrorHandler(object? sender, object? args)
434
+ {
435
+ try
436
+ {
437
+ var msg = args?.ToString() ?? "(core unhandled)";
438
+ SendUnhandledToJs("coreUnhandled", msg);
439
+ }
440
+ catch { }
441
+ }
442
+
443
+ private static unsafe void SendUnhandledToJs(string kind, string message)
444
+ {
445
+ try
446
+ {
447
+ if (s_jsInvoker == null || s_unhandledExceptionCallbackId <= 0) return;
448
+ var payload = JsonSerializer.Serialize(new { kind = kind, message = message });
449
+ var bytes = System.Text.Encoding.UTF8.GetBytes(payload);
450
+ fixed (byte* p = bytes)
451
+ {
452
+ byte* respPtr = null;
453
+ int respLen = 0;
454
+ s_jsInvoker(s_unhandledExceptionCallbackId, p, bytes.Length, &respPtr, &respLen);
455
+ if (respPtr != null && respLen > 0) Marshal.FreeHGlobal((IntPtr)respPtr);
456
+ }
457
+ }
458
+ catch { }
459
+ }
460
+
329
461
  [UnmanagedCallersOnly(EntryPoint = "Invoke",
330
462
  CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])]
331
463
  public static unsafe int Invoke(
@@ -115,10 +115,23 @@ internal readonly struct DispatchResult
115
115
  break;
116
116
 
117
117
  case DispatchKind.Handle:
118
- w.WriteStartObject();
119
- w.WriteNumber("__handle"u8, _handle);
120
- w.WriteString("__type"u8, _typeName);
121
- w.WriteEndObject();
118
+ w.WriteStartObject();
119
+ w.WriteNumber("__handle"u8, _handle);
120
+ w.WriteString("__type"u8, _typeName);
121
+ // If the bridge has a canonical native pointer for this handle,
122
+ // expose it as a hex string so the runtime can detect and use it.
123
+ if (Bridge.s_nativePtrs.TryGetValue(_handle, out var nativePtr))
124
+ {
125
+ try
126
+ {
127
+ w.WriteString("__native_ptr"u8, nativePtr.ToString("x"));
128
+ }
129
+ catch
130
+ {
131
+ // ignore formatting errors
132
+ }
133
+ }
134
+ w.WriteEndObject();
122
135
  break;
123
136
 
124
137
  case DispatchKind.TaskHandle:
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nativescript/windows",
3
- "version": "0.1.0-alpha.76",
3
+ "version": "0.1.0-alpha.78",
4
4
  "description": "NativeScript for using Windows v8",
5
5
  "repository": {
6
6
  "type": "git",