|
|
|
Microsoft Windows provides several methods for transferring data between applications. One method is to use the Dynamic Data Exchange (DDE) protocol. The DDE protocol is a set of messages and guidelines. It sends messages between applications that share data and uses shared memory to exchange data between applications. Applications can use the DDE protocol for one-time data transfers and for continuous exchanges in which applications send updates to one another as new data becomes available.
About DDEML
The Dynamic Data Exchange Management Library (DDEML) provides an interface that simplifies the task of adding DDE capability to an application. Instead of sending, posting, and processing DDE messages directly, an application uses the functions provided by the DDEML to manage DDE conversations. A DDE conversation is the interaction between client and server applications. The DDEML also provides a means for managing the strings and data shared among DDE applications. Instead of using atoms and pointers to shared memory objects, DDE applications create and exchange string handles, which identify strings, and data handles, which identify DDE objects.
How it works ?
DDE always occurs between a client application and a server application. The DDE client application initiates the exchange by establishing a conversation with the server to send transactions to the server. A transaction is a request for data or services. The DDE server application responds to transactions by providing data or services to the client.
Some Terminology
- Service Names : A service name is a string a server application responds to when a client attempts to establish a conversation with the server. A client must specify this service name to establish a conversation with the server. Although a server can respond to many service names, most servers respond to only one name.
- Topic Names : A topic name is a string that identifies a logical data context. For servers that operate on file-based documents, topic names are typically filenames; for other servers, they are other application-specific strings. A client must specify a topic name along with a server's service name when it attempts to establish a conversation with a server.
- Item Names : An item name is a string that identifies a unit of data a server can pass to a client during a transaction. For example, an item name might identify an integer, a string, several paragraphs of text, or a bitmap.
- Transactions : The DDEML notifies an application about DDE activity that affects the application by sending transactions to the application's DDE callback function. A DDE transaction is similar to a message — it is a named constant accompanied by other parameters that contain additional information about the transaction.
- DDE Callback Function : The DDEML passes a transaction to an application-defined DDE callback function that carries out an action appropriate to the type of transaction. For example, when a client application attempts to establish a conversation with a server application, the client calls the DdeConnect function. This function causes the DDEML to send an XTYP_CONNECT transaction to the server's DDE callback function. The callback function can allow the conversation by returning TRUE to the DDEML, or it can deny the conversation by returning FALSE.
- System Topic :
The System topic provides a context for information of general interest to any DDE client. It is recommended that server applications support the System topic at all times.
Steps to implement DDE Server
- Initialize the DDE subsystem by calling DdeInitialize.
- Create string handles for server/topic using DdeCreateStringHandle
- Now to make sure that we are the only server with a specific server/topic name call DdeConnect with server/topic handles which we created in step 2. If this call succeed mean DDE server is already with specified server/topic name so dont execute the next step
- If step 3 is successful then call DdeNameService with DNS_REGISTER option to register the server with the DDE subsystem.
- If DDE Server is registered then you should receive various transaction request in DDECallback function. Start processing transactions in DDE Callback.
- When you dont want to run DDE Server then call DdeNameService with DNS_UNREGISTER option and then call DdeUninitialize to break down the link with the DDE subsystem so no more client requests can be processed.
DDE Transactions
Here is the list of some transactions and their description
XTYP_CONNECT
- A client uses the XTYP_CONNECT transaction to establish a conversation. A Dynamic Data Exchange (DDE) server callback function, DdeCallback, receives this transaction when a client specifies a service name that the server supports (and a topic name that is not NULL) in a call to the DdeConnect function.
XTYP_ADVDATA
- The XTYP_ADVDATA transaction informs the client that the value of the data item has changed. The Dynamic Data Exchange (DDE) client callback function, DdeCallback, receives this transaction after establishing an advise loop with a server.
XTYP_ADVREQ
- The XTYP_ADVREQ transaction informs the server that an advise transaction is outstanding on the specified topic name and item name pair and that data corresponding to the topic name and item name pair has changed. The system sends this transaction to the Dynamic Data Exchange (DDE) callback function, DdeCallback, after the server calls the DdePostAdvise function.
XTYP_ADVSTART
- A client uses the XTYP_ADVSTART transaction to establish an advise loop with a server. A Dynamic Data Exchange (DDE) server callback function, DdeCallback, receives this transaction when a client specifies XTYP_ADVSTART as the wType parameter of the DdeClientTransaction function.
XTYP_ADVSTOP
XTYP_CONNECT
- A client uses the XTYP_CONNECT transaction to establish a conversation. A Dynamic Data Exchange (DDE) server callback function, DdeCallback, receives this transaction when a client specifies a service name that the server supports (and a topic name that is not NULL) in a call to the DdeConnect function.
XTYP_CONNECT_CONFIRM
- A Dynamic Data Exchange (DDE) server callback function, DdeCallback, receives the XTYP_CONNECT_CONFIRM transaction to confirm that a conversation has been established with a client and to provide the server with the conversation handle. The system sends this transaction as a result of a previous XTYP_CONNECT or XTYP_WILDCONNECT transaction.
XTYP_DISCONNECT
- An application's Dynamic Data Exchange (DDE) callback function, DdeCallback, receives the XTYP_DISCONNECT transaction when the application's partner in a conversation uses the DdeDisconnect function to terminate the conversation.
XTYP_ERROR
- A Dynamic Data Exchange (DDE) callback function, DdeCallback, receives the XTYP_ERROR transaction when a critical error occurs.
XTYP_EXECUTE
XTYP_MONITOR
- A Dynamic Data Exchange (DDE) debugger's DDE callback function, DdeCallback, receives the XTYP_MONITOR transaction whenever a DDE event occurs in the system. To receive this transaction, an application must specify the APPCLASS_MONITOR value when it calls the DdeInitialize function.
XTYP_POKE
XTYP_REGISTER
- A Dynamic Data Exchange (DDE) callback function, DdeCallback, receives the XTYP_REGISTER transaction type whenever a Dynamic Data Exchange Management Library (DDEML) server application uses the DdeNameService function to register a service name, or whenever a non-DDEML application that supports the System topic is started.
XTYP_REQUEST
XTYP_UNREGISTER
- A Dynamic Data Exchange (DDE) callback function, DdeCallback, receives the XTYP_UNREGISTER transaction whenever a Dynamic Data Exchange Management Library (DDEML) server application uses the DdeNameService function to unregister a service name, or whenever a non-DDEML application that supports the System topic is terminated.
XTYP_WILDCONNECT
- The XTYP_WILDCONNECT transaction allows a client to establish a conversation on each of the server's service name and topic name pairs that match the specified service name and topic name. A Dynamic Data Exchange (DDE) server callback function, DdeCallback, receives this transaction when a client specifies a NULL service name, a NULL topic name, or both in a call to the DdeConnect or DdeConnectList function.
XTYP_XACT_COMPLETE
Lets start with actual implementation of DDE Server. DDE Client Implementation is covered in the Part2 of this article
DDE Server
Step-By-Step Example - Create a standard exe project - Rename project to DDEServer - Add one module to the project - Add two command buttons and one textbox control on the form1 - Add the following code in form1 |
Click here to copy the following block | Option Explicit
Private hszDDEServer As Long Private hszDDETopic As Long Private hszDDEItemPoke As Long Private bRunning As Boolean
Private Sub Command2_Click() Text1.Text = "" End Sub
Private Sub Command1_Click() If (DdePostAdvise(lInstID, 0, 0)) Then Debug.Print "DdePostAdvise() Success." Else Debug.Print "DdePostAdvise() Failed." End If End Sub
Private Sub Form_Load() Command1.Caption = "Advice" Command2.Caption = "Clear" Me.Caption = "DDE Server"
If DdeInitialize(lInstID, AddressOf DDECallback, APPCMD_FILTERINITS, 0) Then Exit Sub End If
hszDDEServer = DdeCreateStringHandle(lInstID, DDE_SERVER, CP_WINANSI) hszDDETopic = DdeCreateStringHandle(lInstID, DDE_TOPIC, CP_WINANSI) hszDDEItemPoke = DdeCreateStringHandle(lInstID, DDE_POKE, CP_WINANSI) hszDDEItemAdvise = DdeCreateStringHandle(lInstID, DDE_ADVISE, CP_WINANSI)
If (DdeConnect(lInstID, hszDDEServer, hszDDETopic, ByVal 0&)) Then MsgBox "A DDE server named " & Chr(34) & DDE_SERVER & Chr(34) & " with topic " & _ Chr(34) & DDE_TOPIC & Chr(34) & " is already running.", vbExclamation, App.Title Unload Me Exit Sub End If
If (DdeNameService(lInstID, hszDDEServer, 0, DNS_REGISTER)) Then bRunning = True End If
Me.WindowState = vbMinimized End Sub
Private Sub Form_Terminate() DdeFreeStringHandle lInstID, hszDDEServer DdeFreeStringHandle lInstID, hszDDETopic DdeFreeStringHandle lInstID, hszDDEItemPoke DdeFreeStringHandle lInstID, hszDDEItemAdvise
If bRunning Then DdeNameService lInstID, hszDDEServer, 0, DNS_UNREGISTER End If
DdeUninitialize lInstID End Sub |
- Add the following code in module1 |
Click here to copy the following block | Option Explicit
Global lInstID As Long Global hszDDEItemAdvise As Long
Public Const DDE_SERVER = "MyServer" Public Const DDE_TOPIC = "MyTopic" Public Const DDE_ADVISE = "MyAdvise" Public Const DDE_REQUEST = "MyRequest" Public Const DDE_POKE = "MyPoke" Public Const DDE_COMMAND1 = "MAX" Public Const DDE_COMMAND2 = "MIN" Public Const DDE_COMMAND3 = "NORMAL"
Public Const MAGIC_NUMBER = 3
Public Const DDE_REQUEST_STRING = "The server input window is empty."
Public Const DMLERR_NO_ERROR = 0 Public Const DMLERR_ADVACKTIMEOUT = &H4000 Public Const DMLERR_BUSY = &H4001 Public Const DMLERR_DATAACKTIMEOUT = &H4002 Public Const DMLERR_DLL_NOT_INITIALIZED = &H4003 Public Const DMLERR_DLL_USAGE = &H4004 Public Const DMLERR_EXECACKTIMEOUT = &H4005 Public Const DMLERR_INVALIDPARAMETER = &H4006 Public Const DMLERR_LOW_MEMORY = &H4007 Public Const DMLERR_MEMORY_ERROR = &H4008 Public Const DMLERR_NOTPROCESSED = &H4009 Public Const DMLERR_NO_CONV_ESTABLISHED = &H400A Public Const DMLERR_POKEACKTIMEOUT = &H400B Public Const DMLERR_POSTMSG_FAILED = &H400C Public Const DMLERR_REENTRANCY = &H400D Public Const DMLERR_SERVER_DIED = &H400E Public Const DMLERR_SYS_ERROR = &H400F Public Const DMLERR_UNADVACKTIMEOUT = &H4010 Public Const DMLERR_UNFOUND_QUEUE_ID = &H4011
Public Const APPCMD_FILTERINITS = &H20& Public Const XCLASS_BOOL = &H1000 Public Const XCLASS_DATA = &H2000 Public Const XCLASS_FLAGS = &H4000 Public Const XCLASS_NOTIFICATION = &H8000 Public Const XTYPF_NOBLOCK = &H2 Public Const XTYP_ADVDATA = (&H10 Or XCLASS_FLAGS) Public Const XTYP_ADVREQ = (&H20 Or XCLASS_DATA Or XTYPF_NOBLOCK) Public Const XTYP_ADVSTART = (XCLASS_BOOL Or &H30) Public Const XTYP_ADVSTOP = (XCLASS_NOTIFICATION Or &H40) Public Const XTYP_CONNECT = (XCLASS_BOOL Or &H60 Or XTYPF_NOBLOCK) Public Const XTYP_CONNECT_CONFIRM = (XCLASS_NOTIFICATION Or &H70 Or XTYPF_NOBLOCK) Public Const XTYP_DISCONNECT = (XCLASS_NOTIFICATION Or &HC0 Or XTYPF_NOBLOCK) Public Const XTYP_ERROR = (XCLASS_NOTIFICATION Or &H0 Or XTYPF_NOBLOCK) Public Const XTYP_EXECUTE = (XCLASS_FLAGS Or &H50) Public Const XTYP_MASK = &HF0 Public Const XTYP_MONITOR = (XCLASS_NOTIFICATION Or &HF0 Or XTYPF_NOBLOCK) Public Const XTYP_POKE = (XCLASS_FLAGS Or &H90) Public Const XTYP_REGISTER = (XCLASS_NOTIFICATION Or &HA0 Or XTYPF_NOBLOCK) Public Const XTYP_REQUEST = (XCLASS_DATA Or &HB0) Public Const XTYP_SHIFT = 4 Public Const XTYP_UNREGISTER = (XCLASS_NOTIFICATION Or &HD0 Or XTYPF_NOBLOCK) Public Const XTYP_WILDCONNECT = (XCLASS_DATA Or &HE0 Or XTYPF_NOBLOCK) Public Const XTYP_XACT_COMPLETE = (XCLASS_NOTIFICATION Or &H80) Public Const CP_WINANSI = 1004 Public Const CP_WINUNICODE = 1200 Public Const CF_TEXT = 1 Public Const CBF_SKIP_ALLNOTIFICATIONS = &H3C0000 Public Const TIMEOUT_ASYNC = &HFFFF Public Const DNS_REGISTER = &H1 Public Const DNS_UNREGISTER = &H2 Public Const DDE_FACK = &H8000 Public Const DDE_FBUSY = &H4000 Public Const DDE_FNOTPROCESSED = &H0 Public Const HDATA_APPOWNED = &H1
Public Type SECURITY_QUALITY_OF_SERVICE Length As Long Impersonationlevel As Integer ContextTrackingMode As Integer EffectiveOnly As Long End Type
Public Type CONVCONTEXT cb As Long wFlags As Long wCountryID As Long iCodePage As Long dwLangID As Long dwSecurity As Long qos As SECURITY_QUALITY_OF_SERVICE End Type
Public Declare Function DdeInitialize Lib "user32" Alias "DdeInitializeA" _ (pidInst As Long, _ ByVal pfnCallback As Long, _ ByVal afCmd As Long, _ ByVal ulRes As Long) As Integer
Public Declare Function DdeUninitialize Lib "user32" _ (ByVal idInst As Long) As Long
Public Declare Function DdeNameService Lib "user32" _ (ByVal idInst As Long, _ ByVal hsz1 As Long, _ ByVal hsz2 As Long, _ ByVal afCmd As Long) As Long
Public Declare Function DdeConnect Lib "user32" _ (ByVal idInst As Long, _ ByVal hszService As Long, _ ByVal hszTopic As Long, _ pCC As Any) As Long
Public Declare Function DdeDisconnect Lib "user32" _ (ByVal hConv As Long) As Long
Public Declare Function DdeCreateStringHandle Lib "user32" _ Alias "DdeCreateStringHandleA" _ (ByVal idInst As Long, _ ByVal psz As String, _ ByVal iCodePage As Long) As Long
Public Declare Function DdeFreeStringHandle Lib "user32" _ (ByVal idInst As Long, _ ByVal hsz As Long) As Long
Public Declare Function DdeQueryString Lib "user32" _ Alias "DdeQueryStringA" _ (ByVal idInst As Long, _ ByVal hsz As Long, _ ByVal psz As String, _ ByVal cchMax As Long, _ ByVal iCodePage As Long) As Long
Public Declare Function DdeCreateDataHandle Lib "user32" _ (ByVal idInst As Long, _ ByVal pSrc As String, _ ByVal cb As Long, _ ByVal cbOff As Long, _ ByVal hszItem As Long, _ ByVal wFmt As Long, _ ByVal afCmd As Long) As Long
Public Declare Function DdeClientTransaction Lib "user32" _ (ByVal pData As String, _ ByVal cbData As Long, _ ByVal hConv As Long, _ ByVal hszItem As Long, _ ByVal wFmt As Long, _ ByVal wType As Long, _ ByVal dwTimeout As Long, _ pdwResult As Long) As Long
Public Declare Function DdeGetData Lib "user32" _ (ByVal hData As Long, _ ByVal pDst As String, _ ByVal cbMax As Long, _ ByVal cbOff As Long) As Long
Public Declare Function DdeFreeDataHandle Lib "user32" _ (ByVal hData As Long) As Long
Public Declare Function DdeGetLastError Lib "user32" _ (ByVal idInst As Long) As Long
Public Declare Function DdePostAdvise Lib "user32" _ (ByVal idInst As Long, _ ByVal hszTopic As Long, _ ByVal hszItem As Long) As Long
Function DDECallback(ByVal uType As Long, _ ByVal uFmt As Long, _ ByVal hConv As Long, _ ByVal hszString1 As Long, _ ByVal hszString2 As Long, _ ByVal hData As Long, _ ByVal dwData1 As Long, _ ByVal dwData2 As Long) As Long
Dim lSize As Long Dim lRet As Long Dim sBuffer As String Dim sRequest As String
Select Case uType Case XTYP_CONNECT lRet = DDE_FACK
Form1.WindowState = vbNormal
Case XTYP_REQUEST lSize = DdeQueryString(lInstID, hszString2, vbNullString, 0, CP_WINANSI)
sBuffer = Space(lSize)
DdeQueryString lInstID, hszString2, sBuffer, lSize + 1, CP_WINANSI
If (sBuffer = DDE_REQUEST) Then If (Form1.Text1.Text = "") Then sRequest = DDE_REQUEST_STRING Else sRequest = Form1.Text1.Text End If
lRet = DdeCreateDataHandle(lInstID, sRequest, Len(sRequest), 0, hszString2, CF_TEXT, 0) Else lRet = DDE_FNOTPROCESSED End If
Case XTYP_EXECUTE lSize = DdeGetData(ByVal hData, vbNullString, 0, 0)
sBuffer = Space(lSize)
DdeGetData ByVal hData, sBuffer, lSize, 0
sBuffer = UCase(sBuffer)
lRet = DDE_FACK
If (sBuffer = DDE_COMMAND1) Then Form1.WindowState = vbMaximized ElseIf (sBuffer = DDE_COMMAND2) Then Form1.WindowState = vbMinimized ElseIf (sBuffer = DDE_COMMAND3) Then Form1.WindowState = vbNormal Else lRet = DDE_FNOTPROCESSED End If
Case XTYP_POKE lSize = DdeQueryString(lInstID, hszString2, vbNullString, 0, CP_WINANSI) sBuffer = Space(lSize) DdeQueryString lInstID, hszString2, sBuffer, lSize + 1, CP_WINANSI
If (sBuffer = DDE_POKE) Then lSize = DdeGetData(ByVal hData, vbNullString, 0, 0)
sBuffer = Space(lSize)
DdeGetData ByVal hData, sBuffer, lSize, 0
Form1.WindowState = vbNormal
Form1.Text1.Text = sBuffer
lRet = DDE_FACK Else lRet = DDE_FNOTPROCESSED End If
Case XTYP_ADVREQ Debug.Print "We got the advise request. Conv: " & hConv
If (Form1.Text1.Text = "") Then sRequest = DDE_REQUEST_STRING Else sRequest = Form1.Text1.Text End If
lRet = DdeCreateDataHandle(lInstID, sRequest, Len(sRequest) + MAGIC_NUMBER, 0, hszDDEItemAdvise, CF_TEXT, 0)
Case XTYP_ADVSTART Debug.Print "Start advise request made. Conv: " & hConv
Form1.Command1.Enabled = True
lRet = DDE_FACK
Case XTYP_ADVSTOP Debug.Print "Stop advise request made. Conv: " & hConv
Form1.Command1.Enabled = False
lRet = DDE_FACK
End Select
DDECallback = lRet
End Function |
|
|
|
Submitted By :
Nayan Patel
(Member Since : 5/26/2004 12:23:06 PM)
|
|
|
Job Description :
He is the moderator of this site and currently working as an independent consultant. He works with VB.net/ASP.net, SQL Server and other MS technologies. He is MCSD.net, MCDBA and MCSE. In his free time he likes to watch funny movies and doing oil painting. |
View all (893) submissions by this author
(Birth Date : 7/14/1981 ) |
|
|