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

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

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

Re[4]: 既に開いているエクセルファイルを操作する方法


(過去ログ 150 を表示中)

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

■87274 / inTopicNo.1)  既に開いているエクセルファイルを操作する方法
  
□投稿者/ タク (1回)-(2018/05/02(Wed) 19:04:19)

分類:[C#] 

こんにちは。
C#でエクセルの操作をするプログラムを作っています。
既に開いているエクセルファイルを操作する方法をアドバイスいただけないでしょうか。

もう少し細かくやりたい事を書くと以下です。
@:対象のエクセルファイル名を指定
A:@のエクセルファイル名が開いているか確認
B-1:@のエクセルファイル名があれば、そのファイルに対して操作を実行 ←ここがわかりません
B-2:@のエクセルファイル名が無ければ、そのファイルを開き、操作を実行

現在以下にてコードを作成しているのですが、
既にエクセルファイルが開いている状態での動作に際して、get_itemのところでエラーが出てしまいます。

-------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using uExcel = Microsoft.Office.Interop.Excel;
using System.Diagnostics; //全てのプロセスを取得する


namespace エクセル
{
class Program
{
static void Main(string[] args)
{
OpenExcel();
}

public static void OpenExcel()
{
string myExcelFileName = "XXX.xlsx";
string myExcelFilePath = @"C:\XXX.xlsx";

uExcel.Application InstExcel = new uExcel.Application();
InstExcel.Visible = true;

//全てのプロセスを列挙し、該当のエクセルファイル名がなければ開く
int FileCnt = 0;
foreach (Process myAllProcess in Process.GetProcesses())
{
//メインウィンドウのタイトルがある時だけ列挙する
if (myAllProcess.MainWindowTitle.Length != 0)
{
//該当のエクセルファイルがあればFileCntに1加算
if (myAllProcess.MainWindowTitle.IndexOf(myExcelFileName) > 0)
{
FileCnt = FileCnt + 1;
}
}
}

uExcel.Workbook myWorkBook = null;

// FileCntが0より大きければ既存ファイルありとして、既存ファイルを操作
if (FileCnt > 0) { myWorkBook = InstExcel.Workbooks.get_Item(myExcelFileName); } //◆ここでエラーがでます
if (FileCnt == 0)
{
myWorkBook = InstExcel.Workbooks.Open(myExcelFilePath);
}

// シートに記載
uExcel.Worksheet myWorkSheet=null;

myWorkSheet = myWorkBook.Sheets["Sheet1"];
myWorkSheet.Cells[3, 5] = "test";
}

}
}
引用返信 編集キー/
■87281 / inTopicNo.2)  Re[1]: 既に開いているエクセルファイルを操作する方法
□投稿者/ Atata!! (3回)-(2018/05/03(Thu) 14:01:36)
B-1 と B-2 は以下のような方法で実現できます。


●Microsoft.VisualBasic.dll を参照するのをためらわないのであれば、GetObject

using System;
using System.Runtime.InteropServices;
using uExcel = Microsoft.Office.Interop.Excel;
using Microsoft.VisualBasic;

namespace エクセル
{
    class Program
    {
        static void Main(string[] args)
        {
            OpenExcel();
        }

        public static void OpenExcel()
        {
            var myExcelFilePath = Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\Desktop\XXX.xlsx");

            var workbook = Interaction.GetObject(myExcelFilePath) as uExcel.Workbook;
            workbook.Close(false);
            Marshal.FinalReleaseComObject(workbook);
        }

    }
}
--------------------------------------------------------------------------------

●Microsoft.VisualBasic.dll を参照しない(できない)のであれば、Marshal.BindToMoniker

using System;
using System.Runtime.InteropServices;
using uExcel = Microsoft.Office.Interop.Excel;

namespace エクセル
{
    class Program
    {
        static void Main(string[] args)
        {
            OpenExcel();
        }

        public static void OpenExcel()
        {
            var myExcelFilePath = Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\Desktop\XXX.xlsx");

            var workbook = Marshal.BindToMoniker(myExcelFilePath) as uExcel.Workbook;
            workbook.Close(false);
            Marshal.FinalReleaseComObject(workbook);
        }

    }
}
--------------------------------------------------------------------------------

いずれの処理もファイルの存在確認は必要ですので、今回の要件にはピッタリ合ってると思います。

引用返信 編集キー/
■87283 / inTopicNo.3)  Re[2]: 既に開いているエクセルファイルを操作する方法
□投稿者/ タク (3回)-(2018/05/03(Thu) 15:49:23)
Atata!!さん

ありがとうございます。
教えていただいたコードで無事動作できました!

BindToMonikerも同じかもしれませんが、GetObjectでは取得できないケースがあるという記事を見ましたので、Marshal.BindToMonikerにて対応しました。
https://support.microsoft.com/ja-jp/help/238610/getobject-or-getactiveobject-cannot-find-a-running-office-application

色々とネットで調べていたのですがどうしても見つからず質問して良かったです。
本当にありがとうございました!
引用返信 編集キー/
■87286 / inTopicNo.4)  Re[3]: 既に開いているエクセルファイルを操作する方法
□投稿者/ Atata!! (4回)-(2018/05/03(Thu) 19:52:38)
> BindToMonikerも同じかもしれませんが、

MSDN に記述のある通り Marshal.BindToMoniker と GetObject は同じ機能になります。
https://msdn.microsoft.com/ja-jp/library/system.runtime.interopservices.marshal.bindtomoniker(v=vs.110).aspx

Office 2003 以前では先に挙げられた KB のような対応が必要になることがあります。
Office 2003 より後の Excel は、ほぼ起動直後にファイル(モニカ)を ROT に登録するので
以下のコードのように優先度を下げるとかしないと問題を発生させにくいかもしれません。

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using uExcel = Microsoft.Office.Interop.Excel;

namespace エクセル
{
    class Program
    {
        static void Main(string[] args)
        {
            OpenExcel();
        }

        public static void OpenExcel()
        {
            var myExcelFilePath = Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\Desktop\XXX.xlsx");

            // Excel のプロセス優先度を下げて起動する。
            var psi = new ProcessStartInfo("CMD.EXE" , String.Format(@"/C START """" /BELOWNORMAL Excel.exe /E ""{0}""", myExcelFilePath));
            using (var p = Process.Start(psi))
            {
                p.WaitForExit(10);
                var workbook = Marshal.BindToMoniker(myExcelFilePath) as uExcel.Workbook;
                workbook.Close(false);
                Marshal.FinalReleaseComObject(workbook);
            }
        }

    }
}

引用返信 編集キー/
■87288 / inTopicNo.5)  Re[4]: 既に開いているエクセルファイルを操作する方法
□投稿者/ タク (4回)-(2018/05/04(Fri) 12:57:49)
2018/05/04(Fri) 12:58:58 編集(投稿者)
2018/05/04(Fri) 12:58:51 編集(投稿者)

Atata!!さん

新しいバージョンでは改善されているということですね。
確かに、office2003はかなり昔のバージョンでした。。
優先度下げて起動するコードもありがとうございます!
参考になりました。
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -