前置需求
- 參考 COM 元件:Microsoft Office 11.0 Object Library (Office 2003)
- 或透過 NuGet 安裝:
Install-Package Microsoft.Office.Interop.Excel
- 目標機器需安裝 Excel(Interop 需要 Excel 進程)
方法比較
| 方法 | API | 特點 | 適用場景 |
| 1. Pictures.Insert | Worksheet.Pictures.Insert(path) | 簡單、自動對齊儲存格、不支援指定寬高 | 快速插入、不需精確控制大小 |
| 2. Shapes.AddPicture | Worksheet.Shapes.AddPicture(...) | 可精確指定座標、寬高、是否連結檔案 | 需固定尺寸、浮動定位、不想鎖定檔案 |
完整封裝類別:ExcelReportHelper
using System;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
namespace ExcelReport
{
public class ExcelReportHelper : IDisposable
{
private Excel.Application _app;
private Excel.Workbooks _books;
private Excel._Workbook _book;
private Excel.Sheets _sheets;
private Excel._Worksheet _sheet;
private object _missing = Missing.Value;
/// 開啟 Excel,可選擇載入模板
public void Open(string templatePath = "")
{
_app = new Excel.Application
{
Visible = false,
DisplayAlerts = false
};
_books = _app.Workbooks;
_book = string.IsNullOrEmpty(templatePath)
? _books.Add(_missing)
: _books.Open(templatePath, _missing, _missing, _missing, _missing,
_missing, _missing, _missing, _missing, _missing,
_missing, _missing, _missing, _missing, _missing);
_sheets = _book.Worksheets;
_sheet = (Excel._Worksheet)_sheets.get_Item(1);
}
/// 方法一:Pictures.Insert - 簡單插入,自動對齊儲存格左上角
public void InsertPicture(string cellName, string picturePath)
{
Excel.Range range = _sheet.get_Range(cellName, _missing);
range.Select();
Excel.Pictures pics = (Excel.Pictures)_sheet.Pictures(_missing);
pics.Insert(picturePath, _missing);
}
/// 方法二:Shapes.AddPicture - 精確控制位置與尺寸
public void InsertPicture(string cellName, string picturePath, float width, float height)
{
Excel.Range range = _sheet.get_Range(cellName, _missing);
float left = (float)range.Left;
float top = (float)range.Top;
_sheet.Shapes.AddPicture(
picturePath,
Office.MsoTriState.msoFalse, // 不連結檔案,嵌入工作簿
Office.MsoTriState.msoTrue, // 隨文件儲存
left, top, width, height);
}
/// 儲存並關閉
public void SaveAs(string filePath)
{
_book.SaveAs(filePath, _missing, _missing, _missing, _missing,
_missing, Excel.XlSaveAsAccessMode.xlNoChange,
_missing, _missing, _missing, _missing, _missing);
Close();
}
private void Close()
{
_book?.Close(false, _missing, _missing);
_app?.Quit();
}
public void Dispose()
{
ReleaseCom(_sheets);
ReleaseCom(_book);
ReleaseCom(_books);
ReleaseCom(_app);
GC.Collect();
GC.WaitForPendingFinalizers();
}
private void ReleaseCom(object obj)
{
try { Marshal.ReleaseComObject(obj); }
catch { }
finally { obj = null; }
}
}
}
使用範例
using (var helper = new ExcelReportHelper())
{
helper.Open(); // 或 helper.Open(@"C:\Template.xlsx");
// 方法一:簡單插入
helper.InsertPicture("B2", @"C:\logo.gif");
// 方法二:指定尺寸 (單位:points, 1 point = 1/72 inch)
helper.InsertPicture("B8", @"C:\logo.gif", 120f, 80f);
helper.SaveAs(@"C:\Report.xlsx");
}
執行結果示意

重要提醒
- 務必呼叫 Dispose():釋放 COM 物件,否則 Excel 進程會殘留在背景
- 檔案路徑必須為絕對路徑
- 生產環境建議:改用
EPPlus、ClosedXML、NPOI 等純 .NET 程式庫,不需安裝 Excel、效能更好、支援 .NET Core/5+
- 版本相容性:程式碼檢查
_app.Version == "11.0" (Office 2003),新版 Office 可能需調整