nissl-lab / npoi

a .NET library that can read/write Office formats without Microsoft Office installed. No COM+, no interop.
Apache License 2.0
5.73k stars 1.43k forks source link

CreateCellComment() on HSSF: 'An item with the same key has already been added.' #1240

Closed SergiyStoyan closed 6 months ago

SergiyStoyan commented 11 months ago

NPOI Version

2.6.2

File Type

XLS

Upload the Excel File

There is no need for a test file because the error is directly seen in the NPOI code.

Issue Description

Sometimes on calling

var drawingPatriarch = sheet.CreateDrawingPatriarch();
IClientAnchor anchor = drawingPatriarch.CreateAnchor(0,0,0,0,67,70,11,15);
drawingPatriarch.CreateCellComment(anchor);

the core throws the exception:

at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at NPOI.HSSF.Record.EscherAggregate.AddTailRecord(NoteRecord note)
   at NPOI.HSSF.UserModel.HSSFPatriarch.OnCreate(HSSFShape shape)
   at NPOI.HSSF.UserModel.HSSFPatriarch.CreateComment(HSSFAnchor anchor)

Actually it is caused by the following method in npoi-master\main\HSSF\Record\EscherAggregate.cs

        internal void AddTailRecord(NoteRecord note)
        {
            if (tailRec.ContainsKey(note.ShapeId))
                tailRec.Add(note.ShapeId, note);
            else
                tailRec[note.ShapeId] = note;
        }

Where

if (tailRec.ContainsKey(note.ShapeId))
       tailRec.Add(note.ShapeId, note);

will ALWAYS throw an exception if the key exists. It looks like a typo because if the goal was to prohibit resetting the key then why was it not done through an explicit exception instead of calling Add() as if the goal is to reset?

For some reason, sometimes, despite the anchor being created new right before calling drawingPatriarch.CreateCellComment(anchor), tailRec happens to contain the ShapeId and thus weirdly tries adding it instead of resetting. But the main bug is probably within HSSFPatriarch.NewShapeId() which assigns an occupied ID to a new Shape.

tonyqus commented 11 months ago

Please share the xls file.

SergiyStoyan commented 11 months ago

test_FailAddingComment.xls

On the attached file the code following below throws the exception 'An item with the same key has already been added.'

string file = @"c:\test_FailAddingComment.xls";
using (System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
    fs.Position = 0;
    var workbook = new HSSFWorkbook(fs);
    ISheet sheet = workbook.GetSheetAt(0);
    var drawingPatriarch2 = sheet.CreateDrawingPatriarch();
    IClientAnchor anchor2 = drawingPatriarch2.CreateAnchor(0, 0, 0, 0, 55, 71, 58, 75);
    IComment comment2 = drawingPatriarch2.CreateCellComment(anchor2);
}

The initial file was created in Excel and then edited with NPOI without issues. It was a working file. For uploading here it was cleaned from data which does not affect the issue.