我需要通过 DDE 访问旧版应用程序。我没有对这个遗留应用程序的调试访问权限,所以它对我来说几乎是一个黑匣子。
但是,我确实知道它可以工作,因为我有一些 VBA 代码可以通过 DDE 与应用程序通信而没有问题。VBA 代码的前几行基本上是这样的。
lngDDEChannel = DDEInitiate(App:="LEGAPP", Topic:="DDECONV")
DDEExceute channel:=lngDDEChannel, Command:="START_SESSION_12345"
strInfo$ = DDERequest(channel:=lngDDEChannel, Item:="INFO_FIELD")
注意 实际名称和命令与此处显示的不同。但是,命令中的字符数等于原始命令的字符数。只有可以用 ASCII 表示的字符。
如前所述,这段代码工作得很好。附带说明一下,DDERequest 只会在 DDExecute 命令执行后提供数据。如果没有,它将返回空缓冲区。
我正在尝试将此代码移植到 C#。由于微软没有在 DotNet 中实现 DDE,我决定使用开源库NDDE。
这就是我重写上面的代码片段的方式:
using (var client = new DdeClient("LEGAPP", "DDECONV")
{
client.Connect();
client.Execute("START_SESSION_12345");
strVar = client.Request("INFO_FIELD");
}
建立了客户端和服务器之间的连接,我检查了一下。不幸的是,服务器不理解执行命令。它似乎收到了一些乱码,而不是命令“START_SESSION_12345”。
我最初的想法是字符串编码一定有问题。VBA 中的字符串是 7 位 ANSI 字符串,而 DotNet 中的字符串是 16 位。但是,NDDE 似乎比这更聪明,使用连接上下文,可以为与 DDE 服务器交换的所有数据设置特定的编码。默认值是 ASCII,这实际上应该是正确的选择,因为命令字符串中的所有字符都可以用 ASCII 表示。尽管如此,我还是尝试使用所有可能值的上下文编码,例如 UTF-7、UTF-8、ANSI、ASCII、UTF-16(小端和大端)。无论我尝试什么,我都会收到乱码,只是乱码略有不同,这证明编码确实被考虑在内。
我查看了 NDDE 的来源。相关行位于源文件 DdemlClient.cs 中。
var data = _Context.Encoding.GetBytes(command + "\0");
//Send the command to the server.
int returnFlags = 0;
var result = Ddeml.DdeClientTransaction(
data,
data.Length,
_ConversationHandle,
IntPtr.Zero,
Ddeml.CF_TEXT,
Ddeml.XTYP_EXECUTE,
timeout,
ref returnFlags);
DDEClientTransaction 函数在此处进行了详细描述。NDDE 以两种方式调用函数:
[DllImport("user32.dll", EntryPoint = "DdeClientTransaction", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeClientTransaction(IntPtr pData, int cbData, IntPtr hConv, IntPtr hszItem, int wFmt, int wType, int dwTimeout, ref int pdwResult);
[DllImport("user32.dll", EntryPoint = "DdeClientTransaction", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeClientTransaction(byte[] pData, int cbData, IntPtr hConv, IntPtr hszItem, int wFmt, int wType, int dwTimeout, ref int pdwResult);
我的示例中的代码使用第二个 pinvoke 声明,但我也尝试使用第一个,没有区别。
我被困住了。由于通过 VBA 的 DDE 对话工作得很好,我不得不假设 DDE 服务器没有一般问题。我不知道为什么这不起作用。
编辑
我做了一些测试,只是为了澄清自己正在传输什么样的数据。出于本次测试的目的,我将执行命令简单地更改为“ABCD”。
Encoding.Default (=ANSI Codepage) 创建以下字节数组:
应用程序将其作为命令接收:
Encoding.ASCII 创建以下字节数组:
应用程序将其作为命令接收:
Encoding.Unicode(即 UTF-16)创建以下字节数组:
应用程序将其作为命令接收:
也许这会给比我更聪明的人一个正确的想法,什么是错的。