懂VC的请进,重谢100分,要快;帮忙改一句引用外部dll的代码。

afeng124 2009-12-21 04:25:59
VC的原型:
int POS_NETQueryStatus(char *ipAddress,char *pszStatus)
[参数]
ipAddress [in] 设备IP地址。如“192.168.10.251”。
pszStatus [out] 指向接收返回状态的缓冲区,缓冲区大小为 1 个字节。

返回的各状态位意义如下表所示:
Bit Status Meaning
0 0/1 钱箱连接器引脚 3 的电平为低/高(表示打开或关闭)
1 0/1 打印机联机/脱机
2 0/1 上盖关闭/打开
3 0/1 没有/正在由Feed键按下而进纸
4 0/1 打印机没有/有出错
5 0/1 切刀没有/有出错
6 0/1 有纸/纸将尽(纸将尽传感器探测)
7 0/1 有纸/纸用尽(纸传感器探测)
返回值
如果函数成功,则返回值为 POS_SUCCESS(1002)。
如果函数失败,则返回值为以下值之一:POS_FAIL(1001) POS_ERROR_INVALID_HANDLE

以下是小弟的代码:
/// <summary>
/// 通过网络接口查询返回当前打印机的状态。
/// </summary>
/// <param name="ipAddress">设备IP地址。如“192.168.10.251”。</param>
/// <param name="pszStatus">
/// 指向接收返回状态的缓冲区,缓冲区大小为 1 个字节。
/// 0 0/1 钱箱连接器引脚 3 的电平为低/高(表示打开或关闭)
/// 1 0/1 打印机联机/脱机
/// 2 0/1 上盖关闭/打开
/// 3 0/1 没有/正在由Feed键按下而进纸
/// 4 0/1 打印机没有/有出错
/// 5 0/1 切刀没有/有出错
/// 6 0/1 有纸/纸将尽(纸将尽传感器探测)
/// 7 0/1 有纸/纸用尽(纸传感器探测)
/// </param>
/// <returns></returns>
[DllImport("POSDLL.dll", SetLastError = true)]
public static extern IntPtr POS_NETQueryStatus([MarshalAs(UnmanagedType.LPStr)]string ipAddress,Byte szStatus);

调用:
byte b_Result = new byte();
IntPtr handle = BeiYangOPOS.POS_NETQueryStatus("192.168.0.166", b_Result);
(int)handle 的值总是为1001(调用错误);
其实说了半天就是我不明白在C#里面跟C的char *对应的数据类型。有知道的吗,请指教!这个是小票打印机用的opos指令打印的dll.必须要连接了小票打印机才可以测试。
...全文
587 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
jun13949007938 2010-05-21
  • 打赏
  • 举报
回复
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall
soaringbird 2009-12-21
  • 打赏
  • 举报
回复
原来是这种帖,够费劲的了
afeng124 2009-12-21
  • 打赏
  • 举报
回复
chStatus: Char;
iReturn: Integer;
iReturn:=POS_NETQueryStatus(PChar(ipConst),@chStatus)
If (Integer(chStatus) = 1) then
begin
edQuery.Text := '一切正常!';
exit;
end;
for i := 0 to 7 do
begin
bits[i] := (Integer(chStatus) shr i) And 1;
end;
if bits[0] = 0 then
strInfo := '有钱箱打开!';
if bits[1] = 1 then
strInfo := strInfo + '打印机脱机!';
if bits[2] = 1 then
strInfo := strInfo + '上盖打开!';
if bits[3] = 1 then
strInfo := Strinfo + '正在进纸!';
if bits[4] = 1 then
strInfo := strInfo + '打印机出错!';
if bits[5] = 1 then
strInfo := strInfo + '切刀出错!';
if bits[6] = 1 then
strInfo := strInfo + '纸将尽!';
if bits[7] = 1 then
strInfo := strInfo + '缺纸!';
if strInfo = '' then
strInfo := '一切正常!';

分析了delphi的代码,返回值应改是类似这样: 00100001
那么用Byte接收对吗?为什么调用dll成功,这个状态值却和打印机实际状态不符?
afeng124 2009-12-21
  • 打赏
  • 举报
回复
有时候char*也用来做一个字节的字符指针,这时候可以用ref byte。 这个很有道理,不过取出来的状态pszStatus对应的值始终不对。delphi 和 vb 都是用 Byte 传进去的。唯独没有C#调用的例子。哎。烦啊。因为是使用网口的打印机,必须要实时的知道打印机状态。防止漏单,所以要用这个dll.
afeng124 2009-12-21
  • 打赏
  • 举报
