最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#使用SendMessage實現(xiàn)進程間通信的示例代碼

 更新時間:2025年08月22日 08:54:44   作者:墨夶  
在軟件開發(fā)中,進程間通信(IPC)是關鍵技術之一,C#通過調(diào)用Windows API的 SendMessage 函數(shù)實現(xiàn)這一功能,本文將通過實例介紹如何在C#中使用 SendMessage 進行簡單的進程間數(shù)據(jù)傳遞,需要的朋友可以參考下

第一章:SendMessage的底層原理揭秘

核心思想:窗口句柄作為進程通信的"身份證"

// 窗口句柄(HWND)的本質(zhì):進程身份的唯一標識符
public class WindowHandleManager
{
    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    /// <summary>
    /// 獲取目標進程的主窗口句柄
    /// </summary>
    /// <param name="processName">進程名稱(不含.exe后綴)</param>
    /// <returns>窗口句柄</returns>
    public static IntPtr GetWindowHandle(string processName)
    {
        // 查找同名進程
        Process[] processes = Process.GetProcessesByName(processName);
        if (processes.Length == 0)
            throw new Exception($"未找到進程 {processName}");

        // 獲取主窗口句柄
        IntPtr hWnd = processes[0].MainWindowHandle;
        if (hWnd == IntPtr.Zero)
            throw new Exception("未找到窗口句柄");

        return hWnd;
    }
}

靈魂拷問:

為什么必須通過窗口句柄通信?

Windows系統(tǒng)為每個窗口分配唯一句柄,如同進程的“身份證號”,是跨進程通信的唯一身份驗證方式。

第二章:構(gòu)建跨進程通信橋梁

目標:發(fā)送端與接收端的完整握手流程

2.1 定義通信協(xié)議

// 自定義消息結(jié)構(gòu)體(必須與C++定義完全一致)
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
    public IntPtr dwData;    // 自定義標識符(如類型ID)
    public int cbData;       // 數(shù)據(jù)長度(字節(jié)數(shù))
    public IntPtr lpData;    // 數(shù)據(jù)指針
}

// 消息常量定義
public static class WindowMessages
{
    public const uint WM_COPYDATA = 0x004A;  // 標準消息ID
    public const uint CUSTOM_MSG_BASE = 0x8000; // 自定義消息起始點
}

設計哲學:

  • 使用WM_COPYDATA標準消息確??缯Z言兼容性
  • dwData字段可擴展為消息類型標識符(如0x0001表示文本,0x0002表示二進制)

2.2 接收端實現(xiàn)

// 接收端窗體類
public class MessageReceiver : Form
{
    protected override void WndProc(ref Message m)
    {
        // 攔截自定義消息
        if (m.Msg == (int)WindowMessages.WM_COPYDATA)
        {
            try
            {
                // 解析消息結(jié)構(gòu)體
                var cds = (COPYDATASTRUCT)Marshal.PtrToStructure(
                    m.LParam,
                    typeof(COPYDATASTRUCT)
                );

                // 將指針轉(zhuǎn)換為字符串
                string receivedData = Marshal.PtrToStringAnsi(cds.lpData);
                
                // 處理數(shù)據(jù)(示例:顯示消息)
                MessageBox.Show($"收到數(shù)據(jù): {receivedData}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"消息處理異常: {ex.Message}");
            }
        }

        base.WndProc(ref m);
    }

    public static void Main()
    {
        Application.Run(new MessageReceiver());
        Console.WriteLine("接收端啟動,等待消息...");
    }
}

高級技巧:

  • 使用try-catch包裹消息處理防止程序崩潰
  • 添加日志記錄便于調(diào)試
  • 使用GCHandle管理內(nèi)存生命周期(詳見下文)

2.3 發(fā)送端實現(xiàn)

public class ProcessCommunicator
{
    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr SendMessage(
        IntPtr hWnd, 
        uint Msg, 
        IntPtr wParam, 
        ref COPYDATASTRUCT lParam
    );

    /// <summary>
    /// 向指定進程發(fā)送數(shù)據(jù)
    /// </summary>
    /// <param name="targetProcessName">目標進程名</param>
    /// <param name="data">要發(fā)送的數(shù)據(jù)</param>
    public static void SendDataToProcess(string targetProcessName, string data)
    {
        // 1. 獲取目標進程句柄
        IntPtr hWnd = WindowHandleManager.GetWindowHandle(targetProcessName);

        // 2. 將字符串轉(zhuǎn)換為字節(jié)數(shù)組
        byte[] bytes = Encoding.UTF8.GetBytes(data);
        
        // 3. 固定內(nèi)存地址(防止GC回收)
        GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        try
        {
            // 4. 構(gòu)造消息結(jié)構(gòu)體
            COPYDATASTRUCT cds = new COPYDATASTRUCT
            {
                dwData = IntPtr.Zero,        // 自定義標識符
                cbData = bytes.Length,       // 數(shù)據(jù)長度
                lpData = handle.AddrOfPinnedObject() // 數(shù)據(jù)指針
            };

            // 5. 發(fā)送消息
            IntPtr result = SendMessage(
                hWnd, 
                WindowMessages.WM_COPYDATA, 
                IntPtr.Zero, 
                ref cds
            );

            // 6. 錯誤處理
            if (result == IntPtr.Zero)
            {
                int errorCode = Marshal.GetLastWin32Error();
                throw new Exception($"發(fā)送失敗,錯誤碼:{errorCode}");
            }
        }
        finally
        {
            // 7. 釋放內(nèi)存
            handle.Free();
        }
    }
}

性能優(yōu)化:

  • 使用GCHandle.Alloc固定內(nèi)存地址防止GC干擾
  • 批量發(fā)送時復用內(nèi)存緩沖區(qū)
  • 添加發(fā)送頻率限制(如每秒不超過100次)

第三章:突破SendMessage的性能瓶頸

讓進程通信速度提升10倍的關鍵技巧

3.1 異步通信模式

// 異步發(fā)送任務(避免阻塞主線程)
public static async Task SendDataAsync(
    string targetProcessName, 
    string data,
    CancellationToken cancellationToken)
{
    await Task.Run(() =>
    {
        try
        {
            SendDataToProcess(targetProcessName, data);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"異步發(fā)送異常: {ex.Message}");
        }
    }, cancellationToken);
}

設計原則:

  • 使用Task.Run隔離耗時操作
  • 添加取消令牌支持中斷機制
  • 使用ValueTask優(yōu)化小數(shù)據(jù)場景

3.2 高吞吐量優(yōu)化

// 批量發(fā)送優(yōu)化器
public class BatchMessageOptimizer
{
    private readonly Queue<string> _messageQueue = new Queue<string>();
    private readonly object _lock = new object();
    private Timer _timer;

    public BatchMessageOptimizer(int intervalMs)
    {
        _timer = new Timer(SendBatch, null, Timeout.Infinite, Timeout.Infinite);
        _timer.Change(intervalMs, intervalMs);
    }

    public void Enqueue(string message)
    {
        lock (_lock)
        {
            _messageQueue.Enqueue(message);
        }
    }

    private void SendBatch(object state)
    {
        List<string> batch;
        lock (_lock)
        {
            batch = _messageQueue.ToList();
            _messageQueue.Clear();
        }

        foreach (var msg in batch)
        {
            ProcessCommunicator.SendDataToProcess("Receiver", msg);
        }
    }
}

性能對比:

模式吞吐量(條/秒)適用場景
單條發(fā)送50實時性要求高
批量發(fā)送500+大批量數(shù)據(jù)傳輸

第四章:解決SendMessage的致命缺陷

從理論到實踐的全面加固

4.1 窗口句柄失效問題

// 帶重試機制的句柄獲取
public static IntPtr GetWindowHandleWithRetry(
    string processName, 
    int maxRetries = 5, 
    int retryIntervalMs = 1000)
{
    for (int i = 0; i < maxRetries; i++)
    {
        try
        {
            return WindowHandleManager.GetWindowHandle(processName);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"第{i + 1}次嘗試失敗: {ex.Message}");
            Thread.Sleep(retryIntervalMs);
        }
    }
    throw new Exception("多次嘗試獲取句柄失敗");
}

防御策略:

  • 設置最大重試次數(shù)防止單點故障
  • 添加指數(shù)退避算法(每次重試間隔翻倍)
  • 集成健康檢查接口

4.2 內(nèi)存泄漏預防

// 使用對象池復用COPYDATASTRUCT
public class CopyDataPool
{
    private readonly ObjectPool<COPYDATASTRUCT> _pool;

    public CopyDataPool(int initialSize)
    {
        _pool = new ObjectPool<COPYDATASTRUCT>(() => new COPYDATASTRUCT(), initialSize);
    }

    public COPYDATASTRUCT Get()
    {
        return _pool.Get();
    }

    public void Return(COPYDATASTRUCT item)
    {
        // 重置字段
        item.dwData = IntPtr.Zero;
        item.cbData = 0;
        item.lpData = IntPtr.Zero;
        _pool.Return(item);
    }
}

內(nèi)存管理守則:

  • 對象池減少GC壓力
  • 顯式重置結(jié)構(gòu)體字段
  • 使用弱引用跟蹤未釋放資源

第五章:擴展應用場景

讓SendMessage發(fā)揮最大價值

5.1 傳輸復雜數(shù)據(jù)結(jié)構(gòu)

// 自定義數(shù)據(jù)序列化
[StructLayout(LayoutKind.Sequential)]
public struct UserMessage
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string Username;
    public int Score;
    public DateTime Timestamp;
}

// 發(fā)送復雜結(jié)構(gòu)
public static void SendUserMessage(IntPtr hWnd, UserMessage message)
{
    int size = Marshal.SizeOf(message);
    byte[] buffer = new byte[size];
    
    GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    try
    {
        IntPtr pBuffer = handle.AddrOfPinnedObject();
        Marshal.StructureToPtr(message, pBuffer, false);

        COPYDATASTRUCT cds = new COPYDATASTRUCT
        {
            dwData = (IntPtr)1, // 自定義消息類型
            cbData = size,
            lpData = pBuffer
        };

        SendMessage(hWnd, WindowMessages.WM_COPYDATA, IntPtr.Zero, ref cds);
    }
    finally
    {
        handle.Free();
    }
}

設計考量:

  • 使用StructLayout控制內(nèi)存布局
  • 添加版本號字段支持協(xié)議升級
  • 使用二進制序列化提升效率

5.2 實現(xiàn)雙向通信

// 雙向通信示例
public class BidirectionalCommunicator
{
    private IntPtr _serverHandle;
    private int _messageId = WindowMessages.CUSTOM_MSG_BASE + 1;

    public void Connect(string serverProcessName)
    {
        _serverHandle = WindowHandleManager.GetWindowHandle(serverProcessName);
    }

    public void SendRequest(string request)
    {
        // 構(gòu)造請求
        byte[] requestBytes = Encoding.UTF8.GetBytes(request);
        GCHandle requestHandle = GCHandle.Alloc(requestBytes, GCHandleType.Pinned);
        
        // 注冊回調(diào)
        IntPtr callbackPtr = Marshal.GetFunctionPointerForDelegate(
            new MessageCallback(OnResponseReceived)
        );
        
        // 發(fā)送請求
        COPYDATASTRUCT cds = new COPYDATASTRUCT
        {
            dwData = (IntPtr)_messageId,
            cbData = requestBytes.Length,
            lpData = requestHandle.AddrOfPinnedObject()
        };

        IntPtr result = SendMessage(
            _serverHandle, 
            WindowMessages.WM_COPYDATA, 
            callbackPtr, 
            ref cds
        );
        
        requestHandle.Free();
    }

    private void OnResponseReceived(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
    {
        // 處理響應...
    }

    // 服務器端需要實現(xiàn)對應的回調(diào)處理
}

雙向通信架構(gòu):

  • 使用唯一messageId標識會話
  • 回調(diào)函數(shù)地址作為wParam傳遞
  • 需要雙方約定完整的協(xié)議規(guī)范

通過本文,你已經(jīng)掌握了:

