###困っていること
WindowsFormアプリケーションにてエクセルファイルを選択して、
指定したファイルのデータをDataTableにセットする機能を実装しています。
メモリ不足のエラーが発生するのですが、原因がわからず困っています。
###発生している問題・エラーメッセージ
ファイル選択ボタンをクリックしてエクセルファイルのデータを取得しています。
同じファイルを選択して複数回実行したときに、
1~6回目は処理が成功するのですが、7回目でエラーが発生します。
※ファイルのサイズは522KB(65537行,256列)です。
なお、上記の問題はVisual Studioのビルドのプラットフォームターゲットをx86とし、
64bitのマシン環境で実行すると発生します。
※事情によりプラットフォームターゲットをx86にしています。
プラットフォームターゲットをAny CPU にすると発生しないことまではわかりました。
【エラー発生箇所】
DaoExcelFileクラスのReadFileメソッド
【エラーメッセージ】 プログラムを続行するための十分なメモリがありませんでした
###該当のソースコード
public partial class Form1 : Form { private UserInfoFile userFile; public Form1() { InitializeComponent(); } //ファイル選択ボタンクリック private void button1_Click(object sender, EventArgs e) { var selectFileFormat = "Excel"; //ユーザーファイルを選択してデータを読み込み FileReadWriteController.ReadUserInfoFile(selectFileFormat, out userFile); } //ファイルからデータを読み込み、書込みをコントロールするクラス public static class FileReadWriteController { ///ユーザー情報ファイルを選択して読み込み、 ///読み込んだデータをユーザー情報ファイルオブジェクトのDataTabaleにセットする public static bool ReadUserInfoFile( string selectFileFormat, out UserInfoFile userInfoFile) { OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.OK) { userInfoFile = new UserInfoFileExcel(); userInfoFile.FilePath = ofd.FileName; userInfoFile.ReadData(); return true; } else { userInfoFile = null; return false; } } } //ファイルの抽象クラス abstract public class MyFile { public string FilePath; public DataTable FileData; public MyFile() { FileData = new DataTable(); } public abstract void ReadData(); } //ユーザー情報情報ファイルの抽象クラス abstract public class UserInfoFile : MyFile { //省略 } //Excel形式のユーザー情報ファイル public class UserInfoFileExcel : UserInfoFile { public override void ReadData() { using (var excelApp = new DaoExcelFile()) { excelApp.ReadFile(FilePath, FileData, "Info"); excelApp.Quit(); } } } //Excelクラス public class DaoExcelFile : IDisposable { private object xlsApplication = null; private object xlsBooks = null; protected object XlsApplication { get { // 存在しない場合は作成する if (xlsApplication == null) { Type classType = Type.GetTypeFromProgID("Excel.Application"); xlsApplication = Activator.CreateInstance(classType); } return xlsApplication; } } // Workbooksオブジェクト protected object Workbooks { get { if (xlsBooks == null) { xlsBooks = XlsApplication.GetType().InvokeMember("Workbooks", BindingFlags.GetProperty, null, XlsApplication, null); } return xlsBooks; } } //Dispose public void Dispose() { ReleaseComObject(xlsBooks); ReleaseComObject(xlsApplication); } // COMオブジェクトのリリース public void ReleaseComObject(object target) { try { if ((target != null)) { System.Runtime.InteropServices.Marshal.ReleaseComObject(target); } } finally { target = null; } } // Excel終了 public void Quit() { XlsApplication.GetType().InvokeMember("Quit", BindingFlags.InvokeMethod, null, XlsApplication, null); } // 対象ファイルの対象シートのデータをデータテーブルにセットする public void ReadFile(string filePath, DataTable fileData, string sheetName) { object book = null; object sheets = null; object sheet = null; object cells = null; object cella = null; object cellb = null; object targetRange = null; object[,] obj1 = null; try { book = GetOpenFile(filePath); sheets = GetSheets(book); sheet = GetSheet(sheets, 1); int lastRow = 65537; int lastColumn = 256; cells = GetCells(sheet); cella = GetCell(cells, 1, 1); cellb = GetCell(cells, lastRow, lastColumn); targetRange = GetRange(sheet, cella, cellb); //*********ここでエラーが発生する //*********エラー内容:"プログラムを続行するための十分なメモリがありませんでした" //オブジェクトの2次元配列へセット //以降この配列にアクセスすることで処理を高速化 obj1 = (System.Object[,])targetRange.GetType().InvokeMember("Value2", BindingFlags.GetProperty, null, targetRange, null); } finally { //オブジェクトの解放 ReleaseComObject(targetRange); ReleaseComObject(cellb); ReleaseComObject(cella); ReleaseComObject(cells); ReleaseComObject(sheet); ReleaseComObject(sheets); ReleaseComObject(book); } } // Excelファイルを開いてオブジェクトを返す public object GetOpenFile(string xlsFilePath) { object[] parameters = new object[15]; parameters[0] = xlsFilePath; parameters[1] = Type.Missing; parameters[2] = Type.Missing; parameters[3] = Type.Missing; parameters[4] = Type.Missing; parameters[5] = Type.Missing; parameters[6] = Type.Missing; parameters[7] = Type.Missing; parameters[8] = Type.Missing; parameters[9] = Type.Missing; parameters[10] = Type.Missing; parameters[11] = Type.Missing; parameters[12] = Type.Missing; parameters[13] = Type.Missing; parameters[14] = Type.Missing; object openFile = new object(); openFile = Workbooks.GetType().InvokeMember("Open", BindingFlags.InvokeMethod, null, Workbooks, parameters); return openFile; } // Sheetsを取得 public object GetSheets(object book) { return book.GetType().InvokeMember("Worksheets", BindingFlags.GetProperty, null, book, null); } // シートインデックスからSheetを取得 public object GetSheet(object sheets, int index) { object[] parameters = new object[1]; parameters[0] = index; return sheets.GetType().InvokeMember("Item", BindingFlags.GetProperty, null, sheets, parameters); } // Cellsを取得 public object GetCells(object sheet) { return sheet.GetType().InvokeMember("Cells", BindingFlags.GetProperty, null, sheet, null); } // Cellを取得 public object GetCell(object cells, int row, int column) { object[] parameters = new Object[2]; parameters[0] = row; parameters[1] = column; return cells.GetType().InvokeMember("Item", BindingFlags.GetProperty, null, cells, parameters); } // Rangeを取得 public object GetRange(object sheet, object cell1, object cell2) { object[] parameters = new Object[2]; parameters[0] = cell1; parameters[1] = cell2; return sheet.GetType().InvokeMember("Range", BindingFlags.GetProperty, null, sheet, parameters); } } }
###試したこと
COMオブジェクトが解放されていないのかとも思いましたが、
ファイル選択ボタンのクリック時の処理が終了すれば、
タスクマネージャーにEXCEL.EXEプロセスは残っていない状態にはなっています。
###補足情報(言語/FW/ツール等のバージョンなど)
C#
NET Framework4.0
Microsoft Visual Studio 2015

回答3件
あなたの回答
tips
プレビュー