我正在尝试将二进制数据从 .NET 获取到 FoxPro(一种 COM 兼容语言)。我有一个 ComVisible 的 .NET 对象和一个带有带字符串参数的事件的事件接口(interface)。
在我下面的示例中,我有一个虚拟实现,它返回一个包含从 0 到 255 的每个连续字符的字符串。在 .NET 端,该字符串适本地存储每个未受干扰的字符,但在客户端处理事件时,之间的字符128 和 154 转换为问号。超过 154 个字符再次保持不变。
知道是什么导致了这个问题吗?不幸的是,FoxPro 没有一种方法来本地表示二进制数据,需要在字符串中进行柯里化(Currying)处理。
[Guid("974E3133-9925-4148-8A2B-F4B811072B17"), ComVisible(true), ComSourceInterfaces(typeof(IStreamEvents))]
public class DumbSerialPort {
readonly string _buf;
public event DataReceivedHandler DataReceived;
public event EmptyDelegate Error;
public DumbSerialPort() {
var bbuf = new char[255];
for (int c = 0; c < 255; c++)
bbuf[c] = (char)c;
_buf = new string(bbuf);
}
public void Fire() {
if(DataReceived != null)
DataReceived(_buf);
}
}
[Guid("0F38F3C7-66B2-402B-8C33-A1904F545023"), ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IStreamEvents {
void DataReceived(string data);
void Error();
}
最佳答案
问题
所以问题的原因有点复杂,其根源在于 FoxPro 不支持 Unicode 字符串,并且 COM 被明确定义为 ONLY 对字符串数据使用 Unicode。传递带有不透明二进制数据的字符串可以正常工作,但阻抗不匹配除外。
任何时候 FoxPro 调用返回或具有字符串参数的函数时,它都会在返回用户代码之前在内部进行代码页转换。这种转换显然会导致移动隐藏在字符串中的二进制数据的各种问题。
解决方案(有障碍)
好吧,byte[]
应该 可以工作,而且部分确实 可以工作,这个“部分”是促使我尝试的原因在字符串中隐藏二进制数据。
这是交易(我只用 VFP 9 SP2 验证了这一点,因为我正在使用它);在 C# COM 端,FoxPro CAN 处理定义如下的方法:
public byte[] GetData() { ... }
当调用该方法时,FoxPro 将正确地将数据作为“标记”为二进制的字符串返回(有关“标记的二进制字符串”的解释,请参见 CreateBinary())。这些字符串像非二进制字符串一样支持所有标准字符串操作函数;正是我所需要的。对于由 FoxPro 实现并传递给具有 byte[]
参数的 C# 的 COM 源事件接口(interface)也是如此,就像在我的原始示例中一样。
要防止 FoxPro 在将字符串发送到 COM 对象时对其进行代码页转换,需要使用 CreateBinary()
函数创建该字符串,该函数将字符串标记为二进制并将绕过转换。
但是,FoxPro 所做的不是处理的是将“二进制”字符串传递给如下定义的方法:
public void SendData(byte[] data) { ... }
如果您尝试调用它,您将得到一个无效的参数类型 COM 异常。
这有几个原因不能正常工作,基本上归结为 FoxPro 没有自动处理编码。
解决方案
那么,我们能做什么呢?像这样定义一个函数。
public void SendData(object data) { ... }
好的,现在我们可以调用函数,带有二进制标记的字符串,FoxPro 不会进行任何代码页转换,数据将传给 .NET。但是data
参数的数据类型是什么?它是一个 System.Byte[*]
。那个星号是干什么用的?我不知道所以我 asked the brilliant people on SO .
原来是一个下界非零的数组。
因此,当我们从 FoxPro 获取二进制数据时,我们可以直接转换为 byte[]
,但 FoxPro 数组是从 1 开始的。
因此,为了解决这个问题,这是我在 C# 中所做的:
public void SendData(object data) {
byte[] buf = FPHelper.ToSZArray(data);
// Use buf here
}
public class FPHelper {
public static byte[] ToSZArray(object param) {
var array = param as Array;
if (array == null)
throw new ArgumentException("Expected a binary array, (did you use CREATEBINARY()?)");
if (array.Rank != 1)
throw new ArgumentException("Expected array with rank 1.", "param");
var dest = new byte[array.Length];
Buffer.BlockCopy(array, 0, dest, 0, array.Length);
return dest;
}
}
在 FoxPro 中,唯一的要求是使用“标记”为二进制的字符串调用它:
cData = "Hello World!" + CHR(13) + CHR(12) + CHR(0)
oComObject.SendData(CREATEBINARY(cData))
关于c# - 将字符串中的二进制数据作为 COM 事件参数传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19958315/