Форум: "Основная";
Текущий архив: 2005.06.29;
Скачать: [xml.tar.bz2];
ВнизDrag&drop из программы в проводник Найти похожие ветки
← →
kami © (2005-05-29 01:54) [0]Есть программа с набором данных, каждая группа данных представлена в виде элемента ListView. Если это имеет значение, данные запакованы в TStream. Как можно перетащив ListItem на проводник, сохранить эти данные в файл?
Прошу сильно не пинать, с Drag&Drop столкнулся впервые и имею об этом весьма смутное представление. Порывшись несколько часов в хелпе и MSDN понял, что ничего не понял :(, кроме того, что используются TDragObject и/или IDataObject, но вот как - ???? Подобные ветки уже были, но давно, их следов я не обнаружил.
Подскажите, пожалуйста, последовательность действий для перетаскивания данных из программы в проводник, чтобы тот сохранил их в файл.
← →
Cobalt © (2005-05-29 02:03) [1]Если уж ты сам наткнулся в MSDN на IDataObject - то тебе надо сделать ещё одну вещь - прочитать полностью Overview этой темы.
← →
kami © (2005-05-29 03:42) [2]Мдааа. Наверное, надо было заводить ветку в API :(
2 [1] Cobalt © & all
Подправьте, пожалуйста, если неправильно понял...
Когда определили, что пользователь начал перетаскивать ListItem ( то есть в OnStartDrag?), нужно инициализировать IDataSource, IDropSource и вызвать DoDragDrop, и на этом вроде всё?
Если так, то сразу вопрос : в IDataSource.SetData в FORMATETC что нужно ставить в полях cfFormat, dwAspect ( tymed, как я понял, должен быть TYMED_ISTREAM, т.к. данные у меня хранятся в потоке). С структурой STGMEDIUM вроде понятно, но вот только как проводник узнает, что нужно сохранить данные в файл, если в ней поставить так же tymed:=TYMED_ISTREAM ?
И еще - методы IDropSource::GiveFeedback и QueryContinueDrag нужно определять в своей программе, как, например, обработчики событий компонентов?
← →
kami © (2005-05-29 03:46) [3]Упс... Вопрос про методы IDropSource снимается, посмотрел в OLE2.pas - они объявлены как абстрактные, соответственно - нуна их перекрыть :)
← →
kami © (2005-05-29 03:57) [4][2] kami
IDataSource=>IDataObject
← →
Cobalt © (2005-05-29 13:17) [5]2 kami ©
Попробуй поискать в MSDN примерчик - по ключевым словам - там иногда бывает. Правда, на С, но настоящего программиста это не остановит ;)
не приглядывался, но вот наткнулся в MS SDK на
Scrap Files
Windows allows the user to transfer objects within a data file to the desktop or a folder. The result of the transfer operation is a file icon called a scrap. An OLE application automatically supports the creation of scrap files if its IDataObject interface supports enough data formats so that the drop target can create either an embedding or a shortcut object. You do not need to add any other functionality to your application to allow the user to create a scrap file. However, there are two optional features you may wish to add to your application: round-trip support and caching additional data formats in a scrap file. Round-trip support means that an object can be dragged out of a document and into a new container and then dragged from the new container back into the original document.
Round-Trip Support
When the user transfers a scrap into your application, it should integrate the scrap as if it were being transferred from its original source. For example, if a selected range of cells from a spreadsheet is transferred to the desktop, they become a scrap. If the user transfers the resulting scrap into a word processing document, the cells should be incorporated as if they were transferred directly from the spreadsheet. Similarly, if the user transfers the scrap back into the spreadsheet, the cells should be integrated as if they were originally transferred within that spreadsheet.
Your application must include code that integrates a scrap into a document; otherwise, the embedding object of the scrap is copied into the document rather than the data associated with the scrap. To retrieve the data for the scrap, your application must examine the class identifier, CLSID, of the scrap object by retrieving the CF_OBJECTEDESCRIPTOR file format data. If the application recognizes the CLSID, the application should transfer the native data into the document rather than calling the OleCreateFromData function.
P.S. если реализуешь - было бы любопытно глянуть на реализацию :)
← →
kami © (2005-06-03 02:05) [6]Ура !!!!
После долгих мучений и невозможности дорваться до компьютера (работы навалили выше ушей), все-таки сделал это!!!
Итак, реализация Drag & Drop из MemoryStream в проводник с преобразованием в файл без временного сохранения в TempDirectory. Промежуточные реализации IDataObject и IDropSource писать было лень, поэтому за основу был взят Drag and Drop Component Suite v.3.7 (бесплатный, с открытыми исходниками). Взять можно http://www.torry.ru/vcl/system/draganddrop/dragdrop.exe, а откуда сам скачивал - не помню :))
TFileContent=record
FileName:string;
FileSize:Longint;
FileIStream:IStream;
end;
TDropContentFileSource=class (TDropSource)
protected
function DoGetData(const FormatEtcIn: TFormatEtc;
out Medium: TStgMedium):HRESULT; override;
{ вызывается в IDataObject.GetData}
private
FFileContentsCount:integer;
procedure FillFileDescriptor(FileIndex: integer;var FD:TFileDescriptor);
public
FileContents:array[0..maxFormats-1] of TFileContent;
constructor Create(aOwner: TComponent); override;
procedure AddFileContent(FileName:string; var Stream:TMemoryStream; FreeAfterAdd:Boolean);
procedure DeleteFileContent(FileName:string);overload;
procedure DeleteFileContent(index:integer);overload;
published
property FileContentsCount:integer read FFileContentsCount;
end;
//--------------------------------------------------------
procedure TStreamToIStream(var Stream:TMemoryStream;var stm:IStream;FreeAfterCopy:Boolean);
var
p:Int64;
begin
if not assigned(Stream) then
stm:=nil
else
if CreateStreamOnHGlobal(0,False,stm)=S_OK then
begin
stm._AddRef;
stm.SetSize(Stream.size);
stm.Write(Stream.Memory,Stream.Size,@p);
stm.Seek(0,STREAM_SEEK_SET,p);
if FreeAfterCopy then
Stream.Free;
end;
end;
{ TDropContentFileSource }
procedure TDropContentFileSource.AddFileContent(FileName: string;
var Stream: TMemoryStream; FreeAfterAdd: Boolean);
begin
FileContents[FFileContentsCount].FileName:=FileName;
FileContents[FFileContentsCount].FileSize:=Stream.Size;
TStreamToIStream(Stream,FileContents[FFileContentsCount].FileIStream,FreeAfterAdd);
inc(FFileContentsCount);
end;
constructor TDropContentFileSource.Create(aOwner: TComponent);
begin
inherited Create(AOwner);
FFileContentsCount:=0;
AddFormatEtc(CF_FileGroupDescriptor,nil,DVASPECT_CONTENT,-1, Tymed_HGLOBAL);
AddFormatEtc(CF_FileContents,nil,DVAspect_Content,-1,Tymed_IStream);
end;
procedure TDropContentFileSource.FillFileDescriptor(FileIndex:integer;var FD:TFileDescriptor);
begin
FD.dwFlags:=FD_FILESIZE or FD_ATTRIBUTES or FD_CREATETIME;
FD.nFileSizeHigh:=0;
FD.nFileSizeLow:=FileContents[FileIndex].FileSize;
StrPCopy(@FD.cFileName[0],FileContents[FileIndex].FileName);
FD.dwFileAttributes:=FILE_ATTRIBUTE_NORMAL;
FD.ftCreationTime.dwLowDateTime:=LoWord(DateTimeToFileDate(Now));
FD.ftCreationTime.dwHighDateTime:=HiWord(DateTimeToFileDate(Now));
end;
function TDropContentFileSource.DoGetData(const FormatEtcIn: TFormatEtc;
out Medium: TStgMedium): HRESULT;
var
pFileGroup:pFileGroupDescriptor;
begin
Result:=DV_E_FORMATETC;
Medium.tymed:=0;
Medium.unkForRelease:=nil;
Medium.hglobal:=0;
if FormatEtcIn.cfFormat=CF_FileGroupDescriptor then
if (FormatEtcIn.dwAspect=DVAspect_Content) and
(FormatEtcIn.tymed=Tymed_HGlobal) then
begin
Medium.tymed:=Tymed_HGlobal;
Medium.hGlobal:=GlobalAlloc(GMEM_Share or GHND,SizeOf(TFileGroupDescriptor)+SizeOf(TFileDescriptor)+1);
if Medium.hGlobal=0 then
begin
Result:=E_OutOfMemory;
exit;
end;
pFileGroup:=GlobalLock(Medium.HGlobal);
pFileGroup^.cItems:=1;
FillFileDescriptor(0,pFileGroup^.fgd[0]);
GlobalUnLock(Medium.HGlobal);
Result:=S_OK;
end;
if FormatEtcIn.cfFormat=CF_FileContents then
if (FormatEtcIn.tymed and Tymed_IStream)<>0 then
begin
Medium.tymed:=Tymed_IStream;
Medium.unkForRelease:=nil;
Medium.stm:=Pointer(FileContents[FormatEtcIn.lindex].FileIStream);
Result:=S_OK;
end;
end;
В принципе, все :)) Осталось только пара неясных вопросов - как в FileGroupDescriptor можно запихнуть несколько дескрипторов файлов, ну и разобраться, почему при закрытии тестового приложения вылазит AV. Последнее - мелочи :)
Ежели кто может сказать где в этом коде глюкодром - пожалуйста, ткните меня носом.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2005.06.29;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.035 c