Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu bölümde aşağıdaki görevler için kod örnekleri vardır:
-
Kes, Kopyala ve Yapıştır komutlarını uygulama
- Veri seçme
- Düzenleme Menüsü Oluşturma
- WM_INITMENUPOPUP iletisini işleme
- WM_COMMAND iletisini işleme
- Bilgileri panoya kopyalama
- Panodan bilgileri yapıştırma
- Pano biçimini kaydet
- WM_RENDERFORMAT ve WM_RENDERALLFORMATS iletilerini işleme
- WM_DESTROYCLIPBOARD iletisini işleme
- Sahip-görüntü panosu biçimini kullan
- Pano içeriğini izleme
- Pano sıra numarasını sorgulama
- Pano biçimi dinleyicisi oluşturun
- Pano görüntüleyici penceresi oluşturma
- Pano görüntüleyici zincirine pencere ekleme
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:
- OpenClipboard işlevini çağırarak panoyu açar.
- EmptyClipboard işlevini çağırarak panoyu boşaltır.
- Uygulamanın sağladığı her pano biçimi için SetClipboardData işlevini bir kez çağırır.
- 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:
- OpenClipboard işlevini çağırarak panoyu açar.
- Mevcut pano biçimlerinden hangisinin alınacağını belirler.
- GetClipboardData işlevini çağırarak seçilen biçimdeki verilere tanıtıcıyı alır.
- 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.
- 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 Zincirinden Pencere Kaldırma
- WM_DRAWCLIPBOARD iletisini işleme
- Pano görüntüleyici örneği
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 :
- Kullanılabilir pano biçimlerinden hangisinin görüntüleneceğini belirleyin.
- Pano verilerini alın ve pencerede görüntüleyin. Ya da eğer pano biçimi
CF_OWNERDISPLAYise, pano sahibine WM_PAINTCLIPBOARD iletisi gönderin. - İ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;
}