回复
不好意思,一直搞错了,其实返回1001,是调用成功的意思。现在取出来的值好像不对,不是158,就是0,还有1,(158 = 10011110)这个看起来比较像,但是对照说明
/// <param name="pszStatus">
/// 指向接收返回状态的缓冲区,缓冲区大小为 1 个字节。
/// 0 0/1 钱箱连接器引脚 3 的电平为低/高(表示打开或关闭)
/// 1 0/1 打印机联机/脱机
/// 2 0/1 上盖关闭/打开
/// 3 0/1 没有/正在由Feed键按下而进纸
/// 4 0/1 打印机没有/有出错
/// 5 0/1 切刀没有/有出错
/// 6 0/1 有纸/纸将尽(纸将尽传感器探测)
/// 7 0/1 有纸/纸用尽(纸传感器探测)
发现还是不对。怪了。
  • 打赏
  • 举报
回复
顺便说一下,我也用小票打印机,不过装了驱动程序,只要自己写下打印事件里的代码就行了
你比我痛苦啊
soaringbird 2009-12-21
  • 打赏
  • 举报
回复
char*在C里一般代表字符串,C#里可以用string(传入字符串时)或StringBuilder(传出字符串时),有时候char*也用来做一个字节的字符指针,这时候可以用ref byte。
  • 打赏
  • 举报
回复
有一点要注意:
在现在 的操作系统中Char占两个字节
而C语言不知道跟上时代了没有,有可能它的Char就和Byte是一样的
不过根据你的描述来看(0-7位的编号说明),应该是byte
就用Byte吧,呵呵,试了就知道
afeng124 2009-12-21
  • 打赏
  • 举报
回复
pszStatus [out] 指向接收返回状态的缓冲区,缓冲区大小为 1 个字节。

其实说了半天就是我不明白在C#里面跟C的char *对应的数据类型。有知道的吗,请指教!这个是小票打印机用的opos指令打印的dll.必须要连接了小票打印机才可以测试。

VC的原型:
int POS_NETQueryStatus(char *ipAddress,char *pszStatus)
[参数]
ipAddress [in] 设备IP地址。如“192.168.10.251”。
pszStatus [out] 指向接收返回状态的缓冲区,缓冲区大小为 1 个字节。

各位请抓住重点解答!对我有用的都会得分!
afeng124 2009-12-21
  • 打赏
  • 举报
回复
以上全试过都不行,返回值是1001失败, szStatus 一般存的是1 (char(1))
  • 打赏
  • 举报
回复
根据我的平台调用经验改下:
[DllImport("POSDLL.dll", SetLastError = true)]
public static extern IntPtr POS_NETQueryStatus(
StringBuilder ipAddress,out char szStatus );

字符串直接用StringBuilder,第二个参数要传递地址用out,就行了
soaringbird 2009-12-21
  • 打赏
  • 举报
回复
[DllImport("POSDLL.dll")]
public static extern int POS_NETQueryStatus(string ip,ref byte status);
sjdev 2009-12-21
  • 打赏
  • 举报
回复
返回值还用int就可以。


[DllImport("POSDLL.dll", SetLastError = true)]
public static extern int POS_NETQueryStatus(string ip,ref byte[] status);


调用

byte[] status = new byte[1];
int ret = POS_NETQueryStatus("xx.xx.xx.xx", ref status);
afeng124 2009-12-21
  • 打赏
  • 举报
回复
/// <param name="pszStatus">
/// 指向接收返回状态的缓冲区,缓冲区大小为 1 个字节。
/// 0 0/1 钱箱连接器引脚 3 的电平为低/高(表示打开或关闭)
/// 1 0/1 打印机联机/脱机
/// 2 0/1 上盖关闭/打开
/// 3 0/1 没有/正在由Feed键按下而进纸
/// 4 0/1 打印机没有/有出错
/// 5 0/1 切刀没有/有出错
/// 6 0/1 有纸/纸将尽(纸将尽传感器探测)
/// 7 0/1 有纸/纸用尽(纸传感器探测)
byte[] b_Result = new byte[8];
IntPtr handle = BeiYangOPOS.POS_NETQueryStatus("192.168.0.166", b_Result);
早试过了。也是调用dll不成功,但是 b_Result返回了值 {1,0,0,0,0,0,0,0}
Kession0709 2009-12-21
  • 打赏
  • 举报
回复
顶顶顶。。。。
afeng124 2009-12-21
  • 打赏
  • 举报
回复
zzxap 那个API32.dll我的win2003系统提示没有这个文件。无法验证可行性。
afeng124 2009-12-21
  • 打赏
  • 举报
