Panoyu kullanma

Bu bölümde aşağıdaki görevler için kod örnekleri vardır:

Kes, Kopyala ve Yapıştır komutlarını uygulama

Bu bölümde standart Kes, Kopyala ve Yapıştır komutlarının uygulamada nasıl uygulandığı açıklanmaktadır. Bu bölümdeki örnek, kayıtlı pano biçimini, CF_OWNERDISPLAY biçimini ve CF_TEXT biçimini kullanarak verileri panoya yerleştirmek için bu yöntemleri kullanır. Kayıtlı biçim, etiketler olarak adlandırılan dikdörtgen veya eliptik metin pencerelerini temsil etmek için kullanılır.

Veri seçme

Bilgilerin panoya kopyalanabilmesi için önce kullanıcının kopyalanacak veya kesilecek belirli bilgileri seçmesi gerekir. Bir uygulama, kullanıcının bir belge içindeki bilgileri seçmesi için bir araç ve seçili verileri göstermek için bir tür görsel geri bildirim sağlamalıdır.

Düzenleme Menüsü Oluşturma

Bir uygulama , Düzenle menü komutları için standart klavye hızlandırıcılarını içeren bir hızlandırıcı tablosu yüklemelidir. Hızlandırıcıların etkili olması için TranslateAccelerator işlevinin uygulamanın ileti döngüsüne eklenmesi gerekir. Klavye hızlandırıcıları hakkında daha fazla bilgi için bkz. Klavye Hızlandırıcıları.

WM_INITMENUPOPUP iletisini işleme

Pano komutlarının tümü kullanıcı tarafından herhangi bir zamanda kullanılamaz. Bir uygulama, kullanılabilir komutlar için menü öğelerini etkinleştirmek ve kullanılamayan komutları devre dışı bırakmak için WM_INITMENUPOPUP iletisini işlemelidir.

Aşağıda Label adlı bir uygulamanın WM_INITMENUPOPUP durumu verilmiştir.

case WM_INITMENUPOPUP:
    InitMenu((HMENU) wParam);
    break;

InitMenu İşlev aşağıdaki gibi tanımlanır.

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 
                    ); 
 
        } 
    } 
}

WM_COMMAND iletisini işleme

Menü komutlarını işlemek için uygulamanızın ana pencere yordamına WM_COMMAND servis talebini ekleyin. Aşağıda, WM_COMMAND Label uygulamasının pencere yordamına ilişkin durum örneği gösterilmektedir.

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; 

Kopyala ve Kes komutlarını gerçekleştirmek için pencere yordamı uygulama tanımlı EditCopy işlevi çağırır. Daha fazla bilgi için bkz. Bilgileri panoya kopyalama. Yapıştır komutunu gerçekleştirmek için pencere yordamı uygulama tanımlı EditPaste işlevi çağırır. İşlev hakkında EditPaste daha fazla bilgi için bkz. Panodan bilgi yapıştırma.

Bilgileri panoya kopyalama

Etiket uygulamasında, uygulama tanımlı EditCopy işlevi, mevcut seçimi panoya kopyalar. Bu işlev aşağıdakileri yapar:

  1. OpenClipboard işlevini çağırarak panoyu açar.
  2. EmptyClipboard işlevini çağırarak panoyu boşaltır.
  3. Uygulamanın sağladığı her pano biçimi için SetClipboardData işlevini bir kez çağırır.
  4. CloseClipboard işlevini çağırarak panoyu kapatır.

Geçerli seçime bağlı olarak, EditCopy işlevi bir metin aralığı kopyalar veya etiketin tamamını temsil eden uygulama tanımlı bir yapıyı kopyalar. adlı LABELBOXyapı aşağıdaki gibi tanımlanır:

#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;

Aşağıdaki işlev EditCopy 'dır:

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; 
}

Panodan bilgileri yapıştırma

