C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: エクセルの指定シートを開きたい


(過去ログ 118 を表示中)

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■69096 / inTopicNo.1)  エクセルの指定シートを開きたい
  
□投稿者/ こまったちゃん (1回)-(2013/12/04(Wed) 09:13:22)

分類:[.NET 全般] 

環境:
Windows7
Visualstudio2010

ネットを調べて以下のコードにて
エクセルファイルを開くことができたのですが
指定のシートで開くことができませんでした。
指定のシートでエクセルファイルを開く方法を教えてください。

oWBook = (Excel.Workbook)(oXls.Workbooks.Open(
excelname, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing
));
int sheetId = 0;
foreach (Excel.Worksheet sh in oWBook.Sheets)
{
 sheetId++;
 if ("Work" == sh.Name) {
  oWBook.Sheets[sheetId];
  break;
 }
}
引用返信 編集キー/
■69100 / inTopicNo.2)  Re[1]: エクセルの指定シートを開きたい
□投稿者/ 魔界の仮面弁士 (445回)-(2013/12/04(Wed) 10:14:48)
No69096 (こまったちゃん さん) に返信
> Visualstudio2010
2010 ならオプション引数がサポートされているので、Type.Missing に頼る必要は無いですよ。
まぁ、Missing を使ってはいけない、というわけでは無いですけれども。


> oWBook = (Excel.Workbook)(oXls.Workbooks.Open(
COM 解放の視点から、この書き方はお奨めできません。
こういう場合には、oXls.Workbooks をいったん Workbooks 型の変数に受け取り、
処理後に ReleaseComObject しましょう。
http://bbs.wankuma.com/index.cgi?mode=red&namber=56430&KLOG=95
http://jeanne.wankuma.com/tips/csharp/programming/releasecom.html



> foreach (Excel.Worksheet sh in oWBook.Sheets)
> {
>  sheetId++;
foreach 内でインクリメントするなら、for を使った方が手っ取り早いでしょう。
COM 解放上の理由からも、foreach よりも for を使ったほうが安全です。
http://bbs.wankuma.com/index.cgi?mode=red&namber=54149&KLOG=91
http://www.divakk.co.jp/aoyagi/csharp_tips_vssenum.html


> 指定のシートでエクセルファイルを開く方法を教えてください。
ワークブックを開くことまではできているので、その後、指定したシートな
Sheet オブジェクト(Worksheet オブジェクト)の、Activate メソッドを
呼び出してみてください。処理イメージ的にはこんな感じです。

 // :
 oSheets = oWBook.Sheets;
 // :
 for (int sheetId = 1 ; sheetId <= oWorkSheets.Count; sheetId++)
 {
  oSheet = oSheets[sheetId];
  try
  {
   if(oSheet.Name == シート名)
   {
    oSheet.Activate();
    break;
   }
  }
  finally
  {
   Marshal.ReleaseComObject(oSheet);
  }
 }
 // :
 //Marshal.ReleaseComObject(oSheets);
引用返信 編集キー/
■69181 / inTopicNo.3)  Re[2]: エクセルの指定シートを開きたい
□投稿者/ 悪魔の天使 (3回)-(2013/12/09(Mon) 09:21:20)
ありがとうございます。
おそくなりました。
結局いろいろ調べてみて試行錯誤してみました。

private void button5_Click(object sender, EventArgs e)
{
 string ExcelFile = "D:Test.xls";
 System.IO.File.Delete(ExcelFile);
 Excel.Application xlApplication = null;
 Excel.Workbook xlBook = null;
 Excel.Worksheet xlSheet = null;
 Excel.Range xlRange = null;
 try
 {
  xlApplication = new Excel.Application();
  xlApplication.Visible = true;
  xlBook = xlApplication.Workbooks.Add();
  xlBook.Sheets[1].Name = "Work";
  xlBook.Sheets[2].Name = "Temp";
  xlBook.Sheets[3].Delete();
  xlSheet = xlBook.Sheets[1];
  ((Excel._Worksheet)xlSheet).Activate();
  xlBook.Sheets[2].Select();
  for (int i = 1; i < 20; i++)
  {
   xlRange = xlSheet.Cells[i, 1];
   xlRange.Value2 = i;
  }
  xlBook.SaveAs(ExcelFile, Excel.XlFileFormat.xlWorkbookNormal);
// xlBook.Close(false);
// xlApplication.Quit();
 }
 catch (Exception ex)
 {
  MessageBox.Show(ex.Message);
 }
 finally
 {
  if (xlRange != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(xlRange);
  if (xlSheet != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet);
  if (xlBook != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
  if (xlApplication != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApplication);
 }
}

SelectとActiveの違いが今一つ理解できませんでした。

引用返信 編集キー/
■69185 / inTopicNo.4)  Re[3]: エクセルの指定シートを開きたい
□投稿者/ 魔界の仮面弁士 (451回)-(2013/12/09(Mon) 11:00:31)
2013/12/09(Mon) 18:20:48 編集(投稿者)

No69181 (悪魔の天使 さん) に返信
> SelectとActiveの違いが今一つ理解できませんでした。
Active はアクティブにするためのものですが、
Select は選択するためのものです。

ワークブック上の1つのシートをアクティブにできますが、
複数のシートをアクティブにすることはできません。

一方、シートの選択に関してはその制限が無く、たとえば
Sheet2, Sheet3, Sheet5 の 3 シートを同時に選択することもできます。


複数のシートを選択するという動作は、ユーザー操作では
[Ctrl]を押しながらシートタブをクリックする行為です。
プログラムから操作する場合はこんな感じ:

 Excel.Sheets xlSheets1 = xlApplication.Sheets;

 // 2つのシートを含む Sheets コレクションを取得します
 //
 // Excel.Sheets xlSheets2 = (Excel.Sheets)xlSheets2[new string[] { "Sheet1", "Sheet3" }];
 Excel.Sheets xlSheets2 = (Excel.Sheets)xlSheets2[new int[] { 1, 3 }];
 //
 // ↑ キャストする型に注意!
 // xlSheets[ 1 ] なら Sheet が返されますが、
 / xlSheets[ 配列 ] だと Sheets が返されます

 // 2つのシートを選択します
 xlSheets2.Select();

 // 後始末
 Marshal.ReleaseComObject(xlSheets2);
 Marshal.ReleaseComObject(xlSheets1);


--------------
以下、細かい指摘事項:


>  string ExcelFile = "D:Test.xls";
= "D:\\Test.xls"; や = @"D:Test.xls"; ではなく、
= "D:Test.xls"; を指定されているのは意図的なのでしょうか。

元コードの場合、
  「DドライブのルートディレクトリにあるTest.xls」
という『絶対パス』ではなく、
  「Dドライブ上の現在のディレクトリにあるTest.xls」
という『相対パス』を意味しますが、問題ありませんか?


>  System.IO.File.Delete(ExcelFile);
ファイル操作は例外の発生を伴う可能性がありますので、
必ず try〜catch で囲みましょう。

たとえば ExcelFile が、ファイルではなくディレクトリを
指していた場合や、ファイルが他のアプリで開かれていた場合、
あるいは削除権限が無かった場合、Delete は失敗します。


> System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
コレクション系オブジェクトの解放処理が漏れています。たとえば
> xlBook = xlApplication.Workbooks.Add();

 xlBooks = xlApplication.Workbooks;
 xlBook = xlBooks.Add();
とし、Workbooks オブジェクトも ReleaseComObject に備えることが望ましいです。


また、Excel のオブジェクトでインデクサを使う場合は注意が必要です。

たとえばシート操作で使われている
> xlBook.Sheets[1].Name = "Work";
というコードは、Sheet オブジェクトを変数にとって
 xlSheets = xlBook.Sheets;
 xlSheet1 = (Excel.Worksheet)xlSheets[1]; // xlBook.get_Item(1); でも同義。
 xlSheet1.Name = "Work";
のようにします。

また、Range オブジェクトも同様です。
Cells プロパティの呼び出し部で
> for (int i = 1; i < 20; i++)
> {
>  xlRange = xlSheet.Cells[i, 1];
>  xlRange.Value2 = i;
> }
というインデクサ指定が行われていますが、これも本来は、
 Excel.Range xlCells = xlSheet.Cells;
 for (int i = 1; i < 20; i++)
 {
  Excel.Range xlRange = (Excel.Range)xlCells[i, 1];
  xlRange.Value2 = i;
  Marshal.ReleaseComObject(xlRange);
 }
 Marshal.ReleaseComObject(xlCells);
のように、一度 Range オブジェクトに受けた方が良いでしょう。

(エラー時の対処を考えると、ループ内でも try〜finally で
解放した方が望ましいですが、面倒なので上記では省略)


> xlBook = xlApplication.Workbooks.Add();
> xlBook.Sheets[1].Name = "Work";
> xlBook.Sheets[2].Name = "Temp";
> xlBook.Sheets[3].Delete();
新規ブックのシート数が、常に 3 (もしくは 3 以上)であるとは限りません。
xlApplication.SheetsInNewWorkbook を併用するようにしてみてください。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -