A vágólap használata
Ez a szakasz kódmintákat biztosít a következő feladatokhoz:
-
kivágási, másolási és beillesztési parancsok implementálása
- Adatok kijelölése
- Szerkesztés menü létrehozása
-
WM_INITMENUPOPUP
üzenet feldolgozása -
WM_COMMAND
üzenet feldolgozása - Adatok másolása a vágólapra
- Információk beillesztése a vágólapról
- Vágólapformátum regisztrálása
-
Üzenetek
WM_RENDERFORMAT
ésWM_RENDERALLFORMATS
feldolgozása -
WM_DESTROYCLIPBOARD
üzenet feldolgozása - Owner-Display A vágólap formátum használata
- Vágólap tartalmának figyelése
- A vágólap sorszámának lekérdezése
- Vágólapformátum-figyelő létrehozása
- Vágólapmegjelenítő ablak létrehozása
- Ablak hozzáadása a vágólapmegjelenítő lánchoz
A kivágási, másolási és beillesztési parancsok implementálása
Ez a szakasz azt ismerteti, hogy a standard Kivágás, Másolásés Beillesztés parancsok hogyan implementálhatók egy alkalmazásban. Az ebben a szakaszban szereplő példa az alábbi módszerekkel helyezi el az adatokat a vágólapra regisztrált vágólapformátum, a CF_OWNERDISPLAY
formátum és a CF_TEXT
formátum használatával. A regisztrált formátum négyszögletes vagy háromliptikus szövegablakokat, úgynevezett címkéket jelöl.
Adatok kiválasztása
Ahhoz, hogy az adatok átmásolhatók legyenek a vágólapra, a felhasználónak ki kell választania a másolandó vagy kivágandó adatokat. Az alkalmazásnak módot kell biztosítania arra, hogy a felhasználó információkat válasszon ki egy dokumentumon belül, és valamilyen vizuális visszajelzéssel jelezze a kiválasztott adatokat.
Szerkesztési menü létrehozása
Az alkalmazásoknak be kell tölteniük a Edit menüparancsokhoz tartozó szabványos billentyűzetgyorsítókat tartalmazó gyorsítótáblát. A TranslateAccelerator
függvényt hozzá kell adni az alkalmazás üzenethurkához, hogy a gyorsítók érvénybe léphessenek. A billentyűzetgyorsítókkal kapcsolatos további információkért lásd: Billentyűzetgyorsítók.
A WM_INITMENUPOPUP
üzenet feldolgozása
Nem minden vágólapparancs érhető el a felhasználó számára egy adott időpontban. Az alkalmazásnak feldolgoznia kell a WM_INITMENUPOPUP
üzenetet, hogy engedélyezze a menüelemeket az elérhető parancsokhoz, és letiltsa a nem elérhető parancsokat.
Az alábbiakban a WM_INITMENUPOPUP
eset olvasható egy Címke nevű alkalmazás számára.
case WM_INITMENUPOPUP:
InitMenu((HMENU) wParam);
break;
A InitMenu
függvény a következőképpen van definiálva.
void WINAPI InitMenu(HMENU hmenu)
{
int cMenuItems = GetMenuItemCount(hmenu);
int nPos;
UINT id;
UINT fuFlags;
PLABELBOX pbox = (hwndSelected == NULL) ? NULL :
(PLABELBOX) GetWindowLong(hwndSelected, 0);
for (nPos = 0; nPos < cMenuItems; nPos++)
{
id = GetMenuItemID(hmenu, nPos);
switch (id)
{
case IDM_CUT:
case IDM_COPY:
case IDM_DELETE:
if (pbox == NULL || !pbox->fSelected)
fuFlags = MF_BYCOMMAND | MF_GRAYED;
else if (pbox->fEdit)
fuFlags = (id != IDM_DELETE && pbox->ichSel
== pbox->ichCaret) ?
MF_BYCOMMAND | MF_GRAYED :
MF_BYCOMMAND | MF_ENABLED;
else
fuFlags = MF_BYCOMMAND | MF_ENABLED;
EnableMenuItem(hmenu, id, fuFlags);
break;
case IDM_PASTE:
if (pbox != NULL && pbox->fEdit)
EnableMenuItem(hmenu, id,
IsClipboardFormatAvailable(CF_TEXT) ?
MF_BYCOMMAND | MF_ENABLED :
MF_BYCOMMAND | MF_GRAYED
);
else
EnableMenuItem(hmenu, id,
IsClipboardFormatAvailable(
uLabelFormat) ?
MF_BYCOMMAND | MF_ENABLED :
MF_BYCOMMAND | MF_GRAYED
);
}
}
}
A WM_COMMAND
üzenet feldolgozása
A menüparancsok feldolgozásához adja hozzá a WM_COMMAND
esetet az alkalmazás főablakának eljárásához. A következő a WM_COMMAND
eset a Label alkalmazás ablakeljárásához.
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_CUT:
if (EditCopy())
EditDelete();
break;
case IDM_COPY:
EditCopy();
break;
case IDM_PASTE:
EditPaste();
break;
case IDM_DELETE:
EditDelete();
break;
case IDM_EXIT:
DestroyWindow(hwnd);
}
break;
A másolása és kivágása parancs végrehajtásához az ablak eljárás meghívja az alkalmazás által definiált EditCopy
függvényt. További információ: Adatok másolása a vágólapra. A Beillesztés parancs végrehajtásához az ablakművelet meghívja az alkalmazás által definiált EditPaste
függvényt. A EditPaste
függvényről további információt a A vágólapról történő információ beillesztésecímű témakörben talál.
Adatok másolása a vágólapra
A Címke alkalmazásban az alkalmazás által definiált EditCopy függvény átmásolja az aktuális kijelölést a vágólapra. Ez a függvény a következőket teszi:
- A vágólap megnyitásához hívja meg a
OpenClipboard
függvényt. - Kiüríti a vágólapot a
EmptyClipboard
függvény meghívásával. - Egyszer meghívja a
SetClipboardData
függvényt az alkalmazás által biztosított minden vágólapformátumhoz. - A vágólap bezárása a
CloseClipboard
függvény meghívásával.
Az Aktuális kijelöléstől függően az EditCopy függvény vagy egy szövegtartományt másol, vagy egy alkalmazás által definiált struktúrát másol, amely egy teljes címkét jelöl. A LABELBOX
nevű struktúra a következőképpen van definiálva.
#define BOX_ELLIPSE 0
#define BOX_RECT 1
#define CCH_MAXLABEL 80
#define CX_MARGIN 12
typedef struct tagLABELBOX { // box
RECT rcText; // coordinates of rectangle containing text
BOOL fSelected; // TRUE if the label is selected
BOOL fEdit; // TRUE if text is selected
int nType; // rectangular or elliptical
int ichCaret; // caret position
int ichSel; // with ichCaret, delimits selection
int nXCaret; // window position corresponding to ichCaret
int nXSel; // window position corresponding to ichSel
int cchLabel; // length of text in atchLabel
TCHAR atchLabel[CCH_MAXLABEL];
} LABELBOX, *PLABELBOX;
Az EditCopy
függvény alábbi.
BOOL WINAPI EditCopy(VOID)
{
PLABELBOX pbox;
LPTSTR lptstrCopy;
HGLOBAL hglbCopy;
int ich1, ich2, cch;
if (hwndSelected == NULL)
return FALSE;
// Open the clipboard, and empty it.
if (!OpenClipboard(hwndMain))
return FALSE;
EmptyClipboard();
// Get a pointer to the structure for the selected label.
pbox = (PLABELBOX) GetWindowLong(hwndSelected, 0);
// If text is selected, copy it using the CF_TEXT format.
if (pbox->fEdit)
{
if (pbox->ichSel == pbox->ichCaret) // zero length
{
CloseClipboard(); // selection
return FALSE;
}
if (pbox->ichSel < pbox->ichCaret)
{
ich1 = pbox->ichSel;
ich2 = pbox->ichCaret;
}
else
{
ich1 = pbox->ichCaret;
ich2 = pbox->ichSel;
}
cch = ich2 - ich1;
// Allocate a global memory object for the text.
hglbCopy = GlobalAlloc(GMEM_MOVEABLE,
(cch + 1) * sizeof(TCHAR));
if (hglbCopy == NULL)
{
CloseClipboard();
return FALSE;
}
// Lock the handle and copy the text to the buffer.
lptstrCopy = GlobalLock(hglbCopy);
memcpy(lptstrCopy, &pbox->atchLabel[ich1],
cch * sizeof(TCHAR));
lptstrCopy[cch] = (TCHAR) 0; // null character
GlobalUnlock(hglbCopy);
// Place the handle on the clipboard.
SetClipboardData(CF_TEXT, hglbCopy);
}
// If no text is selected, the label as a whole is copied.
else
{
// Save a copy of the selected label as a local memory
// object. This copy is used to render data on request.
// It is freed in response to the WM_DESTROYCLIPBOARD
// message.
pboxLocalClip = (PLABELBOX) LocalAlloc(
LMEM_FIXED,
sizeof(LABELBOX)
);
if (pboxLocalClip == NULL)
{
CloseClipboard();
return FALSE;
}
memcpy(pboxLocalClip, pbox, sizeof(LABELBOX));
pboxLocalClip->fSelected = FALSE;
pboxLocalClip->fEdit = FALSE;
// Place a registered clipboard format, the owner-display
// format, and the CF_TEXT format on the clipboard using
// delayed rendering.
SetClipboardData(uLabelFormat, NULL);
SetClipboardData(CF_OWNERDISPLAY, NULL);
SetClipboardData(CF_TEXT, NULL);
}
// Close the clipboard.
CloseClipboard();
return TRUE;
}
Adatok beillesztése a vágólapról
A Címke alkalmazásban az alkalmazás által definiált EditPaste
függvény beilleszti a vágólap tartalmát. Ez a függvény a következőket teszi:
- A vágólap megnyitásához hívja meg a
OpenClipboard
függvényt. - Meghatározza, hogy az elérhető vágólapformátumok közül melyiket szeretné lekérni.
- A
GetClipboardData
függvény meghívásával lekéri a kiválasztott formátumban lévő adatok fogantyúját. - Beszúrja az adatok másolatát a dokumentumba. A
GetClipboardData
által visszaadott fogópont továbbra is a vágólap tulajdonában van, ezért az alkalmazás nem szabadíthatja fel, és nem hagyhatja zárolva. - A vágólap bezárása a
CloseClipboard
függvény meghívásával.
Ha egy címke van kijelölve, és beszúrási pontot tartalmaz, az EditPaste függvény beszúrja a szöveget a vágólapról a beszúrási pontra. Ha nincs kijelölés, vagy ha egy címke van kijelölve, a függvény létrehoz egy új címkét az alkalmazás által definiált LABELBOX
szerkezet használatával a vágólapon. A LABELBOX
szerkezet regisztrált vágólapformátum használatával kerül a vágólapra.
A LABELBOX
nevű struktúra a következőképpen van definiálva.
#define BOX_ELLIPSE 0
#define BOX_RECT 1
#define CCH_MAXLABEL 80
#define CX_MARGIN 12
typedef struct tagLABELBOX { // box
RECT rcText; // coordinates of rectangle containing text
BOOL fSelected; // TRUE if the label is selected
BOOL fEdit; // TRUE if text is selected
int nType; // rectangular or elliptical
int ichCaret; // caret position
int ichSel; // with ichCaret, delimits selection
int nXCaret; // window position corresponding to ichCaret
int nXSel; // window position corresponding to ichSel
int cchLabel; // length of text in atchLabel
TCHAR atchLabel[CCH_MAXLABEL];
} LABELBOX, *PLABELBOX;
Az alábbiakban következik a EditPaste
függvény.
VOID WINAPI EditPaste(VOID)
{
PLABELBOX pbox;
HGLOBAL hglb;
LPTSTR lptstr;
PLABELBOX pboxCopy;
int cx, cy;
HWND hwnd;
pbox = hwndSelected == NULL ? NULL :
(PLABELBOX) GetWindowLong(hwndSelected, 0);
// If the application is in edit mode,
// get the clipboard text.
if (pbox != NULL && pbox->fEdit)
{
if (!IsClipboardFormatAvailable(CF_TEXT))
return;
if (!OpenClipboard(hwndMain))
return;
hglb = GetClipboardData(CF_TEXT);
if (hglb != NULL)
{
lptstr = GlobalLock(hglb);
if (lptstr != NULL)
{
// Call the application-defined ReplaceSelection
// function to insert the text and repaint the
// window.
ReplaceSelection(hwndSelected, pbox, lptstr);
GlobalUnlock(hglb);
}
}
CloseClipboard();
return;
}
// If the application is not in edit mode,
// create a label window.
if (!IsClipboardFormatAvailable(uLabelFormat))
return;
if (!OpenClipboard(hwndMain))
return;
hglb = GetClipboardData(uLabelFormat);
if (hglb != NULL)
{
pboxCopy = GlobalLock(hglb);
if (pboxCopy != NULL)
{
cx = pboxCopy->rcText.right + CX_MARGIN;
cy = pboxCopy->rcText.top * 2 + cyText;
hwnd = CreateWindowEx(
WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT,
atchClassChild, NULL, WS_CHILD, 0, 0, cx, cy,
hwndMain, NULL, hinst, NULL
);
if (hwnd != NULL)
{
pbox = (PLABELBOX) GetWindowLong(hwnd, 0);
memcpy(pbox, pboxCopy, sizeof(LABELBOX));
ShowWindow(hwnd, SW_SHOWNORMAL);
SetFocus(hwnd);
}
GlobalUnlock(hglb);
}
}
CloseClipboard();
}
Vágólapformátum regisztrálása
Vágólapformátum regisztrálásához adjon hozzá egy hívást a RegisterClipboardFormat
függvényhez az alkalmazás példány inicializálási függvényéhez az alábbiak szerint.
// Register a clipboard format.
// We assume that atchTemp can contain the format name and
// a null-terminator, otherwise it is truncated.
//
LoadString(hinstCurrent, IDS_FORMATNAME, atchTemp,
sizeof(atchTemp)/sizeof(TCHAR));
uLabelFormat = RegisterClipboardFormat(atchTemp);
if (uLabelFormat == 0)
return FALSE;
A WM_RENDERFORMAT
és WM_RENDERALLFORMATS
üzenetek feldolgozása
Ha egy ablak átad egy NULL
leírót a SetClipboardData
függvénynek, a WM_RENDERFORMAT
és WM_RENDERALLFORMATS
üzeneteket kell feldolgoznia, hogy kérésre megjelenítse az adatokat.
Ha egy ablak késlelteti egy adott formátum megjelenítését, majd egy másik alkalmazás adatokat kér ebben a formátumban, akkor a rendszer egy WM_RENDERFORMAT
üzenetet küld az ablaknak. Ezenkívül ha egy ablak késlelteti egy vagy több formátum megjelenítését, és egyes formátumok rendezetlenek maradnak az ablak megsemmisítése előtt, akkor a rendszer WM_RENDERALLFORMATS
üzenetet küld az ablaknak a megsemmisítés előtt.
A vágólap formátumának megjelenítéséhez az ablakeljárásnak egyNULL
-tól eltérő adatleírót kell elhelyeznie a vágólapon a SetClipboardData
függvénnyel. Ha az ablakművelet formátumot jelenít meg a WM_RENDERFORMAT
üzenetre válaszul, nem nyithatja meg a vágólapot a SetClipboardData
hívása előtt. Ha azonban egy vagy több formátumot jelenít meg a WM_RENDERALLFORMATS
üzenetre válaszul, meg kell nyitnia a vágólapot, és ellenőriznie kell, hogy az ablak továbbra is a vágólap tulajdonosa-e, mielőtt meghívná SetClipboardData
, és a visszatérés előtt be kell zárnia a vágólapot.
A Címke alkalmazás az alábbiak szerint dolgozza fel a WM_RENDERFORMAT
és WM_RENDERALLFORMATS
üzeneteket.
case WM_RENDERFORMAT:
RenderFormat((UINT) wParam);
break;
case WM_RENDERALLFORMATS:
if (OpenClipboard(hwnd))
{
if (GetClipboardOwner() == hwnd)
{
RenderFormat(uLabelFormat);
RenderFormat(CF_TEXT);
}
CloseClipboard();
}
break;
Az ablakos eljárás mindkét esetben meghívja az alkalmazás által definiált RenderFormat
függvényt, amely az alábbiak szerint van definiálva.
A LABELBOX
nevű struktúra a következőképpen van definiálva.
#define BOX_ELLIPSE 0
#define BOX_RECT 1
#define CCH_MAXLABEL 80
#define CX_MARGIN 12
typedef struct tagLABELBOX { // box
RECT rcText; // coordinates of rectangle containing text
BOOL fSelected; // TRUE if the label is selected
BOOL fEdit; // TRUE if text is selected
int nType; // rectangular or elliptical
int ichCaret; // caret position
int ichSel; // with ichCaret, delimits selection
int nXCaret; // window position corresponding to ichCaret
int nXSel; // window position corresponding to ichSel
int cchLabel; // length of text in atchLabel
TCHAR atchLabel[CCH_MAXLABEL];
} LABELBOX, *PLABELBOX;
void WINAPI RenderFormat(UINT uFormat)
{
HGLOBAL hglb;
PLABELBOX pbox;
LPTSTR lptstr;
int cch;
if (pboxLocalClip == NULL)
return;
if (uFormat == CF_TEXT)
{
// Allocate a buffer for the text.
cch = pboxLocalClip->cchLabel;
hglb = GlobalAlloc(GMEM_MOVEABLE,
(cch + 1) * sizeof(TCHAR));
if (hglb == NULL)
return;
// Copy the text from pboxLocalClip.
lptstr = GlobalLock(hglb);
memcpy(lptstr, pboxLocalClip->atchLabel,
cch * sizeof(TCHAR));
lptstr[cch] = (TCHAR) 0;
GlobalUnlock(hglb);
// Place the handle on the clipboard.
SetClipboardData(CF_TEXT, hglb);
}
else if (uFormat == uLabelFormat)
{
hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(LABELBOX));
if (hglb == NULL)
return;
pbox = GlobalLock(hglb);
memcpy(pbox, pboxLocalClip, sizeof(LABELBOX));
GlobalUnlock(hglb);
SetClipboardData(uLabelFormat, hglb);
}
}
A WM_DESTROYCLIPBOARD
üzenet feldolgozása
Az ablak feldolgozhatja a WM_DESTROYCLIPBOARD
üzenetet, hogy felszabadítsa az általa félretett erőforrásokat a késleltetett renderelés támogatásához. A Címke alkalmazás például egy címke vágólapra másolásakor lefoglal egy helyi memóriaobjektumot. Ezután felszabadítja ezt az objektumot a WM_DESTROYCLIPBOARD
üzenetre válaszul, az alábbiak szerint.
case WM_DESTROYCLIPBOARD:
if (pboxLocalClip != NULL)
{
LocalFree(pboxLocalClip);
pboxLocalClip = NULL;
}
break;
A Owner-Display vágólap formátumának használata
Ha egy ablak a CF_OWNERDISPLAY
vágólap formátumával helyezi el az adatokat a vágólapon, a következőt kell tennie:
- Dolgozza fel a
WM_PAINTCLIPBOARD
üzenetet. Ezt az üzenetet a vágólap tulajdonosának küldi el, amikor újra kell festeni a vágólapmegjelenítő ablak egy részét. - Dolgozza fel a
WM_SIZECLIPBOARD
üzenetet. Ez az üzenet a vágólap tulajdonosának lesz elküldve, ha a vágólapmegjelenítő ablakát átméretezték, vagy a tartalma megváltozott. Az ablak általában a vágólapmegjelenítő ablak görgetési pozícióinak és tartományainak beállításával válaszol erre az üzenetre. Az üzenetre válaszul a Címke alkalmazás a vágólapmegjelenítő ablakánakSIZE
struktúráját is frissíti. - Dolgozza fel a
WM_HSCROLLCLIPBOARD
ésWM_VSCROLLCLIPBOARD
üzeneteket. Ezek az üzenetek a vágólap tulajdonosának lesznek elküldve, amikor egy görgetősáv-esemény történik a vágólapmegjelenítő ablakban. - Dolgozza fel a
WM_ASKCBFORMATNAME
üzenetet. A vágólapmegjelenítő ablaka elküldi ezt az üzenetet egy alkalmazásnak a tulajdonosi megjelenítési formátum nevének lekéréséhez.
A Címke alkalmazás ablakművelete az alábbiak szerint dolgozza fel ezeket az üzeneteket.
LRESULT CALLBACK MainWindowProc(hwnd, msg, wParam, lParam)
HWND hwnd;
UINT msg;
WPARAM wParam;
LPARAM lParam;
{
static RECT rcViewer;
RECT rc;
LPRECT lprc;
LPPAINTSTRUCT lpps;
switch (msg)
{
//
// Handle other messages.
//
case WM_PAINTCLIPBOARD:
// Determine the dimensions of the label.
SetRect(&rc, 0, 0,
pboxLocalClip->rcText.right + CX_MARGIN,
pboxLocalClip->rcText.top * 2 + cyText
);
// Center the image in the clipboard viewer window.
if (rc.right < rcViewer.right)
{
rc.left = (rcViewer.right - rc.right) / 2;
rc.right += rc.left;
}
if (rc.bottom < rcViewer.bottom)
{
rc.top = (rcViewer.bottom - rc.bottom) / 2;
rc.bottom += rc.top;
}
// Paint the image, using the specified PAINTSTRUCT
// structure, by calling the application-defined
// PaintLabel function.
lpps = (LPPAINTSTRUCT) GlobalLock((HGLOBAL) lParam);
PaintLabel(lpps, pboxLocalClip, &rc);
GlobalUnlock((HGLOBAL) lParam);
break;
case WM_SIZECLIPBOARD:
// Save the dimensions of the window in a static
// RECT structure.
lprc = (LPRECT) GlobalLock((HGLOBAL) lParam);
memcpy(&rcViewer, lprc, sizeof(RECT));
GlobalUnlock((HGLOBAL) lParam);
// Set the scroll ranges to zero (thus eliminating
// the need to process the WM_HSCROLLCLIPBOARD and
// WM_VSCROLLCLIPBOARD messages).
SetScrollRange((HWND) wParam, SB_HORZ, 0, 0, TRUE);
SetScrollRange((HWND) wParam, SB_VERT, 0, 0, TRUE);
break;
case WM_ASKCBFORMATNAME:
LoadString(hinst, IDS_OWNERDISPLAY,
(LPSTR) lParam, wParam);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
Vágólap tartalmának figyelése
A vágólap módosításait háromféleképpen figyelheti. A legrégebbi módszer egy vágólapmegjelenítő ablak létrehozása. A Windows 2000 lehetővé tette a vágólap sorszámának lekérdezését, a Windows Vista pedig támogatja a vágólapformátum-figyelőket. A vágólapmegjelenítő ablakai támogatják a Windows korábbi verzióival való visszamenőleges kompatibilitást. Az új programoknak a vágólap formátumfigyelőit vagy a vágólap sorszámát kell használniuk.
A vágólap sorszámának lekérdezése
Minden alkalommal, amikor a vágólap tartalma megváltozik, a vágólap sorszámaként ismert 32 bites érték növekszik. A program a GetClipboardSequenceNumber
függvény meghívásával lekérheti a vágólap aktuális sorszámát. Ha összehasonlítja a visszaadott értéket egy korábbi GetClipboardSequenceNumber
hívás által visszaadott értékkel, a program meghatározhatja, hogy a vágólap tartalma megváltozott-e. Ez a módszer alkalmasabb azokra a programokra, amelyek a vágólap aktuális tartalma alapján gyorsítótárazják az eredményeket, és tudniuk kell, hogy a számítások még érvényesek-e a gyorsítótárból származó eredmények használata előtt. Vegye figyelembe, hogy ez nem értesítési módszer, és nem használható lekérdezési ciklusban. Ha értesítést szeretne kapni a vágólap tartalmának változásakor, használjon vágólapformátum-figyelőt vagy vágólapmegjelenítőt.
Vágólapformátum-figyelő létrehozása
A vágólapformátum-figyelő egy olyan ablak, amely regisztrálva van, hogy értesítést kapjon a vágólap tartalmának módosításakor. Ez a módszer a vágólapmegjelenítő ablak létrehozásakor ajánlott, mert egyszerűbb implementálni és elkerülni a problémákat, ha a programok nem tartják megfelelően a vágólapmegjelenítő láncot, vagy ha a vágólapmegjelenítő lánc egy ablaka nem válaszol az üzenetekre.
Az ablak a AddClipboardFormatListener
függvény meghívásával regisztrál vágólapformátum-figyelőként. Amikor a vágólap tartalma megváltozik, az ablak egy WM_CLIPBOARDUPDATE
üzenetet jelenít meg. A regisztráció mindaddig érvényes marad, amíg az ablak a RemoveClipboardFormatListener
függvény meghívásával meg nem szünteti a regisztrációt.
Vágólapmegjelenítő ablak létrehozása
A vágólapmegjelenítő ablak megjeleníti a vágólap aktuális tartalmát, és üzeneteket fogad, amikor a vágólap tartalma megváltozik. Vágólapmegjelenítő ablak létrehozásához az alkalmazásnak a következőket kell tennie:
- Adja hozzá az ablakot a vágólap-megtekintő lánchoz.
- Dolgozza fel a
WM_CHANGECBCHAIN
üzenetet. - Dolgozza fel a
WM_DRAWCLIPBOARD
üzenetet. - Távolítsa el az ablakot a vágólap megtekintő láncából, mielőtt az megsemmisül.
Ablak hozzáadása a vágólapmegjelenítő láncához
Egy ablak hozzáadja magát a vágólap-megjelenítő lánchoz a SetClipboardViewer
függvény meghívásával. A visszatérési érték a lánc következő ablakának hivatkozása. Az ablaknak nyomon kell követnie ezt az értéket – például egy hwndNextViewer
nevű statikus változóba kell mentenie.
Az alábbi példa egy ablakot ad hozzá a vágólapmegjelenítő lánchoz a WM_CREATE
üzenetre válaszul.
case WM_CREATE:
// Add the window to the clipboard viewer chain.
hwndNextViewer = SetClipboardViewer(hwnd);
break;
A kódrészletek a következő feladatokhoz jelennek meg:
-
WM_CHANGECBCHAIN
üzenet feldolgozása - Ablak eltávolítása a vágólapmegjelenítő láncból
-
WM_DRAWCLIPBOARD
üzenet feldolgozása - A vágólap-megjelenítő példája
A WM_CHANGECBCHAIN
üzenet feldolgozása
A vágólapmegjelenítő ablak akkor kapja meg a WM_CHANGECBCHAIN
üzenetet, ha egy másik ablak eltávolítja magát a vágólapmegjelenítő láncból. Ha az eltávolított ablak a lánc következő ablaka, az üzenetet fogadó ablaknak le kell választania a lánc következő ablakát. Ellenkező esetben ezt az üzenetet át kell adni a lánc következő ablakának.
Az alábbi példa a WM_CHANGECBCHAIN
üzenet feldolgozását mutatja be.
case WM_CHANGECBCHAIN:
// If the next window is closing, repair the chain.
if ((HWND) wParam == hwndNextViewer)
hwndNextViewer = (HWND) lParam;
// Otherwise, pass the message to the next link.
else if (hwndNextViewer != NULL)
SendMessage(hwndNextViewer, uMsg, wParam, lParam);
break;
Ablak eltávolítása a vágólapmegjelenítő láncából
Ha el szeretné távolítani magát a vágólapmegjelenítő láncából, egy ablak meghívja a ChangeClipboardChain
függvényt. Az alábbi példa eltávolít egy ablakot a vágólapmegjelenítő láncából a WM_DESTROY
üzenetre válaszul.
case WM_DESTROY:
ChangeClipboardChain(hwnd, hwndNextViewer);
PostQuitMessage(0);
break;
A WM_DRAWCLIPBOARD
üzenet feldolgozása
A WM_DRAWCLIPBOARD
üzenet értesíti a vágólapmegjelenítő ablakát, hogy a vágólap tartalma megváltozott. A WM_DRAWCLIPBOARD
üzenet feldolgozásakor az ablaknak a következőket kell tennie:
- Határozza meg, hogy a megjelenítendő vágólapformátumok közül melyiket szeretné megjeleníteni.
- Kérje le a vágólap adatait, és jelenítse meg az ablakban. Vagy ha a vágólap formátuma
CF_OWNERDISPLAY
, küldjön egyWM_PAINTCLIPBOARD
üzenetet a vágólap tulajdonosának. - Küldje el az üzenetet a vágólap-megtekintő lánc következő ablakára.
A WM_DRAWCLIPBOARD
üzenet feldolgozására példaként tekintse meg Példa a vágólapmegjelenítőcímű témakört.
Példa vágólapmegjelenítőre
Az alábbi példa egy egyszerű vágólapmegjelenítő alkalmazást mutat be.
HINSTANCE hinst;
UINT uFormat = (UINT)(-1);
BOOL fAuto = TRUE;
LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)
HWND hwnd;
UINT uMsg;
WPARAM wParam;
LPARAM lParam;
{
static HWND hwndNextViewer;
HDC hdc;
HDC hdcMem;
PAINTSTRUCT ps;
LPPAINTSTRUCT lpps;
RECT rc;
LPRECT lprc;
HGLOBAL hglb;
LPSTR lpstr;
HBITMAP hbm;
HENHMETAFILE hemf;
HWND hwndOwner;
switch (uMsg)
{
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
// Branch depending on the clipboard format.
switch (uFormat)
{
case CF_OWNERDISPLAY:
hwndOwner = GetClipboardOwner();
hglb = GlobalAlloc(GMEM_MOVEABLE,
sizeof(PAINTSTRUCT));
lpps = GlobalLock(hglb);
memcpy(lpps, &ps, sizeof(PAINTSTRUCT));
GlobalUnlock(hglb);
SendMessage(hwndOwner, WM_PAINTCLIPBOARD,
(WPARAM) hwnd, (LPARAM) hglb);
GlobalFree(hglb);
break;
case CF_BITMAP:
hdcMem = CreateCompatibleDC(hdc);
if (hdcMem != NULL)
{
if (OpenClipboard(hwnd))
{
hbm = (HBITMAP)
GetClipboardData(uFormat);
SelectObject(hdcMem, hbm);
GetClientRect(hwnd, &rc);
BitBlt(hdc, 0, 0, rc.right, rc.bottom,
hdcMem, 0, 0, SRCCOPY);
CloseClipboard();
}
DeleteDC(hdcMem);
}
break;
case CF_TEXT:
if (OpenClipboard(hwnd))
{
hglb = GetClipboardData(uFormat);
lpstr = GlobalLock(hglb);
GetClientRect(hwnd, &rc);
DrawText(hdc, lpstr, -1, &rc, DT_LEFT);
GlobalUnlock(hglb);
CloseClipboard();
}
break;
case CF_ENHMETAFILE:
if (OpenClipboard(hwnd))
{
hemf = GetClipboardData(uFormat);
GetClientRect(hwnd, &rc);
PlayEnhMetaFile(hdc, hemf, &rc);
CloseClipboard();
}
break;
case 0:
GetClientRect(hwnd, &rc);
DrawText(hdc, "The clipboard is empty.", -1,
&rc, DT_CENTER | DT_SINGLELINE |
DT_VCENTER);
break;
default:
GetClientRect(hwnd, &rc);
DrawText(hdc, "Unable to display format.", -1,
&rc, DT_CENTER | DT_SINGLELINE |
DT_VCENTER);
}
EndPaint(hwnd, &ps);
break;
case WM_SIZE:
if (uFormat == CF_OWNERDISPLAY)
{
hwndOwner = GetClipboardOwner();
hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(RECT));
lprc = GlobalLock(hglb);
GetClientRect(hwnd, lprc);
GlobalUnlock(hglb);
SendMessage(hwndOwner, WM_SIZECLIPBOARD,
(WPARAM) hwnd, (LPARAM) hglb);
GlobalFree(hglb);
}
break;
case WM_CREATE:
// Add the window to the clipboard viewer chain.
hwndNextViewer = SetClipboardViewer(hwnd);
break;
case WM_CHANGECBCHAIN:
// If the next window is closing, repair the chain.
if ((HWND) wParam == hwndNextViewer)
hwndNextViewer = (HWND) lParam;
// Otherwise, pass the message to the next link.
else if (hwndNextViewer != NULL)
SendMessage(hwndNextViewer, uMsg, wParam, lParam);
break;
case WM_DESTROY:
ChangeClipboardChain(hwnd, hwndNextViewer);
PostQuitMessage(0);
break;
case WM_DRAWCLIPBOARD: // clipboard contents changed.
// Update the window by using Auto clipboard format.
SetAutoView(hwnd);
// Pass the message to the next window in clipboard
// viewer chain.
SendMessage(hwndNextViewer, uMsg, wParam, lParam);
break;
case WM_INITMENUPOPUP:
if (!HIWORD(lParam))
InitMenu(hwnd, (HMENU) wParam);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_EXIT:
DestroyWindow(hwnd);
break;
case IDM_AUTO:
SetAutoView(hwnd);
break;
default:
fAuto = FALSE;
uFormat = LOWORD(wParam);
InvalidateRect(hwnd, NULL, TRUE);
}
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return (LRESULT) NULL;
}
void WINAPI SetAutoView(HWND hwnd)
{
static UINT auPriorityList[] = {
CF_OWNERDISPLAY,
CF_TEXT,
CF_ENHMETAFILE,
CF_BITMAP
};
uFormat = GetPriorityClipboardFormat(auPriorityList, 4);
fAuto = TRUE;
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
void WINAPI InitMenu(HWND hwnd, HMENU hmenu)
{
UINT uFormat;
char szFormatName[80];
LPCSTR lpFormatName;
UINT fuFlags;
UINT idMenuItem;
// If a menu is not the display menu, no initialization is necessary.
if (GetMenuItemID(hmenu, 0) != IDM_AUTO)
return;
// Delete all menu items except the first.
while (GetMenuItemCount(hmenu) > 1)
DeleteMenu(hmenu, 1, MF_BYPOSITION);
// Check or uncheck the Auto menu item.
fuFlags = fAuto ? MF_BYCOMMAND | MF_CHECKED :
MF_BYCOMMAND | MF_UNCHECKED;
CheckMenuItem(hmenu, IDM_AUTO, fuFlags);
// If there are no clipboard formats, return.
if (CountClipboardFormats() == 0)
return;
// Open the clipboard.
if (!OpenClipboard(hwnd))
return;
// Add a separator and then a menu item for each format.
AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
uFormat = EnumClipboardFormats(0);
while (uFormat)
{
// Call an application-defined function to get the name
// of the clipboard format.
lpFormatName = GetPredefinedClipboardFormatName(uFormat);
// For registered formats, get the registered name.
if (lpFormatName == NULL)
{
// Note that, if the format name is larger than the
// buffer, it is truncated.
if (GetClipboardFormatName(uFormat, szFormatName,
sizeof(szFormatName)))
lpFormatName = szFormatName;
else
lpFormatName = "(unknown)";
}
// Add a menu item for the format. For displayable
// formats, use the format ID for the menu ID.
if (IsDisplayableFormat(uFormat))
{
fuFlags = MF_STRING;
idMenuItem = uFormat;
}
else
{
fuFlags = MF_STRING | MF_GRAYED;
idMenuItem = 0;
}
AppendMenu(hmenu, fuFlags, idMenuItem, lpFormatName);
uFormat = EnumClipboardFormats(uFormat);
}
CloseClipboard();
}
BOOL WINAPI IsDisplayableFormat(UINT uFormat)
{
switch (uFormat)
{
case CF_OWNERDISPLAY:
case CF_TEXT:
case CF_ENHMETAFILE:
case CF_BITMAP:
return TRUE;
}
return FALSE;
}