Etiket uygulamasında, uygulama tanımlı EditPaste işlev panonun içeriğini yapıştırır. Bu işlev aşağıdakileri yapar:

  1. OpenClipboard işlevini çağırarak panoyu açar.
  2. Mevcut pano biçimlerinden hangisinin alınacağını belirler.
  3. GetClipboardData işlevini çağırarak seçilen biçimdeki verilere tanıtıcıyı alır.
  4. Verilerin bir kopyasını belgeye ekler. GetClipboardData tarafından döndürülen tutamaç hala panoya aittir, bu nedenle bir uygulama onu serbest bırakmamalı veya kilitli tutmamalıdır.
  5. CloseClipboard işlevini çağırarak panoyu kapatır.

Bir etiket seçiliyse ve ekleme noktası içeriyorsa, EditPaste işlevi panodaki metni ekleme noktasına ekler. Seçim yoksa veya bir etiket seçiliyse işlev, panodaki uygulama tanımlı LABELBOX yapıyı kullanarak yeni bir etiket oluşturur. Yapı LABELBOX, kayıtlı bir pano biçimi kullanılarak panoya yerleştirilir.

adlı LABELBOXyapı aşağıdaki gibi tanımlanır:

#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;

Aşağıdaki EditPaste fonksiyonudur:

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(); 
}

Pano biçimini kaydet

Pano biçimini kaydetmek için, uygulamanızın örnek başlatma işlevine RegisterClipboardFormat işlevine aşağıdaki gibi bir çağrı ekleyin:

// 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;

WM_RENDERFORMAT ve WM_RENDERALLFORMATS iletilerini işleme

Bir pencere SetClipboardData işlevine bir NULL tanıtıcı geçirirse, istek üzerine verileri işlemek için WM_RENDERFORMAT ve WM_RENDERALLFORMATS iletilerini işlemesi gerekir.

Bir pencere belirli bir biçimin işlenmesini geciktirirse ve başka bir uygulama bu biçimde veri isterse, pencereye bir WM_RENDERFORMAT iletisi gönderilir. Buna ek olarak, bir pencere bir veya daha fazla biçimin işlenmesini geciktirirse ve pencere yok edilmek üzereyken bu biçimlerden bazıları kayıtsız kalırsa, yok edilmeden önce pencereye bir WM_RENDERALLFORMATS iletisi gönderilir.

Bir panoya formatını oluşturmak için pencere yordamı, SetClipboardData işlevini kullanarak panoya veri içermeyen bir tutamacı yerleştirmelidir. Pencere işlemi, WM_RENDERFORMAT iletisine yanıt olarak bir biçim işliyorsa, SetClipboardData çağrısından önce panoyu açmamalıdır. Ancak , WM_RENDERALLFORMATS iletisine yanıt olarak bir veya daha fazla biçim işleniyorsa, SetClipboardData çağrısında bulunmadan önce panonun hala pencerenin sahibi olduğunu kontrol etmesi ve geri dönmeden önce panoyu kapatması gerekir.

Label uygulaması , WM_RENDERFORMAT ve WM_RENDERALLFORMATS iletilerini aşağıdaki gibi işler:

case WM_RENDERFORMAT: 
    RenderFormat((UINT) wParam); 
    break; 
 
case WM_RENDERALLFORMATS:
    if (OpenClipboard(hwnd))
    {
        if (GetClipboardOwner() == hwnd)
        {
            RenderFormat(uLabelFormat);
            RenderFormat(CF_TEXT);
        }
        CloseClipboard();
    }
    break;

Her iki durumda da pencere yordamı, aşağıdaki kodda tanımlanan uygulama tanımlı RenderFormat işlevi çağırır.

adlı LABELBOXyapı aşağıdaki gibi tanımlanır:

#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); 
    } 
}

WM_DESTROYCLIPBOARD iletisini işleme

Bir pencere, gecikmeli işlemeyi desteklemek üzere ayırmış olduğu kaynakları serbest bırakmak için WM_DESTROYCLIPBOARD iletisini işleyebilir. Örneğin Etiket uygulaması, panoya bir etiket kopyalarken yerel bir bellek nesnesi ayırır. Daha sonra, bu nesneyi WM_DESTROYCLIPBOARD iletisine yanıt olarak şu şekilde serbest bırakır:

case WM_DESTROYCLIPBOARD: 
    if (pboxLocalClip != NULL) 
    { 
        LocalFree(pboxLocalClip); 
        pboxLocalClip = NULL; 
    } 
    break;

Sahip görüntüleme pano biçimini kullanma

Bir pencere pano biçimini kullanarak panoya CF_OWNERDISPLAY bilgi yerleştirirse, aşağıdakileri yapmalıdır:

  • WM_PAINTCLIPBOARD iletisini işleme. Pano görüntüleyici penceresinin bir bölümünün yeniden boyanması gerektiğinde bu ileti pano sahibine gönderilir.
  • WM_SIZECLIPBOARD iletisini işleme. Pano görüntüleyici penceresi yeniden boyutlandırıldığında veya içeriği değiştiğinde bu ileti pano sahibine gönderilir. Genellikle, bir pencere pano görüntüleyici penceresinin kaydırma konumlarını ve aralıklarını ayarlayarak bu iletiye yanıt verir. Bu iletiye yanıt olarak, Etiket uygulaması pano görüntüleyici penceresi için BOYUT yapısını da güncelleştirir.
  • WM_HSCROLLCLIPBOARD ve WM_VSCROLLCLIPBOARD iletilerini işleme. Bu iletiler, pano görüntüleyici penceresinde bir kaydırma çubuğu olayı gerçekleştiğinde pano sahibine gönderilir.
  • WM_ASKCBFORMATNAME iletisini işleme. Pano görüntüleyici penceresi, sahip görüntüleme biçiminin adını almak için bu iletiyi bir uygulamaya gönderir.

Etiket uygulamasının bu iletileri işlediği pencere yordamı aşağıdaki gibi tanımlanır:

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; 
}

Pano içeriğini izleme

Panodaki değişiklikleri izlemenin üç yolu vardır. En eski yöntem, pano görüntüleyici penceresi oluşturmaktır. Windows 2000 pano sıra numarasını sorgulama özelliğini ekledi ve Windows Vista pano biçimi dinleyicileri için destek ekledi. Pano görüntüleyici pencereleri, Windows'un önceki sürümleriyle geriye dönük uyumluluk için desteklenir. Yeni programlar, pano biçimi dinleyicilerini veya pano sırası numarasını kullanmalıdır.

Panodaki sıra numarasını sorgula

Panonun içeriği her değiştiğinde, pano sıra numarası olarak bilinen 32 bitlik bir değer artırılır. Bir program , GetClipboardSequenceNumber işlevini çağırarak geçerli pano sıra numarasını alabilir. Bir program, döndürülen değeri, önceki bir çağrısından döndürülen değerle GetClipboardSequenceNumber karşılaştırarak pano içeriğinin değişip değişmediğini belirleyebilir. Bu yöntem, sonuçları geçerli pano içeriğine göre önbelleğe alan ve bu önbellekteki sonuçları kullanmadan önce hesaplamaların hala geçerli olup olmadığını bilmesi gereken programlara daha uygundur. Bunun bir bildirim yöntemi olmadığını ve yoklama döngüsünde kullanılmaması gerektiğini unutmayın. Pano içeriği değiştiğinde bildirim almak için pano biçimi dinleyicisi veya pano görüntüleyicisi kullanın.

Pano Biçimi Dinleyicisi Oluşturma

Pano biçimi dinleyicisi, panonun içeriği değiştiğinde bildirim almak üzere kaydedilmiş bir penceredir. Bu yöntem, panoya ait bir görüntüleyici pencere oluşturmak yerine tercih edilir çünkü uygulanması daha kolaydır ve programlar pano görüntüleyici zincirini düzgün koruyamazsa veya pano görüntüleyici zincirindeki bir pencere iletilere yanıt vermeyi durdurursa, bu tür sorunlardan kaçınır.

