DOBON.NET DOBON.NETプログラミング掲示板過去ログ

C#→VBへの移植でうまくいきません

環境/言語:[.NET Framework2.0]
分類:[.NET]

いつも参考にさせて頂いております。
自PC内でのプロセス間通信をやりたくてC#で記述されたサンプルをネット上で見つけました。
「吟遊詩人の戯言」さんのサイトです。
http://gurizuri0505.halfmoon.jp/develop/csharp/processmessage
これをVBで書き換えようとしてますが、うまくいきません。
以下はクライアント側のソースですが、実行して「送信」クリックすると
System.Runtime.Remoting.RemotingException' の初回例外が mscorlib.dll で発生しました。
とメッセージが出てしまいます。どこが悪いのでしょうか。

'System.Runtime.Remotingを参照設定する必要があります
Imports System.Runtime.Remoting.Channels.ipc
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting
'Imports RemoteTranceObject

Public Class FormClient

    Private m_mode As Integer = 0
    Private m_msg As RemoteTranceObject.ClassFileInfo = Nothing

    Public Sub New()
        ' この呼び出しは、Windows フォーム デザイナで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。
        m_mode = 1
    End Sub

    Private Sub FormClient_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'IPC Channel を作成
        Dim clientChannel As IpcClientChannel = New IpcClientChannel()
        'IpcClientChannel clientChannel = new IpcClientChannel();

        'リモートオブジェクトを登録
        ChannelServices.RegisterChannel(clientChannel, True)
        'ChannelServices.RegisterChannel(clientChannel, true);

        'オブジェクトを作成
        m_msg = Activator.GetObject(GetType(RemoteTranceObject.ClassFileInfo), "ipc://processtrancetest/message")
        'm_msg = (ClassFileInfo)Activator.GetObject(typeof(ClassFileInfo), "ipc://processtrancetest/message");

    End Sub


    'ラジオボタンでモードを設定
    Private Sub RadioButton1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton1.CheckedChanged, RadioButton3.CheckedChanged, RadioButton2.CheckedChanged
        Dim st As String
        If sender.tag = Nothing Then
            Exit Sub
        End If
        st = sender.Tag
        m_mode = Integer.Parse(st)

        'string st = (sender as RadioButton).Tag as string;
        'm_mode = int.Parse(st);

    End Sub

    'ボタンを押すたびに,モードと入力文字をサーバ側へ送信
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim st As String = TextBox1.Text

        If st = "" Then
            st = "空文字"
        End If

        m_msg.DataTrance(m_mode, st)                'サーバーへ伝送

        'string st = textBox1.Text;

        'if (st == "")
        '{
        '    st = "空文字";
        '}

        'm_msg.DataTrance(m_mode, st);                //サーバーへ伝送

    End Sub
End Class


Namespace RemoteTranceObject                '共有オブジェクト(サーバー/クライアントで全く同一内容で定義してください)
    Public Class ClassFileInfo
        Inherits MarshalByRefObject

        Public Class ClassFileInfoEventArg
            Inherits EventArgs          '情報を引き渡すイベント引数クラス

            Private m_mode As Integer = 0              'モード
            Private m_FileName As String = ""          '文字列

            Property Mode() As Integer
                Get
                    Return m_mode
                End Get
                Set(ByVal value As Integer)
                    m_mode = value
                End Set
            End Property

            Property FileName() As String
                Get
                    Return m_FileName
                End Get
                Set(ByVal value As String)
                    m_FileName = value
                End Set
            End Property

            Public Sub New(ByVal tmpMode As Integer, ByVal tmpfName As String)
                m_mode = tmpMode
                m_FileName = tmpfName
            End Sub
        End Class

        Public Delegate Sub CallEventHandler(ByVal e As ClassFileInfoEventArg)
        Public Event OnTrance As CallEventHandler

        Public Sub DataTrance(ByVal tmpmode As Integer, ByVal tmpfname As String)
            RaiseEvent OnTrance(New ClassFileInfoEventArg(tmpmode, tmpfname))
        End Sub
    End Class
End Namespace
■No28890に返信(ひで46 さんの記事)
> System.Runtime.Remoting.RemotingException' の初回例外が mscorlib.dll で発生しました。
> とメッセージが出てしまいます。どこが悪いのでしょうか。

RemotingException とともに何かメッセージが出ていませんでしたか?
(たとえば、「AA 型がシリアライズ可能とマークされていません」といったもの)

そのメッセージがないと、エラー要因がわかりづらいと思います。
あと、サーバー側は今どうなっているんですか?
コメント頂き、ありがとうございます。
エラーメッセージですが、
  Message="型 'ClientTest.RemoteTranceObject.ClassFileInfo, ClientTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' を読み込めません。"
というのが出てます。
それと、以下、サーバー側のコードです。
よろしくお願いします。

'System.Runtime.Remotingを参照設定する必要があります
Imports System.Runtime.Remoting.Channels.ipc
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting
'Imports RemoteTranceObject

Public Class FormSrever

    Dim m_msg As RemoteTranceObject.ClassFileInfo


    'フォームロード
    Private Sub FormSrever_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load


        'このチャネル生成系は一度通せばいいっぽい

        'IPC Channel を作成
        Dim servChannel As IpcServerChannel = New IpcServerChannel("processtrancetest")
        'IpcServerChannel servChannel = new IpcServerChannel("processtrancetest");

        'リモートオブジェクトを登録
        ChannelServices.RegisterChannel(servChannel, True)
        'ChannelServices.RegisterChannel(servChannel, true);

        'ChannelのURIを表示
        Label1.Text = servChannel.GetChannelUri()
        'label1.Text = servChannel.GetChannelUri();

        'イベントを登録
        m_msg = New RemoteTranceObject.ClassFileInfo()
        AddHandler m_msg.OnTrance, AddressOf m_msg_OnTrance
        RemotingServices.Marshal(m_msg, "message", GetType(RemoteTranceObject.ClassFileInfo))
        'm_msg = new ClassFileInfo();
        'm_msg.OnTrance += new ClassFileInfo.CallEventHandler(m_msg_OnTrance);
        'RemotingServices.Marshal(m_msg, "message", typeof(ClassFileInfo));

    End Sub

    'クライアントから転送されてきた情報をリストボックスに表示
    Private Sub m_msg_OnTrance(ByVal e As RemoteTranceObject.ClassFileInfo.ClassFileInfoEventArg)
        Dim st As String

        Select Case e.Mode
            Case 1
                st = "モード1"
            Case 2
                st = "モード2"
            Case 3
                st = "モード3"
            Case Else
                st = "???"
        End Select
        ListBox1.Items.Add(st + " , " + e.FileName)
    End Sub

End Class


Namespace RemoteTranceObject                '共有オブジェクト(サーバー/クライアントで全く同一内容で定義してください)
    Public Class ClassFileInfo
        Inherits MarshalByRefObject

        Public Class ClassFileInfoEventArg
            Inherits EventArgs          '情報を引き渡すイベント引数クラス

            Private m_mode As Integer = 0              'モード
            Private m_FileName As String = ""          '文字列

            Property Mode() As Integer
                Get
                    Return m_mode
                End Get
                Set(ByVal value As Integer)
                    m_mode = value
                End Set
            End Property

            Property FileName() As String
                Get
                    Return m_FileName
                End Get
                Set(ByVal value As String)
                    m_FileName = value
                End Set
            End Property

            Public Sub New(ByVal tmpMode As Integer, ByVal tmpfName As String)
                m_mode = tmpMode
                m_FileName = tmpfName
            End Sub
        End Class

        Public Delegate Sub CallEventHandler(ByVal e As ClassFileInfoEventArg)
        Public Event OnTrance As CallEventHandler

        Public Sub DataTrance(ByVal tmpmode As Integer, ByVal tmpfname As String)
            RaiseEvent OnTrance(New ClassFileInfoEventArg(tmpmode, tmpfname))
        End Sub
    End Class

End Namespace


