Chamar APIs do Windows a partir de JavaScript (bindings JS)

Este guia mostra-lhe como chamar APIs do Windows — tanto do SDK de Aplicações Windows como do Windows SDK — diretamente do JavaScript da sua aplicação Electron, sem extensão nativa nem etapa de node-gyp / MSBuild. Vai abrir um seletor de ficheiros nativo (SDK de Aplicações Windows) e, em seguida, inspecionar a imagem selecionada com as APIs de ficheiros e de imagem do Windows SDK adicionadas através de winapp.jsBindings.

Pré-requisitos

Antes de começar este guia, certifique-se de que:

Passo 1: Confirme as suas fixações

A configuração inicial gerou um diretório .winapp/bindings/ junto dos seus ficheiros de origem — um .js + .d.ts par por cada classe do SDK de Aplicações Windows gerada, além de um index.js que reexporta todos eles:

.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
└── …

Passo 2: Adicionar APIs do SDK do Windows às suas associações

As ligações padrão cobrem apenas APIs do SDK de Aplicações Windows. Para abrir e decodificar a imagem escolhida, também precisamos de duas classes SDK do Windows:

  • Windows.Storage.StorageFile — para enrolar um caminho de ficheiro.
  • Windows.Graphics.Imaging.BitmapDecoder — para ler as suas dimensões.

Abra package.json e adicione um additionalWinmds array dentro do winapp.jsBindings bloco que winapp init criou:

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

Em seguida, regenere as associações:

npx winapp node generate-bindings

StorageFile.js, BitmapDecoder.js, e os ficheiros enum de que dependem (FileAccessMode.js, BitmapPixelFormat.js, ...) aparecem agora em .winapp/bindings/.

Note

O dynwinrt-codegen inclui automaticamente os tipos dependentes de que precisas para chamar estas classes (por exemplo, IRandomAccessStream, devolvido por StorageFile.openAsync), por isso selecionar apenas as classes de ponto de entrada é geralmente suficiente.

Passo 3: Chamar APIs do Windows a partir do seu código Electron

Todas as classes geradas são exportadas através #winapp/bindingsde:

Requer @microsoft/dynwinrt-codegen0.1.0-preview.8 — veja Comece com o Electron para alternativas de projetos mais antigos.

// 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);
});

Depois estabelece a ligação ao processo de renderização através do teu script de pré-carga:

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

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

Por fim, adiciona um botão ao teu renderizador e chama window.winapp.pickAndInspectImage() quando este for clicado:

<!-- 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>

Passo 4: Executa

Antes de o seletor de ficheiros funcionar, tens de garantir que a tua aplicação corre com identidade. Executar:

npx winapp node add-electron-debug-identity

Note

Este comando já faz parte do postinstall script que adicionámos no guia de configuração, por isso corre automaticamente após npm install. No entanto, tens de o executar manualmente sempre que modificas Package.appxmanifest, atualizas assets da aplicação ou reinstalas dependências.

Agora inicia a aplicação:

npm start

Clica no botão: o seletor nativo de ficheiros do Windows aparece, e assim que escolhes uma imagem, o caminho e as dimensões dos píxeis aparecem abaixo do botão. 🎉 Importar de .winapp/bindings/ carrega @microsoft/dynwinrt, que encaminha cada chamada para a API WinRT subjacente — de forma transparente para o seu código.

Próximas Etapas

Parabéns! Agora pode invocar APIs do Windows — SDK de Aplicações Windows e Windows SDK — diretamente a partir de JavaScript, sem extensão nativa nem qualquer etapa de compilação node-gyp. 🎉

Agora está pronto para:

Ou explore outros guias:

Recursos adicionais