JavaScript (JS バインディング) から Windows API を呼び出す

このガイドでは、ネイティブ アドオンもnode-gyp/MSBuild ステップも使用せず、electron アプリの JavaScript から Windows API (Windows アプリ SDK と Windows SDK の両方) を直接呼び出す方法について説明します。 ネイティブ ファイル ピッカー (Windows アプリ SDK) を開き、次に winapp.jsBindings を通じて追加された Windows SDK のファイル API とイメージング API を使用して、選択した画像を調査します。

[前提条件]

このガイドを開始する前に、次の作業が完了していることを確認してください。

手順 1: バインディングを確認する

セットアップでは、ソースの横に .winapp/bindings/ ディレクトリが生成されました。出力されたWindows アプリ SDK クラスごとに 1 つの.js + .d.ts ペアに加えて、それらすべてを再エクスポートするindex.jsが生成されました。

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

手順 2: Windows SDK API をバインドに追加する

既定のバインドでは、Windows アプリ SDK API のみが対象となります。 選択したイメージを開いてデコードするには、次の 2 つのWindows SDK クラスも必要です。

  • Windows.Storage.StorageFile — ファイル パスをラップします。
  • Windows.Graphics.Imaging.BitmapDecoder — 寸法を読み取ります。

package.jsonを開き、作成したadditionalWinmds ブロック内にwinapp.jsBindings配列winapp init追加します。

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

次に、バインディングを再生成します。

npx winapp node generate-bindings

StorageFile.jsBitmapDecoder.js、および依存する列挙型ファイル (FileAccessMode.jsBitmapPixelFormat.js、...) が .winapp/bindings/に表示されるようになりました。

Note

dynwinrt-codegen では、これらのクラスを呼び出すために必要な依存型 (たとえば、IRandomAccessStreamによって返されるStorageFile.openAsync) が自動的にプルされるため、通常はエントリ ポイント クラスだけを選択するだけで十分です。

手順 3: Electron コードから Windows API を呼び出す

生成されたすべてのクラスは、 #winapp/bindingsを介してエクスポートされます。

@microsoft/dynwinrt-codegen0.1.0-preview.8 が必要です — 古いプロジェクト向けの代替手段については、Electron を使い始めるを参照してください。

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

その後、事前読み込みスクリプトを使用してレンダラーにブリッジします。

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

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

最後に、レンダラーにボタンを追加し、クリックされたときに window.winapp.pickAndInspectImage() を呼び出します。

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

手順 4: 実行する

ファイル ピッカーが機能する前に、アプリが ID で実行されていることを確認する必要があります。 Run:

npx winapp node add-electron-debug-identity

Note

このコマンドは既にセットアップ ガイドで追加した postinstall スクリプトの一部であるため、 npm install後に自動的に実行されます。 ただし、 Package.appxmanifestを変更したり、アプリ資産を更新したり、依存関係を再インストールしたりするたびに、手動で実行する必要があります。

次に、アプリを起動します。

npm start

ボタンをクリックすると、ネイティブ Windows ファイル ピッカーが表示され、イメージを選択すると、そのパスとピクセル サイズがボタンの下に表示されます。 🎉 .winapp/bindings/ からインポートすると @microsoft/dynwinrt が読み込まれ、各呼び出しは基盤となる WinRT API にディスパッチされます。これはコードからは透過的に行われます。

次のステップ

おめでとうございます! JavaScript から、ネイティブ アドオンも node-gyp ビルド ステップも不要で、Windows API(Windows アプリ SDK と Windows SDK)を直接呼び出せるようになりました。 🎉

これで、次の準備ができました。

または、他のガイドを調べる:

その他のリソース