Windowsアプリのデータ保存先の選び方 ── SQLite / JSON / レジストリ / Access 判断表

· · SQLite, Windows, .NET, C#, データ保存, レジストリ, Access, 設計, 判断表, 技術相談

「設定は INI ファイルでいいのか」「履歴データが増えてきたので Access に入れたい」「レジストリと設定ファイルはどう使い分けるのか」。Windows の業務アプリを作っていると、データの保存先の選択は必ず通る道です。ところが、この選択は最初に何となく決まったまま見直されないことが多く、数年後に「JSON ファイルが数十 MB に育って起動が遅い」「共有フォルダーの Access ファイルが週に一度壊れる」「Program Files 直下に書き込んでいて Windows 11 の環境で動かない」といった形で問題が表面化します。

この記事では、業務 Windows アプリのローカルデータ保存について、「どこに置くか」(フォルダーの選択)と「何で保存するか」(形式・エンジンの選択)を分けて整理します。当ブログで何度か使っている判断表の形式で、SQLite / JSON / レジストリ / Access それぞれの得意分野と落とし穴をまとめます。

1. まず結論

  • 保存先選びは「どこに置くか」と「何で保存するか」の 2 つの独立した判断です。前者を間違えると権限・マルチユーザーの事故、後者を間違えると破損・性能・保守の事故になります。
  • 置き場所の基本は、ユーザーごとの設定・データなら %LOCALAPPDATA%Environment.SpecialFolder.LocalApplicationData)、全ユーザー共有なら %PROGRAMDATA%、そして exe と同じフォルダー(Program Files 配下)には書き込まないです。1
  • 形式の第一候補はシンプルに 2 つです。構造化された小さい設定は JSON ファイル、増えていく業務データ・履歴・検索したいデータは SQLite。この 2 つで業務アプリのローカル保存の大半はカバーできます。2
  • レジストリは「小さなフラグや Windows との連携情報を置く場所」であって、アプリのデータストアではありません。32bit/64bit のレジストリリダイレクト(Wow6432Node)を理解せずに使うと、「書いたはずの値が見えない」問題を踏みます。3
  • Access(.accdb)を新規開発のデータストアに選ぶ理由はほぼなくなりました。既存資産との連携で使う場合も、ACE プロバイダーのビット数一致という配布上の制約が付きまといます。4
  • どの形式でも、機密情報(パスワード・API キー)だけは別扱いです。平文で JSON やレジストリに置かず、DPAPI で保護します。詳細は別記事「Windowsアプリの機密情報保存 - DPAPIで平文設定を避ける」を参照してください。

2. 保存するデータを4種類に分類する

何で保存するかを決める前に、保存しようとしているデータの性質を分類します。業務アプリのローカルデータは、だいたい次の 4 種類に分かれます。

分類 特徴
設定 接続先、画面レイアウト、前回開いたフォルダー 小さい。起動時に全部読む。ユーザーが直接編集したい場合もある
業務データ・履歴 測定結果、処理履歴、マスタのローカルコピー 増え続ける。検索・集計したい。壊れると業務影響が大きい
キャッシュ サムネイル、ダウンロード済みリソース 消えても再生成できる。容量管理が必要
機密情報 保存されたパスワード、トークン 少量。平文で置いてはいけない

この分類ごとに適切な置き場所と形式が違う、というのがこの記事の骨子です。「設定も履歴も全部ひとつの XML に入っている」ようなアプリは、この分類をやり直すところが改善の第一歩になります。

3. どこに置くか ── フォルダー選択の基本

.NET なら Environment.GetFolderPath で取得できる場所を基準にします。5

場所 取得方法 用途
%LOCALAPPDATA%\会社名\アプリ名 SpecialFolder.LocalApplicationData ユーザーごとのデータの既定。まずここ
%APPDATA%\会社名\アプリ名(Roaming) SpecialFolder.ApplicationData 移動ユーザープロファイル環境でユーザーに追従させたい設定のみ
%PROGRAMDATA%\会社名\アプリ名 SpecialFolder.CommonApplicationData 全ユーザー共有のデータ。ACL 設計が必要
ドキュメント配下 SpecialFolder.MyDocuments ユーザーが自分のファイルとして扱う成果物(エクスポートした帳票など)のみ

