Documente online.
Zona de administrare documente. Fisierele tale
Am uitat parola x Creaza cont nou
 HomeExploreaza
upload
Upload




Adatcsere a Windows applikációk között

Maghiara


Adatcsere a Windows applikációk között

Az eddigiek során kiderült az, hogy a Windows alatt több program is futhat egyszerre. Ezek a programok kommunikálhatnak egymással. A kommunikációra számos lehetőség kínálkozik. Az előzőek folyamán már megismerkedtünk az egyik ilyen fajta kommunikációval a DLL-el. Amint azt a korábbiakban láttuk, a DLL használata biztosítja annak a lehetőségét, hogy több program hívja a függvényeit vagy betöltse az erőforrásait. Ez természetesen bizonyos esetekben nem bizonyul elegendőnek az adatcserére. Számos esetben adódhat olyan feladat, amelynél az egyik applikációnak folyamatosan kell küldenie az adatokat a másiknak. Például egy ipari megjelenítő rendszer esetén gyakran előfordulhat, hogy számos applikáció fut egyszerre. Az egyik begyűjti az adatokat, a másik feldolgozza illetve értékeli és a harmadik megjeleníti. Az adatoknak egyik applikációról a másikra való juttatására a Windows több lehetőséget kinál, ezek közül az egyik a DDE protokoll. Ez egy kliens-szerver alapú kommunikáció, ahol a szerver kiszolgálja a kliens kéréseit és a megfelelő adatokat is eljuttatja hozzá. Egy másik ilyen adatcsere módszer a Clipboard (vágólap)használata. Biztos, hogy majdnem mindenki használta már a vágólapot. Pl. amikor egy szövegszerkesztő egyik dokumentumából adatot másolunk(Copy), és egy másik dokumentumba beillesztjük (Paste), akkor az adatok a vágólapon keresztül kerülnek az egyik dokumentumból a másikba. A DDE esetén lehetőség van arra, hogy amennyiben Windows for Workgroups-ot használunk az egymással kommunikáló programok külön gépen fussanak. Ez az NDDE. Ilyenkor a kommunikációhoz szükségünk van a gépnevére is. Egy másik kommunikációs módszert jelent az OLE (Object Linking and Embedding). Ebben a fejezetben nem térünk ki az OLE-re, de a VC++ tárgyalásakor elő fog kerülni az OLE illetve az OCX (OLE Custom Control) létrehozása és felhasználása.



17.1. Clipboard (Vágólap)

A vágólap a globális memóriának olyan területe, amelyet megosztva használ minden futó applikáció. A program írhat adatokat a vágólapra és olvashat adatokat a vágólapról. Általában az egyik program ír a vágólapra, a másik pedig olvas róla.

Amikor a program lefoglal egy memóriablokkot a GHND attribútummal (GMEM_MOVEABLE és GMEM_ZEROINIT kombinációja), akkor azt jelzi, hogy ez a blokk ehhez a programhoz tartozik. Amikor a program ír a vágólapra (átad egy globális leírót a vágólapnak), akkor a Windows átveszi magának a programtól a leíróhoz tartozó memóriablokk tulajdonát. Ilyenkor a Windows megváltoztatja a blokk attribútumát (GMEM_MODIFY és GMEM_DDESHARE)-re. A USER modul veszi át a memóriablokk kezelését. Ezek után a program már nem tudja használni ezt a blokkot, amíg a vágólap nem adja neki a blokkhoz való hozzáférési jogot, más szavakkal, amíg nem nyitja meg a vágólapot. A USER modul gondoskodik a memória blokk felszabadításáról.

Egyidejűleg több olyan program is működhet a Windows felügyelete alatt, amelyek az átmeneti tárolót olvassák. Ezeknek mind üzenetet kell kapniuk az átmeneti tárolón történt változásokról. A Windowsnak csak egyetlen átmeneti tárolót olvasó programja létezik, az aktuális olvasó program. A Windows csak ezt értesíti a változásokról. A vágólap olvasó applikációkat láncba kell kötni. Ha a lánc egyik szeméhez megérkezett valamilyen információ a vágólapról, akkor értesítenie kell a következő láncbeli szomszédját arról.

Az összes vágólapot olvasó alkalmazás fő ablakkezelője kell, hogy reagáljon a WM_CHANGECBCCHAN, a WM_DESTROY és a WM_DRAWCLIPBOARD üzenetekre.

A WM_CHANGECBCCHAN üzenetet a lánc változásakor küldi a Windows. A wParam a kivett láncszem ablakleírója, az lParam alsó szava a következő láncszem leírója. Az alkalmazásnak az üzenet hatására ugyanezt az üzenetet el kell küldenie a követő ablaknak.

A WM_DRAWCLIPBOARD üzenetet a Windows az első láncszemnek küldi, ha a vágólap tartalma megváltozott. Ezt minden láncbeli ablakkezelő függvénynek tovább kell küldenie.

A WM_DESTROY üzenetnél az ablakkezelőnek ki kell iktatnia magát a láncból, ha szerepelt ebben a láncban.

A következő táblázat összefoglalja a vágólapot kezelő függvényeket:

Függvény

Funkció

