Copy/paste grid image in Excel not as good as export to Excel

Dear all

In my app a TAdvStringGrid with 2 columns displays JPG images in column 2 (see screenshot 3).
The images are loaded with:
AGrid.CreateFilePicture(1, irow, true, ShrinkWithAspectRatio, 10, haLeft, vaTop).Filename := sFilenameLong;

When exporting the grid, images are transferred to the XLSX file (see screenshot 2):
asgExcelExport.AdvStringGrid := AExportGrid;
asgExcelExport.Export(SaveDlg.Filename);

However when copying the grid to the clipboaed and the pasting it into Excel a lot of formatting and also the images get lost (see screenshot 1):
asg_doc.Navigation.AllowClipboardAlways := true;
asg_Doc.ExcelClipboardFormat := true;
asg_Doc.Navigation.AllowFmtClipboard := true;
asg_Doc.Navigation.CopyHTMLTagsToClipboard := true;
asg_Doc.CopyToClipBoardAsHTML;

Any idea how to have the same perfect result as with export?

My environment: Delphi Prof. 11.3. Patch 1; TMS VCL UI Pack 13.0.8.0; TMS Flexcel 7.21.0.0; Microsoft Office Home and Business 2019

Best regards HG Kneip

CopyPasteToExcel

Export to Excel

GridwImage

Hi,
It is sadly not possible (not by us, and not by anyone, including Excel itself) to include images when copying cells to paste in Excel. Yes, I know, You can ctrl-c some cells with images in Excel, then open a new file also in Excel, ctrl-v and the image will be copied. But this is because Excel bypasses the clipboard and copies the stuff directly.

If you do the following:

  1. Create a file with an image:
    image

  2. Copy the cells from A1 to D10 in Excel
    image

  3. Close Excel completely. (This is important. If Excel remains in memory, it will bypass the clipboard and paste the image)

  4. Open a new file, and ctrl-V:

The image won't be there anymore. We can't bypass the clipboard as Excel does, so we are subject to the limitations the clipboard has. Besides the image thing, the other limitation is that strings will be cut at 256 characters: FlexCel API Developer Guide | FlexCel Studio for VCL and FireMonkey documentation

Now, if those aren't deal breakers, some other stuff like merged cells, formulas and such can be copied, and you might be able to improve a little over what you have (but not much).
Using the code in this example: Copy and paste (Delphi) | FlexCel Studio for VCL and FireMonkey documentation

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, UAdvGridExcelExport, FlexCel.Core, FlexCel.XlsAdapter,
  AdvUtil, Vcl.Grids, AdvObj, BaseGrid, AdvGrid;

type
  TForm1 = class(TForm)
    AdvGridExcelExport1: TAdvGridExcelExport;
    AdvStringGrid1: TAdvStringGrid;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation
uses Clipbrd;

{$R *.dfm}

procedure CopyToClipboard(const DataFormat: TFlexCelClipboardFormat; const DataStream: TStream);
var
  MyHandle: THandle;
  BiffPtr: pointer;
  FreeHandle: boolean;
  Df: string;
begin
  DataStream.Position := 0;
  FreeHandle := true;
  MyHandle := GlobalAlloc(GMEM_MOVEABLE, DataStream.Size);
  try
    BiffPtr := GlobalLock(MyHandle);
    try
      DataStream.ReadBuffer(BiffPtr^, DataStream.Size);
    finally
      GlobalUnlock(MyHandle);
    end; //finally

    Clipboard.Open;
    try
      //Text format is standard, must be handled differently.
      if DataFormat = TFlexCelClipboardFormat.Text then
      begin
         //Setting CF_UNICODE_TEXT will also set CF_TEXT and CF_OEMTEXT
         Clipboard.SetAsHandle(CF_UNICODETEXT, MyHandle);
      end else
      begin
        //Other formats than TEXT must be registered with RegisterClipboardFormat.
        Df := TFlexCelDataFormats.GetString(DataFormat);
        Clipboard.SetAsHandle(RegisterClipboardFormat(PChar(Df)), MyHandle);
      end;
      FreeHandle := false;       //Note that we dont have to free MyHandle if the clipboard takes care of it
    finally
      Clipboard.Close;
    end; //Finally
  except
    if FreeHandle then GlobalFree(MyHandle);
    raise
  end; //except
end;

procedure CopyXlsToClipboard(const Xls: TExcelFile);
begin
  try
    Clipboard.Clear;
    Clipboard.Open; //The other open calls in CopyToCliboard will be ignored.
    try
      for var cf := Low(TFlexCelClipboardFormat) to High(TFlexCelClipboardFormat) do
      begin
        var DataStream := TMemoryStream.Create;
        try
          Xls.CopyToClipboardFormat(TFlexCelClipboardFormat.Xls, TXlsCellRange.Create(1, 1, 10, 10), DataStream);
          // You could also coy the full sheet with:
          //Xls.CopyToClipboard(cf, DataStream);
          //Copying the full sheet allows for copying column widths/row heights and column/row formats too.
          CopyToClipboard(cf, DataStream);
        finally
          FreeAndNil(DataStream)
        end;
      end;
    finally
      Clipboard.Close;
    end;
  except on ex: Exception do
    begin
      ShowMessage(ex.Message);
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  AdvStringGrid1.Cells[1,1] := 'hello';
  var Xls := TXlsFile.Create(1, TExcelFileFormat.v2023, true);
  try
    AdvGridExcelExport1.Export(Xls);
    var Data := TMemoryStream.Create;
    try
      CopyXlsToClipboard(Xls);

    finally
      Data.Free;
    end;
  finally
    Xls.Free;
  end;
end;

end.

Very helpful explanations indeed. It is better to now where the limitations are - and why - instead of trying yet another idea. I will try your example asap. But I assume I have to become more acquainted with the Flexcel help first. Thank you very much. HG Kneip