DDEML Wrapper -- Fail to disconnect

  • Thread starter Thread starter Homa
  • Start date Start date
H

Homa

Hi all,
I'm writing a DDEML wrapper in C#.

I'm able to establish a connection to the server application but
when I try to disconnect it using DdeDisconnect, I got an error
message DMLERR_INVALIDPARAMETER.

I looked at the spec of the function
(http://msdn.microsoft.com/library/d...ExchangeManagementFunctions/DdeDisconnect.asp)

and see that the error message I could get are
DMLERR_DLL_NOT_INITIALIZED, DMLERR_NO_CONV_ESTABLISHED, and
DMLERR_NO_ERROR.

I don't know why would the error DMLERR_INVALIDPARAMETER show up at
this place.

I tested it and indeed it comes from the DdeDisconnect call.

There is the boilerplate of the coding,
internal class ddeClass
{
[DllImport("user32")]
internal static extern bool DdeDisconnect(ref int hConv);

[DllImport("user32")]
internal static extern int DdeConnect(int idInst, int hszService, int
hszTopic, out CONVCONTEXT pCC);

[DllImport("user32")]
internal static extern int DdeCreateStringHandle(int idInst, string
psz, int iCodePage);

[DllImport("user32")]
internal static extern DMLERR DdeGetLastError(int idInst);

}

internal class ddeTest
{
int idInst = 0; // This is properly initialized in the constructor
// by calling ddeClass.DdeInitialize (not shown)
int hszService = 0;
int hszTopic = 0;
int conHandle = 0;

private void button3_Click(object sender, System.EventArgs e)
{
ddeClass.CONVCONTEXT ccontext;

// I use Excel to test the program. An instance of excel is opened
// when this test program runs.
hszService = ddeClass.DdeCreateStringHandle(idInst, "Excel",
ddeClass.CP_WINANSI);
hszTopic = ddeClass.DdeCreateStringHandle(idInst, "Sheet1",
ddeClass.CP_WINANSI);
conHandle = ddeClass.DdeConnect(idInst, hszService, hszTopic, out
ccontext);

// I get a non-zero conHandle here, the connection success
// Also, if call ddeClass.DdeGetLastError here, I get
DMLERR_NO_ERROR

ddeClass.DdeDisconnect(ref conHandle);
ddeClass.DMLERR derr = ddeClass.DdeGetLastError(idInst);
label1.Text = Enum.GetName(typeof(ddeClass.DMLERR), derr);
// label1.Text => DMLERROR_INVALIDPARAMETER
}

}


Thanks for concern,

Homa Wong
 
Why 'DdeDisconnect(ref int hConv);'? DdeDisconnect takes a HCONV, not a
pointer to a HCONV, so you shouldn't really have a ref here.

Better to use System.IntPtr rather than int for handles, really.

Sunlight
 
Thanks David,
That was the error. Since it's a ref int, the ddeml actually get the
pointer points to my int, not the handle. so the memory is not correct
and it gives me the InvalidParam error.

Thanks for your help and sorry about the late reply.

I made progress after my last posting, and now the DDEML wrapper is
more complete. It's able to do sync communication fine.

But now I'm facing a design decision and want to ask for some advices.

Currently I'm created two exceptions: dmlInternalException and
dmlConnectionException.

dmlInternalException will be thrown when I failed to do something that
is not related to server communciation, such as failed to register
(ddeInitialize), or failed to create/free handles
(ddeCreateDataHandle, ddeCreateStringHandle, ddeFreeDataHandle,
ddeFreeStringHandle)

dmlConnectionException will be thrown when I failed to communicate
with the server (ddeConnect, ddeClientTransaction)

all these exceptions I have the DMLERR stored within.

My question is should I remove the dmlConnectionException?

Since dde is a communication channel between two apps, it is possible
that at any moment the server (I'm writing the client, so I just say
the other app is server) can be not available. It may crash, it may be
busy, closed by user, etc, etc.

So should I consider that as an normal result? If so, then I should
not use Exception to propagate this upward but use other mechanisms to
represent this result.

I received some emails from other developers that asking for the
source code of it. I'm now planning to complete it and publish it
somewhere, where can I do this?


Thanks for concern,
Homa Wong

David McCabe said:
Why 'DdeDisconnect(ref int hConv);'? DdeDisconnect takes a HCONV, not a
pointer to a HCONV, so you shouldn't really have a ref here.

Better to use System.IntPtr rather than int for handles, really.

Sunlight

Homa said:
Hi all,
I'm writing a DDEML wrapper in C#.

I'm able to establish a connection to the server application but
when I try to disconnect it using DdeDisconnect, I got an error
message DMLERR_INVALIDPARAMETER.

I looked at the spec of the function
(http://msdn.microsoft.com/library/d...ExchangeManagementFunctions/DdeDisconnect.asp)

and see that the error message I could get are
DMLERR_DLL_NOT_INITIALIZED, DMLERR_NO_CONV_ESTABLISHED, and
DMLERR_NO_ERROR.

I don't know why would the error DMLERR_INVALIDPARAMETER show up at
this place.

I tested it and indeed it comes from the DdeDisconnect call.

There is the boilerplate of the coding,
internal class ddeClass
{
[DllImport("user32")]
internal static extern bool DdeDisconnect(ref int hConv);

[DllImport("user32")]
internal static extern int DdeConnect(int idInst, int hszService, int
hszTopic, out CONVCONTEXT pCC);

[DllImport("user32")]
internal static extern int DdeCreateStringHandle(int idInst, string
psz, int iCodePage);

[DllImport("user32")]
internal static extern DMLERR DdeGetLastError(int idInst);

}

internal class ddeTest
{
int idInst = 0; // This is properly initialized in the constructor
// by calling ddeClass.DdeInitialize (not shown)
int hszService = 0;
int hszTopic = 0;
int conHandle = 0;

private void button3_Click(object sender, System.EventArgs e)
{
ddeClass.CONVCONTEXT ccontext;

// I use Excel to test the program. An instance of excel is opened
// when this test program runs.
hszService = ddeClass.DdeCreateStringHandle(idInst, "Excel",
ddeClass.CP_WINANSI);
hszTopic = ddeClass.DdeCreateStringHandle(idInst, "Sheet1",
ddeClass.CP_WINANSI);
conHandle = ddeClass.DdeConnect(idInst, hszService, hszTopic, out
ccontext);

// I get a non-zero conHandle here, the connection success
// Also, if call ddeClass.DdeGetLastError here, I get
DMLERR_NO_ERROR

ddeClass.DdeDisconnect(ref conHandle);
ddeClass.DMLERR derr = ddeClass.DdeGetLastError(idInst);
label1.Text = Enum.GetName(typeof(ddeClass.DMLERR), derr);
// label1.Text => DMLERROR_INVALIDPARAMETER
}
}


Thanks for concern,

Homa Wong
 
Back
Top