BOOL ChangeClipboardChain(HWND hwnd, HWND hwndNext)

Egy láncszemet távolít el.

BOOL CloseClipboard(void)

Bezárja a vágólapot. Megszünteti az elérését

BOOL EmptyClipboard(void)

Törli a vágólapot

UINT EnumClipboardFormats(UINT uFormat)

Felsorolja a rendelkezésre álló vágólap formátumokat

HANDLE GetClipboardData(UINT uFormat)

A vágólap adatának leíróját adja meg

int GetClipboardFormatName(UINT uFormat, LPCSTR lpszFormatname, int cMax)

Megadja az aktuális format nevét

HWND GetClipboardOwner(HWND hwnd)

Megadja annak az ablaknak a leíróját, amelyhez a vágólap éppen tartozik

HWND GetClipboardViewer(void)

Megadja a lánc első szemének leíróját

HWND GetOpenClipboardWindow(void)

Megadja annak az ablaknak a leíróját, amely éppen megnyitotta a vágólapot

int GetPriorityClipboardFormat(UINT FAR* PriorityList, int cEntries)

Megadja az adatokhoz tartozó legjobb formátumot

BOOL IsClipboardFormatAvailable(UINT uFormat)

Az adatformátum rendelkezésre áll-e

BOOL OpenClipboard(HWND hwnd)

Megnyitja a vágólapot

UINT RegisterClipboardFormat(LPCSTR lpszFormatName)

Bejegyzi az aktuális adatformátumot

HANDLE SetClipboardData(UINT uFormat, HANDLE hData)

Adatot helyez a vágólapra

HWND SetClipboardViewer(HWND hwnd)

A lánchoz tesz egy új szemet

A gyakrabban használt formátumok a következő táblázatban szerepelnek

Formátum

Formátum típusa

CF_BITMAP

Bitmap

CF_DIB

Bitmap és BITMAPINFO fejléc

CF_DIF

Data Interchamge formátum

CF_DSPBITMAP

Egyéni bitmap

CF_DSPENHMETAFILE

Kiterjesztett egyéni metafile

CF_DSPMETAFILEPICT

Egyéni metafile

CF_DSPTEXT

Egyéni szöveg

CF_ENHMETAFILE

kiterjesztett metafile

CF_METAFILEPICT

METAFILESTRUCT stílusú metafile

CF_OEMTEXT

OEM szöveg

CF_OWNERDISPLAY

Egyénileg definiált formátum

CF_PALETTE

Színpaletta

CF_PENDATA

Toll-alapú rendszerek kiterjesztett formátuma

CF_RIFF

Resource interchange file formátum

CF_SYLK

Symbolic link

CF_TEXT

Szöveg

CF_TIFF

Címke kép formátum

CF_WAVE

Hang forráskód WAVE file-ok

CF_UNICODETEXT

Szöveg UNICODE stílusban



17.1.1. Adatok helyezése vágólapra

Az adatok vágólapra helyezésének általános módszere a következő:

Megfelelő méretű memória foglalása.

Az adat bemásolása a globális memóriába.

A vágólap megnyitása.

A vágólap minden korábbi adatának törlése.

A megadott memóriarésznek, mint a vágólap adatának a megadása.

A vágólap bezárása.

A következő néhány sor példát mutat az adatok vágólapra való helyezéséről

hGout=GlobalAlloc(GHND | GMEM_DDESHARE, (DWORD)100);

p=GlobalLock(hGout);

// adatok másolása a globális memóriába

GlobalUnlock(hGout);

if (OpenClipboard(hwnd))

17.1.2. Adatok beolvasása a vágólapról

Az adatok beolvasásának általános módszere a következő:

A vágólap megnyitása.

A vágólapon lévő adatokhoz tartozó mutató lekérése.

Az adatok másolása a vágólapról.

A vágólap bezárása.

A következő néhány sor példát mutat az adatok vágólapról való olvasásáról

if (OpenClipboard(hwnd)

Érdemes megemlíteni, hogy egy időben egy program nyithatja meg a vágólapot. Ezért fontos, hogy minden vágólapot kezelő program rendben nyissa és zárja azt. Ez az oka annak, hogy a vágólap megnyitása és lezárása közti időben nem szabad használni a SendMessage függvényt, nehogy másik programhoz kerüljön a vezérlés.

Példa a Vágólap használatáról \PELDAK\PELDA4

#include <windows.h>

#include "proba1.h"

long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;

long FAR PASCAL _export GraphProc(HWND hDlg, unsigned message,WORD wParam,LONG lParam);

HWND hwnd ;

HWND  hTextWnd;

HANDLE hInst;

HBITMAP hBitmap ;

HANDLE hGMem ;

HDC hdc ;

LPSTR lpGMem ;

#pragma argsused

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,

LPSTR lpszCmdLine, int nCmdShow)

hInst=hInstance;

hwnd = CreateWindow (szAppName, "Clipboard Viewer",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd,SW_SHOWMAXIMIZED ) ;

UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))

return msg.wParam ;

}

#pragma argsused

long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)

else

}

CloseClipboard () ;

EndPaint (hwnd, &ps) ;

return 0;

case WM_DESTROY:

ChangeClipboardChain (hwnd, hwndNextViewer) ;

PostQuitMessage (0) ;

return 0 ;

}

return DefWindowProc (hwnd, message, wParam, lParam) ;

}

Természetesen a vágólapon levő adatokat fájlba is lehet menteni. Ennek a fájlnak a kiterjesztése általában .clp. Ennek a fájlnak a formátuma ismert és a fejléce tartalmaz információt az adatformátumról, az adatok hosszáról, stb.

17.2. DDE (Dynamic Data Exchange)

A vágólap egy egyszerű kommunikációs formát jelent a Windows-ban. Korlátozott lehetőségei vannak. A másik kommunikációs módszer a DDE. Windows üzeneteket és megosztott memóriát használ ahhoz, hogy az applikációk adatokat cseréljenek egymással. A fő előnye a DDE -nek, hogy a felhasználó beavatkozása nélkül folyamatosan tudja biztosítani a kommunikációt a programok között. A DDE a Windows applikációk szabványos kommunikáció protokollja lett. Szinte alig találunk olyan Windows programot, ami nem támogatja a DDE használatát. A Windows for Workgroups, Win95 és Windows NT esetén az egymással kommunikáló programok külön külön gépen lehetnek.

A DDE egy kliens-szerver kommunikációs forma. Egy applikáció lehet egyszerre kliens is és szerver is. Sőt egy szervere lehet több kliensnek vagy egy kliens több szervertől kérhet adatokat. A DDE esetén mind a kliensnek mind a szervernek ismernie kell az adatformátumot. Általában a DDE sztringekkel dolgozik. A kapcsolat felvételét mindig a kliens kezdeményezi. Minden DDE kommunikáció a következő lépésekből áll.

Kapcsolat felvétel kliens szerver

Adatcsere kliens szerver

kapcsolat lebontás

3 fajta DDE protokoll létezik a hideg, meleg és a forró

Csak kis különbség van a 3 protokoll között. A különbség az adott váltózó frissítési módjában jelentkezik.

Hideg: A hideg (cold) DDE protokoll esetében az adatcsere úgy működik, hogy a szerver azokat az információkat küldi a kliensnek, amelyeket kért a kliens. Amennyiben a lekért információ a későbbiekben megváltozik, akkor a kliens nem vesz tudomást róla és a szerver sem küldi neki.

Meleg: (warm) Annyiban más mint a hideg, hogy amennyiben változik a kért információ, a szerver értesíti a klienst a változásról. A szerver akkor küldi az új információt, amikor a kliens kéri.(Advise)

Forró: (hot) Ebben az esetben a szerver nemcsak értesítést küld a kliensnek a megváltozásról, hanem az új információt is küldi. Természetesen mindegyik típusnak megvan a maga felhasználási területe és az, hogy, melyiket használjuk ez a feladat jellegétől függ. (Advise).

A DDE üzenetek WM_DDE_XXXX felépítésűek. Az XXXX az üzenettől függ (INITIATE, REQUEST, POKE, stb.). Mint említettük a DDE kommunikáció Windows üzeneteken alapszik. Ennek az implementálása eléggé körülményes és sok kódot igényel, nem is beszélve arról, hogy mindenki másképpen implementálja a programjában. A kommunikáció implementálásának az egyszerűsítésére és egyesítésére a Microsoft bevezette a DDE Management Library-t a DDEML-t. Ez a Library API függvényeket tartalmaz, amelyek kezelik a Windows üzeneteket, a programozónak csak ezeket a függvényeket kell meghívnia és nem kell foglalkoznia az üzenetekkel. Természetesen ez nem azt jelenti, hogy aki sima DDE üzenetekkel írja a programját, az nem fog működni, de nehezebb implementálni.

17.3. DDEML (Dynamic Data Exchange Management Library)

A Microsoft bevezette a DDEML API-t, amely takarja a Windows üzeneteken alapuló DDE protokoll nehézségeit. Ahelyett, hogy a programozó SendMessage és PostMessage függvényekkel küldene DDE üzeneteket, ehelyett a DDEML API függvényeit hívja. Ezzel egyszerűbb dolga lett a programozónak.

A DDEML alapgondolata, hogy mind a szerver mind a kliens rendelkezik egy úgynevezett DDE Callback függvénnyel, amely tartja a kapcsolatot a DDEML-lel. A DDEML és a Callback függvény műveletcsomagokat küldenek egymásnak. Ilyen módon jön létre a kapcsolat a DDEML-en keresztül a szerver és kliens között. A műveletcsomagok hasonlítanak az üzenetekhez. Ezek egy konstansból és tőle függő paraméterekből állnak. A szerver és a kliens DDEML függvényeket hív meg a különböző adatcsere megvalósításához. Minden adatcsere a DDEML-en keresztül bonyolódik le. A következő ábra szemlélteti az alapgondolatot.

Mielőtt belevágnánk a DDEML programozásba néhány fogalmat kell tisztáznunk:

1. Kliens és szerver