コードにするとこれだけですが、「会社名\アプリ名」の階層を挟むこと、初回にフォルダーを作ることまで含めて共通処理にしておくと、保存先が場当たり的に増えるのを防げます。

public static class AppPaths
{
    public static string DataDir { get; } = CreateDir(
        Environment.SpecialFolder.LocalApplicationData);

    private static string CreateDir(Environment.SpecialFolder root)
    {
        var dir = Path.Combine(
            Environment.GetFolderPath(root), "KomuraSoft", "MyApp");
        Directory.CreateDirectory(dir);  // 既に存在すれば何もしない
        return dir;
    }
}

環境変数 %LOCALAPPDATA% を文字列連結で組み立てるのではなく Environment.GetFolderPath を使うのは、サービスアカウントや別ユーザーでの実行、フォルダーリダイレクトが構成された環境でも正しい場所を返してくれるからです。タスクスケジューラから別アカウントで動かした瞬間にパスが変わる、という事故(タスクスケジューラ記事の 5 章で書いた「手動なら動く」問題の一種です)もこれで避けられます。

落とし穴を 3 つ挙げます。

  • exe のあるフォルダーに書き込まない。 Program Files 配下は標準ユーザーには書き込めません。古い 32bit アプリでは UAC の互換機能により VirtualStore へ黙ってリダイレクトされることがあり、「管理者で実行したときと標準ユーザーで実行したときで設定ファイルの中身が違う」という不可解な症状の原因になります。
  • ProgramData は「書けるが安全ではない」。 既定の ACL では、あるユーザーが作ったファイルを別のユーザーが変更できない構成になり得ます。全ユーザー共有で読み書きするなら、インストーラーでフォルダーを作成し ACL を明示的に設定します。
  • Roaming を既定にしない。 ドメインの移動ユーザープロファイル環境では Roaming 配下がログオン・ログオフ時に同期されます。サイズの大きいデータやマシン固有のデータ(キャッシュ、ハードウェア設定)を Roaming に置くと、同期の遅延や別マシンへの「汚染」の原因になります。迷ったら Local です。

4. 何で保存するか ── 4つの選択肢の素性

4.1 JSONファイル ── 設定の第一候補

System.Text.Json で素直に読み書きできる、人間が読める、Git 管理や差分比較がしやすい、と設定用途には利点が揃っています。注意点は 2 つです。

破損対策をすること。 書き込み中の電源断で中途半端なファイルが残ると、次回起動時に読めなくなります。「一時ファイルに書いてから置き換える」のが定石で、.NET なら File.Replace がバックアップ付きの置き換えを提供します。

var json = JsonSerializer.Serialize(settings, options);
var tmp = path + ".tmp";
File.WriteAllText(tmp, json);
if (File.Exists(path))
    File.Replace(tmp, path, path + ".bak");
else
    File.Move(tmp, path);

読み込み側も「壊れていたら .bak を試し、それもだめなら既定値で起動して警告する」という縮退動作を最初から入れておくと、設定ファイル破損がサポート案件にならなくなります。

データストアにしないこと。 「起動時に全部読んで、終了時に全部書く」が成立するサイズ(目安として数百 KB まで)が JSON の適用範囲です。追記され続ける履歴やレコード検索が必要なデータを JSON に入れ始めたら、それは次の SQLite のサインです。

4.2 SQLite ── 増えるデータ・検索するデータの第一候補

SQLite はサーバー不要・単一ファイル・パブリックドメインの組み込みデータベースで、.NET からは Microsoft がメンテナンスする ADO.NET プロバイダー Microsoft.Data.Sqlite、または EF Core の SQLite プロバイダーで扱えます。2 Microsoft 自身が Windows アプリのローカルデータ保存手段として推奨しており6、「ローカルで増えていく構造化データ」にはまず SQLite と考えてよい状況です。

まず、どの程度手軽かをコードで示します。NuGet で Microsoft.Data.Sqlite を追加すれば、サーバーのセットアップも接続文字列の管理画面も不要で、ファイルパスを指定するだけで使い始められます。

using Microsoft.Data.Sqlite;

var dbPath = Path.Combine(AppPaths.DataDir, "app.db");
using var conn = new SqliteConnection($"Data Source={dbPath}");
conn.Open();

