Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Dokument Obiekt danych powłoki omówił podejście ogólne używane do transferu danych powłoki za pomocą przeciągania i upuszczania lub Schowka. Jednak aby zaimplementować transfer danych za pomocą powłoki w aplikacji, należy również zrozumieć, jak zastosować te ogólne zasady oraz techniki do różnorodnych sposobów przesyłania danych powłoki. W tym dokumencie przedstawiono typowe scenariusze transferu danych powłoki i omówiono sposób implementowania każdego z nich w aplikacji.
- Ogólne wytyczne
- Kopiowanie nazw plików ze schowka do aplikacji
- Kopiowanie zawartości usuniętego pliku do aplikacji
- Obsługa zoptymalizowanych operacji przenoszenia
- Obsługa operacji usuwania przy wklejaniu
- Transferowanie danych do i z folderów wirtualnych
- Upuszczanie plików do Kosza
- Tworzenie i importowanie plików ze złomowania
- Przeciąganie i upuszczanie obiektów powłoki asynchronicznie
Uwaga / Notatka
Chociaż każdy z tych scenariuszy omawia określoną operację transferu danych, wiele z nich ma zastosowanie do różnych powiązanych scenariuszy. Na przykład podstawową różnicą między większością transferów Schowka a przeciąganiem i upuszczaniem jest sposób, w jaki obiekt danych dociera do docelowego miejsca. Gdy obiekt docelowy ma wskaźnik do interfejsu IDataObject obiektu danych, procedury wyodrębniania informacji są w dużej mierze takie same dla obu typów transferu danych. Jednak niektóre scenariusze są ograniczone do określonego typu operacji. Aby uzyskać szczegółowe informacje, zapoznaj się z poszczególnymi scenariuszami.
Ogólne wytyczne
W każdej z poniższych sekcji omówiono pojedynczy, dość specyficzny scenariusz transferu danych. Jednak transfery danych są często bardziej złożone i mogą obejmować aspekty kilku scenariuszy. Zwykle nie wiadomo z góry, który scenariusz rzeczywiście trzeba będzie obsłużyć. Poniżej przedstawiono kilka ogólnych wytycznych, które należy wziąć pod uwagę.
W przypadku źródeł danych:
- Formaty Schowka powłoki, z wyjątkiem CF_HDROP, nie są wstępnie zdefiniowane. Każdy format, którego chcesz użyć, musi być zarejestrowany przez wywołanie metody RegisterClipboardFormat.
- Formaty w obiektach danych są udostępniane w kolejności preferencji ze źródła. Wylicz obiekt danych i wybierz pierwszy, który możesz użyć.
- Uwzględnij dowolną liczbę formatów, które można obsługiwać. Zazwyczaj nie wiadomo, gdzie obiekt danych zostanie porzucony. Ta praktyka poprawia szanse, że obiekt danych będzie zawierać format, który może zaakceptować obiekt docelowy upuszczania.
- Istniejące pliki powinny być oferowane w formacie CF_HDROP .
- Zaoferuj dane podobne do plików z formatami CFSTR_FILECONTENTS/CFSTR_FILEDESCRIPTOR . Takie podejście umożliwia obiektowi docelowemu utworzenie pliku na podstawie obiektu danych bez konieczności znajomości niczego o bazowym magazynie danych. Dane powinny być zwykle przedstawiane jako interfejs IStream . Ten mechanizm transferu danych jest bardziej elastyczny niż obiekt pamięci globalnej i używa znacznie mniejszej ilości pamięci.
- Przeciągane źródła powinny oferować format CFSTR_SHELLIDLIST podczas przeciągania elementów Shell. Obiekty danych dla elementów można uzyskać za pomocą metod IShellFolder::GetUIObjectOf lub IShellItem::BindToHandler . Źródła danych mogą tworzyć standardową implementację obiektu danych, która obsługuje format CFSTR_SHELLIDLIST za pomocą obiektu SHCreateDataObject.
- Cele upuszczania, które chcą przeanalizować przeciągane elementy przy użyciu modelu programowania powłoki, mogą przekonwertować obiekt IDataObject na obiekt IShellItemArray przy użyciu metody SHCreateShellItemArrayFromDataObject.
- Użyj standardowych kursorów informacyjnych.
- Obsługuje przeciąganie w lewo i w prawo.
- Użyj obiektu danych bezpośrednio z osadzonego obiektu. Takie podejście umożliwia aplikacji pobieranie wszelkich dodatkowych formatów, które obiekt danych ma do zaoferowania i unika tworzenia dodatkowej warstwy zawierania. Na przykład obiekt osadzony z serwera A jest przeciągany z serwera/kontenera B i porzucony w kontenerze C. C powinien utworzyć osadzony obiekt serwera A, a nie osadzony obiekt serwera B zawierający osadzony obiekt serwera A.
- Pamiętaj, że powłoka może korzystać z optymalizowanych operacji przenoszenia lub usuwania po wklejeniu podczas przenoszenia plików. Aplikacja powinna mieć możliwość rozpoznawania tych operacji i odpowiedniego reagowania.
W przypadku obiektów docelowych danych:
- Formaty Schowka powłoki, z wyjątkiem CF_HDROP, nie są wstępnie zdefiniowane. Każdy format, którego chcesz użyć, musi być zarejestrowany przez wywołanie metody RegisterClipboardFormat.
- Implementuj i zarejestruj obiekt docelowy upuszczania OLE. Unikaj używania obiektów docelowych Windows 3.1 lub WM_DROPFILES, jeśli to możliwe.
- Formaty zawarte w obiekcie danych różnią się w zależności od tego, skąd pochodzi obiekt. Ponieważ zazwyczaj nie wiadomo wcześniej, skąd pochodzi obiekt danych, nie należy zakładać, że określony format będzie obecny. Obiekt danych powinien wyliczać formaty w kolejności jakości, począwszy od najlepszych. W związku z tym, aby uzyskać najlepszy dostępny format, aplikacje zwykle wyliczają dostępne formaty i używają pierwszego formatu w wyliczeniu, który potrafią obsłużyć.
- Obsługa funkcji przeciągania prawym przyciskiem. Możesz dostosować menu skrótów przeciągania, tworząc procedurę obsługi przeciągania i upuszczania.
- Jeśli aplikacja zaakceptuje istniejące pliki, musi być w stanie obsłużyć format CF_HDROP .
- Ogólnie rzecz biorąc, aplikacje akceptujące pliki powinny również obsługiwać formaty CFSTR_FILECONTENTS/CFSTR_FILEDESCRIPTOR. Chociaż pliki z systemu plików mają format CF_HDROP , pliki od dostawców, takich jak rozszerzenia przestrzeni nazw, zwykle używają CFSTR_FILECONTENTS/CFSTR_FILEDESCRIPTOR. Przykłady obejmują foldery Windows CE, foldery protokołu TRANSFERU plików (FTP), foldery sieci Web i foldery CAB. Źródło zwykle implementuje interfejs IStream do prezentowania danych z jego magazynu jako pliku.
- Pamiętaj, że powłoka może używać zoptymalizowanych operacji przenoszenia lub usuwania podczas przenoszenia plików. Aplikacja powinna mieć możliwość rozpoznawania tych operacji i odpowiedniego reagowania.
Kopiowanie nazw plików ze Schowka do aplikacji
Scenario: Użytkownik wybiera co najmniej jeden plik w Eksploratorze Windows i kopiuje je do Schowka. Aplikacja wyodrębnia nazwy plików i wkleja je do dokumentu.
Tego scenariusza można użyć na przykład, aby umożliwić użytkownikowi utworzenie linku HTML przez cięcie i wklejanie pliku do aplikacji. Następnie aplikacja może wyodrębnić nazwę pliku z obiektu danych i przetworzyć ją w celu utworzenia tagu kotwicy.
Gdy użytkownik wybierze plik w eksploratorze Windows i skopiuje go do Schowka, powłoka tworzy obiekt danych. Następnie wywołuje OleSetClipboard, aby umieścić wskaźnik do interfejsu IDataObject obiektu danych w Schowku.
Gdy użytkownik wybierze polecenie Wklej z menu lub paska narzędzi aplikacji:
- Wywołaj metodę OleGetClipboard , aby pobrać interfejs IDataObject obiektu danych.
- Wywołaj metodę IDataObject::EnumFormatEtc , aby zażądać obiektu modułu wyliczającego.
- Użyj interfejsu IEnumFORMATETC obiektu modułu wyliczającego, aby wyliczyć formaty zawarte w obiekcie danych.
Uwaga / Notatka
Ostatnie dwa kroki w tej procedurze są podane dla kompletności. Zazwyczaj nie są one niezbędne do prostych transferów plików. Wszystkie obiekty danych używane na potrzeby tego typu transferu danych powinny zawierać format CF_HDROP , który może służyć do określania nazw plików zawartych w obiekcie. Jednak w przypadku bardziej ogólnych transferów danych należy wyliczyć formaty i wybrać najlepszy, który aplikacja może obsłużyć.
Wyodrębnianie nazw plików z obiektu danych
Następnym krokiem jest wyodrębnienie co najmniej jednej nazwy plików z obiektu danych i wklejenie ich do aplikacji. Należy pamiętać, że procedura opisana w tej sekcji dotycząca wyodrębniania nazwy pliku z obiektu danych jest równie dobrze stosowana do przeciągania i upuszczania transferów.
Najprostszym sposobem pobierania nazw plików z obiektu danych jest format CF_HDROP :
Wywołaj metodę IDataObject::GetData. Ustaw członek cfFormat struktury FORMATETC na CF_HDROP i członek tymed na TYMED_HGLOBAL. Element dwAspect jest zwykle ustawiony na DVASPECT_CONTENT. Jeśli jednak musisz mieć ścieżkę pliku w krótkim formacie (8.3), ustaw wartość dwAspect na DVASPECT_SHORT.
Gdy funkcja IDataObject::GetData zwraca, hGlobal struktury STGMEDIUM wskazuje na obiekt pamięci globalnej zawierający dane.
Utwórz zmienną HDROP i ustaw ją na element członkowski hGlobal struktury STGMEDIUM . Zmienna HDROP jest teraz dojściem do struktury DROPFILES, którą następnie tworzy podwójnie zakończony ciąg znaków null zawierający w pełni kwalifikowane ścieżki skopiowanych plików.
Określ, ile ścieżek plików znajduje się na liście, wywołując element DragQueryFile z parametrem iFile ustawionym na 0xFFFFFFFF. Funkcja zwraca liczbę ścieżek plików na liście. Indeks zerowy ścieżki pliku na tej liście jest używany w następnym kroku, aby zidentyfikować określoną ścieżkę.
Wyodrębnij ścieżki plików z obiektu pamięci globalnej, wywołując funkcję DragQueryFile raz dla każdego pliku, ustawiając iFile na indeks pliku.
Przetwarzaj ścieżki plików zgodnie z potrzebami i wklej je do aplikacji.
Wywołaj ReleaseStgMedium i przekaż wskaźnik do struktury STGMEDIUM, którą przekazałeś do IDataObject::GetData w kroku pierwszym. Po wydaniu struktury wartość HDROP utworzona w kroku 2 nie jest już prawidłowa i nie powinna być używana.
Kopiowanie zawartości usuniętego pliku do aplikacji
Scenario: Użytkownik przeciąga jeden lub więcej plików z Eksploratora Windows i upuszcza je w oknie aplikacji. Aplikacja wyodrębnia zawartość pliku (s) i wkleja ją do aplikacji.
Ten scenariusz używa przeciągania i upuszczania, aby przenieść pliki z Windows Explorer do aplikacji. Przed operacją aplikacja musi:
- Wywołaj metodę RegisterClipboardFormat , aby zarejestrować wszystkie potrzebne formaty Schowka powłoki.
- Wywołaj metodę RegisterDragDrop , aby zarejestrować okno docelowe i interfejs IDropTarget aplikacji.
Gdy użytkownik zainicjuje operację, wybierając co najmniej jeden plik i zaczynając je przeciągać:
- Windows Explorer tworzy obiekt danych i ładuje do niego obsługiwane formaty.
- Windows Explorer wywołuje DoDragDrop w celu zainicjowania pętli przeciągania.
- Gdy obraz przeciągania osiągnie okno docelowe, system powiadomi Cię, wywołując metodę IDropTarget::DragEnter.
- Aby określić, co zawiera obiekt danych, wywołaj metodę IDataObject::EnumFormatEtc obiektu danych. Użyj obiektu wyliczającego zwróconego przez metodę, aby wymienić formaty zawarte w obiekcie danych. Jeśli aplikacja nie chce akceptować żadnego z tych formatów, zwróć DROPEFFECT_NONE. Na potrzeby tego scenariusza aplikacja powinna ignorować wszystkie obiekty danych, które nie zawierają formatów używanych do transferu plików, takich jak CF_HDROP.
- Gdy użytkownik upuści dane, system wywołuje IDropTarget::Drop.
- Użyj interfejsu IDataObject , aby wyodrębnić zawartość plików.
Istnieje kilka różnych sposobów wyodrębniania zawartości obiektu powłoki z obiektu danych. Ogólnie rzecz biorąc, użyj następującej kolejności:
- Jeśli plik zawiera format CF_TEXT , dane są tekstem ANSI. Możesz użyć formatu CF_TEXT, aby wyodrębnić dane, zamiast otwierać sam plik.
- Jeśli plik zawiera połączony lub osadzony obiekt OLE, obiekt danych zawiera format CF_EMBEDDEDOBJECT. Użyj standardowych technik OLE, aby wyodrębnić dane. Pliki odpadów zawsze zawierają format CF_EMBEDDEDOBJECT.
- Jeśli obiekt powłoki pochodzi z systemu plików, obiekt danych zawiera format CF_HDROP z nazwami plików. Wyodrębnij nazwę pliku z CF_HDROP i wywołaj metodę OleCreateFromFile , aby utworzyć nowy obiekt połączony lub osadzony. Aby zapoznać się z omówieniem pobierania nazwy pliku z formatu CF_HDROP , zobacz Kopiowanie nazw plików ze Schowka do aplikacji.
- Jeśli obiekt danych zawiera format CFSTR_FILEDESCRIPTOR, możesz wyodrębnić zawartość pliku z formatu pliku CFSTR_FILECONTENTS. Aby zapoznać się z omówieniem tej procedury, zobacz Using the CFSTR_FILECONTENTS Format to Extract Data from a File (Używanie formatu CFSTR_FILECONTENTS do wyodrębniania danych z pliku).
- Przed powłoką w wersji 4.71 aplikacja wskazała, że przesyła typ pliku skrótu, ustawiając FD_LINKUI w elemencie dwFlags struktury FILEDESCRIPTOR . W przypadku nowszych wersji powłoki systemowej, preferowanym sposobem wskazania, że skróty są przesyłane, jest użycie formatu CFSTR_PREFERREDDROPEFFECT ustawionego na DROPEFFECT_LINK. Takie podejście jest znacznie bardziej wydajne niż wyodrębnianie struktury FILEDESCRIPTOR tylko w celu sprawdzenia flagi.
Jeśli proces wyodrębniania danych będzie długi, możesz wykonać operację asynchronicznie w wątku w tle. Następnie główny wątek może kontynuować bez zbędnych opóźnień. Aby zapoznać się z omówieniem sposobu obsługi wyodrębniania danych asynchronicznych, zobacz Przeciąganie i upuszczanie obiektów powłoki asynchronicznie.
Wyodrębnianie danych z pliku przy użyciu formatu CFSTR_FILECONTENTS
Format CFSTR_FILECONTENTS zapewnia bardzo elastyczny i zaawansowany sposób transferu zawartości pliku. Nie jest nawet konieczne przechowywanie danych jako pojedynczego pliku. Wszystko, co jest wymagane dla tego formatu, jest to, że obiekt danych przedstawia dane do obiektu docelowego tak, jakby był to plik. Na przykład rzeczywiste dane mogą być sekcją dokumentu tekstowego lub blokiem danych wyodrębnianych z bazy danych. Obiekt docelowy może traktować dane jako plik i nie musi nic wiedzieć o podstawowym mechanizmie magazynowania.
Rozszerzenia przestrzeni nazw zwykle używają CFSTR_FILECONTENTS do transferu danych, ponieważ ten format nie zakłada żadnego określonego mechanizmu przechowywania. Rozszerzenie przestrzeni nazw może używać dowolnego mechanizmu przechowywania i używać tego formatu, aby przedstawić swoje obiekty aplikacjom tak, jakby były plikami.
Mechanizm transferu danych dla CFSTR_FILECONTENTS jest zwykle TYMED_ISTREAM. Transferowanie wskaźnika interfejsu IStream wymaga znacznie mniejszej ilości pamięci niż załadowanie danych do obiektu pamięci globalnej, a IStream to prostszy sposób reprezentowania danych niż IStorage.
Format CFSTR_FILECONTENTS jest zawsze dołączony do formatu CFSTR_FILEDESCRIPTOR . Najpierw należy sprawdzić zawartość tego formatu. Jeśli transferowany jest więcej niż jeden plik, obiekt danych będzie zawierać wiele formatów CFSTR_FILECONTENTS , po jednym dla każdego pliku. Format CFSTR_FILEDESCRIPTOR zawiera nazwę i atrybuty każdego pliku oraz zawiera wartość indeksu dla każdego pliku potrzebnego do wyodrębnienia CFSTR_FILECONTENTS formatu określonego pliku.
Aby wyodrębnić format CFSTR_FILECONTENTS :
- Wyodrębnij format CFSTR_FILEDESCRIPTOR jako wartość TYMED_HGLOBAL .
- Element hGlobal zwróconej struktury STGMEDIUM wskazuje na obiekt pamięci globalnej. Zablokuj ten obiekt, przekazując wartość hGlobal do elementu GlobalLock.
- Rzutuj wskaźnik zwrócony przez GlobalLock na wskaźnik FILEGROUPDESCRIPTOR. Będzie wskazywać strukturę FILEGROUPDESCRIPTOR , po której następuje co najmniej jedna struktura FILEDESCRIPTOR . Każda struktura FILEDESCRIPTOR zawiera opis pliku, który jest zawarty w jednym z towarzyszących CFSTR_FILECONTENTS formatów.
- Sprawdź struktury FILEDESCRIPTOR , aby określić, który z nich odpowiada plikowi, który chcesz wyodrębnić. Zerowy indeks tej struktury FILEDESCRIPTOR służy do identyfikowania CFSTR_FILECONTENTS formatu pliku. Ponieważ rozmiar globalnego bloku pamięci nie jest dokładny, użyj elementów członkowskich nFileSizeLow i nFileSizeHigh struktury, aby określić, ile bajtów reprezentuje plik w obiekcie pamięci globalnej.
- Wywołaj IDataObject::GetData z członkiem cfFormat struktury FORMATETC ustawionym na wartość CFSTR_FILECONTENTS i członkiem lIndex ustawionym na indeks określony w poprzednim kroku. Ten członek zazwyczaj jest ustawiony na TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE. Obiekt danych może następnie wybrać preferowany mechanizm transferu danych.
- Struktura STGMEDIUM zwrócona przez obiekt IDataObject::GetData będzie zawierać wskaźnik do danych pliku. Zapoznaj się z członkiem tymed struktury, aby określić mechanizm transferu danych.
- Jeśli tymed jest ustawiony na TYMED_ISTREAM lub TYMED_ISTORAGE, użyj interfejsu, aby wyodrębnić dane. Jeśli wartość tymed jest ustawiona na TYMED_HGLOBAL, dane są zawarte w obiekcie pamięci globalnej. Aby zapoznać się z omówieniem sposobu wyodrębniania danych z obiektu pamięci globalnej, zobacz sekcję Wyodrębnianie obiektu pamięci globalnej z obiektu danych w Obiekcie danych powłoki.
- Wywołaj metodę GlobalLock , aby odblokować obiekt pamięci globalnej, który został zablokowany w kroku 2.
Obsługa zoptymalizowanych operacji przenoszenia
Scenariusz: Plik jest przenoszony z systemu plików do rozszerzenia przestrzeni nazw za pomocą zoptymalizowanego przenoszenia.
W konwencjonalnej operacji przenoszenia obiekt docelowy tworzy kopię danych, a źródło usuwa oryginał. Ta procedura może być nieefektywna, ponieważ wymaga dwóch kopii danych. W przypadku dużych obiektów, takich jak bazy danych, konwencjonalna operacja przenoszenia może nawet nie być praktyczna.
Dzięki zoptymalizowanemu przeniesieniu obiekt docelowy wykorzystuje zrozumienie sposobu przechowywania danych, aby obsłużyć całą operację przenoszenia. Nigdy nie istnieje druga kopia danych i nie ma potrzeby usunięcia oryginalnych danych przez źródło. Dane powłoki są dobrze dostosowane do zoptymalizowanych ruchów, ponieważ obiekt docelowy może obsłużyć całą operację przy użyciu interfejsu API powłoki. Typowym przykładem jest przenoszenie plików. Gdy obiekt docelowy ma ścieżkę pliku do przeniesienia, można go przenieść za pomocą polecenia SHFileOperation . Nie ma potrzeby usuwania oryginalnego pliku przez źródło.
Uwaga / Notatka
Powłoka zwykle używa zoptymalizowanej metody do przenoszenia plików. Aby prawidłowo obsługiwać transfer danych Shell, aplikacja musi być w stanie wykrywać i obsługiwać zoptymalizowane przenoszenie.
Zoptymalizowane ruchy są obsługiwane w następujący sposób:
Źródło wywołuje element DoDragDrop z parametrem dwEffect ustawionym na DROPEFFECT_MOVE, aby wskazać, że obiekty źródłowe można przenosić.
Obiekt docelowy odbiera wartość DROPEFFECT_MOVE za pomocą jednej z metod IDropTarget , co wskazuje, że przeniesienie jest dozwolone.
Obiekt docelowy kopiuje obiekt (niezoptymalizowany ruch) lub przenosi obiekt (zoptymalizowany ruch).
Następnie docelowy element informuje źródło, czy jest potrzeba usunięcia oryginalnych danych.
Zoptymalizowany ruch to domyślna operacja z danymi usuniętymi przez obiekt docelowy. Aby poinformować źródło, że wykonano zoptymalizowany ruch:
-
- Element docelowy ustawia wartość pdwEffect, jaką otrzymał za pośrednictwem metody IDropTarget::Drop, na wartość inną niż DROPEFFECT_MOVE. Zazwyczaj jest ustawiona na wartość DROPEFFECT_NONE lub DROPEFFECT_COPY. Wartość zostanie zwrócona do źródła przez doDragDrop.
- Obiekt docelowy wywołuje również metodę IDataObject::SetData obiektu danych i przekazuje jej identyfikator formatu CFSTR_PERFORMEDDROPEFFECT ustawiony na DROPEFFECT_NONE. To wywołanie metody jest konieczne, ponieważ niektóre obiekty docelowe upuszczania mogą nie ustawić parametru pdwEffectelementu DoDragDrop poprawnie. Format CFSTR_PERFORMEDDROPEFFECT jest niezawodnym sposobem określenia, że nastąpił zoptymalizowany ruch.
Jeśli obiekt docelowy wykonał niezoptymalizowany ruch, dane muszą zostać usunięte przez źródło. Aby poinformować źródło, że wykonano niezoptymalizowany ruch:
-
- Element docelowy ustawia wartość pdwEffect, którą otrzymał za pośrednictwem metody IDropTarget::Drop, na DROPEFFECT_MOVE. Wartość zostanie zwrócona do źródła przez doDragDrop.
- Obiekt docelowy wywołuje również metodę IDataObject::SetData obiektu danych i przekazuje jej identyfikator formatu CFSTR_PERFORMEDDROPEFFECT ustawiony na DROPEFFECT_MOVE. To wywołanie metody jest konieczne, ponieważ niektóre obiekty docelowe upuszczania mogą nie ustawić parametru pdwEffectelementu DoDragDrop poprawnie. Format CFSTR_PERFORMEDDROPEFFECT jest niezawodnym sposobem wskazania, że nastąpił niezoptymalizowany ruch.
-
Źródło sprawdza dwie wartości, które mogą być zwracane przez obiekt docelowy. Jeśli oba są ustawione na DROPEFFECT_MOVE, wykonuje on niezoptymalizowany ruch, usuwając oryginalne dane. W przeciwnym razie cel wykonał zoptymalizowany ruch i oryginalne dane zostały usunięte.
Obsługa operacji usuwania przy wklejaniu
Scenario: Co najmniej jeden plik jest wycinany z folderu w Eksploratorze Windows i wklejany do rozszerzenia przestrzeni nazw. Windows Explorer pozostawia wyróżnione pliki, dopóki nie otrzyma opinii na temat wyniku operacji wklejania.
Tradycyjnie, gdy użytkownik wycina dane, natychmiast znikają z ekranu. Może to nie być wydajne i może prowadzić do problemów z użytecznością, jeśli użytkownik staje się zaniepokojony tym, co się stało z danymi. Alternatywnym podejściem jest użycie operacji usuwania podczas wklejania.
W przypadku operacji usuwania przy wklejaniu wybrane dane nie są natychmiast usuwane z widoku. Zamiast tego aplikacja źródłowa oznacza ją jako wybraną, na przykład przez zmianę czcionki lub koloru tła. Po wklejeniu danych przez aplikację docelową powiadamia źródło o wyniku operacji. Jeśli cel wykonał zoptymalizowany ruch, źródło może po prostu zaktualizować jego wyświetlacz. Jeśli obiekt docelowy wykonał normalny ruch, źródło musi również usunąć jego kopię danych. Jeśli wklejanie zakończy się niepowodzeniem, aplikacja źródłowa przywraca wybrane dane do oryginalnego wyglądu.
Uwaga / Notatka
Powłoka zazwyczaj wykorzystuje operację usunięcia przy wycinaniu/wklejaniu, gdy operacja wycinania/wklejania jest używana do przenoszenia plików. Operacje usuwania podczas wklejania z obiektami powłoki zwykle używają zoptymalizowanego przenoszenia do przenoszenia plików. Aby prawidłowo obsługiwać transfer danych powłoki, aplikacja musi być w stanie wykrywać i obsługiwać operacje usuwania podczas wklejania.
Podstawowym wymaganiem dla operacji delete-on-paste jest to, że docelowy musi przekazywać wynik operacji do źródła. Jednak standardowe techniki schowka nie mogą być używane do implementacji usuwania po wklejeniu, ponieważ nie zapewniają one sposobu na komunikację między celem a źródłem. Zamiast tego aplikacja docelowa używa metody IDataObject::SetData obiektu danych, aby zgłosić wynik do obiektu danych. Obiekt danych może następnie komunikować się ze źródłem za pośrednictwem interfejsu prywatnego.
Podstawowa procedura operacji usuwania podczas wklejania jest następująca:
- Źródło oznacza ekran wyświetlania wybranych danych.
- Źródło tworzy obiekt danych. Wskazuje operację wycinania przez dodanie formatu CFSTR_PREFERREDDROPEFFECT z wartością danych DROPEFFECT_MOVE.
- Źródło umieszcza obiekt danych w Schowku przy użyciu narzędzia OleSetClipboard.
- Obiekt docelowy pobiera obiekt danych ze Schowka przy użyciu narzędzia OleGetClipboard.
- Obiekt docelowy wyodrębnia dane CFSTR_PREFERREDDROPEFFECT. Jeśli ustawiono tylko na DROPEFFECT_MOVE, obiekt docelowy może albo wykonać zoptymalizowane przeniesienie, albo po prostu skopiować dane.
- Jeśli obiekt docelowy nie wykonuje zoptymalizowanego przenoszenia, wywołuje metodę IDataObject::SetData z formatem CFSTR_PERFORMEDDROPEFFECT ustawionym na DROPEFFECT_MOVE.
- Po zakończeniu wklejania, element docelowy wywołuje metodę IDataObject::SetData z formatem CFSTR_PASTESUCCEEDED ustawionym na DROPEFFECT_MOVE.
- Gdy metoda IDataObject::SetData źródła jest wywoływana z użyciem formatu CFSTR_PASTESUCCEEDED ustawionego na DROPEFFECT_MOVE, należy sprawdzić, czy również otrzymała format CFSTR_PERFORMEDDROPEFFECT ustawiony na DROPEFFECT_MOVE. Jeśli oba formaty są wysyłane przez obiekt docelowy, źródło będzie musiało usunąć dane. Jeśli zostanie odebrany tylko format CFSTR_PASTESUCCEEDED , źródło może po prostu usunąć dane z jego wyświetlania. Jeśli transfer zakończy się niepowodzeniem, źródło aktualizuje ekran do oryginalnego wyglądu.
Transferowanie danych do i z folderów wirtualnych
Scenariusz: Użytkownik przeciąga obiekt do lub z folderu wirtualnego.
Foldery wirtualne zawierają obiekty, które zazwyczaj nie są częścią systemu plików. Niektóre foldery wirtualne, takie jak Kosz, mogą reprezentować dane przechowywane na dysku twardym, ale nie jako zwykłe obiekty systemu plików. Niektóre mogą reprezentować przechowywane dane, które znajdują się w systemie zdalnym, takim jak komputer podręczny lub lokacja FTP. Inne, takie jak folder Drukarki, zawierają obiekty, które w ogóle nie reprezentują przechowywanych danych. Chociaż niektóre foldery wirtualne są częścią systemu, deweloperzy mogą również tworzyć i instalować niestandardowe foldery wirtualne, implementując rozszerzenie przestrzeni nazw.
Niezależnie od typu danych lub sposobu ich przechowywania, folder i obiekty plików, które znajdują się w folderze wirtualnym, są prezentowane przez powłokę tak, jakby były normalnymi plikami i folderami. Obowiązkiem folderu wirtualnego jest odpowiednie zarządzanie danymi, które zawiera, i prezentowanie ich w powłoce. To wymaganie oznacza, że foldery wirtualne zwykle obsługują transfery danych przeciągania i upuszczania i schowka.
W związku z tym istnieją dwie grupy deweloperów, którzy muszą zajmować się transferem danych do i z folderów wirtualnych:
- Deweloperzy, których aplikacje muszą akceptować dane przesyłane z folderu wirtualnego.
- Deweloperzy, których rozszerzenia przestrzeni nazw muszą prawidłowo obsługiwać transfer danych.
Akceptowanie danych z folderu wirtualnego
Foldery wirtualne mogą reprezentować praktycznie dowolny typ danych i mogą przechowywać te dane w dowolny sposób. Niektóre foldery wirtualne mogą zawierać zwykłe pliki i foldery systemu plików. Inne mogą na przykład spakować wszystkie swoje obiekty do pojedynczego dokumentu lub bazy danych.
Gdy obiekt systemu plików jest przesyłany do aplikacji, obiekt danych zwykle zawiera format CF_HDROP z w pełni kwalifikowaną ścieżką obiektu. Aplikacja może wyodrębnić ten ciąg i użyć normalnych funkcji systemu plików, aby otworzyć plik i wyodrębnić jego dane. Jednak ponieważ foldery wirtualne zwykle nie zawierają normalnych obiektów systemu plików, zazwyczaj nie używają CF_HDROP.
Zamiast CF_HDROP dane są zwykle przesyłane z folderów wirtualnych z formatami CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS . Format CFSTR_FILECONTENTS ma dwie zalety CF_HDROP:
- Nie zakłada się żadnej konkretnej metody przechowywania danych.
- Format jest bardziej elastyczny. Obsługuje trzy mechanizmy transferu danych: globalny obiekt pamięci, interfejs IStream lub interfejs IStorage .
Obiekty pamięci globalnej są rzadko używane do transferu danych do lub z obiektów wirtualnych, ponieważ dane muszą być kopiowane do pamięci w całości. Transferowanie wskaźnika interfejsu nie wymaga niemal żadnej pamięci i jest o wiele bardziej wydajne. W przypadku bardzo dużych plików wskaźnik interfejsu może być jedynym praktycznym mechanizmem transferu danych. Zazwyczaj dane są reprezentowane przez wskaźnik IStream , ponieważ ten interfejs jest nieco bardziej elastyczny niż IStorage. Obiekt docelowy wyodrębnia wskaźnik z obiektu danych i używa metod interfejsu do wyodrębniania danych.
Aby uzyskać dalszą dyskusję na temat obsługi formatów CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/, zobacz Using the CFSTR_FILECONTENTS Format to Extract Data from a File (Używanie formatu CFSTR_FILECONTENTS do wyodrębniania danych z pliku).
Transferowanie danych do i z rozszerzenia przestrzeni nazw
Podczas implementowania rozszerzenia przestrzeni nazw zwykle należy obsługiwać możliwości przeciągania i upuszczania. Postępuj zgodnie z zaleceniami dotyczącymi upuszczania źródeł i obiektów docelowych omówionych w ogólnych wytycznych. W szczególności rozszerzenie przestrzeni nazw musi:
- Obsługa formatów CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS . Te dwa formaty są zwykle używane do transferu obiektów do i z rozszerzeń przestrzeni nazw.
- Być w stanie obsługiwać zoptymalizowane ruchy. Powłoka oczekuje, że obiekty Shell zostaną przeniesione w sposób zoptymalizowany.
- Możliwość obsługiwania operacji usuwania przy wklejaniu. Powłoka używa funkcji delete-on-paste, gdy obiekty są przenoszone z powłoki za pomocą operacji wycinania/wklejania.
- Obsługa transferu danych za pośrednictwem interfejsu IStream lub IStorage . Transfer danych do lub z folderu wirtualnego jest zwykle obsługiwany przez transfer jednego z tych dwóch wskaźników interfejsu, zazwyczaj wskaźnik IStream . Następnie obiekt docelowy wywołuje metody interfejsu w celu wyodrębnienia danych:
-
- Jako źródło upuszczania rozszerzenie przestrzeni nazw musi wyodrębnić dane z magazynu i przekazać je przez ten interfejs do obiektu docelowego.
- Jako obiekt docelowy upuszczania rozszerzenie przestrzeni nazw musi akceptować dane ze źródła za pośrednictwem tego interfejsu i przechowywać je prawidłowo.
-
Upuszczanie plików do Kosza
Scenariusz: Użytkownik odrzuca plik w Koszu. Rozszerzenie twojej aplikacji lub przestrzeni nazw usuwa oryginalny plik.
Kosz to folder wirtualny, który jest używany jako repozytorium plików, które nie są już potrzebne. Jeśli Kosz nie został opróżniony, użytkownik może później odzyskać plik i zwrócić go do systemu plików.
W większości przypadków przenoszenie obiektów Shell do Kosza funkcjonuje podobnie jak w przypadku każdego innego folderu. Jednak gdy użytkownik upuści plik na Kosz, źródło musi usunąć oryginał, nawet jeśli informacja zwrotna z folderu wskazuje operację kopiowania pliku. Zwykle źródło upuszczania nie ma możliwości sprawdzenia, który folder jego obiektu danych został porzucony. Jednak w przypadku systemów Windows 2000 i nowszych, gdy obiekt danych zostanie porzucony na Recycle Bin, Powłoka wywoła IDataObject::SetData metodę CFSTR_TARGETCLSID ustawioną na identyfikator klasy Kosza (CLSID) (CLSID_RecycleBin). Aby prawidłowo obsłużyć przypadek Kosza, obiekt danych powinien być w stanie rozpoznać ten format i przekazać informacje do źródła za pośrednictwem interfejsu prywatnego.
Uwaga / Notatka
Gdy wywoływana jest metoda IDataObject::SetData z użyciem formatu CFSTR_TARGETCLSID ustawionego na CLSID_RecycleBin, źródło danych powinno zamknąć wszystkie otwarte uchwyty do obiektów, które są przesyłane, przed powrotem z metody. W przeciwnym razie możesz utworzyć naruszenia udostępniania.
Tworzenie i importowanie plików tymczasowych
Scenario: Użytkownik przeciąga dane z pliku danych aplikacji OLE i porzuca je na pulpicie lub Windows Explorer.
Windows umożliwia użytkownikom przeciąganie obiektu z pliku danych aplikacji OLE i upuszczanie go na pulpicie lub folderze systemu plików. Ta operacja tworzy plik tymczasowy, który zawiera dane lub link do danych. Nazwa pliku jest pobierana z krótkiej nazwy zarejestrowanej dla CLSID obiektu i danych CF_TEXT . Aby powłoka mogła utworzyć plik tymczasowy zawierający dane, interfejs IDataObject aplikacji musi obsługiwać format schowka CF_EMBEDSOURCE. Aby utworzyć plik zawierający link, obiekt IDataObject musi obsługiwać format CF_LINKSOURCE.
Istnieją również trzy opcjonalne funkcje, które aplikacja może zaimplementować w celu obsługi plików roboczych:
- Pomoc techniczna dotycząca podróży dwukierunkowej
- Buforowane formaty danych
- Opóźnione renderowanie
Obsługa dwukierunkowa
Runda obejmuje przeniesienie obiektu danych do innego kontenera, a następnie powrót do oryginalnego dokumentu. Na przykład użytkownik może przenieść grupę komórek z arkusza kalkulacyjnego na pulpit, tworząc plik tymczasowy z danymi. Jeśli użytkownik następnie przeniesie złom z powrotem do arkusza kalkulacyjnego, dane muszą zostać zintegrowane z dokumentem, tak jak przed oryginalnym przeniesieniem.
Gdy powłoka tworzy plik złomowy, reprezentuje dane jako osadzony obiekt. Gdy złom jest przenoszony do innego kontenera, jest przenoszony jako obiekt osadzania, nawet jeśli jest zwracany do oryginalnego dokumentu. Aplikacja jest odpowiedzialna za określenie formatu danych zawartych w wycinku i w razie potrzeby przywrócenie danych do ich natywnego formatu.
Aby ustanowić format obiektu osadzonego, określ jego identyfikator CLSID, pobierając CF_OBJECTDESCRIPTOR format obiektu. Jeśli identyfikator CLSID wskazuje format danych należący do aplikacji, powinien on przesyłać dane natywne zamiast wywoływać obiekt OleCreateFromData.
Buforowane formaty danych
Gdy Shell tworzy plik tymczasowy, sprawdza rejestr w celu uzyskania listy dostępnych formatów. Domyślnie dostępne są dwa formaty: CF_EMBEDSOURCE i CF_LINKSOURCE. Istnieje jednak wiele scenariuszy, w których aplikacje mogą potrzebować posiadania plików tymczasowych w różnych formatach.
- Aby zezwolić na transfer fragmentów do kontenerów innych niż OLE, które nie mogą akceptować formatów osadzonych obiektów.
- Umożliwianie zestawom aplikacji komunikowania się z formatem prywatnym.
- Aby ułatwić obsługę podróży w obie strony.
Aplikacje mogą dodawać formaty do złomu, buforując je w rejestrze. Istnieją dwa typy formatów buforowanych:
- Formaty pamięci podręcznej o wysokim priorytecie. W przypadku tych formatów dane są kopiowane w całości do schowka z obiektu danych.
- Formaty renderowane z opóźnieniem. W przypadku tych formatów obiekt danych nie jest kopiowany do schowka. Zamiast tego renderowanie jest opóźnione do momentu żądania danych przez element docelowy. Renderowanie opóźnione zostało omówione bardziej szczegółowo w następnej sekcji.
Aby dodać pamięć podręczną o priorytecie lub format renderowany z opóźnieniem, utwórz podklucz DataFormat w kluczu CLSID aplikacji będącej źródłem danych. W tym podkluczu utwórz podklucz PriorityCacheFormats lub DelayRenderFormats. Dla każdej priorytetowej pamięci podręcznej lub formatu renderowanego z opóźnieniem utwórz numerowany podklucz rozpoczynający się od zera. Ustaw wartość tego klucza na ciąg o zarejestrowanej nazwie formatu lub wartości #X, gdzie X reprezentuje numer formatu standardowego schowka.
Poniższy przykład przedstawia buforowane formaty dla dwóch aplikacji. Aplikacja MyProg1 ma format RTF jako priorytetowy format pamięci podręcznej i format prywatny "My Format" jako format opóźnionego renderowania. Aplikacja MyProg2 ma format CF_BITMAP ("#8") jako priorytetowy format pamięci podręcznej.
HKEY_CLASSES_ROOT
CLSID
{GUID}
(Default) = MyProg1
DataFormats
PriorityCacheFormats
0
(Default) = Rich Text Format
DelayRenderFormats
0
(Default) = My Format
{GUID}
(Default) = MyProg2
DataFormats
PriorityCacheFormats
0
(Default) = #8
Dodatkowe formaty można dodać, tworząc dodatkowe podklucze numerowane.
Opóźnione renderowanie
Opóźniony format renderowania pozwala aplikacji utworzyć plik tymczasowy, ale odroczyć koszty renderowania danych do momentu, gdy zostaną zażądane przez odbiorcę. Interfejs IDataObject wycinka będzie oferował opóźnione formaty renderowania do obiektu docelowego, razem z natywnymi i buforowanymi danymi. Jeśli cel żąda opóźnionego formatu renderowania, Shell uruchomi aplikację i dostarczy dane do celu z obiektu aktywnego.
Uwaga / Notatka
Ponieważ opóźnione renderowanie jest nieco ryzykowne, należy go używać ostrożnie. Nie będzie działać, jeśli serwer nie jest dostępny lub w aplikacjach, które nie są włączone przez obiekt OLE.
Przeciąganie i upuszczanie obiektów powłoki asynchronicznie
Scenariusz: Użytkownik przesyła duży blok danych ze źródła do miejsca docelowego. Aby uniknąć blokowania obu aplikacji przez znaczną ilość czasu, obiekt docelowy wyodrębnia dane asynchronicznie.
Zwykle przeciąganie i upuszczanie jest operacją synchroniczną. Krótko mówiąc:
- Źródło upuszczania wywołuje element DoDragDrop i blokuje jego wątek podstawowy do momentu, gdy funkcja zwróci wartość . Blokowanie wątku podstawowego zwykle blokuje przetwarzanie interfejsu użytkownika.
- Po wywołaniu metody IDropTarget::D rop obiektu docelowego obiekt docelowy wyodrębnia dane z obiektu danych w jego wątku podstawowym. Ta procedura zwykle blokuje przetwarzanie interfejsu użytkownika obiektu docelowego przez czas trwania procesu wyodrębniania.
- Po wyodrębnieniu danych obiekt docelowy zwraca wywołanie IDropTarget::D rop , system zwraca element DoDragDrop, a oba wątki mogą kontynuować.
Krótko mówiąc, synchroniczny transfer danych może blokować podstawowe wątki obu aplikacji przez znaczną ilość czasu. W szczególności oba wątki muszą czekać, gdy obiekt docelowy wyodrębnia dane. W przypadku małych ilości danych czas wymagany do wyodrębnienia danych jest mały, a synchroniczny transfer danych działa całkiem dobrze. Jednak synchronicznie wyodrębnianie dużych ilości danych może powodować długie opóźnienia i zakłócać interfejs użytkownika zarówno docelowego, jak i źródłowego.
Interfejs IAsyncOperation/IDataObjectAsyncCapability jest opcjonalnym interfejsem, który można zaimplementować przez obiekt danych. Daje ona docelową możliwość wyodrębniania danych z obiektu danych asynchronicznie w wątku w tle. Po przekazaniu wyodrębniania danych do wątku w tle podstawowe wątki obu aplikacji mogą być kontynuowane.
Korzystanie z klasy IASyncOperation/IDataObjectAsyncCapability
Uwaga / Notatka
Interfejs został pierwotnie nazwany IAsyncOperation, ale został później zmieniony na IDataObjectAsyncCapability. W przeciwnym razie dwa interfejsy są identyczne.
Celem operacji IAsyncOperation/IDataObjectAsyncCapability jest umożliwienie lokalizacji docelowej upuszczania i upuszczania w celu negocjowania, czy dane mogą być wyodrębniane asynchronicznie. Poniższa procedura przedstawia sposób użycia interfejsu przez źródło upuszczania:
- Utwórz obiekt danych, który uwidacznia IAsyncOperation/IDataObjectAsyncCapability.
- Wywołaj metodę SetAsyncMode za pomocą polecenia fDoOpAsync ustawioną na VARIANT_TRUE , aby wskazać, że operacja asynchroniczna jest obsługiwana.
- Po powrocie elementu DoDragDrop wywołaj metodę InOperation:
- Jeśli działanie inOperation zakończy się niepowodzeniem lub zwróci VARIANT_FALSE, nastąpi normalny synchroniczny transfer danych, a proces wyodrębniania danych zostanie zakończony. Źródło powinno wykonać wszelkie wymagane czyszczenie i kontynuować.
- Jeśli funkcja InOperation zwraca VARIANT_TRUE, dane są wyodrębniane asynchronicznie. Operacje oczyszczania powinny być obsługiwane przez operację EndOperation.
- Zwolnij obiekt danych.
- Po zakończeniu asynchronicznego transferu danych obiekt danych zwykle powiadamia źródło za pośrednictwem interfejsu prywatnego.
Poniższa procedura przedstawia sposób, w jaki obiekt docelowy upuszczania używa interfejsu IAsyncOperation/IDataObjectAsyncCapability do wyodrębniania danych asynchronicznie:
- Gdy system wywołuje IDropTarget::Drop, wywołaj metodę IDataObject::QueryInterface i zażądaj interfejsów IAsyncOperation/ oraz IDataObjectAsyncCapability (IID_IAsyncOperation/IID_IDataObjectAsyncCapability) z obiektu danych.
- Wywołaj metodę GetAsyncMode. Jeśli metoda zwróci VARIANT_TRUE, obiekt danych obsługuje asynchroniczne wyodrębnianie danych.
- Utwórz oddzielny wątek do obsługi wyodrębniania danych i wywoływania operacji StartOperation.
- Zwróć wywołanie IDropTarget::D rop , tak jak w przypadku normalnej operacji transferu danych. Funkcja DoDragDrop zwróci i odblokuje źródło upuszczania. Nie należy wywoływać obiektu IDataObject::SetData , aby wskazać wynik zoptymalizowanej operacji przenoszenia lub usuwania w wklejaniu. Poczekaj na zakończenie operacji.
- Wyodrębnij dane w wątku w tle. Podstawowy wątek celu jest odblokowany i gotowy do kontynuowania.
- Jeśli transfer danych był zoptymalizowaną operacją przenoszenia lub usuwania podczas wklejania , wywołaj metodę IDataObject::SetData , aby wskazać wynik.
- Powiadom obiekt danych, że wyodrębnianie zostało zakończone przez wywołanie EndOperation.