A kliens az az applikáció, amely inicializálja a kapcsolatot (felveszi) és parancsokat illetve kéréseket küld a szervernek. A szerver az az applikáció, amely válaszol a kliensnek vagy a kért adatokkal vagy egy kliens által küldött parancs végrehatásával. Egy applikáció lehet kliens is és szerver is egyszerre.

2. Műveletcsomagok (Transactions and Conversations)

Amikor a kliens felveszi a kapcsolatot a szerverrel, akkor a két applikáció elkezd beszélgetni egymással. A kliens vagy adatokat kér és a szerver ezeket küldi, vagy parancsokat küld és a szerver ezeket végrehajtja. A kliens és a szerver között az adatok csomagok formájában mennek át. Természetesen ezek a csomagok minden oldalon a Callback függvény és a DDEML között mozognak.

3. Service, Topic, Item

A DDE szerver egy vagy több service-t (szolgáltatás név) támogathat. Minden szolgáltatás egy névvel azonosítandó. Általában azt a megoldást használják, hogy a szerverhez egy service tartozik, amelynek a neve megegyezik a szerver applikáció nevével. Például a Program Manager egy Progman, a Word egy WinWord és az Excel pedig egy Excel nevű szolgáltatást támogat. A fő előnye annak, hogy a service név megegyezik a szerverével, hogy megtudhatjuk, hogy melyik programot kell futtatni, ha nem sikerült felvenni a kapcsolatot a szerverrel. Például ha valaki kliensként inicializálni akar egy kapcsolatot az Excellel és az nem válaszol, akkor a WinExec API függvény segítségével indíthatjuk az Excelt és újból próbálkozhatunk. Az NDDE esetén (természetesen csak Workgroups, Win95, Win NT esetén) a service neve a következőképpen kell hogy kinézzen \\COMPUTER_NAME\NDDE$.

Minden service számos topic-ot (témakör) támogat. Például az Excel esetében a topic név egy megnyitott fájl neve. Természetesen a mi programunk tetszés szerinti topic nevet vehet fel. Az NDDE esetén a topic neve egy úgynevezett Shared névvel kell, hogy megegyezzen. Ez nem más mint egy bejegyzés, ami a system.ini-ben van és vagy kézzel vagy egy úgynevezett share manager segéd program segítségével jegyezhetjük be. Erre jó példa a chat program, amely a Workgroupsban van. Ha egy Workgroups system.ini-jébe belenézünk a [DDEShares] szekcióban a következő sort látjuk. CHAT$=winchat,chat,,31,,0,,0,0,0. Ilyenkor a topic név a CHAT$ kell, hogy legyen. Természetesen érdemes használni az említett segéd programot , hogy ne kelljen nekünk beállítani a paramétereket.

Minden topic-hoz több Item (tétel) tartozhat. Egy item egy adatnak felel meg, amit a kliens kaphat a szervertől. Például az Excelnél maradva egy item egy cella intervallumot jelent pl. R1C1:R5C6.

System topic

A 3.1 verziótól a kliens applikációk segítségére egy speciális topic (system topic) került bevezetésre. A DDE szerverek többsége támogatja a system topic-ot. A system topic segítségével a DDE kliensek könnyen jutnak fontos információhoz. Ez az információ lehet: milyen topic-ok érvényesek az adott szervernél, milyen adatformátumokat támogat a szerver, a szerver státusza és hasonló információk. A következő táblázat tartalmazza azokat a konstansokat és értelmezésüket, melyeket támogat a DDE szerver. Ezek a konstansok a DDEML.h fájlban találhatók:

Definiált konstans

Név

Magyarázat

SZDDESYS_TOPIC

"System"

A System topic kiválasztására használható szimbólum.

SZDDESYS_ITEM_SYSITEMS

"SysItems"

A system topic Item-einek listája. Minden szervernek minimum tudnia kell a topic-okat, Item-eket, adatformátumokat.

SYDDESYS_ITEM_TOPICS

"Topics"

A szerveren pillanatnyilag érvényes topic-ok

SZDDESYS_ITEM_FORMATS

"Formats"

Az érvényes adatformátumok. Minden DDE szervernek támogatnia kell a CF_TEXT adatformátumot. Az NT esetén a CF_UNICODETEXT támogatása is kötelező.

SZDDE_ITEM_ITEMLIST

"TopicItemList"

A system topic-on kívül minden topichoz milyen itemek tartoznak.

SZDDESYS_ITEM_HELP

"Help"

Egy szöveg, amely megmondja, hogy hogyan kell használni a DDE szervert

SZDDESYS_ITEM_STATUS

"Status"

Busy vagy Ready.

SZDDESYS_ITEM_RTNMSG

"ReturnMessage"

Speciális adatforgalom is van.

5. DDE Commands (parancsok)

Az adatokon kívül parancsok is mehetnek a kliensről a szerverre. (XTYP_EXECUTE transaction)



6. DDE Handles (leírók)

A DDEML -ben a sztringek és adatok leírókkal azonosíthatók. Az adat, amely a szervertől a kliens felé megy egy HDDEDATA típusúval azonosítható. A sztringek, amelyek azonosítják a service-t, topic-ot és item-et HSZ típusúak. Itt kell megemlíteni, hogy a DDE esetén a kommunikáció üzeneteken keresztül valósul meg. Ilyenkor a service, topic és item sztringek azonosítására egy úgynevezett ATOM táblát hoznak létre és ennek a táblának az egyik indexét adják át egymásnak a kommunikáló applikációk. A DDEML esetén is hasonló a helyzet a HSZ (Handle Sztring) bevezetésével.

