Opcenito vidim da na netu ima jako slabo materijala sto se tice samog DDE-a i DDE optimizacije kod raznih softwareskih paketa (osim MSDN-a), pa evo ako ce nekom trebat??
Neda mi se o njemu pricat... uglavnom postoje 3 vrste veza:
1. hot link-vruca veza
2. warm link-topla veza
3. cold link-hladna veza
DDE se moze koristit preko samog win32apija ili pak preko DDEML-a (Dynamic Data Exchange Managment Library)
Ovdje cu napravit primjer hot linka bez azuriranja podataka preko apija, kod je iskompajliran u Dev-C++ 4.9.9.2!
Znaci ovo je DDE server:
Code:
#include <windows.h>
#include <dde.h>
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char szClassName[ ] = "WindowsApp";
BOOL ProvjeriDalGaIma(char szBr[100])
{
BOOL nadjen=FALSE;
char brojevi[11][10] = {"nula","jedan","dva","tri","cetri","pet","sest","sedam",
"osam","devet","deset"};
for (int x=0;x<=10;x++) if (strcmp(brojevi[x],szBr)==0) nadjen=TRUE;
if (nadjen==TRUE) return TRUE; else return FALSE;
}
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Windows App", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ ATOM aApp, aTopic, aItem, aRecvItem, aSentItem;
UINT uiLow, uiHi;
GLOBALHANDLE hDdeAdvise, hDdeData;
DDEADVISE *pDdeAdvise;
DDEDATA *pDdeData;
DDEACK DdeAck;
WORD wStatus;
char RecvBuff[100], SendBuff[10];
switch (message) /* handle the messages */
{
case WM_DDE_INITIATE:
aApp=GlobalAddAtom("generator");
aTopic=GlobalAddAtom("brojevi");
if (LOWORD(lParam)==aApp && HIWORD(lParam)==aTopic)
SendMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, MAKELPARAM(aApp, aTopic));
else{GlobalDeleteAtom(aApp);
GlobalDeleteAtom(aTopic);}
break;
case WM_DDE_ADVISE:
UnpackDDElParam(WM_DDE_ADVISE, lParam, &uiLow, &uiHi);
FreeDDElParam(WM_DDE_ADVISE, lParam);
hDdeAdvise=(GLOBALHANDLE) uiLow;
pDdeAdvise=(DDEADVISE *) GlobalLock(hDdeAdvise);
aRecvItem=(ATOM)uiHi;
GlobalGetAtomName(aRecvItem, RecvBuff, sizeof(RecvBuff));
if (ProvjeriDalGaIma(RecvBuff)==TRUE)
{
if (strcmp(RecvBuff,"nula")==0) strcpy(SendBuff,"0");
if (strcmp(RecvBuff,"jedan")==0) strcpy(SendBuff,"1");
if (strcmp(RecvBuff,"dva")==0) strcpy(SendBuff,"2");
if (strcmp(RecvBuff,"tri")==0) strcpy(SendBuff,"3");
if (strcmp(RecvBuff,"cetiri")==0) strcpy(SendBuff,"4");
if (strcmp(RecvBuff,"pet")==0) strcpy(SendBuff,"5");
if (strcmp(RecvBuff,"sest")==0) strcpy(SendBuff,"6");
if (strcmp(RecvBuff,"sedam")==0) strcpy(SendBuff,"7");
if (strcmp(RecvBuff,"osam")==0) strcpy(SendBuff,"8");
if (strcmp(RecvBuff,"devet")==0) strcpy(SendBuff,"9");
if (strcmp(RecvBuff,"deset")==0) strcpy(SendBuff,"10");
//saljemo WM_DDE_DATA
hDdeData=(GLOBALHANDLE) GlobalAlloc(GHND | GMEM_DDESHARE,
sizeof(DDEDATA)+strlen(SendBuff));
pDdeData=(DDEDATA *) GlobalLock(hDdeData);
pDdeData->cfFormat=CF_TEXT;
if (pDdeAdvise->fAckReq==TRUE) pDdeData->fAckReq=TRUE; else
pDdeData->fAckReq=FALSE;
pDdeData->fResponse=FALSE;
pDdeData->fRelease=TRUE;
lstrcpy((PSTR)pDdeData->Value, SendBuff);
GlobalUnlock(hDdeData);
PostMessage((HWND)wParam, WM_DDE_DATA, (WPARAM)hwnd, PackDDElParam(WM_DDE_DATA,
(UINT)hDdeData,
aRecvItem));
GlobalFree(hDdeData);
}
else {
//saljemo WM_DDE_ACK jer nemamo trazeni podatak
DdeAck.bAppReturnCode=0;
DdeAck.reserved=0;
DdeAck.fAck=FALSE;
DdeAck.fBusy=FALSE;
wStatus=*((WORD *)&DdeAck);
PostMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, PackDDElParam(WM_DDE_ACK,
wStatus,
aRecvItem));
}
GlobalUnlock(hDdeAdvise);
GlobalFree(hDdeAdvise);
break;
case WM_DDE_UNADVISE:
aItem=HIWORD(lParam);
DdeAck.bAppReturnCode=0;
DdeAck.reserved=0;
DdeAck.fAck=FALSE;
DdeAck.fBusy=FALSE;
wStatus=*((WORD *)&DdeAck);
PostMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, PackDDElParam(WM_DDE_ACK,
wStatus,
aItem));
break;
case WM_DDE_TERMINATE:
PostMessage((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)hwnd, 0L);
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
#include <windows.h>
#include <dde.h>
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char szClassName[ ] = "WindowsApp";
BOOL ProvjeriDalGaIma(char szBr[100])
{
BOOL nadjen=FALSE;
char brojevi[11][10] = {"nula","jedan","dva","tri","cetri","pet","sest","sedam",
"osam","devet","deset"};
for (int x=0;x<=10;x++) if (strcmp(brojevi[x],szBr)==0) nadjen=TRUE;
if (nadjen==TRUE) return TRUE; else return FALSE;
}
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Windows App", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ ATOM aApp, aTopic, aItem, aRecvItem, aSentItem;
UINT uiLow, uiHi;
GLOBALHANDLE hDdeAdvise, hDdeData;
DDEADVISE *pDdeAdvise;
DDEDATA *pDdeData;
DDEACK DdeAck;
WORD wStatus;
char RecvBuff[100], SendBuff[10];
switch (message) /* handle the messages */
{
case WM_DDE_INITIATE:
aApp=GlobalAddAtom("generator");
aTopic=GlobalAddAtom("brojevi");
if (LOWORD(lParam)==aApp && HIWORD(lParam)==aTopic)
SendMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, MAKELPARAM(aApp, aTopic));
else{GlobalDeleteAtom(aApp);
GlobalDeleteAtom(aTopic);}
break;
case WM_DDE_ADVISE:
UnpackDDElParam(WM_DDE_ADVISE, lParam, &uiLow, &uiHi);
FreeDDElParam(WM_DDE_ADVISE, lParam);
hDdeAdvise=(GLOBALHANDLE) uiLow;
pDdeAdvise=(DDEADVISE *) GlobalLock(hDdeAdvise);
aRecvItem=(ATOM)uiHi;
GlobalGetAtomName(aRecvItem, RecvBuff, sizeof(RecvBuff));
if (ProvjeriDalGaIma(RecvBuff)==TRUE)
{
if (strcmp(RecvBuff,"nula")==0) strcpy(SendBuff,"0");
if (strcmp(RecvBuff,"jedan")==0) strcpy(SendBuff,"1");
if (strcmp(RecvBuff,"dva")==0) strcpy(SendBuff,"2");
if (strcmp(RecvBuff,"tri")==0) strcpy(SendBuff,"3");
if (strcmp(RecvBuff,"cetiri")==0) strcpy(SendBuff,"4");
if (strcmp(RecvBuff,"pet")==0) strcpy(SendBuff,"5");
if (strcmp(RecvBuff,"sest")==0) strcpy(SendBuff,"6");
if (strcmp(RecvBuff,"sedam")==0) strcpy(SendBuff,"7");
if (strcmp(RecvBuff,"osam")==0) strcpy(SendBuff,"8");
if (strcmp(RecvBuff,"devet")==0) strcpy(SendBuff,"9");
if (strcmp(RecvBuff,"deset")==0) strcpy(SendBuff,"10");
//saljemo WM_DDE_DATA
hDdeData=(GLOBALHANDLE) GlobalAlloc(GHND | GMEM_DDESHARE,
sizeof(DDEDATA)+strlen(SendBuff));
pDdeData=(DDEDATA *) GlobalLock(hDdeData);
pDdeData->cfFormat=CF_TEXT;
if (pDdeAdvise->fAckReq==TRUE) pDdeData->fAckReq=TRUE; else
pDdeData->fAckReq=FALSE;
pDdeData->fResponse=FALSE;
pDdeData->fRelease=TRUE;
lstrcpy((PSTR)pDdeData->Value, SendBuff);
GlobalUnlock(hDdeData);
PostMessage((HWND)wParam, WM_DDE_DATA, (WPARAM)hwnd, PackDDElParam(WM_DDE_DATA,
(UINT)hDdeData,
aRecvItem));
GlobalFree(hDdeData);
}
else {
//saljemo WM_DDE_ACK jer nemamo trazeni podatak
DdeAck.bAppReturnCode=0;
DdeAck.reserved=0;
DdeAck.fAck=FALSE;
DdeAck.fBusy=FALSE;
wStatus=*((WORD *)&DdeAck);
PostMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, PackDDElParam(WM_DDE_ACK,
wStatus,
aRecvItem));
}
GlobalUnlock(hDdeAdvise);
GlobalFree(hDdeAdvise);
break;
case WM_DDE_UNADVISE:
aItem=HIWORD(lParam);
DdeAck.bAppReturnCode=0;
DdeAck.reserved=0;
DdeAck.fAck=FALSE;
DdeAck.fBusy=FALSE;
wStatus=*((WORD *)&DdeAck);
PostMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, PackDDElParam(WM_DDE_ACK,
wStatus,
aItem));
break;
case WM_DDE_TERMINATE:
PostMessage((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)hwnd, 0L);
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
Jedan od DDE klijent programa je i MS Excel, naime svaka DDE komunikacija se sastoji od 3 elementa: aplikacija, predmet i element!
U ovom gore slucaju aplikacija se zove generator, predmet se zove brojevi a elementi su brojevi [nula, jedan, dva.... deset], znaci ako u MS Excel celiji ukucate "=generator|brojevi!jedan" (bez navodnika) i lupite enter u celiji ce se pojavit broj 1, ako napisete =generator|brojevi!osam u celiji ce se pojavit broj 8, naime onaj nas DDE server pretvara brojeve pisane slovima u brojke!! Naravno DDE server mora bit upaljen u to vrijeme, evo slika kako to izgleda:
U attachu imate iskompajliran kod!
z
[Ovu poruku je menjao passwdpasswd dana 02.11.2006. u 20:23 GMT+1]