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

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

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

Re[1]: VB.NETより、EXCELファイルを開く


(過去ログ 145 を表示中)

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

■84930 / inTopicNo.1)  VB.NETより、EXCELファイルを開く
  
□投稿者/ やま (1回)-(2017/08/24(Thu) 12:47:08)

分類:[VB.NET/VB2005 以降] 

2017/08/24(Thu) 16:21:19 編集(投稿者)

お世話になります

下記コードで、EXCELファイルを立ち上げています


VisualStudio2015を使っています
EXCEL2016を使っています



御教示頂けませんでしょうか?

引用返信 編集キー/
■84932 / inTopicNo.2)  Re[1]: VB.NETより、EXCELファイルを開く
□投稿者/ 774RR (559回)-(2017/08/24(Thu) 13:34:13)
したい=要望、これは「案件」という。
案件だけではプログラムにならないので「仕様」を考えなきゃ。

ボタン1をクリックしたとき
・ Excel を起動する条件は何?
・ Excel を起動させない条件は何?

例1:ボタンクリック1回目だけOKにする。(すると2度目以後は一切起動させないってことになる)
例2: Excel が起動していなかったらOKにする。(するとユーザーが自分で Excel を起動していたら NG になる)

などなど、自分の中でどうなってほしいのかを考察して仕様を作るのが先。
引用返信 編集キー/
■84934 / inTopicNo.3)  Re[2]: VB.NETより、EXCELファイルを開く
□投稿者/ やま (2回)-(2017/08/24(Thu) 13:46:49)
774RR さん

ありがとうございます

ボタンクリックを1回目だけOKにするが、コードで指定したファイルを閉じていたり、終了していれば、
クリックして立ち上げるのは可能にしたく考えております

引用返信 編集キー/
■84938 / inTopicNo.4)  Re[3]: VB.NETより、EXCELファイルを開く
□投稿者/ 774RR (560回)-(2017/08/24(Thu) 14:34:37)
ならば
> コードで指定したファイルを閉じていたり、
> 終了していれば、
これをどう判断するか、を考えないといけないよね。

> ボタンクリックを1回目だけOKにするが
ここも「既に開いていたときどうするか」の考察がもれているよね

プロセスを探す、とかそういうあたりがキーワードになるかも。
引用返信 編集キー/
■84940 / inTopicNo.5)  Re[4]: VB.NETより、EXCELファイルを開く
□投稿者/ やま (3回)-(2017/08/24(Thu) 14:39:41)
2017/08/24(Thu) 14:42:49 編集(投稿者)
2017/08/24(Thu) 14:42:43 編集(投稿者)

イメージとしてはこんなことでしょか?

コードで指定したファイルが開いているのかをまず確認

開いていなければ開きます
開いていれば、開かない(メッセージを出すか、ボタンをクリックしてもファイルを表示させない)

開いていなかったときに、クリックして開きます

ボタンクリックを1回目だけOKにするが、
コードで指定したファイルを閉じていたり、終了していれば、
クリックして立ち上げるのは可能にしたく考えております



引用返信 編集キー/
■84942 / inTopicNo.6)  Re[5]: VB.NETより、EXCELファイルを開く
□投稿者/ 774RR (561回)-(2017/08/24(Thu) 15:22:45)
そういうことになるわけで、だからやるべきことは

Excel が既に起動されているか+その Excel で対象ファイルが開かれているか、のチェック。
参考 http://dobon.net/vb/dotnet/index.html#process

それができれば if で分岐するだけだよね。具体的コード書いてくれは勘弁しておくれ。
引用返信 編集キー/
■84944 / inTopicNo.7)  Re[6]: VB.NETより、EXCELファイルを開く
□投稿者/ 大谷刑部 (39回)-(2017/08/24(Thu) 15:56:09)
No84942 (774RR さん) に返信
> そういうことになるわけで、だからやるべきことは
>
> Excel が既に起動されているか+その Excel で対象ファイルが開かれているか、のチェック。
> 参考 http://dobon.net/vb/dotnet/index.html#process
>
> それができれば if で分岐するだけだよね。具体的コード書いてくれは勘弁しておくれ。

そもそも質問者が自分で考える気がないのが見え見えなので、
相手する必要ないのでは?
引用返信 編集キー/
■84947 / inTopicNo.8)  Re[7]: VB.NETより、EXCELファイルを開く
□投稿者/ やま (4回)-(2017/08/24(Thu) 16:21:01)
初心者につき、分からないことだらけですみません

アドバイスを頂きましてありがとうございました

イメージがなんとなく分かりました


解決済み
引用返信 編集キー/
■84951 / inTopicNo.9)  Re[1]: VB.NETより、EXCELファイルを開く
□投稿者/ 魔界の仮面弁士 (1396回)-(2017/08/24(Thu) 18:37:29)
No84930 (やま さん) に返信
> 下記コードで、EXCELファイルを立ち上げています

最初の質問がごっそり削られているようですが、
 『Excel ファイルを開きたいが、既に開いていたら何もしない』
という処理とみなして、とりあえずこんな感じ。


Option Strict On
Imports Excel = Microsoft.Office.Interop.Excel
Imports System.IO
Imports System.Runtime.InteropServices.ComTypes
Imports System.Runtime.InteropServices
Public Class Form1
  Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    If Not File.Exists(TextBox1.Text) Then
      MsgBox("Excel ファイル名が指定されていません")
      Return
    End If

    Dim found As Boolean = False
    For Each app In GetExcels()
      Dim books = app.Workbooks
      Dim n As Integer = 1
      While n <= books.Count
        Dim book As Excel.Workbook = Nothing
        Try
          book = books(n)
          If String.Compare(TextBox1.Text, book.FullName, False) = 0 Then
            found = True
            Exit For
          End If
        Finally
          Marshal.ReleaseComObject(book)
        End Try
        n += 1
      End While
      Marshal.ReleaseComObject(books)
    Next

    If found Then
      MsgBox("既に開かれていました")
    Else
      MsgBox("新たに開きます")
      'Excel.Application のインスタンスから Workbooks.Open する手もあるけれど
      'ただ開くだけならばこれで十分
      Process.Start(TextBox1.Text)
    End If
  End Sub

  Friend Iterator Function GetExcels() As IEnumerable(Of Excel.Application)
    Dim rot As IRunningObjectTable = Nothing
    Dim oEnumMoniker As IEnumMoniker = Nothing
    Dim oBindCtx As IBindCtx = Nothing
    Try
      GetRunningObjectTable(0, rot)
      CreateBindCtx(0, oBindCtx)
      rot.EnumRunning(oEnumMoniker)
      Dim oMoniker As IMoniker() = {Nothing}
      Do While oEnumMoniker.Next(1, oMoniker, IntPtr.Zero) = 0
        Dim unk As Object = Nothing
        rot.GetObject(oMoniker(0), unk)
        Dim app = TryCast(unk, Excel.Application)
        If app IsNot Nothing Then
          Yield app
          Marshal.ReleaseComObject(app)
        End If
        Dim m As Integer = Marshal.ReleaseComObject(oMoniker(0))
      Loop
    Finally
      If oBindCtx IsNot Nothing Then
        Marshal.ReleaseComObject(oBindCtx)
      End If
      If oEnumMoniker IsNot Nothing Then
        Marshal.ReleaseComObject(oEnumMoniker)
      End If
      If rot IsNot Nothing Then
        Marshal.ReleaseComObject(rot)
      End If
    End Try
  End Function

  <DllImport("ole32", PreserveSig:=True, SetLastError:=True)>
  Private Shared Sub GetRunningObjectTable(reserved As Integer, <Out()> ByRef pprot As IRunningObjectTable)
  End Sub
  <DllImport("ole32", PreserveSig:=True, SetLastError:=True)>
  Private Shared Sub CreateBindCtx(reserved As Integer, <Out()> ByRef ppbc As IBindCtx)
  End Sub
End Class
引用返信 編集キー/
■84963 / inTopicNo.10)  Re[2]: VB.NETより、EXCELファイルを開く
□投稿者/ furu (119回)-(2017/08/28(Mon) 11:47:25)
No84951 (魔界の仮面弁士 さん) に返信

found = Trueの場合、booksがReleaseComObjectされないようです。

また、found = Trueの場合、GetExcels()のappは
いつReleaseComObjectされるか教えてください。

引用返信 編集キー/
■84964 / inTopicNo.11)  Re[3]: VB.NETより、EXCELファイルを開く
□投稿者/ 魔界の仮面弁士 (1399回)-(2017/08/28(Mon) 14:02:50)
No84963 (furu さん) に返信
> found = Trueの場合、booksがReleaseComObjectされないようです。
> また、found = Trueの場合、GetExcels()のappは
> いつReleaseComObjectされるか教えてください。

されないですね。御指摘感謝。m(_ _)m

加えて、found するための判定処理も見直しが必要そうです。


> If String.Compare(TextBox1.Text, book.FullName, False) = 0 Then
>   found = True

C:\ と c:\ を同一視するために、String.Compare で ignoreCase:=True を
指定したつもりだったのですが、うっかり False を指定してしまっていたようで。
引用返信 編集キー/
■84996 / inTopicNo.12)  Re[4]: VB.NETより、EXCELファイルを開く
□投稿者/ なちゃ (216回)-(2017/09/02(Sat) 11:47:07)
ちなみに個人的には、きちんとオブジェクトを管理するために払う労力、メンテナンス性の低下が許容範囲を超えているので、ファイナライズに任せてしまうことが多いです。
あきらめてるとも言います。
確実にファイナライズを行わせるために、アプリケーションオブジェクトのExitだけは確実に実行させるように注意します。
あとは、Excelのオブジェクトを使う処理全般をメソッドに追い出しておいて、呼び出し側で処理終了後にGCを起動します。
※これは、できるだけすぐに解放開始を行いたい場合の話ですが、まあやっておくのが無難です。
 すぐに実行しない場合は、GUIに戻ってアイドルになってからGCするといった、より凝った方法もあります。

ついでにexcelが終了するまで待ちたいならPendingFinalizersだったかな、も実行しておきます(保証にはなりませんが)。

当然こういうやり方はパフォーマンス上良い方法とはいえませんが、excelをサーバやサービスアプリで使う事はありませんし、クライアントアプリなら実質何も困りません(はっきり言ってまず差は出ない)。

excelでの処理を大量に繰り返す場合はもちろん、excelの起動は一回にしてインスタンスを一貫して管理し、最後一回、またはある程度の処理毎に定期的にGCするようにします。

個別のExcel操作において気にすることはほぼなくなって、大変すっきりします。
このメンテナンスの楽さ、見た目のわかりやすさに比べたら、真面目に解放処理を全部書く気はなくなります。
※個人の感想です。
引用返信 編集キー/
■84997 / inTopicNo.13)  Re[1]: VB.NETより、EXCELファイルを開く
□投稿者/ shu (1052回)-(2017/09/04(Mon) 07:48:36)
No84930 (やま さん) に返信

起動するだけなら
Process.Start("〜.xlsx")

だけで済むと思いますがどうでしょう?
引用返信 編集キー/
■84998 / inTopicNo.14)  Re[5]: VB.NETより、EXCELファイルを開く
□投稿者/ なちゃ (217回)-(2017/09/04(Mon) 09:16:20)
No84996 (なちゃ さん) に返信
すみません、私の書き込みは今回の話題や話の流れから思い切りずれてます、ごめんなさい。

引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -