Discussion:
Receiving Windows messages in a remoted object
(too old to reply)
ChrisKemmerer
2009-05-07 12:43:01 UTC
Permalink
I have a .NET assembly that interacts with a third party driver that
communicates using custom Windows messages. This assembly is then used by
others in their application. The purpose of the assembly is to hide the ugly
details of communicating with the driver. In my assembly I have a class
derived from NativeWindow that creates a message only window (HWND_MESSAGE).
In the overridden WndProc procedure I check for the custom messages and
handle them. This works fine when using the assembly from a normal Windows
Forms application in C# or VB.NET. It doesn't work with remoting.

For testing I created a stripped down version of my assembly and checked to
make sure that the overridden WndProc was being called and found that it was
not. I could tell that the message window was created and can find it using
another test application that calls FindWindowEx and then posts a WM_NULL
message to it. I could also see that Windows messages were being processed
while the message window was being created (WM_NCCREATE, WM_CREATE, ...).
After that, nothing. Again, this assembly works fine with normal Windows
Forms apps but not when remoted. Below is my code.

Just to make sure this wasn't just an issue with Message Windows I tried
creating a normal window and still had the same problem.

I'm hoping it is just something stupid that I forgot. Thanks.

-------------------------
RemoteNET.h
-------------------------

using namespace System;
using namespace System::Windows::Forms;

namespace RemoteNET {

ref class CNETWnd;

public ref class CTestClass
{
public:
CTestClass();
~CTestClass();

private:
CNETWnd^ m_pWnd;
};

public ref class CNETWnd : public NativeWindow
{
public:
CNETWnd(CTestClass^ pClass);
~CNETWnd();

protected:
CTestClass^ m_pClass;

protected:
virtual void WndProc(Message % msg) override;
};
}
}
}

------------------
RemoteNET.cpp
------------------

namespace RemoteNET
{
CTestClass::CTestClass()
{
m_pWnd = gcnew CNETWnd(this);
}

CTestClass::~CTestClass()
{
}

CNETWnd::~CNETWnd()
{
}

CNETWnd::CNETWnd(CTestClass^ pClass) : m_pClass(pClass)
{
CreateParams^ cp = gcnew CreateParams;

// create the message window to receive Windows messages
cp->Caption = "NETWnd";
cp->ClassName = "Message";
cp->Parent = IntPtr(HWND_MESSAGE);

this->CreateHandle(cp);
}

void CNETWnd::WndProc(Message % msg)
{
System::Diagnostics::Debug::WriteLine(String::Format("WndProc msg:
0x{0:X}.", msg.Msg));

NativeWindow::WndProc(msg);
}
}
}
}

My remote class that wraps the .NET assembly.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using RemoteNET;

namespace RemoteClass
{
public class RemoteClass : MarshalByRefObject
{
private CTestClass objTestClass;

public RemoteClass()
{
objTestClass = new CTestClass();
}

public void DoSomething()
{
return;
}
}
}

Remote Server.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace RemoteServer
{
class Program
{
static void Main(string[] args)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
//string configFile = "App.config";
RemotingConfiguration.Configure(configFile, true);

Console.Write("Sever is Ready........");
Console.Read();
}
}
}

Remote server config file.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
objectUri="RemoteController"
mode="Singleton"
/>
</service>

<channels>
<channel ref="tcp" port="2000">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>

</application>
</system.runtime.remoting>
</configuration>

Client.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace RemoteClient
{
public partial class TestClass : Form
{
RemoteClass.RemoteClass test;

public TestClass()
{
InitializeComponent();
}

private void TestClass_Load(object sender, EventArgs e)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
RemotingConfiguration.Configure(configFile, true);

string url = "tcp://localhost:2000/CameraController";
test =
(RemoteClass.RemoteClass)RemotingServices.Connect(typeof(RemoteClass.RemoteClass), url);
}

private void button1_Click(object sender, EventArgs e)
{
test.DoSomething();
}
}
}

Client config file.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
url="tcp://localhost:2000/RemoteController"
/>
</client>

<channels>
<channel ref="tcp" port="0">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>

</application>
</system.runtime.remoting>
</configuration>
Jesse Houwing
2009-05-07 13:13:07 UTC
Permalink
Hello ChrisKemmerer,

Your remote server does not start an application, nor does it process window
events like a normal windows forms app would do. My guess is that if you
host your remote form in a windows forms application instead of a commandline
app, then it would work. Hosting an application (using application.start)
would make sure a thread is created to process and receive window messages.

Jesse
Post by ChrisKemmerer
I have a .NET assembly that interacts with a third party driver that
communicates using custom Windows messages. This assembly is then used
by others in their application. The purpose of the assembly is to hide
the ugly details of communicating with the driver. In my assembly I
have a class derived from NativeWindow that creates a message only
window (HWND_MESSAGE). In the overridden WndProc procedure I check for
the custom messages and handle them. This works fine when using the
assembly from a normal Windows Forms application in C# or VB.NET. It
doesn't work with remoting.
For testing I created a stripped down version of my assembly and
checked to make sure that the overridden WndProc was being called and
found that it was not. I could tell that the message window was
created and can find it using another test application that calls
FindWindowEx and then posts a WM_NULL message to it. I could also see
that Windows messages were being processed while the message window
was being created (WM_NCCREATE, WM_CREATE, ...). After that, nothing.
Again, this assembly works fine with normal Windows Forms apps but not
when remoted. Below is my code.
Just to make sure this wasn't just an issue with Message Windows I
tried creating a normal window and still had the same problem.
I'm hoping it is just something stupid that I forgot. Thanks.
-------------------------
RemoteNET.h
-------------------------
using namespace System;
using namespace System::Windows::Forms;
namespace RemoteNET {
ref class CNETWnd;
public ref class CTestClass
{
CTestClass();
~CTestClass();
CNETWnd^ m_pWnd;
};
public ref class CNETWnd : public NativeWindow
{
CNETWnd(CTestClass^ pClass);
~CNETWnd();
CTestClass^ m_pClass;
virtual void WndProc(Message % msg) override;
};
}
}
}
------------------
RemoteNET.cpp
------------------
namespace RemoteNET
{
CTestClass::CTestClass()
{
m_pWnd = gcnew CNETWnd(this);
}
CTestClass::~CTestClass()
{
}
CNETWnd::~CNETWnd()
{
}
CNETWnd::CNETWnd(CTestClass^ pClass) : m_pClass(pClass)
{
CreateParams^ cp = gcnew CreateParams;
// create the message window to receive Windows messages
cp->Caption = "NETWnd";
cp->ClassName = "Message";
cp->Parent = IntPtr(HWND_MESSAGE);
this->CreateHandle(cp);
}
void CNETWnd::WndProc(Message % msg)
{
0x{0:X}.", msg.Msg));
NativeWindow::WndProc(msg);
}
}
}
}
My remote class that wraps the .NET assembly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RemoteNET;
namespace RemoteClass
{
public class RemoteClass : MarshalByRefObject
{
private CTestClass objTestClass;
public RemoteClass()
{
objTestClass = new CTestClass();
}
public void DoSomething()
{
return;
}
}
}
Remote Server.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteServer
{
class Program
{
static void Main(string[] args)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
//string configFile = "App.config";
RemotingConfiguration.Configure(configFile, true);
Console.Write("Sever is Ready........");
Console.Read();
}
}
}
Remote server config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
objectUri="RemoteController"
mode="Singleton"
/>
</service>
<channels>
<channel ref="tcp" port="2000">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Client.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteClient
{
public partial class TestClass : Form
{
RemoteClass.RemoteClass test;
public TestClass()
{
InitializeComponent();
}
private void TestClass_Load(object sender, EventArgs e)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
RemotingConfiguration.Configure(configFile, true);
string url = "tcp://localhost:2000/CameraController";
test =
(RemoteClass.RemoteClass)RemotingServices.Connect(typeof(RemoteClass.R
emoteClass), url);
}
private void button1_Click(object sender, EventArgs e)
{
test.DoSomething();
}
}
}
Client config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
url="tcp://localhost:2000/RemoteController"
/>
</client>
<channels>
<channel ref="tcp" port="0">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
--
Jesse Houwing
jesse.houwing at sogeti.nl
ChrisKemmerer
2009-05-07 13:38:03 UTC
Permalink
I just supply a class in an assembly. The client application creates a new
instance of that class which triggers the creation of the message window.
When that happens I can see my overridden WndProc being called with the
various winodw creation messages (WM_NCCREATE, WM_CREATE, ...) and I can find
the window using FindWindowEx. After that my WndProc is never called.
Post by Jesse Houwing
Hello ChrisKemmerer,
Your remote server does not start an application, nor does it process window
events like a normal windows forms app would do. My guess is that if you
host your remote form in a windows forms application instead of a commandline
app, then it would work. Hosting an application (using application.start)
would make sure a thread is created to process and receive window messages.
Jesse
Post by ChrisKemmerer
I have a .NET assembly that interacts with a third party driver that
communicates using custom Windows messages. This assembly is then used
by others in their application. The purpose of the assembly is to hide
the ugly details of communicating with the driver. In my assembly I
have a class derived from NativeWindow that creates a message only
window (HWND_MESSAGE). In the overridden WndProc procedure I check for
the custom messages and handle them. This works fine when using the
assembly from a normal Windows Forms application in C# or VB.NET. It
doesn't work with remoting.
For testing I created a stripped down version of my assembly and
checked to make sure that the overridden WndProc was being called and
found that it was not. I could tell that the message window was
created and can find it using another test application that calls
FindWindowEx and then posts a WM_NULL message to it. I could also see
that Windows messages were being processed while the message window
was being created (WM_NCCREATE, WM_CREATE, ...). After that, nothing.
Again, this assembly works fine with normal Windows Forms apps but not
when remoted. Below is my code.
Just to make sure this wasn't just an issue with Message Windows I
tried creating a normal window and still had the same problem.
I'm hoping it is just something stupid that I forgot. Thanks.
-------------------------
RemoteNET.h
-------------------------
using namespace System;
using namespace System::Windows::Forms;
namespace RemoteNET {
ref class CNETWnd;
public ref class CTestClass
{
CTestClass();
~CTestClass();
CNETWnd^ m_pWnd;
};
public ref class CNETWnd : public NativeWindow
{
CNETWnd(CTestClass^ pClass);
~CNETWnd();
CTestClass^ m_pClass;
virtual void WndProc(Message % msg) override;
};
}
}
}
------------------
RemoteNET.cpp
------------------
namespace RemoteNET
{
CTestClass::CTestClass()
{
m_pWnd = gcnew CNETWnd(this);
}
CTestClass::~CTestClass()
{
}
CNETWnd::~CNETWnd()
{
}
CNETWnd::CNETWnd(CTestClass^ pClass) : m_pClass(pClass)
{
CreateParams^ cp = gcnew CreateParams;
// create the message window to receive Windows messages
cp->Caption = "NETWnd";
cp->ClassName = "Message";
cp->Parent = IntPtr(HWND_MESSAGE);
this->CreateHandle(cp);
}
void CNETWnd::WndProc(Message % msg)
{
0x{0:X}.", msg.Msg));
NativeWindow::WndProc(msg);
}
}
}
}
My remote class that wraps the .NET assembly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RemoteNET;
namespace RemoteClass
{
public class RemoteClass : MarshalByRefObject
{
private CTestClass objTestClass;
public RemoteClass()
{
objTestClass = new CTestClass();
}
public void DoSomething()
{
return;
}
}
}
Remote Server.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteServer
{
class Program
{
static void Main(string[] args)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
//string configFile = "App.config";
RemotingConfiguration.Configure(configFile, true);
Console.Write("Sever is Ready........");
Console.Read();
}
}
}
Remote server config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
objectUri="RemoteController"
mode="Singleton"
/>
</service>
<channels>
<channel ref="tcp" port="2000">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Client.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteClient
{
public partial class TestClass : Form
{
RemoteClass.RemoteClass test;
public TestClass()
{
InitializeComponent();
}
private void TestClass_Load(object sender, EventArgs e)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
RemotingConfiguration.Configure(configFile, true);
string url = "tcp://localhost:2000/CameraController";
test =
(RemoteClass.RemoteClass)RemotingServices.Connect(typeof(RemoteClass.R
emoteClass), url);
}
private void button1_Click(object sender, EventArgs e)
{
test.DoSomething();
}
}
}
Client config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
url="tcp://localhost:2000/RemoteController"
/>
</client>
<channels>
<channel ref="tcp" port="0">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
--
Jesse Houwing
jesse.houwing at sogeti.nl
Jesse Houwing
2009-05-07 13:57:06 UTC
Permalink
Hello ChrisKemmerer,
Post by ChrisKemmerer
I just supply a class in an assembly. The client application creates a
new instance of that class which triggers the creation of the message
window. When that happens I can see my overridden WndProc being called
with the various winodw creation messages (WM_NCCREATE, WM_CREATE,
...) and I can find the window using FindWindowEx. After that my
WndProc is never called.
Yes I read that. But after because after the window is created, you see nor
hear anything from it, my guess is that you'd have to supply it with a thread
which will read these messages and forward them to your window. Because it
is craeted in a new appdomain, no such thread was ever started for this specific
window. You need to start a Message Pump thread in the second appdomain in
which the remote window lives, otherwise t will not receive any messages
from outside of the form itself (which is what you're seeing).

Have you tried hosting the remote window in it's own windows forms application?
That should work.

Jesse
Post by ChrisKemmerer
Post by Jesse Houwing
Hello ChrisKemmerer,
Your remote server does not start an application, nor does it process
window events like a normal windows forms app would do. My guess is
that if you host your remote form in a windows forms application
instead of a commandline app, then it would work. Hosting an
application (using application.start) would make sure a thread is
created to process and receive window messages.
Jesse
Post by ChrisKemmerer
I have a .NET assembly that interacts with a third party driver that
communicates using custom Windows messages. This assembly is then
used by others in their application. The purpose of the assembly is
to hide the ugly details of communicating with the driver. In my
assembly I have a class derived from NativeWindow that creates a
message only window (HWND_MESSAGE). In the overridden WndProc
procedure I check for the custom messages and handle them. This
works fine when using the assembly from a normal Windows Forms
application in C# or VB.NET. It doesn't work with remoting.
For testing I created a stripped down version of my assembly and
checked to make sure that the overridden WndProc was being called
and found that it was not. I could tell that the message window was
created and can find it using another test application that calls
FindWindowEx and then posts a WM_NULL message to it. I could also
see that Windows messages were being processed while the message
window was being created (WM_NCCREATE, WM_CREATE, ...). After that,
nothing. Again, this assembly works fine with normal Windows Forms
apps but not when remoted. Below is my code.
Just to make sure this wasn't just an issue with Message Windows I
tried creating a normal window and still had the same problem.
I'm hoping it is just something stupid that I forgot. Thanks.
-------------------------
RemoteNET.h
-------------------------
using namespace System;
using namespace System::Windows::Forms;
namespace RemoteNET {
ref class CNETWnd;
public ref class CTestClass
{
CTestClass();
~CTestClass();
CNETWnd^ m_pWnd;
};
public ref class CNETWnd : public NativeWindow
{
CNETWnd(CTestClass^ pClass);
~CNETWnd();
CTestClass^ m_pClass;
virtual void WndProc(Message % msg) override;
};
}
}
}
------------------
RemoteNET.cpp
------------------
namespace RemoteNET
{
CTestClass::CTestClass()
{
m_pWnd = gcnew CNETWnd(this);
}
CTestClass::~CTestClass()
{
}
CNETWnd::~CNETWnd()
{
}
CNETWnd::CNETWnd(CTestClass^ pClass) : m_pClass(pClass)
{
CreateParams^ cp = gcnew CreateParams;
// create the message window to receive Windows messages
cp->Caption = "NETWnd";
cp->ClassName = "Message";
cp->Parent = IntPtr(HWND_MESSAGE);
this->CreateHandle(cp);
}
void CNETWnd::WndProc(Message % msg)
{
0x{0:X}.", msg.Msg));
NativeWindow::WndProc(msg);
}
}
}
}
My remote class that wraps the .NET assembly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RemoteNET;
namespace RemoteClass
{
public class RemoteClass : MarshalByRefObject
{
private CTestClass objTestClass;
public RemoteClass()
{
objTestClass = new CTestClass();
}
public void DoSomething()
{
return;
}
}
}
Remote Server.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteServer
{
class Program
{
static void Main(string[] args)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
//string configFile = "App.config";
RemotingConfiguration.Configure(configFile, true);
Console.Write("Sever is Ready........");
Console.Read();
}
}
}
Remote server config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
objectUri="RemoteController"
mode="Singleton"
/>
</service>
<channels>
<channel ref="tcp" port="2000">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Client.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteClient
{
public partial class TestClass : Form
{
RemoteClass.RemoteClass test;
public TestClass()
{
InitializeComponent();
}
private void TestClass_Load(object sender, EventArgs e)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
RemotingConfiguration.Configure(configFile, true);
string url = "tcp://localhost:2000/CameraController";
test =
(RemoteClass.RemoteClass)RemotingServices.Connect(typeof(RemoteClass
.R
emoteClass), url);
}
private void button1_Click(object sender, EventArgs e)
{
test.DoSomething();
}
}
}
Client config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
url="tcp://localhost:2000/RemoteController"
/>
</client>
<channels>
<channel ref="tcp" port="0">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
--
Jesse Houwing
jesse.houwing at sogeti.nl
--
Jesse Houwing
jesse.houwing at sogeti.nl
ChrisKemmerer
2009-05-07 21:26:04 UTC
Permalink
Thank you. I'll think about that a bit and see if I can come up with some
kind of lightweight app or thread that still allows the client app to use the
class as an API.
Post by Jesse Houwing
Hello ChrisKemmerer,
Post by ChrisKemmerer
I just supply a class in an assembly. The client application creates a
new instance of that class which triggers the creation of the message
window. When that happens I can see my overridden WndProc being called
with the various winodw creation messages (WM_NCCREATE, WM_CREATE,
...) and I can find the window using FindWindowEx. After that my
WndProc is never called.
Yes I read that. But after because after the window is created, you see nor
hear anything from it, my guess is that you'd have to supply it with a thread
which will read these messages and forward them to your window. Because it
is craeted in a new appdomain, no such thread was ever started for this specific
window. You need to start a Message Pump thread in the second appdomain in
which the remote window lives, otherwise t will not receive any messages
from outside of the form itself (which is what you're seeing).
Have you tried hosting the remote window in it's own windows forms application?
That should work.
Jesse
Post by ChrisKemmerer
Post by Jesse Houwing
Hello ChrisKemmerer,
Your remote server does not start an application, nor does it process
window events like a normal windows forms app would do. My guess is
that if you host your remote form in a windows forms application
instead of a commandline app, then it would work. Hosting an
application (using application.start) would make sure a thread is
created to process and receive window messages.
Jesse
Post by ChrisKemmerer
I have a .NET assembly that interacts with a third party driver that
communicates using custom Windows messages. This assembly is then
used by others in their application. The purpose of the assembly is
to hide the ugly details of communicating with the driver. In my
assembly I have a class derived from NativeWindow that creates a
message only window (HWND_MESSAGE). In the overridden WndProc
procedure I check for the custom messages and handle them. This
works fine when using the assembly from a normal Windows Forms
application in C# or VB.NET. It doesn't work with remoting.
For testing I created a stripped down version of my assembly and
checked to make sure that the overridden WndProc was being called
and found that it was not. I could tell that the message window was
created and can find it using another test application that calls
FindWindowEx and then posts a WM_NULL message to it. I could also
see that Windows messages were being processed while the message
window was being created (WM_NCCREATE, WM_CREATE, ...). After that,
nothing. Again, this assembly works fine with normal Windows Forms
apps but not when remoted. Below is my code.
Just to make sure this wasn't just an issue with Message Windows I
tried creating a normal window and still had the same problem.
I'm hoping it is just something stupid that I forgot. Thanks.
-------------------------
RemoteNET.h
-------------------------
using namespace System;
using namespace System::Windows::Forms;
namespace RemoteNET {
ref class CNETWnd;
public ref class CTestClass
{
CTestClass();
~CTestClass();
CNETWnd^ m_pWnd;
};
public ref class CNETWnd : public NativeWindow
{
CNETWnd(CTestClass^ pClass);
~CNETWnd();
CTestClass^ m_pClass;
virtual void WndProc(Message % msg) override;
};
}
}
}
------------------
RemoteNET.cpp
------------------
namespace RemoteNET
{
CTestClass::CTestClass()
{
m_pWnd = gcnew CNETWnd(this);
}
CTestClass::~CTestClass()
{
}
CNETWnd::~CNETWnd()
{
}
CNETWnd::CNETWnd(CTestClass^ pClass) : m_pClass(pClass)
{
CreateParams^ cp = gcnew CreateParams;
// create the message window to receive Windows messages
cp->Caption = "NETWnd";
cp->ClassName = "Message";
cp->Parent = IntPtr(HWND_MESSAGE);
this->CreateHandle(cp);
}
void CNETWnd::WndProc(Message % msg)
{
0x{0:X}.", msg.Msg));
NativeWindow::WndProc(msg);
}
}
}
}
My remote class that wraps the .NET assembly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RemoteNET;
namespace RemoteClass
{
public class RemoteClass : MarshalByRefObject
{
private CTestClass objTestClass;
public RemoteClass()
{
objTestClass = new CTestClass();
}
public void DoSomething()
{
return;
}
}
}
Remote Server.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteServer
{
class Program
{
static void Main(string[] args)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
//string configFile = "App.config";
RemotingConfiguration.Configure(configFile, true);
Console.Write("Sever is Ready........");
Console.Read();
}
}
}
Remote server config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
objectUri="RemoteController"
mode="Singleton"
/>
</service>
<channels>
<channel ref="tcp" port="2000">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Client.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteClient
{
public partial class TestClass : Form
{
RemoteClass.RemoteClass test;
public TestClass()
{
InitializeComponent();
}
private void TestClass_Load(object sender, EventArgs e)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
RemotingConfiguration.Configure(configFile, true);
string url = "tcp://localhost:2000/CameraController";
test =
(RemoteClass.RemoteClass)RemotingServices.Connect(typeof(RemoteClass
.R
emoteClass), url);
}
private void button1_Click(object sender, EventArgs e)
{
test.DoSomething();
}
}
}
Client config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
url="tcp://localhost:2000/RemoteController"
/>
</client>
<channels>
<channel ref="tcp" port="0">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
--
Jesse Houwing
jesse.houwing at sogeti.nl
--
Jesse Houwing
jesse.houwing at sogeti.nl
ChrisKemmerer
2009-05-07 21:55:01 UTC
Permalink
I am a little confused though. My class creates an instance of a class
derived from NativeWindow. Doesn't NativeWindow already create a message
loop? Also, everything works fine when the DLL that contains my class is
called from a local application, it only fails if the calling application is
a remote client.
Post by ChrisKemmerer
Thank you. I'll think about that a bit and see if I can come up with some
kind of lightweight app or thread that still allows the client app to use the
class as an API.
Post by Jesse Houwing
Hello ChrisKemmerer,
Post by ChrisKemmerer
I just supply a class in an assembly. The client application creates a
new instance of that class which triggers the creation of the message
window. When that happens I can see my overridden WndProc being called
with the various winodw creation messages (WM_NCCREATE, WM_CREATE,
...) and I can find the window using FindWindowEx. After that my
WndProc is never called.
Yes I read that. But after because after the window is created, you see nor
hear anything from it, my guess is that you'd have to supply it with a thread
which will read these messages and forward them to your window. Because it
is craeted in a new appdomain, no such thread was ever started for this specific
window. You need to start a Message Pump thread in the second appdomain in
which the remote window lives, otherwise t will not receive any messages
from outside of the form itself (which is what you're seeing).
Have you tried hosting the remote window in it's own windows forms application?
That should work.
Jesse
Post by ChrisKemmerer
Post by Jesse Houwing
Hello ChrisKemmerer,
Your remote server does not start an application, nor does it process
window events like a normal windows forms app would do. My guess is
that if you host your remote form in a windows forms application
instead of a commandline app, then it would work. Hosting an
application (using application.start) would make sure a thread is
created to process and receive window messages.
Jesse
Post by ChrisKemmerer
I have a .NET assembly that interacts with a third party driver that
communicates using custom Windows messages. This assembly is then
used by others in their application. The purpose of the assembly is
to hide the ugly details of communicating with the driver. In my
assembly I have a class derived from NativeWindow that creates a
message only window (HWND_MESSAGE). In the overridden WndProc
procedure I check for the custom messages and handle them. This
works fine when using the assembly from a normal Windows Forms
application in C# or VB.NET. It doesn't work with remoting.
For testing I created a stripped down version of my assembly and
checked to make sure that the overridden WndProc was being called
and found that it was not. I could tell that the message window was
created and can find it using another test application that calls
FindWindowEx and then posts a WM_NULL message to it. I could also
see that Windows messages were being processed while the message
window was being created (WM_NCCREATE, WM_CREATE, ...). After that,
nothing. Again, this assembly works fine with normal Windows Forms
apps but not when remoted. Below is my code.
Just to make sure this wasn't just an issue with Message Windows I
tried creating a normal window and still had the same problem.
I'm hoping it is just something stupid that I forgot. Thanks.
-------------------------
RemoteNET.h
-------------------------
using namespace System;
using namespace System::Windows::Forms;
namespace RemoteNET {
ref class CNETWnd;
public ref class CTestClass
{
CTestClass();
~CTestClass();
CNETWnd^ m_pWnd;
};
public ref class CNETWnd : public NativeWindow
{
CNETWnd(CTestClass^ pClass);
~CNETWnd();
CTestClass^ m_pClass;
virtual void WndProc(Message % msg) override;
};
}
}
}
------------------
RemoteNET.cpp
------------------
namespace RemoteNET
{
CTestClass::CTestClass()
{
m_pWnd = gcnew CNETWnd(this);
}
CTestClass::~CTestClass()
{
}
CNETWnd::~CNETWnd()
{
}
CNETWnd::CNETWnd(CTestClass^ pClass) : m_pClass(pClass)
{
CreateParams^ cp = gcnew CreateParams;
// create the message window to receive Windows messages
cp->Caption = "NETWnd";
cp->ClassName = "Message";
cp->Parent = IntPtr(HWND_MESSAGE);
this->CreateHandle(cp);
}
void CNETWnd::WndProc(Message % msg)
{
0x{0:X}.", msg.Msg));
NativeWindow::WndProc(msg);
}
}
}
}
My remote class that wraps the .NET assembly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RemoteNET;
namespace RemoteClass
{
public class RemoteClass : MarshalByRefObject
{
private CTestClass objTestClass;
public RemoteClass()
{
objTestClass = new CTestClass();
}
public void DoSomething()
{
return;
}
}
}
Remote Server.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteServer
{
class Program
{
static void Main(string[] args)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
//string configFile = "App.config";
RemotingConfiguration.Configure(configFile, true);
Console.Write("Sever is Ready........");
Console.Read();
}
}
}
Remote server config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
objectUri="RemoteController"
mode="Singleton"
/>
</service>
<channels>
<channel ref="tcp" port="2000">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Client.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteClient
{
public partial class TestClass : Form
{
RemoteClass.RemoteClass test;
public TestClass()
{
InitializeComponent();
}
private void TestClass_Load(object sender, EventArgs e)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
RemotingConfiguration.Configure(configFile, true);
string url = "tcp://localhost:2000/CameraController";
test =
(RemoteClass.RemoteClass)RemotingServices.Connect(typeof(RemoteClass
.R
emoteClass), url);
}
private void button1_Click(object sender, EventArgs e)
{
test.DoSomething();
}
}
}
Client config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
url="tcp://localhost:2000/RemoteController"
/>
</client>
<channels>
<channel ref="tcp" port="0">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
--
Jesse Houwing
jesse.houwing at sogeti.nl
--
Jesse Houwing
jesse.houwing at sogeti.nl
Jesse Houwing
2009-05-07 22:18:30 UTC
Permalink
Hello ChrisKemmerer,
Post by ChrisKemmerer
I am a little confused though. My class creates an instance of a class
derived from NativeWindow. Doesn't NativeWindow already create a
message loop? Also, everything works fine when the DLL that contains
my class is called from a local application, it only fails if the
calling application is a remote client.
The message loop is not created per window, it is created per application(domain)
(using the application.run method).

It works when calling locally, because it is hosted in the application and
can utilize the message pump.

This article might help:
http://www.codeproject.com/KB/system/NET_and_COM.aspx

It explains about the message pump in a console application and revolves
around the same problem you are having.

If it were me I'd host the remote form in it's own windows forms app, for
ease... you can hide the taskbar entry for the app if needed.

Jesse
Post by ChrisKemmerer
Post by ChrisKemmerer
Thank you. I'll think about that a bit and see if I can come up with
some kind of lightweight app or thread that still allows the client
app to use the class as an API.
Post by Jesse Houwing
Hello ChrisKemmerer,
Post by ChrisKemmerer
I just supply a class in an assembly. The client application
creates a new instance of that class which triggers the creation of
the message window. When that happens I can see my overridden
WndProc being called with the various winodw creation messages
(WM_NCCREATE, WM_CREATE, ...) and I can find the window using
FindWindowEx. After that my WndProc is never called.
Yes I read that. But after because after the window is created, you
see nor hear anything from it, my guess is that you'd have to supply
it with a thread which will read these messages and forward them to
your window. Because it is craeted in a new appdomain, no such
thread was ever started for this specific window. You need to start
a Message Pump thread in the second appdomain in which the remote
window lives, otherwise t will not receive any messages from outside
of the form itself (which is what you're seeing).
Have you tried hosting the remote window in it's own windows forms
application? That should work.
Jesse
Post by ChrisKemmerer
Post by Jesse Houwing
Hello ChrisKemmerer,
Your remote server does not start an application, nor does it
process window events like a normal windows forms app would do. My
guess is that if you host your remote form in a windows forms
application instead of a commandline app, then it would work.
Hosting an application (using application.start) would make sure a
thread is created to process and receive window messages.
Jesse
Post by ChrisKemmerer
I have a .NET assembly that interacts with a third party driver
that communicates using custom Windows messages. This assembly is
then used by others in their application. The purpose of the
assembly is to hide the ugly details of communicating with the
driver. In my assembly I have a class derived from NativeWindow
that creates a message only window (HWND_MESSAGE). In the
overridden WndProc procedure I check for the custom messages and
handle them. This works fine when using the assembly from a
normal Windows Forms application in C# or VB.NET. It doesn't work
with remoting.
For testing I created a stripped down version of my assembly and
checked to make sure that the overridden WndProc was being called
and found that it was not. I could tell that the message window
was created and can find it using another test application that
calls FindWindowEx and then posts a WM_NULL message to it. I
could also see that Windows messages were being processed while
the message window was being created (WM_NCCREATE, WM_CREATE,
...). After that, nothing. Again, this assembly works fine with
normal Windows Forms apps but not when remoted. Below is my code.
Just to make sure this wasn't just an issue with Message Windows
I tried creating a normal window and still had the same problem.
I'm hoping it is just something stupid that I forgot. Thanks.
-------------------------
RemoteNET.h
-------------------------
using namespace System;
using namespace System::Windows::Forms;
namespace RemoteNET {
ref class CNETWnd;
public ref class CTestClass
{
CTestClass();
~CTestClass();
CNETWnd^ m_pWnd;
};
public ref class CNETWnd : public NativeWindow
{
CNETWnd(CTestClass^ pClass);
~CNETWnd();
CTestClass^ m_pClass;
virtual void WndProc(Message % msg) override;
};
}
}
}
------------------
RemoteNET.cpp
------------------
namespace RemoteNET
{
CTestClass::CTestClass()
{
m_pWnd = gcnew CNETWnd(this);
}
CTestClass::~CTestClass()
{
}
CNETWnd::~CNETWnd()
{
}
CNETWnd::CNETWnd(CTestClass^ pClass) : m_pClass(pClass)
{
CreateParams^ cp = gcnew CreateParams;
// create the message window to receive Windows messages
cp->Caption = "NETWnd";
cp->ClassName = "Message";
cp->Parent = IntPtr(HWND_MESSAGE);
this->CreateHandle(cp);
}
void CNETWnd::WndProc(Message % msg)
{
0x{0:X}.", msg.Msg));
NativeWindow::WndProc(msg);
}
}
}
}
My remote class that wraps the .NET assembly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RemoteNET;
namespace RemoteClass
{
public class RemoteClass : MarshalByRefObject
{
private CTestClass objTestClass;
public RemoteClass()
{
objTestClass = new CTestClass();
}
public void DoSomething()
{
return;
}
}
}
Remote Server.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteServer
{
class Program
{
static void Main(string[] args)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
//string configFile = "App.config";
RemotingConfiguration.Configure(configFile, true);
Console.Write("Sever is Ready........");
Console.Read();
}
}
}
Remote server config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
objectUri="RemoteController"
mode="Singleton"
/>
</service>
<channels>
<channel ref="tcp" port="2000">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Client.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteClient
{
public partial class TestClass : Form
{
RemoteClass.RemoteClass test;
public TestClass()
{
InitializeComponent();
}
private void TestClass_Load(object sender, EventArgs e)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
RemotingConfiguration.Configure(configFile, true);
string url = "tcp://localhost:2000/CameraController";
test =
(RemoteClass.RemoteClass)RemotingServices.Connect(typeof(RemoteCl
ass
.R
emoteClass), url);
}
private void button1_Click(object sender, EventArgs e)
{
test.DoSomething();
}
}
}
Client config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
url="tcp://localhost:2000/RemoteController"
/>
</client>
<channels>
<channel ref="tcp" port="0">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
--
Jesse Houwing
jesse.houwing at sogeti.nl
--
Jesse Houwing
jesse.houwing at sogeti.nl
--
Jesse Houwing
jesse.houwing at sogeti.nl
ChrisKemmerer
2009-05-07 23:11:10 UTC
Permalink
That helps explain things a bit. Thank you.
Post by Jesse Houwing
Hello ChrisKemmerer,
Post by ChrisKemmerer
I am a little confused though. My class creates an instance of a class
derived from NativeWindow. Doesn't NativeWindow already create a
message loop? Also, everything works fine when the DLL that contains
my class is called from a local application, it only fails if the
calling application is a remote client.
The message loop is not created per window, it is created per application(domain)
(using the application.run method).
It works when calling locally, because it is hosted in the application and
can utilize the message pump.
http://www.codeproject.com/KB/system/NET_and_COM.aspx
It explains about the message pump in a console application and revolves
around the same problem you are having.
If it were me I'd host the remote form in it's own windows forms app, for
ease... you can hide the taskbar entry for the app if needed.
Jesse
Post by ChrisKemmerer
Post by ChrisKemmerer
Thank you. I'll think about that a bit and see if I can come up with
some kind of lightweight app or thread that still allows the client
app to use the class as an API.
Post by Jesse Houwing
Hello ChrisKemmerer,
Post by ChrisKemmerer
I just supply a class in an assembly. The client application
creates a new instance of that class which triggers the creation of
the message window. When that happens I can see my overridden
WndProc being called with the various winodw creation messages
(WM_NCCREATE, WM_CREATE, ...) and I can find the window using
FindWindowEx. After that my WndProc is never called.
Yes I read that. But after because after the window is created, you
see nor hear anything from it, my guess is that you'd have to supply
it with a thread which will read these messages and forward them to
your window. Because it is craeted in a new appdomain, no such
thread was ever started for this specific window. You need to start
a Message Pump thread in the second appdomain in which the remote
window lives, otherwise t will not receive any messages from outside
of the form itself (which is what you're seeing).
Have you tried hosting the remote window in it's own windows forms
application? That should work.
Jesse
Post by ChrisKemmerer
Post by Jesse Houwing
Hello ChrisKemmerer,
Your remote server does not start an application, nor does it
process window events like a normal windows forms app would do. My
guess is that if you host your remote form in a windows forms
application instead of a commandline app, then it would work.
Hosting an application (using application.start) would make sure a
thread is created to process and receive window messages.
Jesse
Post by ChrisKemmerer
I have a .NET assembly that interacts with a third party driver
that communicates using custom Windows messages. This assembly is
then used by others in their application. The purpose of the
assembly is to hide the ugly details of communicating with the
driver. In my assembly I have a class derived from NativeWindow
that creates a message only window (HWND_MESSAGE). In the
overridden WndProc procedure I check for the custom messages and
handle them. This works fine when using the assembly from a
normal Windows Forms application in C# or VB.NET. It doesn't work
with remoting.
For testing I created a stripped down version of my assembly and
checked to make sure that the overridden WndProc was being called
and found that it was not. I could tell that the message window
was created and can find it using another test application that
calls FindWindowEx and then posts a WM_NULL message to it. I
could also see that Windows messages were being processed while
the message window was being created (WM_NCCREATE, WM_CREATE,
...). After that, nothing. Again, this assembly works fine with
normal Windows Forms apps but not when remoted. Below is my code.
Just to make sure this wasn't just an issue with Message Windows
I tried creating a normal window and still had the same problem.
I'm hoping it is just something stupid that I forgot. Thanks.
-------------------------
RemoteNET.h
-------------------------
using namespace System;
using namespace System::Windows::Forms;
namespace RemoteNET {
ref class CNETWnd;
public ref class CTestClass
{
CTestClass();
~CTestClass();
CNETWnd^ m_pWnd;
};
public ref class CNETWnd : public NativeWindow
{
CNETWnd(CTestClass^ pClass);
~CNETWnd();
CTestClass^ m_pClass;
virtual void WndProc(Message % msg) override;
};
}
}
}
------------------
RemoteNET.cpp
------------------
namespace RemoteNET
{
CTestClass::CTestClass()
{
m_pWnd = gcnew CNETWnd(this);
}
CTestClass::~CTestClass()
{
}
CNETWnd::~CNETWnd()
{
}
CNETWnd::CNETWnd(CTestClass^ pClass) : m_pClass(pClass)
{
CreateParams^ cp = gcnew CreateParams;
// create the message window to receive Windows messages
cp->Caption = "NETWnd";
cp->ClassName = "Message";
cp->Parent = IntPtr(HWND_MESSAGE);
this->CreateHandle(cp);
}
void CNETWnd::WndProc(Message % msg)
{
0x{0:X}.", msg.Msg));
NativeWindow::WndProc(msg);
}
}
}
}
My remote class that wraps the .NET assembly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RemoteNET;
namespace RemoteClass
{
public class RemoteClass : MarshalByRefObject
{
private CTestClass objTestClass;
public RemoteClass()
{
objTestClass = new CTestClass();
}
public void DoSomething()
{
return;
}
}
}
Remote Server.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteServer
{
class Program
{
static void Main(string[] args)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
//string configFile = "App.config";
RemotingConfiguration.Configure(configFile, true);
Console.Write("Sever is Ready........");
Console.Read();
}
}
}
Remote server config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
objectUri="RemoteController"
mode="Singleton"
/>
</service>
<channels>
<channel ref="tcp" port="2000">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Client.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemoteClient
{
public partial class TestClass : Form
{
RemoteClass.RemoteClass test;
public TestClass()
{
InitializeComponent();
}
private void TestClass_Load(object sender, EventArgs e)
{
string configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
RemotingConfiguration.Configure(configFile, true);
string url = "tcp://localhost:2000/CameraController";
test =
(RemoteClass.RemoteClass)RemotingServices.Connect(typeof(RemoteCl
ass
.R
emoteClass), url);
}
private void button1_Click(object sender, EventArgs e)
{
test.DoSomething();
}
}
}
Client config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown
type="RemoteClass.RemoteClass, RemoteClass"
url="tcp://localhost:2000/RemoteController"
/>
</client>
<channels>
<channel ref="tcp" port="0">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
--
Jesse Houwing
jesse.houwing at sogeti.nl
--
Jesse Houwing
jesse.houwing at sogeti.nl
--
Jesse Houwing
jesse.houwing at sogeti.nl
Günter Prossliner
2009-05-07 14:36:14 UTC
Permalink
Hallo Jesse!
Post by Jesse Houwing
Have you tried hosting the remote window in it's own windows forms application?
You don't have to create a "Windows-Application", but you definitly have to
use an "Application.Run(new CNETWnd())" or a new "CNETWnd.ShowDialog()" to
startup the Message-Queue from you main - method.


GP
Jesse Houwing
2009-05-08 10:22:51 UTC
Permalink
Hello Günter,
Post by Günter Prossliner
Hallo Jesse!
Post by Jesse Houwing
Have you tried hosting the remote window in it's own windows forms application?
You don't have to create a "Windows-Application", but you definitly
have to use an "Application.Run(new CNETWnd())" or a new
"CNETWnd.ShowDialog()" to startup the Message-Queue from you main -
method.
That was what I was trying to explain...

Basically calling Application.Run starts a winforms application context.

--
Jesse Houwing
jesse.houwing at sogeti.nl

Loading...