outlooktarget.pas

来自「Drag files and Drop to delphi forms 0402」· PAS 代码 · 共 855 行 · 第 1/2 页

PAS
855
字号
  else
    Address := '';
  EditFrom.Text := GetSender(AMessage.Msg);
  EditFrom.Hint := Address;

  (*
  ** Get subject
  *)
  EditSubject.Text := GetSubject(AMessage.Msg);

  (*
  ** Get body
  *)
  ReadBodyText(AMessage.Msg);

  (*
  ** Get attachments
  *)
  for i := 0 to AMessage.Attachments.Count-1 do
    AddAttachment(IAttach(AMessage.Attachments[i]), i);

  (*
  ** Only display attachment listview if msg has any attachments.
  *)
  if (ListViewAttachments.Items.Count > 0) then
  begin
    FormatAttachmentList;
    r := ListViewAttachments.Items[0].DisplayRect(drBounds);
    ListViewAttachments.Height := r.Bottom-r.Top+6;
    ListViewAttachments.Top := 0;
    ListViewAttachments.Show;
    SplitterAttachments.Top := 0;
    SplitterAttachments.Show;
  end;

end;
{$RANGECHECKS ON}

procedure TFormOutlookTarget.ListViewToInfoTip(Sender: TObject;
  Item: TListItem; var InfoTip: String);
begin
  // Display email address as a hint
  InfoTip := Item.SubItems[0];
end;

procedure TFormOutlookTarget.ReadBodyText(const AMessage: IMessage);
var
  Data, Chunk: string;
  SourceStream: IStream;
  Size: integer;
  Dummy: int64;
begin
  MemoBody.Lines.Clear;

  (*
  ** We could use HrGetOneProp to get the message body, but since we would like
  ** to limit the amount of data we read, and the body can potentially be quite
  ** big, we read the body text from a stream instead.
  **
  if (Succeeded(HrGetOneProp(AMessage, PR_BODY, Prop))) then
    try
      MemoBody.Lines.Text := Prop.Value.lpszA;
    finally
      MAPIFreeBuffer(Prop);
    end;
  *)

  if (Succeeded(AMessage.OpenProperty(PR_BODY, IStream, STGM_READ, 0, IUnknown(SourceStream)))) then
  begin
    SetLength(Chunk, 64*1024);
    Data := '';

    // Read up to 256Kb from stream
    SourceStream.Seek(0, STREAM_SEEK_SET, Dummy);
    while (Succeeded(SourceStream.Read(PChar(Chunk), Length(Chunk), @Size))) and
      (Size > 0) and (Length(Data) < 1024*1024*256) do
    begin
      Data := Data+Copy(Chunk, 1, Size);
    end;

    MemoBody.Lines.Text := Data;
  end;
end;

const
  // Attachment listview column indices
  ColType = 0;
  ColSize = 1;
  ColDisplay = 2;
  ColFile = 3;

procedure TFormOutlookTarget.AddAttachment(const Attachment: IAttach; Number: integer);
var
  Method: integer;
  Item: TListItem;
  Prop: PSPropValue;
  s: string;
  Size: integer;
  Stream: IStream;
  Pos: Largeint;
  Msg: IMessage;
  SHFileInfo: TSHFileInfo;
