Getting DDEML To Work With Remoting - Please, Please, Please Help

G

Guest

This post was placed in the Dotnet.framework.interop. I think it should have
been placed here. It should not be posted in two places. Sorry about that.

I have a class wrapped around some of the DDEML API functions. Normally, I
can instantiate this class and use it's method to return a value from a DDE
Server. This works great. Now what I really want to do is set this up to work
with the remoting framework. Please note the following steps I did:

1) Made the class wrapper remotable by inheriting from MarshalByRefObject

2) Set up a test remoting server application in Singleton mode with a
registered channel and the registered remotable class.

3) Set up a remoting client with a registered channel and the registered
remotable class.

Both the client application and the server application are on the same
machine for test purposes. When I instantiate the class from the client
application and call the method to retrieve a value from the DDE Server, the
application appears to hang and I do not get any value back. In steping
through the code in debug mode, I know that the remotable class is
instantiated with it's property values set correctly (I have property values
for Service, Topic, Name and Value). Where it hangs is when the DdeConnect
API call is made. This API call uses a callback function which is setup in
the same class. The callback function appears to get correctly initialized in
the DdeInitialize API call.

I'm new to DDEML and to remoting. Any help would be appreciated.

Thanks
 
B

Brian Gideon

Based only on what you've mentioned there are some things that jump out
at me. The DDEML is thread specific. That means all calls to the
DDEML must be from the same thread that called DdeInitialize.
Furthermore, they must also execute on a thread with a message loop.
Unless you have created your own message loop thread from within the
remotable object that all DDEML calls are made on then you're going to
have problems.

Regardless, I'm not sure why DdeConnect would hang. I would have
expected it to return an error code or something. How long does it
hang? Can you provide some of the code? The functions where the DDEML
calls are made will probably be fine for now.

Have you explored other options besides DDE? DDE is old and hard to
work with.

If DDE is your only option then you can try the following class library
to get DDE to work in .NET. It uses the DDEML and the entire source
code is provided.

<http://workspaces.gotdotnet.com/ndde>

Brian
 
G

Guest

Hey Brian,
Thanks for your reply. I really appreciate it. DDE is the only option
in this case. We're using a Stock Quote Server that only supports DDE. The
link you provided I have already downloaded. That project along with another
has been very helpful.

I think the problem is what you had stated. I'm not creating a message loop
from within the remotable object. HONESTLY, I HAVE NO IDEA HOW TO CREATE A
MESSAGE LOOP. IF YOU CAN PROVIDE ANY ADVICE, I WOULD REALLY APPRECIATE IT.

The DdeConnect appears to hang and not return on my computer at work (This
is true using the Stock Quote DDE Server or testing using Excel 97 as a DDE
Server). On my computer at home it hangs from 30 seconds to a minute (Using
Excel 2003 as a DDE Server). After that I'm able to execute my DDE Request
and get a value. Both machines are using XP Professional.

Included below is some of the DDEML code from the remotable object:

Private Sub Initialize(ByVal p_iFlags As Integer)

'********************************************************************************
'* Name: Initialize
*
'* Description: Subroutine method to initialize DDE service
*

'********************************************************************************
If DDEML.DdeInitialize(m_iInstID, m_CallBackDelegate, p_iFlags, 0) Then
Dim message As String = "DDEML INITIALIZATION FAILURE" & vbCrLf &
DdemlError()
Throw New DDEMLException(message)
End If

End Sub

Private Sub Connect()

'********************************************************************************
'* Name: Connect
*
'* Description: Subroutine method to connect to a DDE server
*

'********************************************************************************
'Create string handles for the service name and topic name
Dim h_iService As Integer = CreateStringHandle(Service)
Dim h_iTopic As Integer = CreateStringHandle(Topic)
Dim hDDEConv As Integer

'Estblish a conversation with a server that supports the service name and
topic name pair
m_hDDEConv = DDEML.DdeConnect(m_iInstID, h_iService, h_iTopic, vbNullString)

'Free the string handles
DDEML.DdeFreeStringHandle(m_iInstID, h_iService)
DDEML.DdeFreeStringHandle(m_iInstID, h_iTopic)

'Check for connection error
If m_hDDEConv = 0 Then
Dim message As String = "DDEML CONNECTION FAILURE" & vbCrLf &
DdemlError()
Throw New DDEMLException(message)
End If

End Sub
 
B

Brian Gideon

NeddyRock said:
I think the problem is what you had stated. I'm not creating a message loop
from within the remotable object. HONESTLY, I HAVE NO IDEA HOW TO CREATE A
MESSAGE LOOP. IF YOU CAN PROVIDE ANY ADVICE, I WOULD REALLY APPRECIATE IT.

Use the Application.Run method to start a message loop on the current
thread. The easiest and probably best way of marshaling the remote
calls is to use the Invoke method on a hidden form that is hosted on
the message loop thread. If you're not familar with message loops this
will be a bit confusing. The dependence on windows messages is the
number one reason why DDE is so difficult to use. I recommend using
the code library I already mentioned because it encapsulates all of the
difficult logic in making the DDEML work.
 
G

Guest

Hey Brian,
Thanks for the response. I appreciate it. I did try using that library.
I was able to get it to work from a windows form client application, but I
couldn't get it to work using remoting. I think what I did was create a
remotable class and within that class use the methods and properties exposed
form the library.

Is there any easy example of using Application.Run and PInvoke? Thanks.
I appceciate your advice.
 
B

Brian Gideon

Well, Application.Run is used in every windows form application. Just
look at the Main method. You can use the Win32 APIs to create the
message loop as well, but it's easier to use Application.Run.

I'll take a look at using the DDEML in a remotable class when I get
some time. I'll try to post back in the next few days.
 
B

Brian Gideon

I got it to work in a remotable class. Follow the example on MSDN.

<http://msdn.microsoft.com/library/d...s/cpguide/html/cpconbuildingremotabletype.asp>

I put the following code in the RemotableType.StringMethod.

public string StringMethod()
{
DdeClient client = new DdeClient("excel", "sheet1");
try
{
client.Connect();
byte[] data = client.Request("r1c1", 1, 5000);
string s = Encoding.ASCII.GetString(data);
Console.WriteLine(s);
return s;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return "";
}
finally
{
client.Dispose();
}
}

One thing that is wrong with the library is that one of the exceptions
isn't marked as serializable so it can't cross an application domain.
If you don't want to use the library then you can at least look at the
code to see how everything should be done.

Brian
 
G

Guest

Hey Brian,
Thanks for the reply. I really apprecit it.

Thanks
Ned

Brian Gideon said:
I got it to work in a remotable class. Follow the example on MSDN.

<http://msdn.microsoft.com/library/d...s/cpguide/html/cpconbuildingremotabletype.asp>

I put the following code in the RemotableType.StringMethod.

public string StringMethod()
{
DdeClient client = new DdeClient("excel", "sheet1");
try
{
client.Connect();
byte[] data = client.Request("r1c1", 1, 5000);
string s = Encoding.ASCII.GetString(data);
Console.WriteLine(s);
return s;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return "";
}
finally
{
client.Dispose();
}
}

One thing that is wrong with the library is that one of the exceptions
isn't marked as serializable so it can't cross an application domain.
If you don't want to use the library then you can at least look at the
code to see how everything should be done.

Brian
Hey Brian,
Thanks for the response. I appreciate it. I did try using that library.
I was able to get it to work from a windows form client application, but I
couldn't get it to work using remoting. I think what I did was create a
remotable class and within that class use the methods and properties exposed
form the library.

Is there any easy example of using Application.Run and PInvoke? Thanks.
I appceciate your advice.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top