C#实现EHLLAPI(IBM i ACS):特定字节数据传递问题及解决方案
解决EHLLAPI(PCSHLL32.dll)传递特定字节数组的C#调用问题
我最近在基于IBM i Access Client Solution做绿屏交互开发,需要实现EHLLAPI的部分功能,手里有官方文档和能运行的基础示例,但在实现需要传递特定字节数据的函数(比如窗口状态设置)时遇到了麻烦,折腾了几次终于搞定,分享下过程:
基础背景
一开始的示例代码只实现了简单功能(比如字符串交互),用的是下面的C# P/Invoke接口,运行完全正常:
public class EhllapiFunc { [DllImport("PCSHLL32.dll")] public static extern UInt32 hllapi(out UInt32 Func, StringBuilder Data, out UInt32 Length, out UInt32 RetC); }
但当我需要调用那些要求传递特定位置字节值的函数时,StringBuilder就不适用了,得换成字节数组来控制每个位置的内容。
错误的尝试:误用out修饰符
我一开始直接把Data参数改成了out byte[],并手动赋值字节:
// 错误的接口定义 public class EhllapiFunc { [DllImport("PCSHLL32.dll")] public static extern UInt32 hllapi(out UInt32 Func, out byte[] Data, out UInt32 Length, out UInt32 RetC); } // 调用代码 byte[] buffer = new byte[28]; buffer[0] = (byte)65; // letter A buffer[4] = (byte)0x01; // 第五字节设置为X'01'用于状态控制 // 调用后直接失败
这里的问题在于:EHLLAPI的Data参数是一个预先分配好的输入/输出缓冲区,而out修饰符会告诉CLR让函数返回一个新的数组,这和DLL的调用约定不匹配,导致调用失败。
正确的实现方式
后来调整了接口定义,去掉了Data参数的out修饰符,同时用BinaryWriter精准控制字节数组的特定位置:
正确的P/Invoke接口
public class EhllapiFunc { [DllImport("PCSHLL32.dll")] public static extern UInt32 hllapi(out UInt32 Func, Byte[] Data, out UInt32 Length, out UInt32 RetC); }
注意:这里的Byte[]和byte[]本质上是一样的,只是写法不同,核心是去掉了out,让CLR把我们预先分配的数组直接传递给DLL。
构造特定字节的缓冲区并调用
用MemoryStream配合BinaryWriter可以方便地定位到数组的指定位置写入字节,避免手动计算索引出错:
Byte[] buffer = new Byte[28]; // 分配符合要求的缓冲区大小 using (MemoryStream ms = new MemoryStream(buffer)) using (BinaryWriter bw = new BinaryWriter(ms)) { bw.Write((Byte)65); // 往第一个字节写入字母A的ASCII值 bw.Seek(4, SeekOrigin.Begin); // 跳转到第5个字节(索引从0开始,所以是4) bw.Write((Byte)0X01); // 写入十六进制01,用于设置窗口状态 } // 后续调用EHLLAPI函数 UInt32 funcCode = ...; // 对应窗口状态函数的功能码 UInt32 length = (UInt32)buffer.Length; UInt32 retCode; UInt32 result = EhllapiFunc.hllapi(out funcCode, buffer, out length, out retCode);
这样调整后,功能就正常运行了。
内容的提问来源于stack exchange,提问作者Tobe Tung
相关产品推荐
相关产品推荐