begin
  Item := ListViewAttachments.Items.Add;
  Item.Caption := ''; // Formatted name
  Item.SubItems.Add(''); // File type
  Item.SubItems.Add(''); // Formatted size
  Item.SubItems.Add(''); // Display name
  Item.SubItems.Add(''); // File name
  Item.ImageIndex := 0;

  // Try to get size of attachment (incl. properties and other overhead).
  // Note: This seems to be the correct way of getting the attachment size, but
  // I have never seen the call succeed.
  if (Succeeded(HrGetOneProp(Attachment, PR_ATTACH_SIZE, Prop))) then
    try
      Size := Prop.Value.l;
    finally
      MAPIFreeBuffer(Prop);
    end
  else
    Size := 0;

  if (Succeeded(HrGetOneProp(Attachment, PR_ATTACH_METHOD, Prop))) then
    try
      Method := Prop.Value.l;
    finally
      MAPIFreeBuffer(Prop);
    end
  else
    Method := -1;

  case Method of
    ATTACH_BY_VALUE:
      // Attachment is a file stored in an IStream object
      begin
        // Get size of attachment stream
        if (Size = 0) and
          (Succeeded(Attachment.OpenProperty(PR_ATTACH_DATA_BIN, IStream, STGM_READ, 0, IUnknown(Stream)))) then
        begin
          Stream.Seek(0, STREAM_SEEK_END, Pos);
          Size := Pos;
        end;

        // Get attachment filename
        if (Succeeded(HrGetOneProp(Attachment, PR_ATTACH_FILENAME, Prop))) then
          try
            s := Prop.Value.lpszA;
          finally
            MAPIFreeBuffer(Prop);
          end
        else
          s := '';

        if (s = '') then
          s := format('Attachment %d', [Number]);

        Item.SubItems[ColDisplay] := s;
      end;

    ATTACH_BY_REFERENCE,
    ATTACH_BY_REF_RESOLVE,
    ATTACH_BY_REF_ONLY:
      // Attachment is a link to a file
      begin
        // Get attachment path
        if (Succeeded(HrGetOneProp(Attachment, PR_ATTACH_PATHNAME, Prop))) then
          try
            s := Prop.Value.lpszA;
          finally
            MAPIFreeBuffer(Prop);
          end
        else
          s := '';

        if (s = '') then
          s := format('File reference %d', [Number]);
        Item.SubItems[ColDisplay] := s;
      end;

    ATTACH_EMBEDDED_MSG:
      // Attachment is a message stored in an IMessage object
      begin
        // Get size of message
        if (Size = 0) and
          (Succeeded(Attachment.OpenProperty(PR_ATTACH_DATA_OBJ, IMessage, 0, 0, IUnknown(Msg)))) then
        begin
          if (Succeeded(HrGetOneProp(Msg, PR_MESSAGE_SIZE, Prop))) then
            try
              Size := Prop.Value.l;
            finally
              MAPIFreeBuffer(Prop);
            end
          else
            Size := 0;
        end;


        s := GetSubject(Msg);
        if (s = '') then
          s := format('Embedded message %d', [Number]);
        Item.SubItems[ColDisplay] := s;
        Item.SubItems[ColFile] := s+'.msg';
      end;

    // Attachment is a OLE object stored in a IStream or IStorage object
    ATTACH_OLE:
      begin
        Item.SubItems[ColDisplay] := 'OLE object';
      end;
  else
    // Unsupported attachment
    Item.SubItems[ColDisplay] := 'Unknown attachment';
  end;

  if (Item.SubItems[ColFile] = '') then
    Item.SubItems[ColFile] := Item.SubItems[ColDisplay];

  // Get the icon associated with the attachment file type
  // Beware: SHGetFileInfo can change the "current directory"
  if (Succeeded(SHGetFileInfo(PChar(Item.SubItems[ColFile]), 0, SHFileInfo, sizeOf(SHFileInfo),
      SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX or SHGFI_LARGEICON or SHGFI_TYPENAME))) then
  begin
    Item.ImageIndex := SHFileInfo.iIcon;
    Item.SubItems[ColType] := SHFileInfo.szTypeName;
  end;

  // Format the attachment size
  if (Size > 1024*1014) then
    Item.SubItems[ColSize] := IntToStr(Size div (1024*1024))+'Mb'
  else
    if (Size > 1024) then
      Item.SubItems[ColSize] := IntToStr(Size div 1024)+'Kb'
    else
      if (Size > 0) then
        Item.SubItems[ColSize] := IntToStr(Size)+' bytes'
      else
        Item.SubItems[ColSize] := '';

  // Save interface for later.
  // According to MSDN an Attachment can be opened only once (IMessage.OpenAttach).
  Item.Data := pointer(Attachment);

  // Now that the interface is stored and managed in list items's data property,
  // we avoid decrementing the reference count here.
//  pointer(Attachment) := nil;
end;

procedure TFormOutlookTarget.ListViewAttachmentsDeletion(Sender: TObject;
  Item: TListItem);
begin
  // Zap reference to IAttachment object
//  if (Item.Data <> nil) then
//    IUnknown(Item.Data)._Release;
end;

function MAPIAllocateBuffer(cbSize: ULONG; var lppBuffer: pointer): SCODE; stdcall; external 'mapi32.dll';
function MAPIFreeBuffer(lpBuffer: pointer): ULONG; stdcall; external 'mapi32.dll';

procedure TFormOutlookTarget.ListViewAttachmentsDblClick(Sender: TObject);

  procedure Execute(const FileName: string);
  begin
    if (FileName = '') then
      exit;

    // ... launch the file's default application to open it.
    Screen.Cursor := crAppStart;
    try
      Application.ProcessMessages; {otherwise cursor change will be missed}
      ShellExecute(0, nil, PChar(FileName), nil, nil, SW_NORMAL);
    finally
      Screen.Cursor := crDefault;
    end;

    // Add temp file to list of files to be deleted before we exit
    if (FCleanUpList.IndexOf(FileName) = -1) then
      FCleanUpList.Add(FileName);
  end;

var
  Attachment: IAttach;

  Method: integer;
  Prop: PSPropValue;

  FileName: string;
  SourceStream, DestStream: IStream;
  Dummy: int64;

  Msg: IMessage;

