Operacje schowka
Okno powinno używać schowka podczas wycinania, kopiowania lub wklejania danych. Okno umieszcza dane w schowku na potrzeby operacji wycinania i kopiowania oraz pobiera dane ze schowka na potrzeby operacji wklejania. W poniższych sekcjach opisano te operacje i powiązane problemy.
Aby umieścić dane w schowku lub pobrać je z schowka, okno musi najpierw otworzyć schowek przy użyciu funkcjiopenClipboardOpenClipboard. Naraz może być otwarte tylko jedno okno schowka. Aby dowiedzieć się, które okno ma otwarty schowek, wywołaj funkcję GetOpenClipboardWindow. Po zakończeniu okno musi zamknąć schowek, wywołując funkcję CloseClipboard.
W tej sekcji omówiono następujące tematy.
- operacje wycinania i kopiowania
- operacje wklejania
- własności schowka
- opóźnione renderowanie
- pamięci i schowka
Operacje wycinania i kopiowania
Aby umieścić informacje w schowku, okno najpierw czyści poprzednią zawartość schowka przy użyciu funkcji EmptyClipboard. Ta funkcja wysyła komunikat WM_DESTROYCLIPBOARD do poprzedniego właściciela schowka, zwalnia zasoby skojarzone z danymi w schowku i przypisuje własność schowka do okna z otwartym schowkiem. Aby dowiedzieć się, które okno jest właścicielem schowka, wywołaj funkcję GetClipboardOwner.
Po opróżnieniu schowka okno umieszcza dane w schowku w jak największej liczbą formatów schowka uporządkowaną z najbardziej opisowego formatu schowka do najmniej opisowego. Dla każdego formatu okno wywołuje funkcję SetClipboardData, określając identyfikator formatu i uchwyt pamięci globalnej. Uchwyt pamięci może mieć wartość NULL, co oznacza, że okno renderuje dane na żądanie. Aby uzyskać więcej informacji, zobacz Opóźnione renderowanie.
Operacje wklejania
Aby pobrać informacje z schowka, okno najpierw określa format schowka do pobrania. Zazwyczaj okno wylicza dostępne formaty schowka przy użyciu funkcji EnumClipboardFormats i używa pierwszego rozpoznawanego formatu. Ta metoda wybiera najlepszy dostępny format zgodnie z ustawionym priorytetem podczas umieszczania danych w schowku.
Alternatywnie okno może użyć funkcji GetPriorityClipboardFormat. Ta funkcja identyfikuje najlepszy dostępny format schowka zgodnie z określonym priorytetem. Okno, które rozpoznaje tylko jeden format schowka, może po prostu określić, czy ten format jest dostępny przy użyciu funkcji IsClipboardFormatAvailable.
Po określeniu formatu schowka do użycia okno wywołuje funkcję GetClipboardData. Ta funkcja zwraca uchwyt do obiektu pamięci globalnej zawierającego dane w określonym formacie. Okno może na krótko zablokować obiekt pamięci w celu sprawdzenia lub skopiowania danych. Jednak okno nie powinno zwolnić obiektu ani pozostawić go zablokowanego przez długi czas.
Własność schowka
Właściciel schowka jest oknem skojarzonym z informacjami w schowku. Okno staje się właścicielem schowka, gdy umieszcza dane w schowku, w szczególności, gdy wywołuje funkcję EmptyClipboard. Okno pozostaje właścicielem schowka, dopóki nie zostanie zamknięte lub inne okno opróżni schowek.
Gdy schowek zostanie opróżniony, właściciel schowka otrzyma komunikat WM_DESTROYCLIPBOARD. Poniżej przedstawiono kilka powodów, dla których okno może przetworzyć ten komunikat:
- Okno opóźniło renderowanie co najmniej jednego formatu schowka. W odpowiedzi na komunikat WM_DESTROYCLIPBOARD okno może zwolnić przydzielone zasoby w celu renderowania danych na żądanie. Aby uzyskać więcej informacji na temat renderowania danych, zobacz Opóźnione renderowanie.
- Okno umieściło dane w schowku w formacie prywatnego schowka. Dane dla prywatnych formatów schowka nie są zwalniane przez system po opróżnieniu schowka. W związku z tym właściciel schowka powinien zwolnić dane po otrzymaniu komunikatu WM_DESTROYCLIPBOARD. Aby uzyskać więcej informacji na temat prywatnych formatów schowka, zobacz Formaty schowka.
- Okno umieściło dane w schowku przy użyciu formatu schowka CF_OWNERDISPLAY. W odpowiedzi na komunikat WM_DESTROYCLIPBOARD okno może zwolnić zasoby używane do wyświetlania informacji w oknie przeglądarki schowka. Aby uzyskać więcej informacji na temat tego alternatywnego formatu, zobacz Format wyświetlania właściciela.
Opóźnione renderowanie
Podczas umieszczania formatu schowka w schowku okno może opóźnić renderowanie danych w tym formacie, dopóki dane nie będą potrzebne. W tym celu aplikacja może określić null dla parametru hData funkcji SetClipboardData. Jest to przydatne, jeśli aplikacja obsługuje kilka formatów schowka, z których niektóre lub wszystkie są czasochłonne do renderowania. Przekazując dojście NULL, okno renderuje złożone formaty schowka tylko wtedy, gdy i jeśli są potrzebne.
Jeśli okno opóźni renderowanie formatu schowka, musi być przygotowane do renderowania formatu na żądanie, o ile jest to właściciel schowka. System wysyła właścicielowi schowka komunikat WM_RENDERFORMAT po odebraniu żądania dla określonego formatu, który nie został renderowany. Po otrzymaniu tego komunikatu okno powinno wywołać funkcję SetClipboardData, aby umieścić w schowku uchwyt pamięci globalnej w żądanym formacie.
Aplikacja nie może otworzyć schowka przed wywołaniem SetClipboardData w odpowiedzi na komunikat WM_RENDERFORMAT. Otwarcie schowka nie jest konieczne i próba wykonania tej czynności zakończy się niepowodzeniem, ponieważ schowek jest obecnie otwarty przez aplikację, która zażądała renderowania formatu.
Jeśli właściciel schowka zostanie zniszczony i opóźnił renderowanie niektórych lub wszystkich formatów schowka, otrzyma komunikat WM_RENDERALLFORMATS. Po otrzymaniu tego komunikatu okno powinno otworzyć schowek, sprawdzić, czy nadal jest właścicielem schowka z funkcją GetClipboardOwner, a następnie umieść prawidłowe uchwyty pamięci w schowku dla wszystkich obsługiwanych formatów schowka. Dzięki temu te formaty pozostaną dostępne po zniszczeniu właściciela schowka.
W przeciwieństwie do WM_RENDERFORMATaplikacja odpowiadająca WM_RENDERALLFORMATS powinna otworzyć schowek przed wywołaniem SetClipboardData umieścić wszystkie globalne uchwyty pamięci w schowku.
Wszystkie formaty schowka, które nie są renderowane w odpowiedzi na komunikat WM_RENDERALLFORMATS przestaną być dostępne dla innych aplikacji i nie są już wyliczane przez funkcje schowka.
Wskazówki dotyczące opóźnionego renderowania
Opóźnione renderowanie jest funkcją wydajności, umożliwiając aplikacji unikanie wykonywania pracy w celu renderowania danych schowka w formacie, który nigdy nie może być żądany. Jednak użycie opóźnionego renderowania wiąże się z następującymi kompromisami, które należy wziąć pod uwagę:
- Użycie opóźnionego renderowania zwiększa złożoność aplikacji, co wymaga obsługi dwóch komunikatów okna renderowania, zgodnie z powyższym opisem.
- Użycie opóźnionego renderowania oznacza, że aplikacja traci możliwość reagowania interfejsu użytkownika, jeśli renderowanie danych zajmuje wystarczająco dużo czasu, aby było zauważalne dla użytkownika. W przypadku opóźnionego renderowania, jeśli dane są ostatecznie potrzebne, okno musi renderować dane podczas przetwarzania komunikatu okna renderowania, zgodnie z powyższym opisem. W związku z tym, jeśli dane są bardzo czasochłonne do renderowania, aplikacja może stać się wyraźnie nie odpowiada (zawieszona) podczas renderowania, ponieważ podczas renderowania nie można przetworzyć żadnych innych komunikatów okna podczas przetwarzania komunikatu okna renderowania. Aplikacja, która nie korzysta z opóźnionego renderowania, może zamiast tego zdecydować się na renderowanie danych w wątku w tle, aby zachować odpowiedź interfejsu użytkownika podczas renderowania, na przykład zapewniając opcje postępu lub anulowania, które nie są dostępne podczas korzystania z opóźnionego renderowania.
- Użycie opóźnionego renderowania powoduje dodanie niewielkiej ilości obciążeń, jeśli dane zostaną ostatecznie potrzebne. Podczas korzystania z renderowania opóźnień okno początkowo wywołuje funkcję SetClipboardData z uchwytem o wartości null, a jeśli dane są później potrzebne, okno musi odpowiedzieć na komunikat okna i wywołać SetClipboardData funkcji po raz drugi z uchwytem do renderowanych danych, jak opisano powyżej. W związku z tym, jeśli dane są ostatecznie potrzebne, użycie opóźnionego renderowania spowoduje dodanie kosztu przetwarzania komunikatu okna i wywołania funkcji SetClipboardData po raz drugi. Ten koszt jest mały, ale nie zero. Jeśli aplikacja obsługuje tylko jeden format schowka, a jeśli dane są zawsze w końcu żądane, użycie opóźnionego renderowania tylko dodaje tę niewielką ilość obciążeń (koszt zależy od sprzętu; szacowany koszt wynosi od 10 do 100 mikrosekund). Jeśli jednak dane są małe, obciążenie związane z używaniem opóźnionego renderowania może przekroczyć koszt renderowania danych, co może pokonać cel użycia opóźnionego renderowania w celu zwiększenia wydajności. (Podczas testowania w przypadku danych, które są już w ostatecznej formie, obciążenie związane z używaniem opóźnionego renderowania stale przekracza koszt kopiowania danych do schowka, jeśli dane wynosiły 100 KiB lub mniej. Ten test nie obejmuje kosztów renderowania danych, tylko po skopiowaniu ich po jego renderowaniu).
- Opóźnione renderowanie jest zaletą wydajności netto, jeśli oszczędza więcej czasu niż zwiększa obciążenie. Aby określić obciążenie związane z opóźnionym renderowaniem, pomiar jest najlepszy, ale szacowanie wynosi od 10 do 100 mikrosekund. Aby obliczyć oszczędności wynikające z używania opóźnionego renderowania dla każdego formatu schowka, zmierz koszt renderowania danych w tym formacie i określ, jak często ten format jest ostatecznie żądany (na podstawie komunikatów okna opisanych powyżej). Pomnożyć koszt renderowania danych o wartość procentową czasu, którego dane nie są ostatecznie żądane (zanim schowek zostanie opróżniony lub zmieni jego zawartość), aby określić oszczędności opóźnionego renderowania dla każdego formatu schowka. Opóźnione renderowanie jest zaletą wydajności netto, jeśli oszczędności przekraczają koszty związane z obciążeniem.
- Jako konkretne wytyczne dla aplikacji, które obsługują tylko jeden format schowka, taki jak tekst, gdzie dane nie są znacznie kosztowne do renderowania, rozważ umieszczenie danych bezpośrednio w schowku, jeśli rozmiar danych wynosi 4 KiB lub mniej.
Pamięć i Schowek
Obiekt pamięci, który ma zostać umieszczony w schowku, należy przydzielić przy użyciu funkcji GlobalAlloc z flagą GMEM_MOVEABLE.
Po umieszczeniu obiektu pamięci w schowku własność tego uchwytu pamięci zostanie przeniesiona do systemu. Gdy schowek zostanie opróżniony, a obiekt pamięci ma jeden z następujących formatów schowka, system zwalnia obiekt pamięci przez wywołanie określonej funkcji:
Funkcja zwalniania obiektu | Format schowka |
---|---|
DeleteMetaFile |
CF_DSPENHMETAFILE CF_DSPMETAFILEPICT CF_ENHMETAFILE CF_METAFILEPICT |
DeleteObject |
CF_BITMAP CF_DSPBITMAP CF_PALETTE |
GlobalFree |
CF_DIB CF_DIBV5 CF_DSPTEXT CF_OEMTEXT CF_TEXT CF_UNICODETEXT |
żaden |
CF_OWNERDISPLAY Gdy schowek zostanie opróżniony z obiektu CF_OWNERDISPLAY, aplikacja musi zwolnić obiekt pamięci. |