Pencere, AddClipboardFormatListener işlevini çağırarak bir pano biçimi dinleyicisi olarak kaydolur. Panonun içeriği değiştiğinde, pencereye bir WM_CLIPBOARDUPDATE iletisi gönderilir. Kayıt, RemoveClipboardFormatListener işlevini çağırarak pencere kendi kaydını kaldırana kadar geçerli kalır.

Pano görüntüleyici penceresi oluşturma

Pano görüntüleyici penceresi panonun geçerli içeriğini görüntüler ve pano içeriği değiştiğinde iletileri alır. Pano görüntüleyici penceresi oluşturmak için uygulamanızın aşağıdakileri yapması gerekir:

  • Pencereyi pano görüntüleyici zincirine ekleyin.
  • WM_CHANGECBCHAIN iletisini işleme.
  • WM_DRAWCLIPBOARD iletisini işleme.
  • Yok edilmeden önce pencereyi pano görüntüleyici zincirinden kaldırın.

Pano görüntüleyici zincirine pencere ekleme

SetClipboardViewer işlevini çağırarak bir pencere kendisini pano görüntüleyici zincirine ekler. Dönüş değeri, zincirdeki bir sonraki pencerenin tutamacıdır. Bir pencere bu değeri izlemelidir; örneğin, adlı hwndNextViewerstatik değişkene kaydederek.

Aşağıdaki örnek, WM_CREATE iletisine yanıt olarak pano görüntüleyici zincirine bir pencere ekler.

case WM_CREATE: 
 
    // Add the window to the clipboard viewer chain. 
 
    hwndNextViewer = SetClipboardViewer(hwnd); 
    break;

Aşağıdaki görevler için kod parçacıkları gösterilir:

WM_CHANGECBCHAIN iletisini işleme

Pano görüntüleyici penceresi, başka bir pencere kendisini pano görüntüleyici zincirinden kaldırırken WM_CHANGECBCHAIN iletisini alır. Kaldırılan pencere zincirdeki bir sonraki pencereyse, iletiyi alan pencerenin zincirden sonraki pencerenin bağlantısını kaldırması gerekir. Aksi takdirde, bu ileti zincirdeki bir sonraki pencereye geçirilmelidir.

Aşağıdaki örnekte WM_CHANGECBCHAIN iletisinin işlenmesi gösterilmektedir.

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;

Pano görüntüleyici zincirinden pencereyi kaldır

Kendisini pano görüntüleyici zincirinden kaldırmak için bir pencere ChangeClipboardChain işlevini çağırır. Aşağıdaki örnek, WM_DESTROY iletisine yanıt olarak pano görüntüleyici zincirinden bir pencere kaldırır.

case WM_DESTROY: 
    ChangeClipboardChain(hwnd, hwndNextViewer); 
    PostQuitMessage(0); 
    break;

WM_DRAWCLIPBOARD iletisini işleme

WM_DRAWCLIPBOARD iletisi, pano görüntüleyici penceresine pano içeriğinin değiştiğini bildirir. bir pencere, iletiyi işlerken aşağıdakileri yapmalıdır WM_DRAWCLIPBOARD :

  1. Kullanılabilir pano biçimlerinden hangisinin görüntüleneceğini belirleyin.
  2. Pano verilerini alın ve pencerede görüntüleyin. Ya da eğer pano biçimi CF_OWNERDISPLAY ise, pano sahibine WM_PAINTCLIPBOARD iletisi gönderin.
  3. İletiyi pano görüntüleyici zincirindeki bir sonraki pencereye gönderin.

WM_DRAWCLIPBOARD iletisini işleme örneği için aşağıdaki bölümdeki örnek listeye bakın.

Pano görüntüleyici örneği

Aşağıdaki örnekte eksiksiz, basit bir pano görüntüleyici uygulaması gösterilmektedir:

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; 
} 

Klavye Hızlandırıcıları