首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC++ 進程間通訊 (IPC) 實戰:動態資料交換 (DDE) 實作客戶/伺服器雙向資料傳遞

     編輯:關於VC++

前言:為什麼選擇 DDE?

32 位元 Windows 各進程擁有獨立位址空間,無法直接存取彼此記憶體。IPC 方案包括:剪貼板、共享記憶體、管道、Socket、COM、DDE。DDE (Dynamic Data Exchange) 為 Windows 早期標準協議,建於訊息系統與共享記憶體之上,適合簡單資料交換、啟動關聯應用。本文實作一個 DDE 伺服器/客戶端合一程式,雙擊執行兩個實例即可互通。

DDE 核心概念

  • 三層命名:Service (應用名) → Topic (主題/目錄) → Item (資料項)
  • 角色:Client (發起請求) / Server (回應資料) / Client-Server 合一
  • 連結類型:冷 (單次請求) / 暖 (通知變更不送資料) / 熱 (資料變更即時推送) — 本文採用
  • DDEML:Dynamic Data Exchange Management Library,簡化開發的 API 集合

實作架構:單一程式雙角色

程式啟動即註冊為 Server,並嘗試連接另一實例作為 Client。雙向熱連結交換兩項資料:

  • Item1:使用者輸入的字串
  • Item2:定時器遞增的計數器

關鍵代碼片段

1. 全域定義與變數

#define NITEM 2
const char szApp[] = "DDEDemoServer";
const char szTopic[] = "Topic";
const char* pszItem[NITEM] = {"Item1", "Item2"};

int count = 0;
CString ServerData[NITEM];
HCONV hConv = 0;
DWORD idInst = 0;
HWND hWnd = 0;
HSZ hszApp = 0, hszTopic = 0, hszItem[NITEM];
BOOL bConnect = FALSE;

2. DDE 回呼函式 (核心處理邏輯)

HDDEDATA CALLBACK DdeCallback(UINT wType, UINT wFmt, HCONV hConv, HSZ hszTopic, HSZ hszItem,
                              HDDEDATA hData, DWORD dwData1, DWORD dwData2) {
    char buf[256];
    switch (wType) {
        case XTYP_CONNECT:
        case XTYP_ADVSTART:
            return (HDDEDATA)TRUE; // 允許連線/建議

        case XTYP_ADVDATA: // 客戶端收到伺服器推送資料
            for (int i = 0; i < NITEM; i++) {
                if (hszItem == hszItem[i]) {
                    DdeGetData(hData, (LPBYTE)buf, 255, 0);
                    SetDlgItemText(hWnd, (i==0)?IDC_STATIC2:IDC_STATIC3, buf);
                }
            }
            return (HDDEDATA)DDE_FACK;

        case XTYP_REQUEST: // 客戶端主動請求
        case XTYP_ADVREQ:  // 熱連結定期請求
            for (int i = 0; i < NITEM; i++) {
                if (hszItem == hszItem[i]) {
                    return DdeCreateDataHandle(idInst, (LPBYTE)(LPCTSTR)ServerData[i],
                        ServerData[i].GetLength()+1, 0, hszItem, wFmt, 0);
                }
            }
            break;
    }
    return 0;
}

3. 初始化:OnInitDialog

BOOL CDdeDemoDlg::OnInitDialog() {
    // ... 圖示、選單初始化 ...

    hWnd = m_hWnd;
    if (DdeInitialize(&idInst, (PFNCALLBACK)DdeCallback,
        APPCMD_FILTERINITS | CBF_FAIL_EXECUTES | CBF_SKIP_CONNECT_CONFIRMS |
        CBF_FAIL_SELFCONNECTIONS | CBF_FAIL_POKES, 0)) {
        MessageBox(_T("DDE 初始化失敗!")); return FALSE;
    }

    hszApp = DdeCreateStringHandle(idInst, szApp, CP_WINANSI);
    hszTopic = DdeCreateStringHandle(idInst, szTopic, CP_WINANSI);
    for (int i=0; i

4. 定時器:資料更新與連線嘗試

void CDdeDemoDlg::OnTimer(UINT nIDEvent) {
    count++;
    ServerData[1].Format(_T("%d"), count);
    SetDlgItemText(IDC_STATIC1, ServerData[1]);
    DdePostAdvise(idInst, hszTopic, hszItem[1]); // 推送計數器更新

    if (!bConnect) { // 嘗試連線另一實例
        hConv = DdeConnect(idInst, hszApp, hszTopic, NULL);
        if (hConv) {
            bConnect = TRUE;
            DWORD dwResult;
            for (int i=0; i

5. 使用者輸入變更:推送字串

void CDdeDemoDlg::OnChangeEdit1() {
    UpdateData();
    ServerData[0] = m_edit;
    DdePostAdvise(idInst, hszTopic, hszItem[0]); // 推送字串更新
}

6. 清理:OnDestroy

void CDdeDemoDlg::OnDestroy() {
    KillTimer(1);
    DdeNameService(idInst, 0, 0, DNS_UNREGISTER); // 註銷服務
    DdeFreeStringHandle(idInst, hszApp);
    DdeFreeStringHandle(idInst, hszTopic);
    for (int i=0; i

編譯與測試步驟

  1. 建立 MFC Dialog 專案 `DDEDemo`
  2. 介面放置:Edit (IDC_EDIT1)、Static×3 (IDC_STATIC1~3)、Group Box×2
  3. 加入 `ddeml.h`,連結 `user32.lib` (隱含)
  4. 編譯執行,開啟兩個實例,輸入文字觀察另一端 Static2 更新,計數器同步顯示於 Static1/Static3

其他 IPC 方案簡評

方案優點缺點適用場景
DDE簡單、系統內建、跨語言效能低、功能少、漸被淘汰簡單資料交換、舊系統整合
共享記憶體 + Event極高效能、大資料量需同步機制、複雜高頻大量資料交換
Named Pipe雙向、網路透明、安全性程式碼較多本機/跨機進程通訊
Socket (TCP/UDP)跨平台、跨網路、標準協議設計、連線管理分散式系統、網路通訊
COM / ATL物件導向、語言中立、註冊管理學習曲線陡峭元件化架構、跨語言元件
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved