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.必须要连接了小票打印机才可以测试。

解决方案 »

  1.   

    1. char是字符类型2. string是字符串类型 虽然一字之差,但其本质是很大的。1. char属于基础类型(C++),在C#中它属于值类型(Value Type)。char类型的长度是固定的,上一篇讲到,在C++中它可能是1个字节,或者2个字节(取决于是否为Unicode Char),而在C#中,它永远是2个字节。2. string是一个模板类型,也就是一个class(C++)。在C#中它属于引用类型(Reference Type)。string的长度是无法明确取得的。也就是无法通过sizeof来取得,因为它不是一个基础类型,它本身并不固定长度,而取决于内部包含的字符。
      

  2.   

    你是想在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; 至于参数列表中只有类型,而没有形参名,这是因为对编译器来说,只对形参类型敏感,而形参名字其实是别忽略的,所以写不写对编译器来说都是一样的,但是程序另一方面也是写给人看的,所以作为好习惯呢,还是要写上有意义的形参名最好! 
      

  3.   

     在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;
      

  4.   

    使用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); 谢谢各位的回答,请直接改写我的代码。不用引用其他的例子,看起来比较麻烦。谢谢
      

  5.   

    zzxap 那个API32.dll我的win2003系统提示没有这个文件。无法验证可行性。
      

  6.   

    /// <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}
      

  7.   

    返回值还用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);
      

  8.   

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

  9.   

    根据我的平台调用经验改下:
    [DllImport("POSDLL.dll", SetLastError = true)] 
    public static extern IntPtr POS_NETQueryStatus(
    StringBuilder ipAddress,out char szStatus ); 字符串直接用StringBuilder,第二个参数要传递地址用out,就行了
      

  10.   

    以上全试过都不行,返回值是1001失败,    szStatus 一般存的是1 (char(1))
      

  11.   

    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 个字节。 各位请抓住重点解答!对我有用的都会得分!
      

  12.   

    有一点要注意:
    在现在 的操作系统中Char占两个字节
    而C语言不知道跟上时代了没有,有可能它的Char就和Byte是一样的
    不过根据你的描述来看(0-7位的编号说明),应该是byte
    就用Byte吧,呵呵,试了就知道
      

  13.   

    char*在C里一般代表字符串,C#里可以用string(传入字符串时)或StringBuilder(传出字符串时),有时候char*也用来做一个字节的字符指针,这时候可以用ref byte。
      

  14.   

    不好意思,一直搞错了,其实返回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 有纸/纸用尽(纸传感器探测) 
    发现还是不对。怪了。
      

  15.   

    有时候char*也用来做一个字节的字符指针,这时候可以用ref byte。 这个很有道理,不过取出来的状态pszStatus对应的值始终不对。delphi 和 vb 都是用 Byte 传进去的。唯独没有C#调用的例子。哎。烦啊。因为是使用网口的打印机,必须要实时的知道打印机状态。防止漏单,所以要用这个dll.
      

  16.   

      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成功,这个状态值却和打印机实际状态不符?
      

  17.   

     CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall