@nativescript/windows 0.1.0-alpha.77 → 0.1.0-alpha.79

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.
@@ -33,11 +33,24 @@ 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
+ try { System.Diagnostics.Debug.WriteLine($"[Bridge] Binary __release: Released native ptr for handle {handleToRemove} -> 0x{nativePtr:x}"); } catch { }
46
+ }
47
+ catch
48
+ {
49
+ // best-effort
50
+ }
51
+ }
52
+ return DispatchResult.Void;
53
+ }
41
54
 
42
55
  if (op == 0x05) // members by handle
43
56
  {
@@ -18,11 +18,25 @@ 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
+ try { System.Diagnostics.Debug.WriteLine($"[Bridge] __release: Released native ptr for handle {id} -> 0x{nativePtr:x}"); } catch { }
31
+ }
32
+ catch
33
+ {
34
+ // swallow - best-effort release
35
+ }
36
+ }
37
+
38
+ return DispatchResult.Void;
39
+ }
26
40
 
27
41
  object? target = null;
28
42
  Type type;
@@ -244,8 +258,29 @@ public static partial class Bridge
244
258
  catch { }
245
259
  }
246
260
 
247
- var id = Interlocked.Increment(ref s_nextHandle);
248
- s_handles[id] = value;
261
+ var id = Interlocked.Increment(ref s_nextHandle);
262
+ s_handles[id] = value;
263
+
264
+ // Try to obtain a canonical IUnknown pointer for COM/WinRT objects so the
265
+ // runtime can call native vtable methods directly. We addref via
266
+ // Marshal.GetIUnknownForObject and store the raw pointer; it will be
267
+ // released on __release.
268
+ try
269
+ {
270
+ if (value != null)
271
+ {
272
+ var p = Marshal.GetIUnknownForObject(value);
273
+ if (p != IntPtr.Zero)
274
+ {
275
+ s_nativePtrs[id] = p.ToInt64();
276
+ try { System.Diagnostics.Debug.WriteLine($"[Bridge] Box: handle {id}, type={t.FullName}, native=0x{p.ToInt64():x}"); } catch { }
277
+ }
278
+ }
279
+ }
280
+ catch
281
+ {
282
+ // Not a COM object or failed to obtain native pointer; ignore.
283
+ }
249
284
  var typeName = t.FullName ?? t.Name;
250
285
  return IsAwaitable(value, t)
251
286
  ? DispatchResult.TaskHandle(id, typeName)
@@ -1,4 +1,5 @@
1
1
  using System;
2
+ using System.Diagnostics;
2
3
  using System.Collections.Concurrent;
3
4
  using System.Collections.Generic;
4
5
  using System.IO;
@@ -48,9 +49,15 @@ public static partial class Bridge
48
49
  s_propCache.Clear();
49
50
  s_ctorCache.Clear();
50
51
  s_handles.Clear();
52
+ s_nativePtrs.Clear();
51
53
  s_nextHandle = 0;
52
54
  }
53
55
 
56
+ // Optional mapping from exported handle id -> native IUnknown pointer (Int64)
57
+ // Populated when a managed object can yield a native COM pointer via
58
+ // Marshal.GetIUnknownForObject. Cleared and released on __release.
59
+ internal static readonly ConcurrentDictionary<int, long> s_nativePtrs = new();
60
+
54
61
  // Returns a JSON object mapping top-level namespace roots (e.g. "NativeScript")
55
62
  // to the assembly simple-name that most likely contains that namespace's types.
56
63
  // Reuses s_assemblySearchDirs so plugin and NuGet assemblies are included.
@@ -372,6 +379,41 @@ public static partial class Bridge
372
379
  return 0;
373
380
  }
374
381
 
382
+ // Return a canonical native pointer (IUnknown / IInspectable) for an
383
+ // exported handle id. Returns 0 when no pointer is available. If a
384
+ // pointer isn't already cached in `s_nativePtrs`, attempt to obtain one
385
+ // via `Marshal.GetIUnknownForObject` and cache it for subsequent calls.
386
+ public static long GetNativePtrForHandle(int handleId)
387
+ {
388
+ if (handleId <= 0) return 0;
389
+ if (s_nativePtrs.TryGetValue(handleId, out var p)) {
390
+ try { Debug.WriteLine($"[Bridge] GetNativePtrForHandle({handleId}) -> 0x{p:x} (cached)"); } catch { }
391
+ return p;
392
+ }
393
+
394
+ if (!s_handles.TryGetValue(handleId, out var obj) || obj == null)
395
+ return 0;
396
+
397
+ try
398
+ {
399
+ var ip = Marshal.GetIUnknownForObject(obj);
400
+ if (ip != IntPtr.Zero)
401
+ {
402
+ var val = ip.ToInt64();
403
+ s_nativePtrs[handleId] = val;
404
+ try { Debug.WriteLine($"[Bridge] GetNativePtrForHandle({handleId}) -> 0x{val:x} (new)"); } catch { }
405
+ return val;
406
+ }
407
+ }
408
+ catch (Exception ex)
409
+ {
410
+ try { Debug.WriteLine($"[Bridge] GetNativePtrForHandle({handleId}) threw: {ex}"); } catch { }
411
+ }
412
+
413
+ try { Debug.WriteLine($"[Bridge] GetNativePtrForHandle({handleId}) -> 0 (none)"); } catch { }
414
+ return 0;
415
+ }
416
+
375
417
  private static void OnAppDomainUnhandledException(object? sender, UnhandledExceptionEventArgs e)
376
418
  {
377
419
  try
@@ -404,22 +446,19 @@ public static partial class Bridge
404
446
  catch { }
405
447
  }
406
448
 
407
- private static void SendUnhandledToJs(string kind, string message)
449
+ private static unsafe void SendUnhandledToJs(string kind, string message)
408
450
  {
409
451
  try
410
452
  {
411
453
  if (s_jsInvoker == null || s_unhandledExceptionCallbackId <= 0) return;
412
454
  var payload = JsonSerializer.Serialize(new { kind = kind, message = message });
413
455
  var bytes = System.Text.Encoding.UTF8.GetBytes(payload);
414
- unsafe
456
+ fixed (byte* p = bytes)
415
457
  {
416
- fixed (byte* p = bytes)
417
- {
418
- byte* respPtr = null;
419
- int respLen = 0;
420
- s_jsInvoker(s_unhandledExceptionCallbackId, p, bytes.Length, &respPtr, &respLen);
421
- if (respPtr != null && respLen > 0) Marshal.FreeHGlobal((IntPtr)respPtr);
422
- }
458
+ byte* respPtr = null;
459
+ int respLen = 0;
460
+ s_jsInvoker(s_unhandledExceptionCallbackId, p, bytes.Length, &respPtr, &respLen);
461
+ if (respPtr != null && respLen > 0) Marshal.FreeHGlobal((IntPtr)respPtr);
423
462
  }
424
463
  }
425
464
  catch { }
@@ -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.77",
3
+ "version": "0.1.0-alpha.79",
4
4
  "description": "NativeScript for using Windows v8",
5
5
  "repository": {
6
6
  "type": "git",