7. DDE kommunikáció megvalósításának lépései

A lépések szekvenciáját a következő táblázatban foglaljuk össze:

A kliens

A szerver

1. Inicializálja a DDEML-t a DdeInitialize. Kijelőli a Callback függvényt.

Inicializálja a DDEML-t a DdeInitialize. Kijelőli a Callback függvényt.

2. Kapcsolódik a szerverhez. Erre vagy a DdeConnect vagy a DdeCoonectList függvényt hívja meg.

A szerver Callback függvénye kap egy XTYP_CONNECT tranzakciót. A Callback függvénnyel True-val tér vissza ha a topic és az Item érvényesek.

3. Inicializálja a tranzakciót a DdeClientTransaction függvény meghívásával (ez a szinkron eset. Lásd később).

A szerver Callback függvénye egy XTYP_REQUEST tranzakciót kap. Erre ha tud a szerver válaszolni, létrehoz egy memória blokkot (DdeCreateDataHandle függvénnyel) és ebbe másolja az adatokat. Visszatér a HDDEDATA leíróval.

4. A DdeClientTransaction visszatér a HDDEDATA leíróval. A kliens a DdeAccessData függvénnyel olvashatja az adatokat, ha akarja. (Amennyiben a kommunikáció aszinkron, akkor a kliens Callback függvénye egy XTYP_XACT_COMPLETE tranzakciót kap, hogy az adat kész, elvihető.)

A szerver vár a többi tranzakciókra.

5. A 3. és 4. lépés ismétlése a további adatok eléréséhez.

A szerver kiadja az adatokat, ha tudja.

6. A beszélgetés befejezése a DdeDisconnect vagy a DdeDisconnectList függvénnyel.

A szerver Callback függvénye kap egy XTYP_DISCONNECT tranzakciót. A kapcsolatnak vége van.

Meghívja a DdeUninitialize függvényt, jelezve, hogy nincs többé szüksége a DDEML.DLL-re.

A szervernek is meg kell hívnia a DdeUnitialize függvényt ha már nincsen szüksége a DDEML-re.

Lássuk részletesebben a táblázatban felsorolt lépéseket:

1. Inicializálás

Amikor az applikáció használja a DDEML-t meg kell hívnia a DdeInitialize függvényt mielőtt bármilyen DDEML függvényt meghívna.

UINT DdeInitialize (

LPWORD pidInst, // a DDE példány leíró

PFNCALLBACK pfnCallback, // DDE Callback függvény

DWORD afCmd, // Az applikáció típusa

DWORD ulRes); // 0-nak kell lennie

A függvény visszatérési értéke DMLERR_NO_ERROR ha nem történt hiba. Különben a visszatérési érték lehet: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER vagy DMLERR_SYSERR.

Az első argumentum (pidInst) NULL-nak kell lennie. Amikor a függvény sikeresen tér vissza, ebben a változóban lesz a DDE példány leíró. (Az ACCESS, EXCEL esetén ezt csatorna számnak hívják). Ezt használja minden DDEML függvény a kapcsolat azonosítójaként.

Az (afCmd) argumentum egy vagy kapcsolatban levő flagek egy kombinációja, amely specifikálja, hogy milyen típusú az applikáció illetve szűrőként használható, hogy milyen tranzakciók érdeklik őt. Például a Kliens esetén ez lehet APPCMD_CLIENTONLY. A flagek prefixuma APPCLASS_, APPCMD_, CBF_, MF_. Ha egyik tranzakcióra sem vagyunk kíváncsiak, akkor a CBF_SKIP_ALLNOTIFICATIONS.

A pfnCallback a Callback függvényünk címe. Ha nincsen Callback függvényünk, akkor ez NULL.

DDE Callback függvény

A DDEML meghívja a DDE Callback függvényt, hogy értesítse az applikációt a különböző fajta eseményekről. A DDE Callback függvény prototípusa a következő:

HDDEDATA CALLBACK DdeCallback(

UINT uType, // Tranzakció típusa (lásd táblázat)

UINT uFmt, // Adatformátum

HCONV hConv, // CONVTEXT info. Struktúrára pointer

HSZ hsz1, // String Handle a tranzakciótól függ

HSZ hsz2, // String Handle a tranzakciótól függ

HDDEDATA hData, // DDE adatok leírója

DWORD dwdata1, // Tranzakció specifikus adat

DWORD dwdata2); // Tranzakció specifikus adat

Mivel a DDE Callback függvény sok fajta tranzakciót továbbít, ezért sok argumentuma függ az első argumentumtól, ami a tranzakció típusa. A következő táblázat összefoglalja a tranzakció típusokat és egy kis magyarázattal látja el őket:

Tranzakció

Magyarázat

XTYP_ADVDATA

Értesíti a klienst, hogy az adat megváltozott. A hsz1, hsz2 tartalmazzák a topicot és az itemet. Az adat a hData-ban van. A Callback függvény visszatérési értéke DDE_FACK ha végrehajtotta a tranzakciót, DDE_FBUSY ha foglalt és DDE_FNOTPROCESSED ha nem akarja, vagy nem tudja teljesíteni a kérést. Érdemes itt említeni, hogy az XTYP_ADVXXX tranzakciók advise-t jelentenek azaz meleg vagy forró kapcsolat esetén van értelmük. ( Az advise azt jelenti, hogy vagy értesítést kér az adat megváltozása esetén, vagy magát a megváltozott adatot).

XTYP_ADVREQ

Értesíti a szervert, hogy egy advise tranzakció érkezett és még nem intézte el (ez akkor keletkezik, ha a szerver meghívja a DdePostAdvise függvényt). A hsz1 és hsz2 a topic-ot és az itemet tartalmazzák. A Callback függvénynek meg kell hívnia a DdeCreateDataHandle-t, hogy hozzon létre egy adatleírót és ezzel térjen vissza. Ha a szerver nem fejezte be a tranzakciót, akkor NULL-lal tér vissza.

XTYP_ADVSTART

Értesíti a szervert, hogy egy advise ciklus indul. Ez forró kapcsolatot jelent. Amennyiben meleg kapcsolatot kér a kliens, akkor a fenti tranzakciót egy vagy kapcsolattal kell kombinálnia az XTYPF_NODATA konstanssal. A hsz1 és hsz2 ugyanaz mint az előző. A szerver Callback függvénye TRUE-val tér vissza ha indulhat a ciklus és FALSE-sal ha nem.

XTYP_ADVSTOP

Értesíti a szervert, hogy vége van a ciklusnak, és ne értesítse a klienst az adat megváltozása esetén többé. A hsz1 és hsz2 ugyanaz mint az előzőnél.

XTYP_CONNECT

Értesíti a szervert, hogy a kliens csatlakozást kér a hsz2 service és hsz1 topic-ú azonosítással. A dwData1 argumentum egy CONVTEXT-re mutató pointer kell hogy legyen, amely információkat tartalmaz a továbbiakban történő beszélgetésekről. A dwData2 argumentum 1 ha a szerver és a kliens ugyanahhoz az applikációhoz tartozik, különben 0. A Callback függvénynek TRUE-val kell visszatérnie, ha sikerült a kapcsolat felvétele és FALSE-sal egyébként.

XTYP_CONNECT_CONFIRM

Válasz a szervernek a klienstől, hogy rendben van minden a kapcsolat létrehozásával kapcsolatban. A hsz1, hsz2, dwData2 ugyanaz mint az előzőekben. Nincs visszatérési értéke.

XTYP_DISCONNECT

Értesíti a szervert vagy a klienst, hogy a partner befejezte a kapcsolatot. A dwData2 ugyanaz mint az előzőekben. Nem kell visszatérési érték.

XTYP_ERROR

Értesíti a szervert vagy a klienst, hogy valamilyen kritikus hiba történt. A dwData1 alsó szava tartalmazza a hibakódot.

XTYP_EXECUTE

Értesíti a szervert, hogy a kliens egy végrehajtási parancsot küldött. Hsz1 a topic. A Callback függvény visszatérési értéke DDE_FACK ha végrehajtotta a tranzakciót, DDE_FBUSY ha foglalt és DDE_FNOTPROCESSED ha nem akarja, vagy nem tudja teljesíteni a kérést.

XTYP_POKE

Értesíti a szervert, hogy a kliens által küldött adat kéretlen(önkéntes). Hsz1 a topic, Hsz2 az item. A callback függvény visszatérési értéke DDE_FACK ha végrehajtotta a tranzakciót, DDE_FBUSY ha foglalt és DDE_FNOTPROCESSED ha nem akarja, vagy nem tudja teljesíteni a kérést.

XTYP_REGISTER

Értesít egy DDE applikációt, hogy egy DDE szerver meghívta a DdeNameService, hogy regisztráljon egy service nevet, vagy egy nem DDEML applikáció indult, amely támogatja a system topic-ot. A hsz1 tartalmazza az alap service nevet és a hsz2 tartalmazza a példány specifikus service nevet.

XTYP_REQUEST

Értesíti a szervert, hogy a kliens egy adatot kért. hsz1 a topic, hsz2 az item. A szerver Callback függvénye meghívja a DdeCreateHandleData függvényt, hogy létrehozzon egy adat objektumot. Bemásolja az adatot ebbe az objektumba és visszatér az adatleíróval. Ha nem sikerült teljesíteni a tranzakciót, akkor NULL-la tér vissza. A DDEML küld egy DDE_FNOTPROCESSED flaget a kliensnek.

XTYP_UNREGISTER

Értesíti a DDEML applikációt, hogy DDEML szerver applikáció használta a DdeNameService, hogy unregisztrálja a service nevet. A hsz1, hsz2 ugyanaz mint a regiszter esetén.

XTYP_WILDCONNECT

