MFCプログラマが見るTauri + Rust:MACアドレス取得で理解する構造比較

2026-06-03 5 min read IT
5 min read

はじめに

長年MFCでWindowsアプリを作ってきた視点から見ると、Tauri + Rust構成は「新しいようで、やっていることはかなり似ている」と感じる。

ただし違いは明確で、
UIとロジックが言語レベルで分離されている点が最大のポイントになる。

この記事では「MACアドレス取得ツール」を題材に、

  • MFC版
  • Tauri + Rust版
  • Rust関数の読み方

をまとめて理解できる形に整理する。


作るもの

シンプルなツール:

  • ボタンを押す
  • MACアドレス一覧を取得
  • 画面に表示

MFC版の構造

全体フロー

UI(ダイアログ)
  ↓
イベントハンドラ
  ↓
Win32 API
  ↓
結果をListBoxに表示

ボタンイベント

BEGIN_MESSAGE_MAP(CMainDlg, CDialogEx)
    ON_BN_CLICKED(IDC_BTN_GETMAC, &CMainDlg::OnBnClickedGetMac)
END_MESSAGE_MAP()
void CMainDlg::OnBnClickedGetMac()
{
    GetMacAddresses();
}

MACアドレス取得(Win32)

ULONG ulSize = 0;
GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &ulSize);

std::vector<BYTE> buffer(ulSize);

PIP_ADAPTER_ADDRESSES pAddrs =
    reinterpret_cast<PIP_ADAPTER_ADDRESSES>(buffer.data());

列挙

for (auto p = pAddrs; p != NULL; p = p->Next)
{
    // MAC取得
}

UI更新

m_ListBox.AddString(strMac);

MFCの特徴

  • UIとロジックが密結合
  • メッセージマップでイベント管理
  • Win32 API直叩き
  • すべてC++で完結

Tauri + Rust版の構造

全体フロー

Svelte(UI)
  ↓
invoke(JS)
  ↓
Rust Command
  ↓
OS API / crate
  ↓
結果返却
  ↓
UI更新

Svelte(UI)

<script lang="ts">
  import { invoke } from "@tauri-apps/api/core";

  let macs: string[] = [];

  async function loadMac() {
    macs = await invoke<string[]>("get_mac_addresses");
  }
</script>

<button on:click={loadMac}>
  MAC取得
</button>

{#each macs as mac}
  <p>{mac}</p>
{/each}

Rust側(Tauri Command)

#[tauri::command]
fn get_mac_addresses() -> Vec<String> {
    use network_interface::NetworkInterface;
    use network_interface::NetworkInterfaceConfig;

    NetworkInterface::show()
        .unwrap()
        .into_iter()
        .filter_map(|nic| nic.mac_addr)
        .map(|mac| mac.to_string())
        .collect()
}

コマンド登録

tauri::Builder::default()
    .invoke_handler(tauri::generate_handler![
        get_mac_addresses
    ])

Tauriの特徴

  • UIはWeb技術(Svelte / React / Vue)
  • ロジックはRust
  • invokeで関数呼び出し
  • JSONでデータ通信

MFCとの対応関係

MFCTauri
ダイアログSvelte
ON_BN_CLICKEDon:click
C++関数Rust command
Win32 APIOS / crate
ListBox更新リアクティブ描画
CStringString
CArrayVec

一番大きな違い

MFC

イベントの中で全部処理する
UIとロジックが密結合

Tauri

UI(Svelte)
ロジック(Rust)
完全分離

実装感覚の違い

MFC

void CMainDlg::OnBnClicked()
{
    GetMac();
    UpdateUI();
}

Tauri

UI
↓
invoke()
↓
Rust
↓
戻り値
↓
UI更新

Rust関数の読み方(重要)

ここが分かると一気に読めるようになる。


基本形

fn add(a: i32, b: i32) -> i32 {
    a + b
}

読み方

addという関数は
i32型のaとbを受け取って
i32型を返す
中身はa + b

C++との対応

int add(int a, int b)
{
    return a + b;
}

戻り値なし

fn log(msg: String) {
    println!("{}", msg);
}
値を返さない関数

return省略

fn calc() -> i32 {
    10 + 20
}
最後の式が戻り値になる

ifも戻り値になる

fn abs(x: i32) -> i32 {
    if x >= 0 {
        x
    } else {
        -x
    }
}
分岐そのものが値を返す

Tauriでの意味

Rust関数はほぼローカルAPIとして扱うと分かりやすい。

Svelte
  ↓ invoke
Rust関数(API)
  ↓
戻り値
  ↓
UI更新

まとめ

MACアドレス取得ツールという小さな例でも、

MFCとTauriでは構造が大きく違うように見えるが、本質は同じ「イベント駆動アプリ」である。

違いは1つだけ:

  • MFC:すべてC++で完結
  • Tauri:UIとロジックが分離

そしてRustは「難しい言語」というより、

C++でやっていた安全でない部分をコンパイラが保証してくれる言語

として見ると理解しやすくなる。