begin
  if (ListViewAttachments.Selected <> nil) and (ListViewAttachments.Selected.Data <> nil) then
  begin
    Attachment := IAttach(ListViewAttachments.Selected.Data);

    if (not Succeeded(HrGetOneProp(Attachment, PR_ATTACH_METHOD, Prop))) then
      exit;

    try
      Method := Prop.Value.l;
    finally
      MAPIFreeBuffer(Prop);
    end;

    case Method of
      ATTACH_BY_VALUE:
        // Attachment is a file stored in an IStream object
        begin
          OleCheck(Attachment.OpenProperty(PR_ATTACH_DATA_BIN, IStream, STGM_READ, 0, IUnknown(SourceStream)));

          FileName := ExtractFilePath(Application.ExeName)+
            ListViewAttachments.Selected.SubItems[ColFile];

          // Extract the attachment to an external file and...
          SourceStream.Seek(0, STREAM_SEEK_SET, Dummy);
          OleCheck(OpenStreamOnFile(@MAPIAllocateBuffer, @MAPIFreeBuffer, STGM_CREATE or STGM_READWRITE,
            PChar(FileName), nil, DestStream));
          // Another way to do it: DestStream := TFixedStreamAdapter.Create(TFileStream.Create(FileName, fmCreate), soOwned);
          SourceStream.CopyTo(DestStream, -1, Dummy, Dummy);
          DestStream := nil;

          Execute(FileName);
        end;

      ATTACH_BY_REFERENCE,
      ATTACH_BY_REF_RESOLVE,
      ATTACH_BY_REF_ONLY:
        // Attachment is a link to a file
        begin
          // Get attachment path
          if (not Succeeded(HrGetOneProp(Attachment, PR_ATTACH_PATHNAME, Prop))) then
            exit;
          try
            FileName := Prop.Value.lpszA;
          finally
            MAPIFreeBuffer(Prop);
          end;

          Execute(FileName);
        end;

      ATTACH_EMBEDDED_MSG:
        // Attachment is a message stored in an IMessage object
        begin
          // Get size of message
          if (Succeeded(Attachment.OpenProperty(PR_ATTACH_DATA_OBJ, IMessage, 0, 0, IUnknown(Msg)))) then
          begin
            with TFormOutlookTarget.Create(Self) do
            begin
              OwnedMessage := TMessage.Create(Msg);
              ViewMessage(OwnedMessage);
              Show;
              Msg := nil;
            end;
          end;
        end;

      // Attachment is a OLE object stored in a IStream or IStorage object
      ATTACH_OLE:
        // Note: The actual handling of the OLE object is beyond the scope of
        // this demo. You'll have to figure it out for yourself.
        exit;
    else
      // Unsupported attachment
      exit;
    end;
  end;
end;

procedure TFormOutlookTarget.FormatAttachmentList;
var
  i: integer;
begin
  for i := 0 to ListViewAttachments.Items.Count-1 do
    if (not MenuAttachmentViewDetails.Checked) then
    begin
      if (ListViewAttachments.Items[i].SubItems[ColSize] <> '') then
        // Display attachment as "filename (size)"
        ListViewAttachments.Items[i].Caption :=
          format('%s (%s)', [ListViewAttachments.Items[i].SubItems[ColDisplay],
            ListViewAttachments.Items[i].SubItems[ColSize]])
      else
        // Display attachment as "filename"
        ListViewAttachments.Items[i].Caption :=
          ListViewAttachments.Items[i].SubItems[ColDisplay];
    end else
      ListViewAttachments.Items[i].Caption := ListViewAttachments.Items[i].SubItems[ColDisplay];
end;

procedure TFormOutlookTarget.MenuAttachmentViewLargeIconsClick(Sender: TObject);
begin
  TMenuItem(Sender).Checked := True;
  FormatAttachmentList;
  ListViewAttachments.ViewStyle := vsIcon;
end;

procedure TFormOutlookTarget.MenuAttachmentViewSmallIconsClick(Sender: TObject);
begin
  TMenuItem(Sender).Checked := True;
  FormatAttachmentList;
  ListViewAttachments.ViewStyle := vsSmallIcon;
end;

procedure TFormOutlookTarget.MenuAttachmentViewListClick(Sender: TObject);
begin
  TMenuItem(Sender).Checked := True;
  FormatAttachmentList;
  ListViewAttachments.ViewStyle := vsList;
end;

procedure TFormOutlookTarget.MenuAttachmentViewDetailsClick(Sender: TObject);
begin
  TMenuItem(Sender).Checked := True;
  FormatAttachmentList;
  ListViewAttachments.ViewStyle := vsReport;
end;

procedure TFormOutlookTarget.ListViewAttachmentsResize(Sender: TObject);
begin
  // Work around list view resize/repaint bug.
  ListViewAttachments.Repaint;
end;

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?