Értesít egy szervert, hogy egy kliens kapcsolatot akar felvenni bármilyen szerverrel, ami rendelkezik az adott service és topic szolgáltatással. A hsz1 topic, hsz2 service. Ha hsz1 és hsz2 NULL, akkor minden topic érdekli a klienst, amit a szerver támogat. A dwData1 pointer a CONVTEXT stuktúra, amely  információkat tartalmaz a kapcsolatról. A dwData2 azt jelzi, hogy azonos applikációhoz tartozik-e a két partner vagy sem. A Callback függvény egy HSZPAIR struktúráju tömbbel tér vissza. A tömb tartalmazza a topic-service párokat.

XTYP_XACT_COMPLETE

Értesíti a klienst, hogy aszinkron tranzakció ért véget. A hsz1 és hsz2 tartalmazzák a topicot és az itemet. A hData tartalmazza az adatokat ha van. A Callback függvény meghívja a DdeGetData-t, hogy másolja az adatokat.



Egy tipikus DDE Callback függvény egy hosszú switch-et tartalmaz, amelyben a különböző tranzakciókra történik a reagálás. Például egy kliens Callback függvény a következőképpen néz ki:

// DDE Callback függvény egy DDEML kliens esetén

HDDEDATA FAR PASCAL _export DdeCallback (UINT iType, UINT iFmt, HCONV hConv,HSZ hsz1, HSZ hsz2, HDDEDATA hData,DWORD dwData1, DWORD dwData2)

return NULL ;

}

3. DDE Beszélgetés indítása

Az inicializálás után a kliens felveheti a kapcsolatot a DdeConnect függvény meghívásával. Például ahhoz, hogy elkezdjünk egy DDE beszélgetést egy Excel service név és MINTA.XLS topic nevű szerverrel a következő programrész szükséges:

HSZ hszService, hszTopic;

HCONV hConv;

//tételezzük fel, hogy a DdeInitialize után a példány visszatérési értéke dwDDEInst (a //DdeInitialize első argumentuam)

// A stringből létrehozunk egy leírót, amelyet felhasználunk a kommunikáció során

hszService =DdeCreateStringHandle(dwDDEInst, "Excel", CP_WINANSI);

hszTopic =DdeCreateStringHandle(dwDDEInst, "MINTA.XLS", CP_WINANSI);

hConv=DdeConnect(dwDDEInst, hszService, hszTopic, NULL);

if(!hConv)

// A stringből létrehozott leírók felszabadítása

DdeFreeStringHandle(dwDDEInst, hszService);

DdeFreeStringHandle(dwDDEInst, hszTopic);

A DDE szerverek ilyenkor egy XTYP_CONNECT tranzakciót kapnak. Az a szerver, amely támogatja az adott service és Topic nevet TRUE-val válaszol.

A kliens több szerverre is tud csatlakozni egyszerre. Ehhez a DdeConnect helyett a DdeConnectList függvényt kell meghívni, amely egy HCONVLIST típusú listával tér vissza. Lehet "sétálni" a lista elemein és mindegyiknek a részleteit megvizsgálni. A léptetés a lista elemei között a DdeQueryNextServer segítségével lehetséges.

Általában a fő oka annak, hogy a DdeConnect NULL-lal tér vissza az, hogy az adott applikáció nincsen elindítva. Ilyen esetben el lehet indítani a programot a WinExec API függvény segítségével. Ilyenkor a fenti program a következőre módosul.

HSZ hszService, hszTopic;

HCONV hConv;

//tételezzük fel, hogy a DdeInitialize után a példány visszatérési értéke dwDDEInst (a //DdeInitialize első argumentuam)

// A stringből létrehozunk egy leírót, amelyet felhasználunk a kommunikáció során

hszService =DdeCreateStringHandle(dwDDEInst, "Excel", CP_WINANSI);

hszTopic =DdeCreateStringHandle(dwDDEInst, "MINTA.XLS", CP_WINANSI);

hConv=DdeConnect(dwDDEInst, hszService, hszTopic, NULL);

if(!hConv) // itt van a különbség

// A stringből létrehozott leírók felszabadítása

DdeFreeStringHandle(dwDDEInst, hszService);

DdeFreeStringHandle(dwDDEInst, hszTopic);

4. Adat lekérdezés

Miután létrejött a kapcsolat a kliens és a szerver között kezdődhet az adat lekérdezés-küldés. A következő arra ad példát:

BYTE dbuff;

HSZ hszItem;

HDDEDATA hData;

DWORD dwResult;

// A DdeConnect után

if (hConv)

A szerver Callback függvénye ilyenkor egy ilyen tranzakciót kap. Erre reagálva létrehoz egy leírót a DdeCreateDataHandle függvény segítségével, ebbe bemásolja az adatot és visszatér ezzel a leíróval.

5. Az adatok folyamatos frissítése, küldése