■No28891に返信(Azuleanさんの記事)
> ■No28890に返信(ひで46 さんの記事)
>>System.Runtime.Remoting.RemotingException' の初回例外が mscorlib.dll で発生しました。
>>とメッセージが出てしまいます。どこが悪いのでしょうか。
> 
> RemotingException とともに何かメッセージが出ていませんでしたか?
> (たとえば、「AA 型がシリアライズ可能とマークされていません」といったもの)
> 
> そのメッセージがないと、エラー要因がわかりづらいと思います。
> あと、サーバー側は今どうなっているんですか?
■No28892に返信(ひで46 さんの記事)
> エラーメッセージですが、
> Message="型 'ClientTest.RemoteTranceObject.ClassFileInfo, ClientTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' を読み込めません。"
> というのが出てます。

これは、VB.NET 特有の事情が絡んでいます。
VB.NET のプロジェクトではプロジェクトのプロパティにルート名前空間というものが指定できるようになっており、ここに何か入っているとそのプロジェクトの中のクラスなどはその名前空間以下に属するようになります。
ここで "ClientTest.RemoteTranceObject.ClassFileInfo" と最初に "ClientTest" とついているのはルート名前空間のせいでしょう。
そして、サーバー側は "ServerTest.RemoteTranceObject.ClassFileInfo" となっていると推測され、名前空間を合わせた型名で一致する型が見つからないから例外が発生しているのでしょう。

C# でのサンプルではルート名前空間という概念がないので、名前空間を含めた型名を一致させる書き方だったのでしょう。
VB.NET で合わせるためにはプロジェクトのプロパティからルート名前空間を空欄にしてください。なお、フォームなどのほかのクラスは必要に応じて名前空間を調整してください。


こういった方法が面倒なのであれば、共有するクラスを別のプロジェクトに切り出し、そのプロジェクトをサーバー側、クライアント側が両方とも参照する形にすれば、こういう無理矢理なやり方(厳密に同じ型といえないのにそう見せかけているやり方)からは脱することができると考えられます。
回答ありがとうございます。
ご指摘の通り、ソルーションの中にクライアント用とサーバー用の2つのプロジェクトが
入ってます。
各プロジェクトのプロパティを開いてアプリケーションタブのルート名前空間というところを空欄にしてリビルドしたら見事動作しました。

> こういった方法が面倒なのであれば、共有するクラスを別のプロジェクトに切り出し、
これについては「吟遊詩人の戯言」サイトでも
「この部分だけ,クラスDLLにして,参照設定しちゃうほうが,あとあと管理が楽かも?」
とのコメントが書いてありました。
今回は新しいことを知ることが出来てよかったです。


■No28893に返信(Azuleanさんの記事)
> ■No28892に返信(ひで46 さんの記事)
>>エラーメッセージですが、
>>  Message="型 'ClientTest.RemoteTranceObject.ClassFileInfo, ClientTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' を読み込めません。"
>>というのが出てます。
> 
> これは、VB.NET 特有の事情が絡んでいます。
> VB.NET のプロジェクトではプロジェクトのプロパティにルート名前空間というものが指定できるようになっており、ここに何か入っているとそのプロジェクトの中のクラスなどはその名前空間以下に属するようになります。
> ここで "ClientTest.RemoteTranceObject.ClassFileInfo" と最初に "ClientTest" とついているのはルート名前空間のせいでしょう。
> そして、サーバー側は "ServerTest.RemoteTranceObject.ClassFileInfo" となっていると推測され、名前空間を合わせた型名で一致する型が見つからないから例外が発生しているのでしょう。
> 
> C# でのサンプルではルート名前空間という概念がないので、名前空間を含めた型名を一致させる書き方だったのでしょう。
> VB.NET で合わせるためにはプロジェクトのプロパティからルート名前空間を空欄にしてください。なお、フォームなどのほかのクラスは必要に応じて名前空間を調整してください。
> 
> 
> こういった方法が面倒なのであれば、共有するクラスを別のプロジェクトに切り出し、そのプロジェクトをサーバー側、クライアント側が両方とも参照する形にすれば、こういう無理矢理なやり方(厳密に同じ型といえないのにそう見せかけているやり方)からは脱することができると考えられます。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板