Llamada a las API de Windows desde JavaScript (enlaces JS)

En esta guía se muestra cómo llamar a las API de Windows (tanto SDK de Aplicaciones para Windows como Windows SDK) directamente desde javaScript de la aplicación Electron, sin ningún complemento nativo y ningún paso de node-gyp MSBuild. Abrirá un selector de archivos nativo (SDK de Aplicaciones para Windows) y, a continuación, inspeccionará la imagen seleccionada con las API de archivos y de procesamiento de imágenes de Windows SDK agregadas a través de winapp.jsBindings.

Prerequisites

Antes de iniciar esta guía, asegúrese de que tiene:

Paso 1: Confirme sus asociaciones

La configuración generó un directorio .winapp/bindings/ junto a los archivos fuente: un par .js + .d.ts por cada clase generada de SDK de Aplicaciones para Windows, además de un index.js que los reexporta todos:

.winapp/bindings/
├── index.js                  # entry — re-exports every emitted class
├── index.d.ts                # TS bundle
├── FileOpenPicker.js         # one pair of files per emitted class
├── FileOpenPicker.d.ts
├── PickerLocationId.js
├── PickerLocationId.d.ts
└── …

Paso 2: Incorporación de las API del SDK de Windows a los enlaces

Los enlaces predeterminados solo cubren las API de SDK de Aplicaciones para Windows. Para abrir y descodificar la imagen seleccionada, también necesitamos dos clases de SDK de Windows:

  • Windows.Storage.StorageFile — para encerrar una ruta de archivo.
  • Windows.Graphics.Imaging.BitmapDecoder — para leer sus dimensiones.

Abra package.json y agregue una additionalWinmds matriz dentro del winapp.jsBindings bloque que winapp init creó:

// package.json
{
  "winapp": {
    "jsBindings": {
      "additionalWinmds": [
        { "namespace": "Windows.Storage", "classes": ["StorageFile"] },
        { "namespace": "Windows.Graphics.Imaging", "classes": ["BitmapDecoder"] }
      ]
    }
  }
}

A continuación, vuelva a generar los enlaces:

npx winapp node generate-bindings

StorageFile.js, BitmapDecoder.jsy los archivos de enumeración que dependen de (FileAccessMode.js, BitmapPixelFormat.js, ...) aparecen ahora en .winapp/bindings/.

Note

dynwinrt-codegen extrae automáticamente los tipos dependientes que necesita llamar a estas clases (por ejemplo IRandomAccessStream, , devueltas por StorageFile.openAsync), por lo que seleccionar solo las clases de punto de entrada suele ser suficiente.

Paso 3: Llamar a las API de Windows desde el código de Electron

Todas las clases generadas se exportan a través de #winapp/bindings:

Requiere @microsoft/dynwinrt-codegen0.1.0-preview.8 — consulta Primeros pasos con Electron para soluciones alternativas para proyectos antiguos.

// src/index.js (Electron main, CommonJS)
const { app, BrowserWindow, ipcMain } = require('electron');
const {
  // Windows App SDK (default bindings)
  FileOpenPicker,
  PickerLocationId,
  PickerViewMode,
  // Windows SDK (added via additionalWinmds in Step 2)
  StorageFile,
  FileAccessMode,
  BitmapDecoder,
} = require('#winapp/bindings');

async function pickAndInspectImage(mainWindow) {
  // FileOpenPicker needs the parent window's HWND wrapped in a WindowId struct.
  // Electron's getNativeWindowHandle() returns an 8-byte buffer on 64-bit Windows.
  const hwnd = mainWindow.getNativeWindowHandle().readBigUInt64LE(0);

  const picker = FileOpenPicker.createInstance({ value: hwnd });
  picker.viewMode = PickerViewMode.Thumbnail;
  picker.suggestedStartLocation = PickerLocationId.PicturesLibrary;
  picker.fileTypeFilter.replaceAll(['.png', '.jpg', '.jpeg', '.gif']);

  const result = await picker.pickSingleFileAsync();
  if (!result?.path) return null; // User cancelled.

  // Use Windows SDK APIs to inspect the picked image.
  const file = await StorageFile.getFileFromPathAsync(result.path);
  const stream = await file.openAsync(FileAccessMode.Read);
  const decoder = await BitmapDecoder.createAsync(stream);

  return {
    path: result.path,
    width: decoder.pixelWidth,
    height: decoder.pixelHeight,
  };
}

// Expose it to the renderer via IPC so a button click can trigger the flow.
ipcMain.handle('pick-and-inspect-image', (event) => {
  const win = BrowserWindow.fromWebContents(event.sender);
  return pickAndInspectImage(win);
});

A continuación, conéctalo al proceso de renderizado a través de tu script de precarga:

// src/preload.js
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('winapp', {
  pickAndInspectImage: () => ipcRenderer.invoke('pick-and-inspect-image'),
});

Por último, añada un botón a su renderizador y llame a window.winapp.pickAndInspectImage() al hacer clic en él:

<!-- src/index.html -->
<button id="pick">Pick an image</button>
<p id="result"></p>

<script>
  document.getElementById('pick').addEventListener('click', async () => {
    const info = await window.winapp.pickAndInspectImage();
    document.getElementById('result').textContent = info
      ? `${info.path} (${info.width}×${info.height})`
      : 'Cancelled';
  });
</script>

Paso 4: Ejecutarlo

Antes de que el selector de archivos funcione, debes asegurarte de que la aplicación se ejecuta con identidad. Ejecute:

npx winapp node add-electron-debug-identity

Note

Este comando ya está incluido en el script postinstall que hemos agregado en la guía de configuración, por lo que se ejecuta automáticamente después de npm install. Sin embargo, debe ejecutarlo manualmente siempre que modifique Package.appxmanifest, actualice los recursos de la aplicación o vuelva a instalar las dependencias.

Ahora inicie la aplicación:

npm start

Haga clic en el botón: aparece el selector de archivos Windows nativo y, una vez que elija una imagen, su ruta de acceso y las dimensiones de píxel se muestran debajo del botón. 🎉 Importar desde .winapp/bindings/ carga @microsoft/dynwinrt, que redirige cada llamada a la API WinRT subyacente, de forma transparente para tu código.

Pasos siguientes

¡Felicidades! Ahora puedes llamar a las API de Windows —SDK de Aplicaciones para Windows y Windows SDK— directamente desde JavaScript, sin ningún complemento nativo ni ningún paso de compilación node-gyp. 🎉

Ahora ya está listo para:

O explore otras guías:

Recursos adicionales