none
Excel 2010 (Microsoft Visual Basic for Applications)でシリアル通信を行いたい RRS feed

  • 質問

  • 環境
    Windows 7 Home
    Visual Studio 2010(.NET での開発経験なし)
    Office 2010
    ※Visual Studio 6.0ではVC++、VB開発経験あり

    以前、Office 2003(Excel VBA) + MSComm で
    Excel からシリアルポートを使用して
    外部機器との通信を行うアプリケーションを作成していました。

    今回、Excel 2010 -> 開発メニュー -> Visual Basic で表示される
    Microsoft Visual Basic for Applicationsで
    同様のソフトを作成し、Excel からシリアル通信を行いたいのですが
    どのような方法で実現ができますでしょうか。

    できれば以下の条件を希望いたします。
    ・MSCommは使用しない(VB6は使用しない)
    ・.NET Framework のSerialPort クラスが使用できるのであれば使用したい
    ・API直打ちはできれば使用したくない

    よろしくお願いいたします。

    2011年7月18日 13:47

回答

  • .Netの経験が無くて、VC6を使っていたならVCでMSCommと同じようなCOMを作ってしまうのが早いとは思いますが。
    あげられている条件を満たすようなやり方の一例は以下のようなものがあります。

    方法1(難易度5 professional版なら3)
    VSTOで実装。
    Excel VBAからはCOMと同様に操作。
    非同期受信はイベントの実装次第。
    (コードが長くなるのでサンプル無し)

    方法2(難易度3)
    COM相互運用で、.NetFrameworkで作成したプログラムをCOM参照可能にして公開する。
    Excel VBAからはCOMと同様に操作。
    非同期受信はイベントの実装次第。
    (コードが長くなるのでサンプル無し)

    方法3(難易度1)
    VB.Net等を使用して標準出力経由で通信。
    Excel VBAからはWshShellオブジェクト経由
    非同期受信はできない。(VBA側がマルチスレッドできないのでタイマで代用になる)

    VBAコード

    Sub test()
      Dim line As String
      Dim shell As WshShell
      Dim exec As WshExec
      
      '通信ソフトを別プロセスで起動(引数で通信設定)
      Set shell = New WshShell
      Set exec = shell.exec("""ConsoleApplication1.exe"" COM1,9600,None,8,One")
      
      line = exec.StdErr.ReadLine
      If (line <> "") Then
        'Openできなかったらエラー
        Err.Raise 513, Description:=line
      Else
        '適当に通信
        exec.StdIn.WriteLine ("ABCDE") '送信
        Debug.Print exec.StdOut.ReadLine() '受信
        exec.StdIn.WriteLine ("0123456789") '送信
        Debug.Print exec.StdOut.ReadLine() '受信
        exec.StdIn.WriteLine "" '送信せずに受信待ち
        Debug.Print exec.StdOut.ReadLine() '受信
      End If
      exec.Terminate '
    End Sub
    


    VB.Net(コンソールアプリ)

    Module Module1
      Sub Main()
        Try
          '引数から通信設定を取り出し
          Dim args() As String = System.Environment.GetCommandLineArgs()
          Dim comparam() As String = args(1).Split(","c)
          Dim portName As String = comparam(0)
          Dim baud As Integer = CInt(comparam(1))
          Dim parity As System.IO.Ports.Parity = DirectCast([Enum].Parse(GetType(System.IO.Ports.Parity), comparam(2)), System.IO.Ports.Parity)
          Dim bits As Integer = CInt(comparam(3))
          Dim stopbits As System.IO.Ports.StopBits = DirectCast([Enum].Parse(GetType(System.IO.Ports.StopBits), comparam(4)), System.IO.Ports.StopBits)
    
          'ポートを開く
          Using port As New System.IO.Ports.SerialPort(portName, baud, parity, bits, stopbits)
            port.Open()
    
            Console.Error.WriteLine() '無事に開けたことを通知
    
            Dim line As String
            Do While (True)
              line = Console.In.ReadLine() '送信する文字列を読み取り
              If Not String.IsNullOrEmpty(line) Then
                port.WriteLine(line) '送信
              End If
              line = port.ReadLine() '受信
              Console.Out.WriteLine(line) '受信した文字列を標準出力で通知
            Loop
          End Using
        Catch ex As Exception
          Console.Error.WriteLine(ex.Message)
          System.Environment.ExitCode = 1
        End Try
      End Sub
    End Module
    

     

    2011年7月19日 11:39
  • 1.

    難易度5 professional版なら3
    とありますが、これはなぜでしょうか?

    Professional版以上でVSTOを使う場合はVisualStudioが支援してくれるため、COM相互運用とほとんど違いがありません。
    VSTO特有の手間があることはありますが、COMの登録等の手間が減りますし結果的には同等になると考えられるため3としました。

    Professioan版未満にはVisualStudioにVSTOの機能がありません。
    基本的にVSTOはProfessional版以上のVisualStudioに搭載されています。(エディションの比較を参照してください。)
    また、Express版でVSTOと同等の仕組みをもったアプリを作ったことはありませんし、作り方については見かけたこともありません。
    作れないことは無いと思いますが難しくなると考えられるため、難易度5としました。

    2.
    VSTO みちしるべ ~道標~、拝見させていただきました。
    VSTO についてのサンプル等はインターネット上でも少ないのですが、
    gekka様の情報入手はどちらからされているのでしょうか

    VSTO自体はOffice用のアプリを作りやすくする仕組みなので、普通に作る分にはほとんど手間がかかりません。
    ですからMSDNを読んで、実際に作って試してみればなんとなくわかってきます。。
    それでもわからなければ適等に検索してみたり、VSTOのフォーラム(日本語,英語)を覗いてみたりしてます。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
    2011年7月23日 14:24

すべての返信

  • .Netの経験が無くて、VC6を使っていたならVCでMSCommと同じようなCOMを作ってしまうのが早いとは思いますが。
    あげられている条件を満たすようなやり方の一例は以下のようなものがあります。

    方法1(難易度5 professional版なら3)
    VSTOで実装。
    Excel VBAからはCOMと同様に操作。
    非同期受信はイベントの実装次第。
    (コードが長くなるのでサンプル無し)

    方法2(難易度3)
    COM相互運用で、.NetFrameworkで作成したプログラムをCOM参照可能にして公開する。
    Excel VBAからはCOMと同様に操作。
    非同期受信はイベントの実装次第。
    (コードが長くなるのでサンプル無し)

    方法3(難易度1)
    VB.Net等を使用して標準出力経由で通信。
    Excel VBAからはWshShellオブジェクト経由
    非同期受信はできない。(VBA側がマルチスレッドできないのでタイマで代用になる)

    VBAコード

    Sub test()
      Dim line As String
      Dim shell As WshShell
      Dim exec As WshExec
      
      '通信ソフトを別プロセスで起動(引数で通信設定)
      Set shell = New WshShell
      Set exec = shell.exec("""ConsoleApplication1.exe"" COM1,9600,None,8,One")
      
      line = exec.StdErr.ReadLine
      If (line <> "") Then
        'Openできなかったらエラー
        Err.Raise 513, Description:=line
      Else
        '適当に通信
        exec.StdIn.WriteLine ("ABCDE") '送信
        Debug.Print exec.StdOut.ReadLine() '受信
        exec.StdIn.WriteLine ("0123456789") '送信
        Debug.Print exec.StdOut.ReadLine() '受信
        exec.StdIn.WriteLine "" '送信せずに受信待ち
        Debug.Print exec.StdOut.ReadLine() '受信
      End If
      exec.Terminate '
    End Sub
    


    VB.Net(コンソールアプリ)

    Module Module1
      Sub Main()
        Try
          '引数から通信設定を取り出し
          Dim args() As String = System.Environment.GetCommandLineArgs()
          Dim comparam() As String = args(1).Split(","c)
          Dim portName As String = comparam(0)
          Dim baud As Integer = CInt(comparam(1))
          Dim parity As System.IO.Ports.Parity = DirectCast([Enum].Parse(GetType(System.IO.Ports.Parity), comparam(2)), System.IO.Ports.Parity)
          Dim bits As Integer = CInt(comparam(3))
          Dim stopbits As System.IO.Ports.StopBits = DirectCast([Enum].Parse(GetType(System.IO.Ports.StopBits), comparam(4)), System.IO.Ports.StopBits)
    
          'ポートを開く
          Using port As New System.IO.Ports.SerialPort(portName, baud, parity, bits, stopbits)
            port.Open()
    
            Console.Error.WriteLine() '無事に開けたことを通知
    
            Dim line As String
            Do While (True)
              line = Console.In.ReadLine() '送信する文字列を読み取り
              If Not String.IsNullOrEmpty(line) Then
                port.WriteLine(line) '送信
              End If
              line = port.ReadLine() '受信
              Console.Out.WriteLine(line) '受信した文字列を標準出力で通知
            Loop
          End Using
        Catch ex As Exception
          Console.Error.WriteLine(ex.Message)
          System.Environment.ExitCode = 1
        End Try
      End Sub
    End Module
    

     

    2011年7月19日 11:39
  • gekka様

    ご回答いただきありがとうございます。
    返信が遅くなってしまい申し訳ありません。

    方法3は、容易とは思われますが、今回は見送りたいと思います。

    方法2も、比較的容易と思われます。
    .Netの勉強にもなると思いますが、今回はまず方法1を検討したいと思います。
    (勉強をして、方法1での実現がまったくお手上げであれば方法2を検討します)


    2点お伺いしたいことがあります。

    1.
    難易度5 professional版なら3
    とありますが、これはなぜでしょうか?

    2.
    VSTO みちしるべ ~道標~、拝見させていただきました。
    VSTO についてのサンプル等はインターネット上でも少ないのですが、
    gekka様の情報入手はどちらからされているのでしょうか


    ほかにもお伺いしたいことはありますが、まずは
    VSTO みちしるべ ~道標~
    のサンプルを作成してみようと思います。

     

    2011年7月23日 12:29
  • 1.

    難易度5 professional版なら3
    とありますが、これはなぜでしょうか?

    Professional版以上でVSTOを使う場合はVisualStudioが支援してくれるため、COM相互運用とほとんど違いがありません。
    VSTO特有の手間があることはありますが、COMの登録等の手間が減りますし結果的には同等になると考えられるため3としました。

    Professioan版未満にはVisualStudioにVSTOの機能がありません。
    基本的にVSTOはProfessional版以上のVisualStudioに搭載されています。(エディションの比較を参照してください。)
    また、Express版でVSTOと同等の仕組みをもったアプリを作ったことはありませんし、作り方については見かけたこともありません。
    作れないことは無いと思いますが難しくなると考えられるため、難易度5としました。

    2.
    VSTO みちしるべ ~道標~、拝見させていただきました。
    VSTO についてのサンプル等はインターネット上でも少ないのですが、
    gekka様の情報入手はどちらからされているのでしょうか

    VSTO自体はOffice用のアプリを作りやすくする仕組みなので、普通に作る分にはほとんど手間がかかりません。
    ですからMSDNを読んで、実際に作って試してみればなんとなくわかってきます。。
    それでもわからなければ適等に検索してみたり、VSTOのフォーラム(日本語,英語)を覗いてみたりしてます。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
    2011年7月23日 14:24
  • こんにちは、cow bell さん。

    MSDN フォーラムのご利用ありがとうございます。フォーラム オペレーターの山本です。

    参考になる情報をいただいているようでしたので、他の方にもこの情報を有効活用していただくよう勝手ながら私のほうで回答としてマークさせていただきました。
    gekka さん、情報ありがとうございます。

    いただいた返信の中で、解決に役立った情報や、参考になった情報には、回答としてマークすることをお願いしています。
    今後、同じ問題でこのスレッドを参照される方にも、有効な情報がわかりやすくなるかと思いますので、ご協力よろしくお願いいたします。

    具体的に不明点などが出てきましたら、また投稿くださいね。
    今後とも、MSDN フォーラムをよろしくお願いいたします。それでは。
                                                                                                                                             
    日本マイクロソフト株式会社 フォーラム オペレーター 山本 春海

    2011年7月29日 7:54
    モデレータ
  • gekka様

    ご回答いただきありがとうございます。
    返信が遅くなってしまい申し訳ありません。

    ・通常使用しているPCにはシリアルポートがついていない
    ・シリアルポートがついているPCでのデバッグは行っていない
    状態ですが、以下の操作を行い、
    ポートオープンでエラー(COMポートが無いという内容のエラー)が
    発生することまで確認ができています。


     01.新規作成→新しいプロジェクト→VB→Office→2010→Excel2010ブック
     02.シートにボタンを配置する
     03.ボタンをダブルクリックして Button1_Click を作成
     04.クラスの宣言外に以下を追加
       Imports System.IO.Ports
     05.Button1_Click に以下を追加
      ※ http://msdn.microsoft.com/ja-jp/library/s14dyf47.aspx などを参考に

       Dim _SerialPort As SerialPort
       _SerialPort = New SerialPort()

       ' プロパティ設定
       _serialPort.BaudRate = 19200

       _SerialPort.Open()


    > VSTO自体はOffice用のアプリを作りやすくする仕組みなので、
    > 普通に作る分にはほとんど手間がかかりません。

    VSTOをほんのさわりだけ試しての印象ですが、
    従来のexcel + VBAよりも開発が容易で自由度が高く、
    他の言語(C#)での開発もできる
    という印象がありました。

    上記の「仕組み」や「手間がかかりません」とは
    そのような意味合いととらえてよいでしょうか?

    とりあえず、今まで何を行ったらよいかもわからない状態から
    一歩先に進むことができました。
    ありがとうございました。

     

     

    2011年7月31日 13:44