NET-alapú Excel használata az Excel telepített verziójától függetlenül
Működési környezet
- Visual Studio
-
- Visual Studio 2022
- .HÁLÓ
-
- .NET 6.0
- Windows
-
- Windows 7 esetén
- Windows 11 esetén
- Kitűnik
-
- Microsoft 365 esetén
- Office 2007 esetén
Előfeltételek
- Windows
-
- Az egyik változat
- Kitűnik
-
- Az egyik változat
Az Excellel működő tárakkal kapcsolatos problémák
Az Excellel való programozott interakció egyik módja a Microsoft.Office.Interop.Excel
hivatkozás.
Ez hasonló az Excel alkalmazással való közvetlen munkához a COM-on keresztül, így kissé eltér az Excel-fájlban lévő adatokkal végzett munkától.
Előfeltételként az Excelt telepíteni kell a végrehajtandó környezetbe, de az Excel számos funkciója elérhető a program oldaláról.
Microsoft.Office.Interop.Excel
Ha a programot használja, úgy gondolja, hogy a program a következő módon lesz írva.
// 実行プログラムの場所にある 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);
}
Nehézkes, hogy minden alkalommal erőforrásokat kell felszabadítania, de mivel használhatja az előkészített osztályokat, viszonylag intuitív módon végezheti el az Excel feldolgozását.
A hátránya azonban az, hogy a program által hivatkozott könyvtár verziójának meg kell egyeznie vagy kompatibilisnek kell lennie az Excel verziójával, amely abban a környezetben van telepítve, amelyben fut. Az Excel belső verziójú 15.0-s (2013-as) kódtárára hivatkozva létrehozott program például csak akkor futtatható, ha az Excel 2013 telepítve van. Ha azt szeretné, hogy a program több környezetben is fusson, előfordulhat, hogy az Excel-telepítést konzisztens verzión kell futtatnia.
Ha ilyen művelet lehetséges, akkor rendben van, de ha az Excel telepített verziója más, akkor nem helyezhető el. Ezért valamit tenni kell a program oldalán.
Könyvtárakra való dinamikus hivatkozás dinamikus hivatkozással a közvetlen hivatkozás helyett
A probléma ebben az esetben azért fordul elő, mert a program létrehozásakor a könyvtár verziójára hivatkoznak. Ez azt jelenti, hogy a program létrehozásakor a verzió meghatározása helyett a program végrehajtásakor meg kell határozni a verziót.
Ennek számos módja van, de ezúttal a "" "" és ""Type.GetTypeFromProgID
Activator.CreateInstance
használatával oldjuk meg.dynamic
Általában a C# nyelvben a típusinformációt a program létrehozásakor kell meghatározni, de ha a típus , akkor a típus dynamic
a végrehajtáskor határozható meg.
object
A típusokkal ellentétben dynamic
, ha a változóra beállított példány egy osztály, akkor az adott osztály metódusait és tulajdonságait is meghívhatja.
Mivel azonban a változóba kerülés a végrehajtás időzítésénél kerül meghatározásra, hiba lép fel a végrehajtás időpontjában, ha nincs meghatározott módszer.
Az ezekkel létrehozott kód a következő.
// 実行プログラムの場所にある 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);
}
A változó dynamic
deklarációjának típusa , és Excel.Application
a létrehozása kissé eltérő, de a kód többi része szinte újra felhasználásra kerül.
Mivel a fenti kód nem hivatkozik az Excel-kódtárra, nem lehet használni a cél Excel-hez kapcsolódó osztályinformációkat. Ezért a változó típusa mind dynamic
.
Továbbá, mivel nem hivatkozhatunk közvetlenül az osztályra, ehelyett Excel.Application
Type.GetTypeFromProgID
lekérjük a Type információtActivator.CreateInstance
, és átadjuk neki,Excel.Application
hogy létrehozzuk Excel.Application
a példányát.
By the way, olyan környezetben, ahol az Excel nincs telepítve, nem kaphatja meg Type
, így elkülöníthető, Type.GetTypeFromProgID
hogy telepítve van-e vagy sem.
dynamic
A használat hátránya, hogy az osztály nem határozható meg a program létrehozásakor.
Az Intellisense, amely egy befejező függvény a kód bevitelekor, nem jeleníti meg a metódusneveket és a tulajdonságneveket.
Lehet, hogy kevésbé nehézkes kódot írni a könyvtárra hivatkozva az elején, dynamic
és később lecserélni.
Ha Microsoft 365 környezetben fut, ellenőrizheti, hogy az alábbiak szerint jelenik meg.
Az alábbiakban az Office 2007 sokkal régebbi verzióján való futtatás eredménye. Ha nem használ olyan funkciót, amely csak egy adott verzióban működik, akkor meglehetősen széles körben működhet.
Egyébként, ha olyan környezetben futtatja, ahol az Excel nincs telepítve, helyesen megállapíthatja, hogy nem lehet feldolgozni.