Megosztás a következőn keresztül:


A vágólap használata

Ez a szakasz kódmintákat biztosít a következő feladatokhoz:

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:

  1. A vágólap megnyitásához hívja meg a OpenClipboard függvényt.
  2. Kiüríti a vágólapot a EmptyClipboard függvény meghívásával.
  3. Egyszer meghívja a SetClipboardData függvényt az alkalmazás által biztosított minden vágólapformátumhoz.
  4. 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 LABELBOXnevű 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:

  1. A vágólap megnyitásához hívja meg a OpenClipboard függvényt.
  2. Meghatározza, hogy az elérhető vágólapformátumok közül melyiket szeretné lekérni.
  3. A GetClipboardData függvény meghívásával lekéri a kiválasztott formátumban lévő adatok fogantyúját.
  4. 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.
  5. 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 LABELBOXnevű 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 SetClipboardDatahí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 LABELBOXnevű 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ának SIZE struktúráját is frissíti.
  • Dolgozza fel a WM_HSCROLLCLIPBOARD és WM_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 GetClipboardSequenceNumberhí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 hwndNextViewernevű 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:

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:

  1. Határozza meg, hogy a megjelenítendő vágólapformátumok közül melyiket szeretné megjeleníteni.
  2. 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 egy WM_PAINTCLIPBOARD üzenetet a vágólap tulajdonosának.
  3. 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; 
}