// 初回のみ: WALモード有効化とテーブル作成
using (var cmd = conn.CreateCommand())
{
    cmd.CommandText = """
        PRAGMA journal_mode=WAL;
        CREATE TABLE IF NOT EXISTS measurement (
            id         INTEGER PRIMARY KEY AUTOINCREMENT,
            device_id  TEXT    NOT NULL,
            value      REAL    NOT NULL,
            created_at TEXT    NOT NULL DEFAULT (datetime('now'))
        );
        CREATE INDEX IF NOT EXISTS ix_measurement_device
            ON measurement(device_id, created_at);
        """;
    cmd.ExecuteNonQuery();
}

// 挿入はパラメーター必須(文字列連結でSQLを組み立てない)
using (var cmd = conn.CreateCommand())
{
    cmd.CommandText =
        "INSERT INTO measurement (device_id, value) VALUES ($device, $value)";
    cmd.Parameters.AddWithValue("$device", "CAM-01");
    cmd.Parameters.AddWithValue("$value", 23.5);
    cmd.ExecuteNonQuery();
}

「JSON ファイルに追記していく」のと大差ない手間で、インデックス付きの検索・集計・件数無制限の履歴が手に入るのが分かると思います。ORM を挟みたければ EF Core の SQLite プロバイダーがこのライブラリの上に載ります。

そのうえで、実務ポイントを絞って挙げます。

  • WAL モードを有効にする。 上のコードの PRAGMA journal_mode=WAL; です。読み取りと書き込みの並行性が上がり、UI スレッドとバックグラウンド処理が同じ DB を触る構成でも詰まりにくくなります。WAL の設定はデータベースファイル自体に永続化されるので、接続のたびに発行する必要はありません。
  • 書き込みは 1 プロセス 1 本に寄せる。 SQLite の書き込みはデータベース単位の排他です。複数スレッドから書くなら、キューを介して書き込み役を一本化する設計が安全です。また、細かい INSERT を大量に行うときは明示的なトランザクションでまとめると、1 件ずつコミットするより桁違いに速くなります。
  • ネットワーク共有に置かない。 SMB 越しのファイルロックは環境依存の問題が多く、SQLite 公式も破損原因の筆頭としてネットワークファイルシステム上での共有を挙げています。7 複数台・複数ユーザーから同時に使いたくなったら、それはもうクライアント・サーバー型 DB(SQL Server Express など)の領域です。
  • 型は 4 種類しかないことを知っておく。 SQLite の実体は INTEGER / REAL / TEXT / BLOB で、日付や GUID は TEXT として保存されます。Microsoft.Data.Sqlite の型マッピング規約を一度確認しておくと、日付の比較やソートで悩まなくなります。8 上の例で created_atdatetime('now')(UTC)にしているのも、ローカル時刻を混ぜるとソートとサマータイム跨ぎで揉めるからです。表示時にローカル時刻へ変換する方針が安全です。
  • バックアップは「ファイルコピー」ではなく VACUUM INTO か Backup API で。 稼働中の DB ファイルを単純コピーすると WAL と本体の不整合を拾うことがあります(詳細は第 6 章)。

4.3 レジストリ ── 小さなフラグとWindows連携情報だけ

レジストリが適切なのは、「インストール済みかどうか」「スタートアップ登録」「ファイル関連付け」など Windows 自体との連携情報と、ごく小さなユーザー設定までです。アプリが自分で使う設定は HKCU 配下、マシン共通の情報はインストーラーが HKLM に書く、が原則です(実行時に HKLM へ書く設計は管理者権限を要求することになるので避けます)。

最大の落とし穴はビット数です。64bit Windows では、32bit プロセスから見た HKLM\SoftwareHKLM\Software\Wow6432Node にリダイレクトされます。3 「レジストリエディターで見ると値があるのにアプリから読めない」「32bit アプリで書いた値が 64bit の保守ツールから見えない」という症状は、ほぼこれです。AnyCPU への移行や 64bit 化のタイミングで顕在化するので、COM や ActiveX の 32bit/64bit 問題(「COM/OCX/ActiveXの落とし穴 ── Visual Studioのビット数と管理者権限」)と同じ文脈で押さえておいてください。

.NET からどうしても他ビットのビューを読む必要がある場合(32bit のまま保守しているアプリが、64bit 側に登録された値を読むなど)は、RegistryView で明示的にビューを指定できます。