A fent említett eset egy hideg kapcsolatot (cold link) képez. Gyakran felmerül az igény arra, hogy a kliens tudomást szerezzen az adat változásáról. Ilyenkor a hideg kapcsolat nem tudja ezt garantálni. Ennek megvalósításához a meleg vagy a forró kapcsolat ad megoldást. Advise alatt azt értjük, hogy a kliens mindig kap értesítést az adat megváltozásáról vagy magát az adatot. Az első eset a meleg kapcsolat, az utóbbi pedig a forró. A meleg és a forró kapcsolat esetén egy ciklusban történik az adatfrissítés. A ciklus addig tart, amíg nem szakítjuk meg. A ciklust az XTYP_ADVSTART tranzakcióval lehet indítani és az XTYP_ADVSTOP-pal megszakítani. Amennyiben egy meleg kapcsolatot szeretnénk megvalósítani, akkor az XTYP_ADVSTART-ot kombinálni kell az XTYP_ADVNODATA konstanssal vagy kapcsolattal. Mind a két kapcsolat esetén a kliens Callback függvénye egy XTYP_ADVDATA tranzakciót kap. A forró kapcsolat esetén a hData tartalmazza az adatot, a meleg esetén pedig NULL és csak értesítésről van szó.

6. A DDE beszélgetés befejezése, a kapcsolat lebontása

Miután már nem kell nekünk a DDE kapcsolat, akkor ezt lebonthatjuk. A lebontás a DdeDisconnect, illetve a DdeDisconnectList-tel történik, attól függően, hogy a DdeConnect, illetve DdeConnectList-et használtunk a kapcsolat létrehozásakor. A lebontás után meg kell hívni a DdeUninitialize függvényt, jelezve azt, hogy már egyáltalan nem kell nekünk a DDE szolgáltatás. Példa:

DdeDisconnect(hConv);

DdeUninitialize(dwDDEInst);

7. Szinkron és aszinkron tranzakciók

A tranzakciók kezelhetők szinkron és aszinkron módon. Szinkron kapcsolat esetén definiálható egy timeout, ameddig a kliens vár a szerverre. Ebben az esetben a DdeClientTransaction függvény addig nem tér vissza, amíg a szerver nem fejezi be a tranzakció feldolgozását, vagy megszakítja azt, vagy lejár a timeout. Amíg a DdeClientTransaction függvény nem tér vissza addig a kliens nem küldhet újabb tranzakciót.

Az aszinkron kapcsolat esetén a DdeClientTransaction azonnal visszatér. Az aszinkron mód megvalósításához a DdeClientTransaction uType paraméterét a TIMEOUT_ASYNC konstanssal kell kombinálni. Amikor a szerver befejezi a feldolgozást, akkor egy XTYP_XACT_COMPLETE értesítést küld a kliensnek.

A DdeAbandomTransaction függvénnyel megszakítható az aszinkron üzenetcsomag továbbítása.

8. DDEML függvények

A következő táblázatban összefoglaljuk a DDEML függvényeket.

Függvény neve

funkció

DdeAbandomTransaction

megszakít egy aszinkron tranzakciót

DdeAccessData

Lokkolja a DDE adat objektumot. Egy pointerrel tér vissza, ami az adatokra mutat. NULL-lal tér vissza, ha nem sikerült a lokkolás.

DdeAddData

Újabb adatot ad a specifikált HDDEDATA objektumra.

DdeClientTransaction

Elkezd egy DDE tranzakciót egy adott szerver felé.

DdeCmpStringHandles

Összehasonlít két string leírót. (Case Insensitive)

DdeConnect

Csatlakozás a DDE szerverre.

DdeConnectList

Csatlakozás több mint egy szerverre.

DdeCreateDataHandle

Adat leíró létrehozása.

DdeCreateStringHandle

Egy stringből létrehoz egy leírót.

DdeDisconnect

Kapcsolat lebontás egy szervertől.

DdeDisconnectList

Kapcsolatlebontás több szervertől

DdeEnableCallback

Szűrő, milyen tranzakciók jöhetnek.

DdeFreeDataHandle

Adat leíró felszabadítása

DdeFreeStringHandle

String leíró felszabadítása

DdeGetData

Adatok másolása a HDDEDATA típusú leíróból

DdeGetLastError

Az utolsó DDE hibakód lekérdezése.

DdeInitialize

Kapcsolat felvétele a DDEML-lel.

DdeKeepStringHandle

A string leíró megtartása.

DdeNameService

Service név regisztrálása a DDEML-lel.

DdePostAdvise

A szerver hívja meg, hogy értesítse a klienst az adat megváltozásáról vagy ezzel küldi az adatokat.

DdeQueryConvInfo

DDE tranzakcióról szerez információt.

DdeQueryNextSzerver

A szerverlistán való gyaloglás.

DdeQueryString

Egy stringleíróból visszaadja a stringet.

DdeReconnect

Újból csatlakozás.

DdeUnaccessData

A lokkolás feloldása.

DdeUninitialize

A DDE befejezése. Ez felszabadítja a DDEML erőforrásokat.




Document Info


Accesari: 1077
Apreciat: hand-up

Comenteaza documentul:

Nu esti inregistrat
Trebuie sa fii utilizator inregistrat pentru a putea comenta


Creaza cont nou

A fost util?

Daca documentul a fost util si crezi ca merita
sa adaugi un link catre el la tine in site


in pagina web a site-ului tau.




eCoduri.com - coduri postale, contabile, CAEN sau bancare

Politica de confidentialitate | Termenii si conditii de utilizare




Copyright © Contact (SCRIGROUP Int. 2025 )