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

Este guia mostra como chamar APIs do Windows — tanto da SDK do Aplicativo Windows quanto da Windows SDK — diretamente do JavaScript do seu aplicativo Electron, sem addon nativo e sem nenhuma etapa de node-gyp / MSBuild. Você abrirá um seletor de arquivos nativo (SDK do Aplicativo Windows) e, em seguida, inspecionará a imagem selecionada com as APIs de arquivo e de imagem do SDK do Windows adicionadas por meio de winapp.jsBindings.

Pré-requisitos

Antes de iniciar este guia, verifique se você:

Etapa 1: Confirme suas vinculações

A configuração gerou um diretório .winapp/bindings/ ao lado dos seus arquivos-fonte — um par .js + .d.ts para cada classe emitida do SDK do Aplicativo Windows, além de um index.js que 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
└── …

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

As associações padrão abrangem somente APIs de SDK do Aplicativo Windows. Para abrir e decodificar a imagem escolhida, também precisamos de duas classes Windows SDK:

  • Windows.Storage.StorageFile — para encapsular um caminho de arquivo.
  • Windows.Graphics.Imaging.BitmapDecoder — para verificar suas dimensões.

Abra package.json e adicione uma additionalWinmds matriz 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.jse os arquivos de enumeração dos quais eles dependem (FileAccessMode.js, BitmapPixelFormat.js, ...) agora aparecem em .winapp/bindings/.

Note

dynwinrt-codegen inclui automaticamente os tipos dependentes de que você precisa para chamar essas classes (por exemplo, IRandomAccessStream, retornado por StorageFile.openAsync), portanto, selecionar apenas as classes de entrada geralmente é suficiente.

Etapa 3: Chame APIs do Windows do seu código Electron

Todas as classes geradas são exportadas por meio #winapp/bindingsde:

Requer @microsoft/dynwinrt-codegen0.1.0-preview.8 — consulte Primeiros passos com o Electron para alternativas para projetos 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);
});

Em seguida, exponha-o ao processo de renderização por meio do script de pré-carregamento:

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

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

Por fim, adicione um botão ao seu renderizador e chame window.winapp.pickAndInspectImage() quando ele 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>

Etapa 4: Executá-lo

Antes que o seletor de arquivos funcione, você precisa garantir que seu aplicativo seja executado com identidade. Executar:

npx winapp node add-electron-debug-identity

Note

Esse comando já faz parte do postinstall script que adicionamos no guia de instalação, portanto, ele é executado automaticamente após npm install. No entanto, você precisa executá-lo manualmente sempre que modificar Package.appxmanifest, atualizar ativos de aplicativo ou reinstalar dependências.

Agora inicie o aplicativo:

npm start

Clique no botão: o seletor de arquivos de Windows nativo é exibido e, depois de escolher uma imagem, suas dimensões de caminho e pixel 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 você está chamando APIs do Windows — SDK do Aplicativo Windows e Windows SDK — diretamente do JavaScript, sem addon nativo e sem nenhuma etapa de build node-gyp. 🎉

Agora você está pronto para:

Ou explore outros guias:

Recursos adicionais