Utiliser Excel dans .NET indépendamment de la version installée d’Excel

Page mise à jour :
Date de création de la page :

Environnement d’exploitation

Visual Studio
  • Visual Studio 2022
.FILET
  • .NET 6.0
Windows
  • Fenêtres 7
  • Fenêtres 11
Exceller
  • Microsoft 365 (en anglais)
  • Office 2007

Conditions préalables

Windows
  • L’une des versions
Exceller
  • L’une des versions

Problèmes avec les bibliothèques qui fonctionnent avec Excel

Une façon d’interagir par programmation avec Excel consiste Microsoft.Office.Interop.Excel à référencer . C’est similaire à travailler directement avec l’application Excel via COM, c’est donc légèrement différent de travailler avec des données dans un fichier Excel. En tant que prémisse, Excel doit être installé dans l’environnement à exécuter, mais de nombreuses fonctions d’Excel sont disponibles du côté du programme.

Microsoft.Office.Interop.Excel Si vous utilisez le programme, vous penserez que le programme sera écrit de la manière suivante.

// 実行プログラムの場所にある Excel ファイル
var excelFilePath = $@"{Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName)}\Sample.xlsx";

// Excel のオブジェクトは参照したら必ず解放する必要があります。
// 解放しないと Excel のプロセスが残り続けます。
Microsoft.Office.Interop.Excel.Application? excel = null;
Microsoft.Office.Interop.Excel.Workbooks? books = null;
Microsoft.Office.Interop.Excel.Workbook? book = null;
Microsoft.Office.Interop.Excel.Sheets? sheets = null;
Microsoft.Office.Interop.Excel.Worksheet? sheet = null;
Microsoft.Office.Interop.Excel.Range? cells = null;
Microsoft.Office.Interop.Excel.Range? range1 = null;
Microsoft.Office.Interop.Excel.Range? range2 = null;
try
{
  // Excel アプリケーションを生成(起動)します
  excel = new Microsoft.Office.Interop.Excel.Application
  {
    DisplayAlerts = false
  };

  // ワークブック一覧を参照します。参照する場合は必ず変数に保持します
  books = excel.Workbooks;

  // Excel ファイルを開きます
  book = books.Open(excelFilePath);

  // シート一覧を参照するので変数に保持します
  sheets = book.Worksheets;

  // シートを参照します。最初のシートは 1 になります
  sheet = (Microsoft.Office.Interop.Excel.Worksheet)sheets[1];

  // セル一覧を参照します
  cells = sheet.Cells;

  // 左上のセルを参照します。一番左上は [1, 1] になります
  range1 = (Microsoft.Office.Interop.Excel.Range)cells[1, 1];

  // セルの値を取得します。値の取得なので後で解放する必要はありません
  var value = (int)range1.Value;

  // 下のセルを参照します
  range2 = (Microsoft.Office.Interop.Excel.Range)cells[2, 1];

  // 日付分足してセットします
  range2.Value = DateTime.Now.Day + value;

  // 保存して閉じます
  book.Close(SaveChanges: true);

  Console.WriteLine("処理が完了しました。");
}
catch (Exception ex)
{
  // 閉じていなければ保存せずに閉じます
  // 開きっぱなしだと Excel 起動時に保存されていないデータとして表示される場合があります
  if (book != null) book.Close(SaveChanges: false);

  Console.WriteLine("処理が失敗しました。");
  Console.WriteLine(ex);
}
finally
{
  // 終了していなければ終了します
  if (excel != null) excel.Quit();

  // 例外が発生した場合でも必ずリソースを解放するようにします
  if (range1 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range1);
  if (range2 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range2);
  if (cells != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cells);
  if (sheet != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheet);
  if (sheets != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheets);
  if (book != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(book);
  if (books != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(books);
  if (excel != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);
}

Il est gênant de devoir libérer des ressources à chaque fois, mais comme vous pouvez utiliser les classes préparées, vous pouvez effectuer un traitement Excel de manière relativement intuitive.

L’inconvénient, cependant, est que la version de la bibliothèque référencée par le programme doit correspondre ou être compatible avec la version d’Excel installée dans l’environnement dans lequel il s’exécute. Par exemple, un programme créé en référençant la bibliothèque interne version 15.0 (2013) d’Excel ne peut s’exécuter que lorsque Excel 2013 est installé. Si vous souhaitez que votre programme s’exécute dans de nombreux environnements, vous devrez peut-être maintenir votre installation Excel en cours d’exécution sur une version cohérente.

Si une telle opération est possible, c’est bien, mais si la version installée d’Excel est différente, elle ne peut pas être prise en charge. Par conséquent, il est nécessaire de faire quelque chose du côté du programme.

Référencer les bibliothèques dynamiquement avec dynamic au lieu de les référencer directement

Le problème dans ce cas se produit parce que la version de la bibliothèque est référencée corrigée lors de la création du programme. Cela signifie qu’au lieu de déterminer la version au moment de la création du programme, il est nécessaire de déterminer la version au moment de l’exécution du programme.

Il y a plusieurs façons de le faire, mais cette fois-ci, nous allons le résoudre en utilisant «  » «  » et « Type.GetTypeFromProgIDActivator.CreateInstance ».dynamic

Normalement, en C#, il est nécessaire de déterminer les informations de type au moment de la création du programme, mais si le type est dynamic , le type peut être déterminé au moment de l’exécution. object Contrairement aux dynamic types, si l’instance définie sur une variable est une classe, vous pouvez également appeler les méthodes et les propriétés de cette classe. Cependant, étant donné que ce qui entre dans la variable est déterminé au moment de l’exécution, une erreur se produira au moment de l’exécution s’il n’y a pas de méthode spécifiée.

Le code créé à l’aide de ceux-ci est le suivant.

// 実行プログラムの場所にある Excel ファイル
var excelFilePath = $@"{Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName)}\Sample.xlsx";

// Excel のオブジェクトは参照したら必ず解放する必要があります。
// 解放しないと Excel のプロセスが残り続けます。
dynamic? excel = null;
dynamic? books = null;
dynamic? book = null;
dynamic? sheets = null;
dynamic? sheet = null;
dynamic? cells = null;
dynamic? range1 = null;
dynamic? range2 = null;
try
{
  // Excel.Application の Type を取得
  var type = Type.GetTypeFromProgID("Excel.Application");
  if (type == null)
  {
    Console.WriteLine("Excel がインストールされていません。");
    return;
  }

  // Excel アプリケーションを生成(起動)します
  excel = Activator.CreateInstance(type);
  if (excel == null)
  {
    Console.WriteLine("Excel.Application のインスタンスの生成に失敗しました。");
    return;
  }
  excel.DisplayAlerts = false;

  // ワークブック一覧を参照します。参照する場合は必ず変数に保持します
  books = excel.Workbooks;

  // Excel ファイルを開きます
  book = books.Open(excelFilePath);

  // シート一覧を参照するので変数に保持します
  sheets = book.Worksheets;

  // シートを参照します。最初のシートは 1 になります
  sheet = (Microsoft.Office.Interop.Excel.Worksheet)sheets[1];

  // セル一覧を参照します
  cells = sheet.Cells;

  // 左上のセルを参照します。一番左上は [1, 1] になります
  range1 = (Microsoft.Office.Interop.Excel.Range)cells[1, 1];

  // セルの値を取得します。値の取得なので後で解放する必要はありません
  var value = (int)range1.Value;

  // 下のセルを参照します
  range2 = (Microsoft.Office.Interop.Excel.Range)cells[2, 1];

  // 日付分足してセットします
  range2.Value = DateTime.Now.Day + value;

  // 保存して閉じます
  book.Close(SaveChanges: true);

  Console.WriteLine("処理が完了しました。");
}
catch (Exception ex)
{
  // 閉じていなければ保存せずに閉じます
  // 開きっぱなしだと Excel 起動時に保存されていないデータとして表示される場合があります
  if (book != null) book.Close(SaveChanges: false);

  Console.WriteLine("処理が失敗しました。");
  Console.WriteLine(ex);
}
finally
{
  // 終了していなければ終了します
  if (excel != null) excel.Quit();

  // 例外が発生した場合でも必ずリソースを解放するようにします
  if (range1 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range1);
  if (range2 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range2);
  if (cells != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cells);
  if (sheet != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheet);
  if (sheets != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheets);
  if (book != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(book);
  if (books != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(books);
  if (excel != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);
}

Le type de la déclaration de la variable est , et Excel.Application la création de est légèrement différente, mais le reste du code est dynamic presque réutilisé.

Étant donné que le code ci-dessus ne fait pas référence à la bibliothèque Excel, il n’est pas possible d’utiliser les informations de classe Excel cibles. Par conséquent, le type de la variable est all dynamic . De plus, comme nous ne pouvons pas référencer directement la classe,Excel.Application nous récupérons à la place les informations Activator.CreateInstance Type et les transmettons à Excel.Application Type.GetTypeFromProgID pour créer Excel.Application une instance de . Soit dit en passant, dans un environnement où Excel n’est pas installé, vous ne pouvez pas l’obtenir , Type.GetTypeFromProgID Type il est donc possible d’isoler s’il est installé ou non.

dynamic L’inconvénient de l’utilisation est que la classe ne peut pas être déterminée lors de la construction du programme. IntelliSense, qui est une fonction de complétion lors de la saisie de code, n’affiche pas les noms de méthodes et les noms de propriétés. Il peut être moins fastidieux d’écrire du code en se référant à la bibliothèque au début et de le remplacer par dynamic plus tard.

Lors de l’exécution dans un environnement Microsoft 365, vous pouvez confirmer qu’il est reflété comme suit.

Ce qui suit est le résultat de son exécution sur une version beaucoup plus ancienne d’Office 2007. Si vous n’utilisez pas une fonction qui ne fonctionne que dans une version spécifique, vous pouvez la faire fonctionner assez largement.

Soit dit en passant, si vous l’exécutez dans un environnement où Excel n’est pas installé, vous pouvez déterminer correctement qu’il ne peut pas être traité.