Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

C# 名前付きパイプでプロセス間通信 (IPC) を行う【x64 ⇔ x86】

0
Posted at

はじめに

x64 と x86 のコードを同一プロセス内で混在させることができないため、名前付きパイプを使用したプロセス間通信 (IPC) で対処した時の備忘録です。

改訂履歴

  • 2026/08/10 : 初版公開。

本文

1. 環境

  • .NET 8.0
  • Visual Studio Community 2022

2. 実装

クライアント側では NamedPipeClientStream を使用して名前付きパイプに接続します。メッセージを送信した後、サーバーからの応答を受信します。CancellationToken を使用して、処理のキャンセルも可能です。

NamedPipeClient.cs
using System.IO.Pipes;
using Microsoft.Extensions.Logging;

namespace NamedPipeExample64;

/// <summary>
/// 名前付きパイプを使用して、サーバーに要求を送信し、応答を受信するためのクラスを提供します。
/// </summary>
public class NamedPipeClient
{
    private readonly ILogger _logger;
    private readonly string _serverName;
    private readonly string _pipeName;

    /// <summary>
    /// <see cref="NamedPipeClient"/> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="logger">ログ出力に使用するロガー。</param>
    /// <param name="serverName">名前付きパイプサーバーの名前。既定値は <c>"."</c> で、ローカルコンピューターを指定します。</param>
    /// <param name="pipeName">接続する名前付きパイプの名前。既定値は <c>"NamedPipe"</c> です。</param>
    public NamedPipeClient(
        ILogger logger,
        string serverName = ".",
        string pipeName = "NamedPipe")
    {
        _logger = logger;
        _serverName = serverName ?? string.Empty;
        _pipeName = pipeName ?? string.Empty;
    }

    /// <summary>
    /// 指定されたメッセージをサーバーに送信し、応答を非同期に受信します。
    /// </summary>
    /// <param name="message">サーバーに送信するメッセージ。</param>
    /// <param name="token">キャンセル要求を監視するトークン。既定値は <see cref="CancellationToken.None"/> です。</param>
    /// <returns>処理が正常に完了したかどうかと、サーバーから受信した応答文字列。</returns>
    public async Task<(bool IsSuccess, string Response)> ExecuteAsync(
        string message,
        CancellationToken token = default)
    {
        try
        {
            // 名前付きパイプのストリームを生成、接続する。
            using var pipe = new NamedPipeClientStream(_serverName, _pipeName, PipeDirection.InOut);
            await pipe.ConnectAsync(token);

            // 読込と書込のストリームを生成する。
            using var reader = new StreamReader(pipe);
            using var writer = new StreamWriter(pipe) { AutoFlush = true };

            // 書込する。
            await writer.WriteLineAsync(message ?? string.Empty);

            // 応答を読込して結果を返す。
            var response = await reader.ReadLineAsync(token) ?? string.Empty;
            return (true, response);
        }
        catch (OperationCanceledException)
        {
            // キャンセルは正常終了とする。
            return (true, string.Empty);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An exception occurred.");
            return (false, string.Empty);
        }
    }
}

サーバー側では NamedPipeServerStream を使用してクライアントからの接続を待機します。メッセージを受信した後、動作確認のため 5 秒待機し、受信したメッセージをそのままクライアントに返信します。クライアントと同様、CancellationToken を使用して、処理のキャンセルも可能です。

NamedPipeServer.cs
using System.IO.Pipes;
using Microsoft.Extensions.Logging;

namespace NamedPipeExample86;

/// <summary>
/// 名前付きパイプを使用して、クライアントから要求を受信し、応答するクラスを提供します。
/// </summary>
public class NamedPipeServer
{
    private readonly ILogger _logger;
    private readonly string _pipeName;

    /// <summary>
    /// <see cref="NamedPipeServer"/> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="logger">ログ出力に使用するロガー。</param>
    /// <param name="pipeName">接続する名前付きパイプの名前。既定値は <c>"NamedPipe"</c> です。</param>
    public NamedPipeServer(ILogger logger, string pipeName = "NamedPipe")
    {
        _logger = logger;
        _pipeName = pipeName ?? string.Empty;
    }

    /// <summary>
    /// クライアントからの要求を受信し、応答を返します。
    /// </summary>
    /// <param name="token">キャンセル要求を監視するトークン。既定値は <see cref="CancellationToken.None"/> です。</param>
    /// <returns>処理が正常に完了したかどうかと、クライアントから受信した要求文字列。</returns>
    public async Task<(bool IsSuccess, string Response)> ExecuteAsync(CancellationToken token = default)
    {
        try
        {
            // 名前付きパイプのストリームを生成する。
            using var pipe = new NamedPipeServerStream(_pipeName, PipeDirection.InOut);

            // クライアントからの接続を待機する。
            await pipe.WaitForConnectionAsync(token);

            // 読込と書込のストリームを生成する。
            using var reader = new StreamReader(pipe);
            using var writer = new StreamWriter(pipe) { AutoFlush = true };

            // 読込する。
            var message = await reader.ReadLineAsync(token) ?? string.Empty;

            // 動作確認のため 5 秒待機する。
            await Task.Delay(TimeSpan.FromSeconds(5), token);

            // 応答を書込して結果を返す。
            await writer.WriteLineAsync(message);
            return (true, message);
        }
        catch (OperationCanceledException)
        {
            // キャンセルは正常終了とする。
            return (true, string.Empty);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An exception occurred.");
            return (false, string.Empty);
        }
    }
}

おわりに

既存の x86 ライブラリを x64 アプリケーションから利用したい場合など、ちょっとした処理を別プロセスに切り出す用途で使えそうです。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?