基本概念 (DDE)

這些概念是瞭解動態數據交換 (DDE) 和動態數據交換管理連結庫 (DDEML) 的關鍵。

用戶端和伺服器互動

DDE 一律發生在用戶端應用程式與伺服器應用程式之間。 DDE 用戶端應用程式會藉由建立與伺服器的交談來起始交換,以將交易傳送至伺服器。 交易是數據或服務的要求。 DDE 伺服器應用程式會藉由提供資料或服務給用戶端來回應交易。 例如,圖形應用程式可能包含代表公司季度利潤的條形圖,但條形圖的數據可能會包含在電子錶格應用程式中。 為了取得最新的利潤數位,圖形應用程式(用戶端)可以與電子錶格應用程式(伺服器)建立交談。 圖形應用程式接著可以將交易傳送至電子錶格應用程式,要求最新的收益數位。

伺服器可以同時有許多用戶端,而用戶端可以從多部伺服器要求數據。 應用程式也可以是客戶端和伺服器。 用戶端或伺服器可以隨時終止交談。

交易和 DDE 回呼函式

DDEML 會透過將交易傳送至應用程式的 DDE 回呼函式,通知應用程式有關 DDE 活動的 DDE 活動。 DDE 交易類似於訊息,它是具名常數,隨附其他參數,其中包含有關交易的其他資訊。

DDEML 會將交易傳遞至應用程式定義的 DDE 回呼函式,該函式會執行適用於交易類型的動作。 例如,當用戶端應用程式嘗試建立與伺服器應用程式的交談時,用戶端會呼叫 Dde 連線 函式。 此函式會導致 DDEML 將XTYP_CONNECT交易傳送至伺服器的 DDE 回呼函式。 回呼函式可以藉由將 TRUE 傳回 DDEML 來允許交談,也可以藉由傳回 FALSE 來拒絕交談。 如需交易的詳細討論,請參閱 交易管理

服務名稱、主題名稱和項目名稱

DDE 伺服器會使用三層階層服務名稱(在先前的 DDE 檔中稱為「應用程式名稱」)、主題名稱和專案名稱,以唯一識別伺服器可在交談期間交換的數據單位。

服務名稱是伺服器應用程式嘗試建立與伺服器交談時所回應的字串。 客戶端必須指定此服務名稱,才能建立與伺服器的交談。 雖然伺服器可以回應許多服務名稱,但大部分伺服器只會回應一個名稱。

主題名稱是識別邏輯數據內容的字串。 對於在檔案型檔上運作的伺服器,主題名稱通常是檔名;對於其他伺服器,它們是其他應用程式特定的字串。 用戶端在嘗試與伺服器建立交談時,必須指定主題名稱以及伺服器的服務名稱。

專案名稱是一個字串,可識別伺服器可以在交易期間傳遞至客戶端的數據單位。 例如,專案名稱可能會識別整數、字串、數個文字段落或點陣陣圖。

服務、主題和專案名稱可讓用戶端建立與伺服器的交談,並從伺服器接收數據。

系統主題

系統主題提供任何 DDE 用戶端一般感興趣的資訊內容。 建議伺服器應用程式隨時支援系統主題。 系統主題定義於 DDEML 中。H 頭檔作為SZDDESYS_TOPIC。

若要判斷有哪些伺服器存在,以及他們可以提供的資訊種類,用戶端應用程式可以在啟動時要求系統主題上的交談,並將裝置名稱設定為 NULL。 這類通配符交談在系統效能方面成本很高,因此應該保持在最低水準。 如需起始 DDE 交談的詳細資訊,請參閱 對話管理

伺服器必須支援 System 主題內的下列專案名稱,以及用戶端有用的任何其他項目名稱。

