Mega Code Archive

 
Categories / Delphi / Examples
 

OLE Drag and Drop

Title: OLE Drag and Drop Question: I wonder if there is anyone knowing of a way to drag a mail from Outlook and drop it in a listview control (or something similar). Answer: Create a new unit called "olmailitem", select all the code in that unit, and replace with the code supplied below into it. Include this unit in your project. The object class TOlMailDragDrop allows you to set up a TWinControl (or decendant) to accept drag/drop mail items from Outlook. Example: -------- var olmdd: TOlMailDragDrop; begin olmdd:=TOlMailDragDrop.Create(ListView1); end; This will register ListView1 as a drop target, and the DragEnter code does checking to make sure the drop object is an Outlook mail item(s). There are 2 other things that need to be done in order for this to work; 1.) In the control's OnDragOver, the Accept variable needs to be set to true: Example: -------- procedure TForm1.ListView1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin Accept:=True; end; 2.) There needs to be a procedure assigned to OnDragDrop. Example: -------- procedure TForm1.ListView1DragDrop(Sender, Source: TObject; X, Y: Integer); var maildrop: TOlMailDrop; i: Integer; begin with ListView1 do begin ViewStyle:=vsReport; Columns.Clear; with Columns.Add do begin Caption:='From'; Width:=100; end; with Columns.Add do begin Caption:='Subject'; Width:=100; end; with Columns.Add do begin Caption:='Received'; Width:=100; end; with Columns.Add do begin Caption:='Size'; Width:=80; end; if (Source is TOlMailDrop) then begin maildrop:=TOlMailDrop(Source); for i:=0 to maildrop.ItemCount-1 do begin with ListView1.Items.Add do begin Caption:=maildrop.Items[i].From; SubItems.Add(maildrop.Items[i].Subject); SubItems.Add(maildrop.Items[i].Received); SubItems.Add(maildrop.Items[i].Size); // Body is also available // maildrop.Items[i].Body end; end; end; end; end; In the OnDragDrop, check for (source is TOlMailDrop). If this it true, then cast the Source as a TOLMailDrop item. This class exposes and itemcount and Items[index] property. (zero based to count-1). The items property is a list that holds each mail item. The TOLMailItem is a packed record that is defined as follows: type POLMailItem = ^TOLMailItem; TOlMailItem = packed record From: String; Subject: String; Received: String; Size: String; Body: String; end; Using the TOlMailItem information, you get the same data that outlook displays and can save the information any way you desire. Note: Do not attempt to save/persist the TOLMailDrop item that is sent in as Source. It is automatically freed when the OnDragDrop event is finished. Anyways, hope this gets you started. Let me know if you run into problems regards, Russell --------------------------------------------------------- Code for olmailitem --------------------------------------------------------- unit olmailitem; interface uses Windows, SysUtils, Classes, Controls, ExtCtrls, ShlObj, ComObj, ActiveX; type POLMailItem = ^TOLMailItem; TOlMailItem = packed record From: String; Subject: String; Received: String; Size: String; Body: String; end; type TOlMailDrop = class(TObject) private // Private declarations FItems: TList; protected // Protected declarations function GetItemCount: Integer; procedure AddItem(AItem: POLMailItem); function GetItems(Index: Integer): TOLMailItem; public // Public declarations constructor Create; destructor Destroy; override; property ItemCount: Integer read GetItemCount; property Items[Index: Integer]: TOLMailItem read GetItems; default; end; type TOlMailDragDrop= class(TObject, IUnknown, IDropTarget) private // Private declarations FRefCount: Integer; FControl: TWinControl; protected // Protected declarations for IUnknown function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; // Protected declarations for IDropTarget function DragEnter(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; function DragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; reintroduce; stdcall; function DragLeave: HResult; stdcall; function Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; // Protected declarations public // Public declarations constructor Create(AControl: TWinControl); destructor Destroy; override; end; implementation // Cliboard formats that need to be registered var CF_FILECONTENTS: Integer; CF_FILEDESCRIPTOR:Integer; function TOlMailDrop.GetItems(Index: Integer): TOLMailItem; begin // Return the item data result:=POLMailItem(FItems[Index])^; end; procedure TOlMailDrop.AddItem(AItem: POLMailItem); begin // Add item to string list FItems.Add(AItem); end; function TOlMailDrop.GetItemCount; begin // Return the count of mail items result:=FItems.Count; end; constructor TOlMailDrop.Create; begin // Perform inherited inherited Create; // Set starting values FItems:=TList.Create; end; destructor TOlMailDrop.Destroy; var polmi: POLMailItem; i: Integer; begin // Free the item data and list for i:=FItems.Count-1 downto 0 do begin polmi:=FItems[i]; Dispose(polmi); FItems.Delete(i); end; FItems.Free; // Perform inherited inherited Destroy; end; function TOlMailDragDrop.DragEnter(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; var fc: tagFORMATETC; stgm: tagSTGMEDIUM; pstg: IStorage; pstm: IStream; accept: Boolean; begin // Set default accept:=False; // Check for outlook mail item fc.cfFormat:=CF_FILECONTENTS; fc.ptd:=nil; fc.dwAspect:=1; fc.lindex:=0; fc.tymed:=TYMED_ISTORAGE; if dataObj.GetData(fc, stgm) = S_OK then begin pstg:=IStorage(stgm.stg); // Hard coded to open the outlook message item stream if (pstg.OpenStream('__substg1.0_1000001E', nil, STGM_SHARE_EXCLUSIVE or STGM_READ, 0, pstm) = S_OK) then begin accept:=True; pstm:=nil; end; pstg:=nil; ReleaseStgMedium(stgm); end; // Dont allow drop if not an outlook mail item if not(accept) then begin result:=S_FALSE; exit; end; // Success result:=S_OK; // Send the drag enter message to the control (subclassed as panel) if Assigned(TPanel(FControl).OnDragOver) then begin accept:=False; TPanel(FControl).OnDragOver(FControl, Self, pt.x, pt.y, dsDragEnter, accept); if not(accept) then dwEffect:=DROPEFFECT_NONE; end end; function TOlMailDragDrop.DragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; var accept: Boolean; begin // Always return success result:=S_OK; // Send the drag move message to the control (subclassed as panel) if Assigned(TPanel(FControl).OnDragOver) then begin accept:=False; TPanel(FControl).OnDragOver(FControl, Self, pt.x, pt.y, dsDragMove, accept); if not(accept) then dwEffect:=DROPEFFECT_NONE; end else dwEffect:=DROPEFFECT_NONE; end; function TOlMailDragDrop.DragLeave: HResult; stdcall; var accept: Boolean; pt: TPoint; begin // Always return success result:=S_OK; // Send the drag record message to the control (subclassed as panel) if Assigned(TPanel(FControl).OnDragOver) then begin accept:=False; pt:=FControl.ScreenToClient(Point(0, 0)); TPanel(FControl).OnDragOver(FControl, Self, pt.x, pt.y, dsDragLeave, accept); end; end; function TOlMailDragDrop.Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; var oditem: TOLMailDrop; stgm: tagSTGMEDIUM; stgmitem: tagSTGMEDIUM; tsitems: TStringList; stat: STATSTG; pstg: IStorage; pstm: IStream; polmi: POLMailItem; fc: tagFORMATETC; szhead: String; buff: PChar; pfgd: PFileGroupDescriptor; dwCount: Integer; dwfetch: Integer; begin // Always return success result:=S_OK; // Allocate string list for text form of dropped mail items tsitems:=TStringList.Create; // Send the drop message to the control (subclassed as panel) if Assigned(TPanel(FControl).OnDragDrop) then begin // Create the OLE drop item oditem:=TOLMailDrop.Create; // Get the text first fc.cfFormat:=CF_TEXT; fc.ptd:=nil; fc.dwAspect:=1; fc.lindex:=-1; fc.tymed:=TYMED_HGLOBAL; if (dataObj.GetData(fc, stgm) = S_OK) then begin tsitems.Text:=String(PChar(GlobalLock(stgm.hGlobal))); GlobalUnlock(stgm.hGlobal); ReleaseStgMedium(stgm); end; // First line should contain the header, so remove it if (tsitems.Count 0) then tsitems.Delete(0); // Get the file descriptors fc.cfFormat:=CF_FILEDESCRIPTOR; fc.ptd:=nil; fc.dwAspect:=1; fc.lindex:=-1; fc.tymed:=TYMED_HGLOBAL; if (dataObj.GetData(fc, stgm) = S_OK) then begin pfgd:=PFileGroupDescriptor(GlobalLock(stgm.hGlobal)); // Iterate each of the files for dwCount:=0 to pfgd.cItems-1 do begin // Set up for getting the file data fc.cfFormat:=CF_FILECONTENTS; fc.ptd:=nil; fc.dwAspect:=1; fc.lindex:=dwCount; fc.tymed:=TYMED_ISTORAGE; if (dataObj.GetData(fc, stgmitem) = S_OK) then begin // IStorage (handle the outlook item) pstg:=IStorage(stgmitem.stg); // Hard coded to open the outlook message item stream if (pstg.OpenStream('__substg1.0_1000001E', nil, STGM_SHARE_EXCLUSIVE or STGM_READ, 0, pstm) = S_OK) then begin pstm.Stat(stat, STATFLAG_DEFAULT); buff:=AllocMem(stat.cbSize); pstm.Read(buff, stat.cbSize, @dwFetch); // Build the mail item New(polmi); // Parse the header record if (tsitems.Count dwCount) then begin szhead:=tsitems[dwcount]; polmi.From:=Copy(szhead, 1, Pos(#9, szhead)-1); Delete(szhead, 1, Pos(#9, szhead)); polmi.Subject:=Copy(szhead, 1, Pos(#9, szhead)-1); Delete(szhead, 1, Pos(#9, szhead)); polmi.Received:=Copy(szhead, 1, Pos(#9, szhead)-1); Delete(szhead, 1, Pos(#9, szhead)); polmi.Size:=Copy(szhead, 1, Pos(#9, szhead)-1); Delete(szhead, 1, Pos(#9, szhead)); end else begin polmi.From:=''; polmi.Subject:=''; polmi.Received:=''; polmi.Size:=''; end; // Set the msg body polmi.Body:=String(buff); // Add the mail item oditem.AddItem(polmi); // Free buffer memory FreeMem(buff); // Free the stream pstm:=nil; end; // Free the storage pstg:=nil; // Release the storage medium ReleaseStgMedium(stgmitem); end; end; // Unlock the memory GlobalUnLock(stgm.hGlobal); // Release the storage medium ReleaseStgMedium(stgm); end; // Pass the OLE drop item as the source TPanel(FControl).OnDragDrop(FControl, oditem, pt.x, pt.y); // Free the string list tsitems.Free; // Free the OLE drop item oditem.Free; end else dwEffect:=DROPEFFECT_NONE; end; function TOlMailDragDrop.QueryInterface(const IID: TGUID; out Obj): HResult; begin // Return the requested interface if GetInterface(IID, Obj) then result:=S_OK else result:=E_NOINTERFACE; end; function TOlMailDragDrop._AddRef: Integer; begin // Increment and return the ref count Inc(FRefCount); result:=FRefCount; end; function TOlMailDragDrop._Release: Integer; begin // Decrement and return the ref count Dec(FRefCount); result:=FRefCount; end; constructor TOlMailDragDrop.Create(AControl: TWinControl); begin // Perform inherited inherited Create; // Set ref count FRefCount:=1; // Set control and register as drop target FControl:=AControl; RegisterDragDrop(FControl.Handle, Self); end; destructor TOlMailDragDrop.Destroy; begin // Revoke the drop target RevokeDragDrop(FControl.Handle); // Perform inherited inherited Destroy; end; initialization // Initialize the OLE libraries OleInitialize(nil); // Register the clipboard formats that we need to handle in the // OLE drag drop operation CF_FILECONTENTS:=RegisterClipboardFormat(CFSTR_FILECONTENTS); CF_FILEDESCRIPTOR:=RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR); finalization OleUninitialize; end. also have a look at UNDU: http://www.undu.com/Articles/990111b.html