  1. SendMessage的底層工作原理
  2. 完整的進程間通信實現(xiàn)方案
  3. 高性能優(yōu)化策略
  4. 常見異常的防御性編程
  5. 復雜場景的擴展應用

墨工的終極建議:

  • 對于高可靠性場景,建議結(jié)合MemoryMappedFile實現(xiàn)共享內(nèi)存
  • 使用PerformanceCounter監(jiān)控通信性能
  • 開發(fā)可視化調(diào)試工具(如Wireshark插件)

以上就是C#使用SendMessage實現(xiàn)進程間通信的示例代碼的詳細內(nèi)容,更多關于C# SendMessage進程間通信的資料請關注腳本之家其它相關文章!

相關文章

  • 詳解C#讀寫Excel的幾種方法

    詳解C#讀寫Excel的幾種方法

    這篇文章主要介紹了詳解C#讀寫Excel的幾種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • 一文詳解如何在C#中使用RESTful API

    一文詳解如何在C#中使用RESTful API

    通過Web開發(fā)的路徑,大家會發(fā)現(xiàn)自己遲早需要處理外部API,本文將列出在C#項目中使用RESTful API的方法的最全面列表,希望對大家有所幫助
    2025-03-03
  • Unity實現(xiàn)老虎機滾動抽獎效果的示例代碼

    Unity實現(xiàn)老虎機滾動抽獎效果的示例代碼

    這篇文章主要介紹了Unity實現(xiàn)老虎機滾動抽獎效果的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • C# DataTable中查詢指定字段名稱的數(shù)據(jù)

    C# DataTable中查詢指定字段名稱的數(shù)據(jù)

    這篇文章主要介紹了C# DataTable中查詢指定字段名稱的數(shù)據(jù),本文直接給出實例代碼,簡單易懂,需要的朋友可以參考下
    2015-06-06
  • 手把手教你用c#制作一個小型桌面程序

    手把手教你用c#制作一個小型桌面程序

    本文介紹了使用Visual?Studio創(chuàng)建DLL項目,并通過屬性管理器導入工程屬性表的方法,詳細闡述了制作Windows動態(tài)庫的步驟,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-09-09
  • C#基于Socket的TCP通信實現(xiàn)聊天室案例

    C#基于Socket的TCP通信實現(xiàn)聊天室案例

    這篇文章主要為大家詳細介紹了C#基于Socket的TCP通信實現(xiàn)聊天室案例,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • c#模擬銀行atm機示例分享

    c#模擬銀行atm機示例分享

    這篇文章主要介紹了c#模擬銀行atm機示例,實現(xiàn)了用戶登錄、用戶存款、用戶取款等功能,需要的朋友可以參考下
    2014-03-03
  • vs2019 實現(xiàn)C#調(diào)用c++的dll兩種方法

    vs2019 實現(xiàn)C#調(diào)用c++的dll兩種方法

    這篇文章主要介紹了vs2019 實現(xiàn)C#調(diào)用c++的dll兩種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10
  • 基于C#實現(xiàn)的多邊形沖突檢測實例

    基于C#實現(xiàn)的多邊形沖突檢測實例

    這篇文章主要給大家介紹了基于C#實現(xiàn)的多邊形沖突檢測的相關資料,文中介紹的方法并未使用第三方類庫,可以完美解決這個問題,需要的朋友可以參考下
    2021-07-07
  • C#中MQTT的使用小結(jié)

    C#中MQTT的使用小結(jié)

    本文主要介紹了C#中MQTT的使用小結(jié),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-12-12

最新評論

吉木萨尔县| 双流县| 河曲县| 武陟县| 九龙县| 碌曲县| 东至县| 县级市| 同德县| 临江市| 西乌| 赤峰市| 青铜峡市| 靖江市| 怀来县| 左云县| 兴仁县| 如东县| 平乡县| 洪雅县| 常山县| 太原市| 鹤庆县| 漳州市| 长白| 观塘区| 沁阳市| 苗栗市| 江永县| 广灵县| 平潭县| 扶风县| 舒城县| 凤翔县| 和龙市| 罗定市| 江西省| 凌云县| 宜兴市| 辰溪县| 岚皋县|