using Microsoft.Win32;

// 32bitプロセスから 64bit ビューの HKLM を読む
using var hklm64 = RegistryKey.OpenBaseKey(
    RegistryHive.LocalMachine, RegistryView.Registry64);
using var key = hklm64.OpenSubKey(@"SOFTWARE\KomuraSoft\MyApp");
var installDir = key?.GetValue("InstallDir") as string;

逆に言えば、この指定が必要になった時点で「32bit と 64bit のどちらに書くのが正か」という設計判断を先送りしているサインでもあります。書き込み側と読み取り側のビット数をそろえるのが本筋です。

数 KB を超えるデータや配列的なデータをレジストリに入れるのは、バックアップ・移行・診断のどの面でも不利です。その用途はファイル(JSON / SQLite)に譲ります。

4.4 Access (.accdb) ── 新規採用はほぼなし、既存連携は割り切って

かつて業務アプリのローカル DB といえば Access(JET/ACE)でしたが、新規開発で選ぶ理由は今はほとんどありません。理由は主に配布です。.accdb にコードからアクセスするには ACE(Access Database Engine)プロバイダーが必要で、アプリのビット数と ACE のビット数が一致していなければ接続できません4 Office のビット数との共存問題もあり、「開発機では動くが客先で Microsoft.ACE.OLEDB.12.0 プロバイダーがローカルコンピューターに登録されていません になる」は定番のサポート案件です。再頒布可能パッケージ(Access Database Engine 2016 Redistributable)の導入が必要になる点も、配布物を増やします。9

それでも Access が絡む場面は現実にあります。既存の Access 業務システムとのデータ連携、Access で作られたマスタの読み取りなどです。その場合は、

  • 読み書きするプロセスのビット数を固定し(x86 固定が現実的なことが多い)、インストーラーで対応する ACE の存在を確認する
  • 共有フォルダーに置いた .accdb への多人数同時書き込みは設計として避ける(壊れたときの復旧コストが見合いません)
  • 長期的には SQLite またはサーバー型 DB への移行パスを持っておく

という割り切りをおすすめします。Excel/VBA 資産を含めた既存資産の扱いは「VBAとは何か - 制約、将来性、置き換えるべき場面」でも整理しています。

5. 判断表

観点 JSONファイル SQLite レジストリ Access (.accdb)
得意なデータ 小さな設定 増える構造化データ、検索・集計 小さなフラグ、Windows連携 既存Access資産との連携
データ量の目安 〜数百KB 〜数十GB 〜数KB 〜2GB(仕様上限)
検索・集計 ✕(全読み込み前提) ◎(SQL) ○(SQL)
人間が直接読める △(ツール要) △(Access要)
破損への強さ △(自前で対策) ○(トランザクション)
複数プロセス同時アクセス ○(同一マシン内)
複数マシンからの共有 ✕(事実上)
追加の配布物 なし なし(NuGetに同梱) なし ACEプロバイダー必須

最後の行が示すとおり、ローカル保存の技術はどれも「複数マシンからの共有」には向きません。共有フォルダーに置けば共有できるように見えますが、JSON は排他がなく、SQLite は SMB 上のロックが信頼できず、Access は破損リスクと共に限界が来ます。複数拠点・複数ユーザーで同じデータを触る要件が出てきたら、SQL Server Express などのサーバー型 DB か Web API を立てる判断ラインだと考えてください。

6. 壊れない・移行できる・戻せる ── 形式を問わない共通設計

どの形式を選んでも、数年運用するなら必ず必要になる設計が 3 つあります。最初のリリースに入れておくかどうかで、後の保守コストが大きく変わる部分です。

6.1 スキーマ・形式にバージョン番号を付ける

アプリを更新すれば、保存するデータの形も変わります。「古いバージョンが書いたデータを新しいバージョンが読む」瞬間は必ず来るので、データ側に形式バージョンを持たせておきます。

SQLite なら PRAGMA user_version がまさにこの用途のために用意されています。

int GetVersion(SqliteConnection conn)
{
    using var cmd = conn.CreateCommand();
    cmd.CommandText = "PRAGMA user_version";
    return Convert.ToInt32(cmd.ExecuteScalar());
}

void Migrate(SqliteConnection conn)
{
    void Exec(string sql)
    {
        using var cmd = conn.CreateCommand();
        cmd.CommandText = sql;
        cmd.ExecuteNonQuery();
    }

    var v = GetVersion(conn);
    if (v > 2)
        // 新しいバージョンのアプリが作ったDBを旧アプリで開いたケース。
        // 知らないスキーマに触らず、ここで止めるのが安全
        throw new InvalidOperationException(
            $"このデータベース(バージョン {v})はより新しいアプリで作成されています。");

    using var tx = conn.BeginTransaction();
    if (v < 1) Exec("ALTER TABLE measurement ADD COLUMN unit TEXT");
    if (v < 2) Exec("CREATE TABLE operator (id INTEGER PRIMARY KEY, name TEXT)");
    Exec("PRAGMA user_version = 2");
    tx.Commit();
}

起動時にバージョンを見て差分だけ適用する、いわゆるマイグレーションの最小形です。冒頭で「自分より新しいバージョン」を拒否しているのは、アプリを旧バージョンに戻した(ロールバックした)ときに、旧コードが知らないスキーマへ書き込んで壊す事故を防ぐためです。JSON でも考え方は同じで、ルートに "version": 2 を持たせ、読み込み時に古い形式からの変換を挟み、新しすぎる形式は読み込みを拒否します。「バージョン番号のないデータ形式を世に出さない」、これだけ守れば将来の自分が救われます。

6.2 破損時の縮退動作を決めておく

第 4 章で形式ごとの破損対策(JSON のアトミック書き込み、SQLite のトランザクション)に触れましたが、それでも「読めないデータ」には出会います。ディスク障害、ウイルス対策ソフトの誤検知による隔離、ユーザーによる手編集。そのときアプリがどう振る舞うかを決めていないと、起動すらしないアプリになります。

  • 設定が読めない → 既定値で起動し、その旨をユーザーに通知する(黙って既定値にすると「設定が消えた」問い合わせになります)
  • 業務データが読めない → 読み取り専用モードやエラー画面で「どのファイルが壊れているか」を提示する。自動で上書き修復しない(証拠が消えます)
  • バックアップがある → 復元を提案する。ただし自動復元は「壊れたと誤検知して古いデータに巻き戻す」リスクと表裏一体なので、原則ユーザー操作を挟む

6.3 バックアップは「取れているか」より「戻せるか」

ローカルデータは、サーバーのデータベースと違って誰もバックアップしてくれません。アプリ側で面倒を見るなら、次の 3 点を決めます。

  • 何を: 業務データは対象、キャッシュは対象外、機密情報は DPAPI の性質上、同一ユーザー・同一マシンでしか復号できないことを考慮(別マシンへの移行手順が別途必要)
  • いつ・どこへ: 起動時や日次で、%LOCALAPPDATA% 内の backup フォルダーへ世代付きで。さらに共有フォルダーや既存のPCバックアップ対象フォルダーに乗せるかは運用と相談
  • どうやって: SQLite は稼働中の単純ファイルコピー禁止。VACUUM INTO 'backup.db' なら一貫性のあるスナップショットを 1 文で取れます
// VACUUM INTO は親フォルダーを作らず、出力先が既に存在するとエラーになる。
// フォルダー作成と重複しないファイル名の決定を先に済ませておく
var backupDir = Path.Combine(AppPaths.DataDir, "backup");
Directory.CreateDirectory(backupDir);
var backupPath = Path.Combine(backupDir, $"app-{DateTime.Now:yyyyMMdd-HHmmss}.db");

using var cmd = conn.CreateCommand();
cmd.CommandText = "VACUUM INTO $path";
cmd.Parameters.AddWithValue("$path", backupPath);
cmd.ExecuteNonQuery();

世代がたまり続けるので、バックアップ後に「直近 N 世代だけ残して古いものを消す」処理もセットで入れておきます。

そして一度は復元のリハーサルをしてください。バックアップファイルはあるのに戻し方を誰も知らない・試したことがない、というのは業務システムの「あるある」です。PC の入れ替え時にデータを新しい端末へ移す手順書を書いてみると、バックアップ設計の穴(DPAPI で保護した資格情報が移らない、パスがユーザー名を含んでいて別ユーザーで壊れる等)がだいたい見つかります。PC 廃棄時のデータの消し方については「Windows PCを廃棄する前にやっておきたいこと」も参照してください。