項目 說明
SZDDE_ITEM_ITEMLIST 非系統主題下支援的項目清單。 (這份清單可能因時刻而異,從主題到主題。
SZDDESYS_ITEM_FORMATS 以索引標籤分隔的字串清單,代表服務應用程式可能支援的所有剪貼簿格式。 代表預先定義剪貼簿格式的字串相當於已移除 「CF_」 前置詞的CF_值。 例如,CF_TEXT格式是由字串 「TEXT」 表示。 這些字串必須是大寫,才能進一步將其識別為預先定義的格式。 格式清單必須以內容最豐富的順序顯示到最不豐富的內容。 如需剪貼簿格式和轉譯數據的詳細資訊,請參閱 剪貼簿
SZDDESYS_ITEM_HELP 用戶可讀取的一般興趣資訊。 此專案至少必須包含如何使用伺服器應用程式的 DDE 功能的相關信息。 這項資訊可以包含但不限於如何指定主題中的專案、伺服器可執行的執行字元串、允許哪些戳選交易,以及如何尋找其他系統主題項目的協助。
SZDDESYS_ITEM_RTNMSG 支援最近使用 WM_DDE_ACK 訊息的詳細數據。 當需要超過 8 位的應用程式特定傳回數據時,此專案很有用。
SZDDESYS_ITEM_STATUS 伺服器目前狀態的指示。 一般而言,此專案僅支援CF_TEXT格式,並包含 Ready 或 Busy 字串。
SZDDESYS_ITEM_SYSITEMS 此伺服器在 System 主題下支援的項目清單。
SZDDESYS_ITEM_TOPICS 伺服器目前支援的主題清單。 (這份清單可能因時刻而異。

這些專案名稱是在 DDEML 中定義的值。H 頭檔。 若要取得這些字串的字串句柄,應用程式必須使用 DDEML 字串管理函式,就像 DDEML 應用程式中的任何其他字串一樣。 如需管理字串的詳細資訊,請參閱 字串管理

初始化

呼叫任何其他 DDEML 函式之前,應用程式必須呼叫 DdeInitialize 函式DdeInitialize 會取得應用程式的實例識別碼、向 DDE 註冊應用程式的 DDE 回呼函式,並指定回呼函式的交易篩選旗標。

應用程式或 DLL 的每個實例都必須將其實例識別碼當做 idInst 參數傳遞至任何其他需要它的 DDEML 函式。 多個 DDEML 實例的目的是要支援必須在應用程式使用 DDEML 的同時使用 DDEML 的 DLL。 應用程式不得使用一個以上的 DDEML 實例。

交易篩選 會防止 DDEML 將不必要的交易傳遞至應用程式的 DDE 回呼函式,將系統效能優化。 應用程式會在 DdeInitialize ufCmd 參數中設定交易篩選。 應用程式必須為其回呼函式中未處理的每個交易類型指定交易篩選旗標。 應用程式可以使用對 DdeInitialize 的後續呼叫來變更其交易篩選。 如需交易的詳細資訊,請參閱 交易管理

下列範例示範如何初始化應用程式以使用 DDEML。

DWORD idInst = 0; 
HINSTANCE hinst; 
 
DdeInitialize(&idInst,         // receives instance identifier 
    (PFNCALLBACK) DdeCallback, // pointer to callback function 
    CBF_FAIL_EXECUTES |        // filter XTYPE_EXECUTE 
    CBF_SKIP_ALLNOTIFICATIONS, // filter notifications 
    0); 

應用程式在不再使用 DDEML 時,必須呼叫 DdeUninitialize 函式。 此函式會終止應用程式目前開啟的任何交談,並釋放為應用程式配置之系統的 DDEML 資源。

Callback 函式

使用 DDEML 的應用程式必須提供回呼函式,以處理影響應用程式的 DDE 事件。 DDEML 會將交易傳送至應用程式的 DDE 回呼函式,以通知這類事件的應用程式。 回呼函式收到的交易取決於 DdeInitialize 中指定的應用程式,以及應用程式是否為客戶端、伺服器或兩者所指定的回呼篩選旗標。 如需詳細資訊,請參閱 DdeCallback

下列範例顯示一般用戶端應用程式回呼函式的一般結構。

HDDEDATA CALLBACK DdeCallback(uType, uFmt, hconv, hsz1, 
    hsz2, hdata, dwData1, dwData2) 
UINT uType;       // transaction type 
UINT uFmt;        // clipboard data format 
HCONV hconv;      // handle to conversation 
HSZ hsz1;         // handle to string 
HSZ hsz2;         // handle to string 
HDDEDATA hdata;   // handle to global memory object 
DWORD dwData1;    // transaction-specific data 
DWORD dwData2;    // transaction-specific data 
{ 
    switch (uType) 
    { 
        case XTYP_REGISTER: 
        case XTYP_UNREGISTER: 
            . 
            . 
            . 
            return (HDDEDATA) NULL; 
 
        case XTYP_ADVDATA: 
            . 
            . 
            . 
            return (HDDEDATA) DDE_FACK; 
 
        case XTYP_XACT_COMPLETE: 
            
            // 
            
            return (HDDEDATA) NULL; 
 
        case XTYP_DISCONNECT: 
            
            // 
            
            return (HDDEDATA) NULL; 
 
        default: 
            return (HDDEDATA) NULL; 
    } 
} 

uType 參數會指定由 DDEML 傳送至回呼函式的交易類型。 其餘參數的值取決於交易類型。 下列主題會說明產生交易類型和事件的事件。 如需每個交易類型的詳細資訊,請參閱 交易管理

字串管理

若要執行 DDE 工作,許多 DDEML 函式都需要存取字串。 例如,用戶端在呼叫 Dde 連線 函式以要求與伺服器交談時,必須指定服務名稱和主題名稱。 應用程式會藉由傳遞字串句柄 (HSZ) 而不是 DDEML 函式中的指標來指定字串。 字串句柄是由系統指派的 DWORD 值,可識別字串。

應用程式可以藉由呼叫 DdeCreateStringHandle 函式來取得特定字串的字串句柄。 此函式會向系統註冊字串,並將字串句柄傳回給應用程式。 應用程式可以將句柄傳遞至必須存取字串的 DDEML 函式。 下列範例會取得 System 主題字串和服務名稱字串的字串句柄。

HSZ hszServName; 
HSZ hszSysTopic; 
hszServName = DdeCreateStringHandle( 
    idInst,         // instance identifier 
    "MyServer",     // string to register 
    CP_WINANSI);    // Windows ANSI code page 
 
hszSysTopic = DdeCreateStringHandle( 
    idInst,         // instance identifier 
    SZDDESYS_TOPIC, // System topic 
    CP_WINANSI);    // Windows ANSI code page 
    

上述範例中的 idInst 參數會指定 DdeInitialize 函式取得的實例識別碼。

應用程式 DDE 回呼函式會在大部分的 DDE 交易期間接收一或多個字串句柄。 例如,伺服器會在XTYP_REQUEST交易期間收到兩個字元串句柄:一個會識別指定主題名稱的字串,另一個則識別指定專案名稱的字串串。 應用程式可以取得對應至字串句柄的字串長度,並藉由呼叫 DdeQueryString 函式,將字串複製到應用程式定義的緩衝區,如下列範例所示。

DWORD idInst; 
DWORD cb; 
HSZ hszServ; 
PSTR pszServName; 
cb = DdeQueryString(idInst, hszServ, (LPSTR) NULL, 0, 
    CP_WINANSI) + 1; 
pszServName = (PSTR) LocalAlloc(LPTR, (UINT) cb); 
DdeQueryString(idInst, hszServ, pszServName, cb, CP_WINANSI); 

實例特定的字串句柄無法從字串句柄對應至字串,而無法對應回字串句柄。 例如,雖然 DdeQueryString 會從字串句柄建立字串,但 DdeCreateStringHandle 會從該字串建立字串句柄,但兩個句柄並不相同,如下列範例所示。

DWORD idInst; 
DWORD cb; 
HSZ hszInst, hszNew; 
PSZ pszInst; 
DdeQueryString(idInst, hszInst, pszInst, cb, CP_WINANSI); 
hszNew = DdeCreateStringHandle(idInst, pszInst, CP_WINANSI); 
// hszNew != hszInst ! 

若要比較兩個字串句柄的值,請使用 DdeCmpStringHandles 函式。

當回呼函式傳回時,傳遞至應用程式的 DDE 回呼函式的字串句柄會變成無效。 應用程式可以使用 DdeKeepStringHandle 函式,將字串句柄儲存在回呼函式傳回之後使用。

當應用程式呼叫 DdeCreateStringHandle 時,系統會將指定的字串輸入字串數據表,併產生用來存取字串的句柄。 系統也會維護字串數據表中每個字串的使用計數。

當應用程式呼叫 DdeCreateStringHandle 並指定已存在於資料表中的字串時,系統會遞增使用量計數,而不是新增另一個出現的字串。 (應用程式也可以使用 遞增使用量計數 DdeKeepStringHandle.)當應用程式呼叫 DdeFreeStringHandle 函式時,系統會遞減使用量計數。

當數據表的使用量計數等於零時,就會從數據表中移除字串。 因為一個以上的應用程式可以取得特定字串的句柄,所以應用程式不能釋放字串句柄超過建立或保留句柄的次數。 否則,應用程式可能會導致字串從數據表中移除,而拒絕其他應用程式存取字串。

DDEML 字串管理函式是以 Atom 管理員為基礎,而且受限於與 Atom 相同的大小限制。

DDEML 和線程

DdeInitialize 函式會向 DDEML 註冊應用程式,並建立 DDEML 實例。 DDEML 實例是以線程為基礎,與稱為 DdeInitialize 的線程相關聯。

所有屬於 DDEML 實例之物件的 DDEML 函數呼叫,都必須從呼叫 DdeInitialize 的相同線程建立實例。 如果您從不同的線程呼叫 DDEML 函式,函式將會失敗。 您無法從配置交談的線程存取 DDEML 交談。