Hi all,
I am trying to connect to a electromyograph machine for my thesis project,
and I have a VB DDE client whose DDE functionality I want to convert to VC++.
However I can't make my VC++ version connect to the DDE server somehow --
DdeConnect(idInst,hszService, hszTopic, NULL) is not working
I am not sure if it's because DDEML doesn't support the connection, or if
it's because my code is incorrect (I'm not familiar with VB, so I'm just
guessing on how the service/topic strings should look like in C++).
Thanks so much!
Cindy
-----------------------------------------------------
Here is the VB program frm:
-----------------------------------------------------
VERSION 5.00
Begin VB.Form DDEForm
Caption = "Destination"
ClientHeight = 5655
ClientLeft = 60
ClientTop = 345
ClientWidth = 4740
LinkTopic = "SAM1|DDEForm"
ScaleHeight = 5655
ScaleWidth = 4740
StartUpPosition = 3 'Windows Default
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 495
Left = 3120
TabIndex = 11
Top = 2880
Visible = 0 'False
Width = 1215
End
Begin VB.TextBox saveFileName
Height = 375
Left = 1560
TabIndex = 9
Text = "c:\cpi\data\test"
Top = 1680
Width = 2655
End
Begin VB.ComboBox Combo1
Height = 315
Left = 240
Style = 2 'Dropdown List
TabIndex = 8
Top = 2280
Width = 1335
End
Begin VB.Timer Timer1
Interval = 5000
Left = 240
Top = 5040
End
Begin VB.CommandButton Poke
Caption = "Poke"
Height = 495
Index = 2
Left = 1680
TabIndex = 7
Top = 3360
Width = 1215
End
Begin VB.TextBox Text2
Height = 495
Index = 2
Left = 240
TabIndex = 6
Top = 3360
Width = 1215
End
Begin VB.CommandButton Poke
Caption = "Poke"
Height = 495
Index = 1
Left = 1680
TabIndex = 5
Top = 2760
Width = 1215
End
Begin VB.TextBox Text2
Height = 495
Index = 1
Left = 240
TabIndex = 4
Top = 2760
Width = 1215
End
Begin VB.TextBox Text2
Height = 495
Index = 0
Left = 3000
LinkTimeout = -1
TabIndex = 3
Top = 2160
Visible = 0 'False
Width = 1215
End
Begin VB.CommandButton Request
Caption = "Request"
Height = 495
Left = 3120
TabIndex = 2
Top = 840
Width = 1215
End
Begin VB.CommandButton Poke
Caption = "Poke"
Height = 495
Index = 0
Left = 1680
TabIndex = 1
Top = 2160
Width = 1215
End
Begin VB.TextBox Text1
Height = 495
Left = 240
LinkTimeout = 5000
TabIndex = 0
Text = "Text1"
Top = 240
Width = 4095
End
Begin VB.Label Label1
Caption = "Aquire File Name:"
Height = 375
Left = 120
TabIndex = 10
Top = 1680
Width = 1335
End
End
Attribute VB_Name = "DDEForm"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Const AUTOMATIC = 1, MANUAL = 2, NONE = 0
Dim FileOpen As Boolean
Dim AppReady As Boolean
Dim FileNum3 As Integer
Dim buffer() As Byte
Private Sub Option1_Click()
End Sub
Private Sub AutomaticLink_Click()
Request.Visible = False 'No need for button with automatic link.
Text1.LinkMode = NONE 'Clear DDE Link.
Text1.LinkMode = AUTOMATIC 'Reestablish new LinkMode.
End Sub
Private Sub Command1_Click()
Text2(0).LinkExecute Text2(0).Text
End Sub
Private Sub Combo1_Change()
If Combo1.Text = "FILE" Then
Text2(0).Text = Combo1.Text & " " & saveFileName.Text
Else
Text2(0).Text = Combo1.Text
End If
End Sub
Private Sub Combo1_Click()
If Combo1.Text = "FILE" Then
Text2(0).Text = Combo1.Text & " " & saveFileName.Text
Else
Text2(0).Text = Combo1.Text
End If
End Sub
Private Sub Form_Load()
Dim z As Long
AppReady = False
'This procedure will start the VB source application.
z = Shell("c:\cpi\sam2", 1)
z = DoEvents() 'Causes Windows to finish processing Shell command.
Combo1.AddItem "FILE"
Combo1.AddItem "START"
Combo1.AddItem "STOP"
Combo1.AddItem "AQUIRE"
Combo1.AddItem "HIDE"
Combo1.AddItem "SHOW"
Combo1.AddItem "SETUP"
Combo1.AddItem "BEGIN"
If Combo1.Text = "FILE" Then
Text2(0).Text = Combo1.Text & " " & saveFileName.Text
Else
Text2(0).Text = Combo1.Text
End If
Text1.LinkMode = NONE 'Clears DDE link if it already exists.
Do While Not AppReady
DoEvents
Loop
Text1.LinkTopic = "sam2|frmDDE" 'Sets up link with VB source.
Text1.LinkItem = "Text1" 'Set link to text box on source.
Text1.LinkMode = MANUAL 'Establish a manual DDE link.
For i = 0 To 2
Text2(i).LinkTopic = "sam2|frmDDE" 'Sets up link with VB source.
Select Case i
Case 0
Text2(i).LinkItem = "Text2" 'Set link to text box
on source.
Case 1
Text2(i).LinkItem = "Text3" 'Set link to text box
on source.
Case 2
Text2(i).LinkItem = "Text4" 'Set link to text box
on source.
End Select
Text2(i).LinkMode = MANUAL 'Establish a manual DDE link.
Next i
Text1.LinkTopic = "sam2|frmDDE" 'Sets up link with VB source.
Text1.LinkItem = "Text1" 'Set link to text box on source.
Text1.LinkMode = MANUAL 'Establish a manual DDE link.
AutomaticLink_Click
If FileOpen = False Then
FileNum3 = FreeFile
Open "Outputdata.txt" For Output As #FileNum3
FileOpen = True
End If
End Sub
Private Sub ManualLink_Click()
Request.Visible = True 'Make request button valid.
Text1.LinkMode = NONE 'Clear DDE Link.
Text1.LinkMode = MANUAL 'Reestablish new LinkMode.
End Sub
Private Sub Form_Unload(Cancel As Integer)
Close #FileNum3
End Sub
Private Sub Poke_Click(Index As Integer)
'With any DDE link, this button will be visible, and when it's
'selected, will poke information from the destination application
'into the source application.
Text2(Index).LinkPoke
End Sub
Private Sub Request_Click()
'With a manual DDE link, this button will be visible, and when
'selected it will request an update of information from the source
'application to the destination application.
Text1.LinkRequest
End Sub
Private Sub Text1_Change()
Print #FileNum3, Text1.Text
End Sub
Private Sub Timer1_Timer()
Timer1.Enabled = False
AppReady = True
End Sub
-----------------------------------------------------
Here are snippets of my VC++ code that deals with the DDE:
-----------------------------------------------------
//Initialize DDE
UINT ui;
idInst = 0;
HINSTANCE hinst;
ui = DdeInitialize(&idInst, // receives instance identifier
(PFNCALLBACK) DdeCallback, // pointer to callback function
CBF_FAIL_EXECUTES | // filter XTYPE_EXECUTE
CBF_SKIP_ALLNOTIFICATIONS, // filter notifications
0);
if (ui != DMLERR_NO_ERROR)
{
richTextBox1->Text = "Failed to initialize as DDE client\n";
}
//Now try connecting to server
LPSTR lpszService = "c:\\CPI\\SAM2.EXE";
LPSTR lpszTopic = "frmDDE";
LPSTR lpszItem = "FILE c:\\CPI\\data\\MyFileName";
HSZ hszTopic = DdeCreateStringHandle(idInst, lpszTopic, CP_WINANSI);
HSZ hszService = DdeCreateStringHandle(idInst, lpszService, CP_WINANSI);
hconvNew = DdeConnect(idInst,hszService, hszTopic, NULL);
// Free the HSZs now
DdeFreeStringHandle(idInst, hszTopic);
DdeFreeStringHandle(idInst, hszService);
if (!hconvNew)
{
richTextBox1->AppendText("Couldn't connect to: ");
richTextBox1->AppendText(lpszService);
richTextBox1->AppendText(lpszTopic);
richTextBox1->AppendText("\n");
return;
}
// Try to get the item we are interrested in
DWORD dwResult;
HSZ hszItem = DdeCreateStringHandle(idInst,lpszItem,CP_WINANSI);
HDDEDATA hDDEData =
DdeClientTransaction(NULL,0,hconvNew,hszItem,CF_TE XT,XTYP_REQUEST,1000,&dwResult);
DdeFreeStringHandle(idInst, hszItem);
if (hDDEData)
{
// Lock the data so we can access it
BYTE FAR* pData;
DWORD dwLength;
pData = DdeAccessData(hDDEData, &dwLength);
if (pData)
{
// Just show it
richTextBox1->AppendText( (*pData).ToString() );
richTextBox1->AppendText("\n");
}
// Done with the data
DdeUnaccessData(hDDEData);
DdeFreeDataHandle(hDDEData);
}
else
{
richTextBox1->AppendText("couldn't get any data");
}
----------------------------------------
// Callback function for DDE messages
static HDDEDATA CALLBACK DdeCallback(UINT wType,
UINT wFmt,
HCONV hConv,
HSZ hsz1,
HSZ hsz2,
HDDEDATA hDDEData,
DWORD dwData1,
DWORD dwData2)
{
BYTE FAR *pData;
DWORD dwLength;
switch (wType)
{
case XTYP_ADVDATA:
return (HDDEDATA) DDE_FACK;
case XTYP_DISCONNECT:
return (HDDEDATA) NULL;
default:
return NULL;
break;
}
}