7. 迷いやすいケースの指針

  • 「設定だけど将来増えそう」 ── 起動時に全部読む使い方が崩れる見込みがあるなら、最初から SQLite にします。SQLite に「settings テーブル」を作るのは何も悪いことではありません。
  • 「INI/XML からの移行」 ── 形式の置き換えだけなら JSON へ、そのタイミングで履歴系データが混ざっているなら分離して SQLite へ。読み込み側に旧形式のフォールバックを 1〜2 バージョン残すと移行が安全です。
  • 「Excel で見たいと言われる」 ── データストアを Excel/Access にするのではなく、SQLite に保存して CSV/Excel へエクスポートする機能を付けるほうが、データの信頼性と要望の両方を満たせます。帳票出力の作り方は「Excel帳票出力をどう作るか」を参照してください。
  • 「複数プロセスで同じファイルを読み書きしたい」 ── 同一マシン内なら SQLite(WAL)でかなり戦えますが、書き込み競合の設計が必要です。ファイルベースで連携するなら「ファイル連携とロックのベストプラクティス」の排他パターンを使ってください。
  • 「複数マシンで共有したい」 ── ローカル保存の卒業です。第一候補は SQL Server Express(無償、データベース 10GB まで)をファイルサーバー相当のマシンに立てるクライアント・サーバー構成。なお SQL Server「LocalDB」は名前に反して開発用途向けの単一ユーザー環境なので、共有目的では選ばないでください。拠点をまたぐ、社外からも使う、となったら Web API を挟む構成を検討するラインです。

8. まとめ

保存先の選択は、「どこに置くか」(LocalAppData / ProgramData、そして Program Files には書かない)と「何で保存するか」(設定は JSON、増えるデータは SQLite、レジストリは最小限、Access は既存連携のみ)に分けて考えると、ほとんどのケースで迷わず決められます。

そのうえで、形式を問わず第 6 章の 3 点セット──形式バージョン番号、破損時の縮退動作、戻せるバックアップ──を最初のリリースに入れておくこと。機密情報だけは常に別枠で DPAPI へ。この記事の判断表と共通設計を押さえておけば、「数十 MB に育った JSON」「週一で壊れる共有 Access」のような、後から高くつく構成はほぼ避けられます。既存アプリの保存方式に不安がある場合は、まず「何がどこに保存されているかの棚卸し」から始めることをおすすめします。

関連記事

関連する相談領域

合同会社小村ソフトでは、業務アプリのデータ保存方式の見直し(INI/XML/Access からの移行設計を含む)や、データ破損・性能劣化の原因調査を扱っています。

参考リンク

  1. Microsoft Learn, KNOWNFOLDERID. LocalAppData、RoamingAppData、ProgramData など Windows の既知フォルダーの定義について。 

  2. Microsoft Learn, Microsoft.Data.Sqlite overview. Microsoft がメンテナンスする SQLite 用 ADO.NET プロバイダーの概要と、EF Core SQLite プロバイダーの土台であることについて。  2

  3. Microsoft Learn, Registry Redirector. 64bit Windows で 32bit プロセスのレジストリアクセスが Wow6432Node へリダイレクトされる仕組みについて。  2

  4. Microsoft Learn, Can’t establish a connection to Access Database Engine OLE DB. ACE OLE DB プロバイダーはアクセスするプロセスとビット数が一致している必要があることについて。  2

  5. Microsoft Learn, Environment.SpecialFolder Enum. .NET から既知フォルダーを取得するための列挙型について。 

  6. Microsoft Learn, Use a SQLite database in a Windows app. Windows アプリのローカルデータ保存に SQLite と Microsoft.Data.Sqlite / EF Core を推奨する公式チュートリアル。 

  7. SQLite, How To Corrupt An SQLite Database File. ネットワークファイルシステム上でのロック不全がデータベース破損の主要因であることについて。 

  8. Microsoft Learn, Data types (Microsoft.Data.Sqlite). SQLite の 4 つのプリミティブ型と、DateTime や Guid が TEXT にマップされる規約について。 

  9. Microsoft, Microsoft Access Database Engine 2016 Redistributable. .accdb / .mdb にアクセスするための ACE 再頒布可能パッケージ(32bit/64bit)について。 

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る