回复
使用out 或者 ref,用 byte[]去接收也试了。都不行。
[DllImport("POSDLL.dll", SetLastError = true)]
public static extern IntPtr POS_NETQueryStatus([MarshalAs(UnmanagedType.LPStr)]string ipAddress,ref byte[] szStatus);

[DllImport("POSDLL.dll", SetLastError = true)]
public static extern IntPtr POS_NETQueryStatus([MarshalAs(UnmanagedType.LPStr)]string ipAddress,out byte[] szStatus);

谢谢各位的回答,请直接改写我的代码。不用引用其他的例子,看起来比较麻烦。谢谢
afeng124 2009-12-21
  • 打赏
  • 举报
回复
zzxap 2009-12-21
  • 打赏
  • 举报
回复
在C++程序设计中一般采用char*来处理字符或字符串,在C#和C++协同工作中,从C#通过InteropServices调用原生C++实现DLL中的函数时其他基本数据类型比较好对应,难以处理的是字符或字符串。网上有人给出了一些方案,可以用,不过,个人认为在C#中采用Byte[]和char*对应的方法最稳健,因为Byte对应大小为无符号整形数的字节流,其他,采用C#中字符或者字符串类型的方法,可能存在Unicode和Ansi码等问题,可靠性不好。

示例:

1 原始C++实现DLL的函数原形 int getapiversion(char*version, int len);

2 C#中封装DLL API的基础类:

using System.Runtime.InteropServices;

namespace CDLLSample
{
class CSample
{
[DllImport("API32.dll", CharSet = CharSet.Auto)]
public static extern Int32 getapiversion(byte[] version, int i);

}

}

3 转换成C#可以使用的类库

namespace CDLLSample
{
public class CLib
{
public static Int32 GetVersion(ref string version)
{
Int32 result=1;

Byte[] sb=new Byte[8]; //4*8=32
result = CSample.getapiversion(sb, 32);
ASCIIEncoding encoding = new ASCIIEncoding( );
version = encoding.GetString(sb);
if (result != 0) version ="NULL";
return result;
}

}

4 C#中使用

string verStr="";
CDLLSample.CLib.GetVersion(ref verStr);
TextBox1.Text = verStr;
zzxap 2009-12-21
  • 打赏
  • 举报
回复
你是想在C#中调用C++ DLL中提供的函数接口吧?假如你的DLL名字为MyLib.dll,且位于系统路径中或运行目录中,那么在C#中如此写就可以调用了:

[DllImport("MyLib.dll")]
public extern static void lpOnReceiveUserData(
Intptr buffer,
Int32 sizeBuffer,
ref Byte name,
Int32 sizeSomething);

说明3点:

a。请注意参数转换,你可能注意到了我对C++中数据类型unsigned long和unsigned int 都转换为了C#中的Int32,这个基本没有问题,在我们现在用的32位操作系统中,都是4个字节,即32位;在16位系统中,是有区别的,long 为32位,int为16位,我想现在都应该基本没有人用16位的操作系统了吧,呵呵;

b。另外形参的名字是我根据此函数接口的意思加上的,也许名字命名得不太准确,但这并不影响正确使用,没有办法,原型中没有形参的名字(对于这个问题,稍后给你解释。顺便说一句:如果是故作高深其实很肤浅,当然也许DLL的作者有其特殊的原因,其意图我不可臆测 );

c。因为调用的是__stdcall函数,所以使用了P/Invoke的调用方法。其中的方法FunctionName必须声明为静态外部函数,即加上 extern static声明头。


(2)关于补充问题:
在C++中BYTE*一般写法是PBYTE(不过没有关系,反正都是正确的),其实BYTE就是unsigned char,<WinDef.h>中是这样定义BYTE的:typedef unsigned char BYTE;所以其在C#中对应参数转换为ref Byte;

给你解释一下C++ 中定义的这个函数接口:
typedef void(__stdcall *lpOnReceiveUserData)(void *, unsigned long, unsigned char *, unsigned int);

返回值为void,即无返回值;

__stdcall为函数的调用规范,Windows中的WINAPI宏就是被定义为__stdcall的(<WinDef.h>有这样的宏定义:#define WINAPI __stdcall),这个调用规范定义的函数接口是标准的windows API;

至于参数列表中只有类型,而没有形参名,这是因为对编译器来说,只对形参类型敏感,而形参名字其实是别忽略的,所以写不写对编译器来说都是一样的,但是程序另一方面也是写给人看的,所以作为好习惯呢,还是要写上有意义的形参名最好!
加载更多回复(1)

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