I am trying to read the cell value from an Excel sheet, and used Value and Value2 to see the Cell value. It keeps throwing "System.NullReferenceException: 'Object reference not set to an instance of an object.'" Error. I am unable to figure out where is the issue in code.
I know the file path and the Excel sheet it's reading is correct.
public String readEDriver()
{
int nRows = 1;
int nCols = 1;
String driverLoc = null;
Excel.Application excelApp = new Excel.Application();
if (excelApp != null)
{
Workbook excelWorkbook;
excelWorkbook = excelApp.Workbooks.Open("C:\\A\\Config.xlsx", 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
Worksheet excelWorksheet;
excelWorksheet = (Excel.Worksheet)excelWorkbook.Worksheets[1];
excelWorksheet.Activate();
String eName =excelWorksheet.Name;
if (excelWorksheet == null)
{
throw new Exception(string.Format("Named worksheet ({0}) not found.", excelWorksheet));
}
else
{
var cellVal = ((Microsoft.Office.Interop.Excel.Range)excelWorksheet.Cells[nRows, nCols]).Value2;
if (excelWorksheet.Cells[nRows,nCols]!=null)
{
cellVal = ((Microsoft.Office.Interop.Excel.Range)excelWorksheet.Cells[nRows, nCols]).Value2;
driverLoc = cellVal.ToString();
}
}
excelWorkbook.Close();
excelApp.Quit();
}
return driverLoc;
}
it breaks at the
var cellVal = ((Microsoft.Office.Interop.Excel.Range)excelWorksheet.Cells[nRows, nCols]).Value2;
It fails to retrieve the Excel Range and gives NullReferenceException
Message:
System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
I tried your code because it seemed OK.
It works for me with a couple of minor compiling topics:
1.- Use "/" instead od "\" for the paths. Windows doesn´t like those.
2.- I had to add the Excel.Workbook and Excel.Worksheet because the compiler warned me
Apart from that it works. Below your code with my slight corrections.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Excel = Microsoft.Office.Interop.Excel;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string aux = readEDriver();
Console.WriteLine(aux);
Console.ReadLine();
}
public static string readEDriver()
{
int nRows = 1;
int nCols = 1;
String driverLoc = null;
Excel.Application excelApp = new Excel.Application();
if (excelApp != null)
{
Excel.Workbook excelWorkbook;
excelWorkbook = excelApp.Workbooks.Open("C:/Users/Usuario/Desktop/PruebasTxtFile.xlsx", 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
Excel.Worksheet excelWorksheet;
excelWorksheet = (Excel.Worksheet)excelWorkbook.Worksheets[1];
excelWorksheet.Activate();
String eName = excelWorksheet.Name;
if (excelWorksheet == null)
{
throw new Exception(string.Format("Named worksheet ({0}) not found.", excelWorksheet));
}
else
{
var cellVal = ((Microsoft.Office.Interop.Excel.Range)excelWorksheet.Cells[nRows, nCols]).Value2;
if (excelWorksheet.Cells[nRows, nCols] != null)
{
cellVal = ((Microsoft.Office.Interop.Excel.Range)excelWorksheet.Cells[nRows, nCols]).Value2;
driverLoc = cellVal.ToString();
}
}
excelWorkbook.Close();
excelApp.Quit();
}
return driverLoc;
}
}
}
Hope that helps!
Related
The Bellow function is used to formate the excel file but after running the function the Application Excel is not closeing from the Try.. (not able to kill the application) Please Help me on this
private void FormateExcelFile()
{
try
{
int nI = 0;//For Loop
string nFieldName = string.Empty;
nUserName= WindowsIdentity.GetCurrent().Name; //Get Windows Login User
string reportFilenPath = Application.StartupPath + "\\OutPutFiles\\" + "NewTempFile.xls";
string connString = "provider=Microsoft.Jet.OLEDB.4.0;Data Source='" + reportFilenPath + "';Extended Properties=Excel 8.0;";
DataTable parts = new DataTable();
using (OleDbConnection conn = new OleDbConnection(connString))
{
string sqlParts = "Select * from [" + nSheetName + "]";
OleDbDataAdapter adapter = new OleDbDataAdapter(sqlParts, conn);
adapter.Fill(parts);
}
for (nI = 0; nI < parts.Columns.Count; nI++)
{
DataColumn column = parts.Columns[nI];
if (nI == 0) { nFieldName = column.ColumnName; }
else { nFieldName = nFieldName + "," + column.ColumnName; }
}
parts.Dispose(); parts = null;
oExcel = new Excel.Application();
oBook = oExcel.Workbooks.Open(reportFilenPath, 0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
oSheet = (Microsoft.Office.Interop.Excel.Worksheet)oBook.Worksheets.get_Item(nSheetName.Replace("$", ""));
oExcel.DisplayAlerts = false;
oExcel.Visible = true;
//Check the Field Is Avilable in the Sheet if not then Add
if (nFieldName.Contains("Sub Device") == false)
{
nRng = oSheet.get_Range("A1", oMissing);
nRng.EntireColumn.Insert(Microsoft.Office.Interop.Excel.XlInsertShiftDirection.xlShiftToRight, false);
oSheet.Cells[1, 1] = "Sub Device";
}
if (nFieldName.Contains("Brand") == false)
{
nRng = oSheet.get_Range("A1", oMissing);
nRng.EntireColumn.Insert(Microsoft.Office.Interop.Excel.XlInsertShiftDirection.xlShiftToRight, false);
oSheet.Cells[1, 1] = "Brand";
}
if (nFieldName.Contains("Model") == false)
{
nRng = oSheet.get_Range("A1", oMissing);
nRng.EntireColumn.Insert(Microsoft.Office.Interop.Excel.XlInsertShiftDirection.xlShiftToRight, false);
oSheet.Cells[1, 1] = "Model";
}
if (nFieldName.Contains("Product Details") == false)
{
nRng = oSheet.get_Range("A1", oMissing);
nRng.EntireColumn.Insert(Microsoft.Office.Interop.Excel.XlInsertShiftDirection.xlShiftToRight, false);
oSheet.Cells[1, 1] = "Product Details";
}
if (nFieldName.Contains("Price") == false)
{
nRng = (Excel.Range)oSheet.Cells[1, 1];
//nRng = oSheet.get_Range("A1", oMissing);
nRng.EntireColumn.Insert(Microsoft.Office.Interop.Excel.XlInsertShiftDirection.xlShiftToRight, false);
oSheet.Cells[1, 1] = "Price";
}
oBook.Save();
oBook.Close(false, oMissing, oMissing);
oExcel.DisplayAlerts = true;
releaseObject(oSheet);
releaseObject(oBook);
oExcel.Quit();
releaseObject(oExcel);
releaseObject(nRng);
nRng = null;
oExcel = null;
oSheet = null;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
releaseObject(oSheet);
releaseObject(oBook);
//oExcel.Quit();
releaseObject(oExcel);
}
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Exception Occured while releasing object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
You need to release all the Excel objects you're referencing. For example:
if (nFieldName.Contains("Sub Device") == false)
{
nRng = oSheet.get_Range("A1", oMissing);
nRng.EntireColumn.Insert(Microsoft.Office.Interop.Excel.XlInsertShiftDirection.xlShiftToRight, false);
oSheet.Cells[1, 1] = "Sub Device";
}
should be something like (leaving out try/finally for simplicity)
if (nFieldName.Contains("Sub Device") == false)
{
nRng = oSheet.get_Range("A1", oMissing);
var col = nRng.EntireColumn
col.Insert(Microsoft.Office.Interop.Excel.XlInsertShiftDirection.xlShiftToRight, false);
var cells = oSheet.Cells;
var firstCell = cells[1,1];
firstCell.Value = "Sub Device";
Marshal.ReleaseComObject(nRng);
Marshal.ReleaseComObject(col);
Marshal.ReleaseComObject(cells);
Marshal.ReleaseComObject(firstCell);
}
Similarly:
oBook = oExcel.Workbooks.Open(reportFilenPath, 0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
oSheet = (Microsoft.Office.Interop.Excel.Worksheet)oBook.Worksheets.get_Item(nSheetName.Replace("$", ""));
needs to be:
oBooks = oExcel.Workbooks
oBook = oBooks.Open(...);
oSheets = oBook.Worksheets
oSheet = oSHeets.get_Item(...);
and you need to release oBooks and oSheets.
Try to end your excel task with these commands:
Marshal.FinalReleaseComObject(sheet);
app.DisplayAlerts = false; //Very important!
range = null;
sheet = null;
// Garbage collecting
GC.Collect();
GC.WaitForPendingFinalizers();
book.Close(false, Missing.Value, Missing.Value);
Marshal.FinalReleaseComObject(book);
book = null;
app.Quit();
Marshal.FinalReleaseComObject(app);
app = null;
I had the same problem accessing my excel files, but with the shown code it closes all the time.
Of course not if the program crashes before it reaches the code, check your code with the debugger.
In your case: book --> oBook, app --> oExcel, sheet --> oSheet.
Take away these lines:
nRng = null;
oExcel = null;
oSheet = null;
I think you are releasing your Excel object, and then by making it equal to null afterwards you are doing something with Excel which starts a new instance on your machine.
After releasing the object, you don't need to set variables to null, or run GC.Collect();, the garbage collector will take care of this for you, and I think in this instance trying to clean up the managed objects yourself (after correctly cleaning up the unmanaged Excel object) is actually causing your problems.
I had the same kind of issue working with Excel interop. The problem should be originated by this kind of lines (at least it was in my case):
oBook = oExcel.Workbooks.Open(reportFilenPath, 0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
In the end you reales oBook, but this is what's really happening here: in order to get oBook pointing to your opened workbook, you accessed a Workbooks object (using oExcel.Workbooks). This is never released, and keeps Excel from quitting.
I solved the problem by rewriting that line as:
Microsoft.Interop.Excel.Workbooks oBooks = oExcel.Workbooks;
oBook = oBooks.Open(reportFilenPath, 0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
releaseObject(oBooks);
Of course this has to be done for every line of this kind (for instance oBook.Worksheets.get_Item(...), nRng.EntireColumn.Insert(...), and so on).
Hi i have written code using the Microsoft.Office.Interop.Excel dll but it is not supported online when i published my website. I then found the EPPlus dll witch is supported online but i am having troubles converting the code to use this new dll.
Old Code useing Interop.Excel:
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet[] xlWorkSheet = new Excel.Worksheet[8];
public void ToSpreadSheet()
{
xlApp = new Excel.ApplicationClass();
xlWorkBook = xlApp.Workbooks.Open(tempFolderPathAlt + "dvforms\\InvestecTemplate.xlsx", 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
xlWorkSheet[0] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
xlWorkSheet[1] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(2);
xlWorkSheet[2] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(3);
xlWorkSheet[3] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(4);
xlWorkSheet[4] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(5);
xlWorkSheet[5] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(6);
xlWorkSheet[6] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(7);
xlWorkSheet[7] = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(8);
}
This worked great but now i need to use the EPPlus dll and i'm having problems.
using Excel = OfficeOpenXml;
Excel.ExcelPackage xlApp;
Excel.ExcelWorkbook xlWorkBook;
Excel.ExcelWorksheet[] xlWorkSeet = new Excel.ExcelWorksheet[8];
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(tempFolderPathAlt + "dvforms\\InvestecTemplate.xlsx");
Excel.ExcelPackage xlApp = new Excel.ExcelPackage(stream);
//This is where the problems begin, xlWorkBook.Worksheets.Add(1) is all underlined in red.
xlWorkSeet[0] = (Excel.ExcelWorksheet)xlWorkBook.Worksheets.Add(1);
How do i load the work sheets from my Excel template? I am unsure if i have done the above correctly, Please help i need it badly.
Thanks in advance.
FileInfo existingFile = new FileInfo(filePath);
using (var package = new ExcelPackage(existingFile))
{
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
int i = 0;
foreach(ExcelWorksheet worksheet in workBook.Worksheets)
{
xlWorkSeet1[i] = worksheet;
i = i + 1;
}
}
}
The function Add() takes in a string parameter that's the name of your worksheet. Try:
xlWorkSeet[0] = (Excel.ExcelWorksheet)xlWorkBook.Worksheets.Add("Sheet1");
inside my class i am declaring
public Excel.Range range { get; set; }
the constructor of the class calls this method:
private void OpenWorkBook()
{
string str;
int rCnt = 0;
int cCnt = 0;
xlApp = new Excel.ApplicationClass();
xlWorkBook = xlApp.Workbooks.Open(MasterFileName, 0, true, 5, "", "", true,
Microsoft.Office.Interop.Excel.XlPlatform.xlWindows,
"\t", false, false, 0, true, 1, 0);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
range = xlWorkSheet.UsedRange;
}
after that when i reference range from a different method:
public void CreateFiles(string column)
{
try
{
var valueRange = range.get_Range(column + "3", column + range.Rows.Count.ToString());
var deleteRange = range;
i am getting:
valueRange threw an exception of type System.Runtime.InteropServices.InvalidComObjectException'
does anyone know why i am losing the contents of this variable?
here's my full code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
namespace EmailSalesVolumeSolution
{
class WorkBook
{
public string MasterFileName { get; set; }
public string[] DistinctEmails { get; set; }
public Excel.Application xlApp {get;set;}
public Excel.Workbook xlWorkBook { get; set; }
public Excel.Worksheet xlWorkSheet { get; set; }
public Excel.Range range { get; set; }
private void OpenWorkBook()
{
string str;
int rCnt = 0;
int cCnt = 0;
xlApp = new Excel.ApplicationClass();
xlWorkBook = xlApp.Workbooks.Open(MasterFileName, 0, true, 5, "", "", true,
Microsoft.Office.Interop.Excel.XlPlatform.xlWindows,
"\t", false, false, 0, true, 1, 0);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
range = xlWorkSheet.UsedRange;
}
public WorkBook(string filename)
{
MasterFileName = filename;
//xlWorkBook = null;
//xlApp = null;
//xlWorkSheet = null;
//range = null;
OpenWorkBook();
}
public void SendEmail()
{
}
public void CreateFiles(string column)
{
try
{
var valueRange = range.get_Range(column + "3", column + range.Rows.Count.ToString());
var deleteRange = range;
string cell = "";
DistinctEmails = DistinctValues(valueRange);
foreach (string email in DistinctEmails)
{
for (int rCnt = 2; rCnt <= valueRange.Rows.Count; rCnt++)
{
cell = (string)(valueRange.Cells[rCnt, 1] as Excel.Range).Value2;
if (cell == null || cell != email)
{
deleteRange=xlWorkSheet.get_Range(column + rCnt.ToString() + ":" + column + rCnt.ToString(), Type.Missing);
deleteRange.Delete(Excel.XlDeleteShiftDirection.xlShiftUp);
}
}
xlWorkBook.SaveAs(xlWorkBook.Path + #"\" + email, Excel.XlFileFormat.xlWorkbookDefault, Type.Missing, Type.Missing,
false, false, Excel.XlSaveAsAccessMode.xlNoChange,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
finally
{
//DisposeMe();
// Release all COM RCWs.
// The "releaseObject" will just "do nothing" if null is passed,
// so no need to check to find out which need to be released.
// The "finally" is run in all cases, even if there was an exception
// in the "try".
// Note: passing "by ref" so afterwords "xlWorkSheet" will
// evaluate to null. See "releaseObject".
releaseObject( xlWorkSheet);
releaseObject( xlWorkBook);
// The Quit is done in the finally because we always
// want to quit. It is no different than releasing RCWs.
if (xlApp != null)
{
xlApp.Quit();
}
releaseObject( xlApp);
}
}
private string[] DistinctValues(Excel.Range EmailList)
{
string cell = "";
List<string> emails = new List<string>();
for (int rCnt = 1; rCnt <= EmailList.Rows.Count; rCnt++)
{
cell = (string)(EmailList.Cells[ rCnt,1] as Excel.Range).Value2;
if (cell!=null)
emails.Add(cell.ToString());
}
releaseObject(EmailList);
return emails.Distinct().ToArray();
}
private void releaseObject( object obj) // note ref!
{
// Do not catch an exception from this.
// You may want to remove these guards depending on
// what you think the semantics should be.
if (obj != null && Marshal.IsComObject(obj))
{
Marshal.ReleaseComObject(obj);
}
// Since passed "by ref" this assingment will be useful
// (It was not useful in the original, and neither was the
// GC.Collect.)
obj = null;
}
private void DisposeMe()
{
// Cleanup:
GC.Collect();
GC.WaitForPendingFinalizers();
Marshal.FinalReleaseComObject(xlWorkSheet);
xlWorkBook.Close(false, Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(xlWorkBook);
xlApp.Quit();
Marshal.FinalReleaseComObject(xlApp);
}
}
}
here's how i instantiate the class!!
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog.
if (result == DialogResult.OK) // Test result.
InitializeWorkBook(openFileDialog1.FileName);
}
private void InitializeWorkBook(string filename)
{
WorkBook wb= new WorkBook(filename);
wb.CreateFiles("A");
}
I've written this code to count the number of rows that are populated in an excel worksheet. It works until it gets yo a certain number of rows (not the total). Then comes up with the error message "Exception from HRESULT: 0x800A01A8" Any help much appreciated
namespace ConsoleApplication1
{
class ExcelClass
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Excel.Application excelApp = new Excel.Application(); // Creates a new Excel Application
excelApp.Visible = true; // Makes Excel visible to the user.
// The following code opens an existing workbook
string workbookPath = "D:\\RSG_D.xls"; // Add your own path here
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath, 0,
false, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true,
false, 0, true, false, false);
// The following gets the Worksheets collection
Excel.Sheets excelSheets = excelWorkbook.Worksheets;
// The following gets Sheet1 for editing
string currentSheet = "Sheet1";
Excel.Worksheet excelWorksheet = (Excel.Worksheet)excelSheets.get_Item(currentSheet);
//declare a variable to hold the CurrentCulture
System.Globalization.CultureInfo oldCI;
//get the old CurrenCulture and set the new, en-US
//void SetNewCurrentCulture()
//{
oldCI = System.Threading.Thread.CurrentThread.CurrentCulture;
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
//}
int rowCounter = 1;
while ( rowCounter != null)
{
Excel.Range countRows = (Excel.Range)excelWorksheet.Cells[rowCounter, 1] as Excel.Range;
object CountRows = countRows.Value;
rowCounter++;
Console.WriteLine(CountRows);
}
excelWorkbook.Close(0);
excelApp.Quit();
//reset Current Culture back to the originale
System.Threading.Thread.CurrentThread.CurrentCulture = oldCI;
}
}
}
I had the exact same problem tonight: Here is the code I have used and it's worked properly for me:
Excel.Application oExcel = new Excel.Application();
//oExcel.Visible = true; (this caused me huge problems
Excel.Workbook oBook = oExcel.Workbooks.Open(#"C:\Yoink\Birr Castle Demesne Interactive Map\Birr Castle Demesne Interactive Map\bin\Debug\Red Tree Trail.xlsx");
Excel.Worksheet oSheet1 = oBook.Worksheets["Red Tree Trail"] as Excel.Worksheet; (use your own worksheet title there)
Excel.Range rng = oSheet1.get_Range("A1", "AJ51"); (use your own range there
int rowCount = rng.Rows.Count;
int colCount = rng.Columns.Count;
string[,] tsReqs = new string[rowCount, colCount];
for (int i = 1; i <= rowCount; i++)
{
for (int j = 1; j <= colCount; j++)
{
string str = rng.Cells[i, j].Text;
tsReqs[i - 1, j - 1] = str;
}
}
I think your problem is in this line:
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath, 0,
false, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true,
false, 0, true, false, false);
I am creating an excel application with c#.
Since I will maintain the excel file in urgency I want to keep its handler open.
I want to keep the excel process id so I will be able to kill it in case the system crashs.
How can I get the Excel Pid when creating it?
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
using System.Diagnostics;
class Sample
{
[DllImport("user32.dll")]
static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);
Process GetExcelProcess(Excel.Application excelApp)
{
int id;
GetWindowThreadProcessId(excelApp.Hwnd, out id);
return Process.GetProcessById(id);
}
}
Here's an example of how to open an Excel file using Excel-Interop, and properly disposing the instance
(source: google)
Application ExcelObj = new Application();
Workbook WB = ExcelObj.Workbooks.Open(fileName,
0, true, 5, "", "", true, XlPlatform.xlWindows, "\t",
false, false, 0, true, false, false);
Sheets sheets = WB.Worksheets;
Worksheet WS = (Worksheet)sheets.get_Item(1);
Range excelRange = WS.UsedRange;
... (DO STUFF?)
// Get rid of everything - close Excel
while (Marshal.ReleaseComObject(WB) > 0) { }
WB = null;
while (Marshal.ReleaseComObject(sheets) > 0) { }
sheets = null;
while (Marshal.ReleaseComObject(WS) > 0) { }
WS = null;
while (Marshal.ReleaseComObject(excelRange) > 0) { }
excelRange = null;
GC();
ExcelObj.Quit();
while (Marshal.ReleaseComObject(ExcelObj) > 0) { }
ExcelObj = null;
GC();
public static void GC()
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
}