none
C# 使用writefile如何指定设备地址,万分紧急! RRS feed

  • 问题

  • 问题如下:
           我现在接手别人的工作,驱动别人是用evc4.2写dll,驱动经测试可用。
           我现在用C#开发应用程序。
           现在的问题是,驱动writefile第二个参数他传的是一个结构体引用。里面有设备的基地址。
          evc的结构体如下:
          struct SetInfo
          {
               ULONG address;
               BYTE data[4];
            }
         在evc里的调用
         writefile(handle,&setinfo,sizeof(setinfo),&nWriten,NULL)
         没有问题,
        现在我的问题是,我要写数据,我用C#该如何用他这个驱动?
        刚才我测试了一下,试着传一个结构体进去,但出错提示:NotSupportedException
        估计行不通。
        但我对驱动不太了解,不想改他的驱动(驱动可用),我该怎么用这个驱动?

        感激!


    yolon
    2009年3月24日 3:55

答案

  • 把结构定义改成这样: 
    unsafe public struct SetInfo
            {
               public  ulong  address;
               public  byte data1;
               public  byte data2;

               public  byte data3;

               public  byte data4;

            }
    或者试一下这样:
     [StructLayout(LayoutKind.Explicit)]
     public struct SetInfo  
     {
      [FieldOffset(0)] public  uint32  address;
      [FieldOffset(4)] public uint32 data;  
     };

    其中第二种方式我自己试过,是可行的
    2009年3月30日 7:08

全部回复

  •  操作代码如下:
                common.IOFile.SetInfo Setinfo = new IOtest.common.IOFile.SetInfo();
                Setinfo.address = 0x200;  //设置IO板基地址
                Setinfo.data = new byte[4];
                Setinfo.data[0] = Convert.ToByte(this.tb1.Text.ToString().Trim());  //这里得到输入的数字,下同
                Setinfo.data[1] = Convert.ToByte(this.tb2.Text.ToString().Trim());
                Setinfo.data[2] = Convert.ToByte(this.tb3.Text.ToString().Trim());
                Setinfo.data[3] = Convert.ToByte(this.tb4.Text.ToString().Trim());
                if (common.IOFile.WriteFile(HandlePtr,ref Setinfo, ref HasWriten))
                {
                    this.lbState.Text = HasWriten + " bytes data have writen to the IOBoard !";
                }
                else
                {
                    this.lbState.Text = "Some Error ocurred ,can not write to the IOBoard !";
                }

    SetInfo结构体如下
            public struct SetInfo
            {
              public  ulong  address;
              public  byte[] data;
            }
    申明的writefile如下:
            [DllImport("coredll.dll")]       
            private static extern bool WriteFile(
            System.IntPtr h_comm,                                        //  file  name 
            ref SetInfo text,
            System.UInt32 length,
            ref  int length2,
            int overlap
            );
    重载了一次:
            public static bool WriteFile(System.IntPtr HandleName,ref SetInfo buffer,ref int length)
            {
                UInt32 TotalSize = 96;
                return WriteFile(HandleName,ref buffer,TotalSize,ref length,0);
            }


    如果不是这与写的话,
    在C#里我该怎么写呢?
    谢谢!
    yolon
    2009年3月24日 4:24
  • 楼主,你好

    关于如何在C#中利用EVC的dll你可以参考下面的文章。


    C#调用C++写的非托管的DLL中导出的函数和结构体

    Microsoft Online Community Support
    2009年3月26日 4:08
  • 使用unsafe的方法
     [DllImport("coredll.dll")]       
            private static extern bool WriteFile( 
            uint32 h_comm,                                        //  file  name  
            SetInfo *text, 
            uint32 length, 
            uint32 *length2,
            uint32 overlap
            );
    2009年3月29日 1:45
  • To:kaianli
        我用你的方法申明函数。
        现在的新问题是编译报错:
         错误 1 无法获取托管类型(“IOtest.common.IOFile.SetInfo”)的地址和大小,或无法声明指向它的指针 C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\Projects\IOtest\IOtest\common\IOFile.cs 136 42 IOtest
       我看了一下,原因是在SetInfo里有一个Byte[]数组,如果没有数组的话,这里是不会报错的!
       现在我该怎么做?
       急请回复!

    yolon
    2009年3月30日 1:45
  • 补充:
        我把SetInfo改成:
       [StructLayout(LayoutKind.Sequential)]
            unsafe public struct SetInfo
            {
               public  ulong  address;
               [MarshalAs(UnmanagedType.ByValArray,SizeConst=4)]
               public  byte[] data;
            }
       也还不行。
    yolon
    2009年3月30日 1:46
  • 在evc里的调用
         writefile(handle,&setinfo,sizeof(setinfo),&nWriten,NULL)
    我这里用:
            [DllImport("coredll.dll")]       
            unsafe public static extern bool WriteFile(
            System.IntPtr h_comm,                                         //   file handle  
            SetInfo *text,
            UInt32 length,
            UInt32 *length2,
            UInt32 overlap
            );
    编译都通不过?
    如何解决?
    盼回复!
    yolon
    2009年3月30日 3:22
  • 把结构定义改成这样: 
    unsafe public struct SetInfo
            {
               public  ulong  address;
               public  byte data1;
               public  byte data2;

               public  byte data3;

               public  byte data4;

            }
    或者试一下这样:
     [StructLayout(LayoutKind.Explicit)]
     public struct SetInfo  
     {
      [FieldOffset(0)] public  uint32  address;
      [FieldOffset(4)] public uint32 data;  
     };

    其中第二种方式我自己试过,是可行的
    2009年3月30日 7:08
  • To:kaianli
       感谢先!!
       您说的第一个方案应该不行,我调用的是别人写的驱动dll,他用的是数组,所以,这里的第一种方法基本不行!
       第二种方法您是否可以把你测试的代码贴出来,恕小弟愚昧!
       之前我又用 Marshal.StructureToPtr
       作了测试,没报错,但结果不是我想要的。
       我再按你说的改改!
     

    yolon
    2009年3月30日 8:36
  • TO:kaianli
           这里是触发代码:
                     unsafe
                {
                    UInt32 HasWriten = 0;
                    common.IOFile.SetInfo Setinfo = new IOtest.common.IOFile.SetInfo();
                    Setinfo.address = 0x200;
                    Setinfo.data0 = 0x3;
                    Setinfo.data1 = 0x4;
                    Setinfo.data2 = 0x5;
                    Setinfo.data3 = 0x6;

                    if (common.IOFile.WriteFile(HandlePtr, &Setinfo, (UInt32)Marshal.SizeOf(Setinfo), &HasWriten, 0))
                    {
                        this.lbState.Text = HasWriten + " bytes data have writen to the IOBoard !  structSize: " + Marshal.SizeOf(Setinfo);
                    }
                    else
                    {
                        this.lbState.Text = "Some Error ocurred ,can not write to the IOBoard !  LastErrorCode:" + common.IOFile.GetLastError();
                    }
                }


    writefile申明:
            [DllImport("coredll.dll")]       
            unsafe public static extern bool WriteFile(
            System.IntPtr h_comm,                                         //   file handle  
            SetInfo *text,
            UInt32 length,
            UInt32 *length2,
            UInt32 overlap
            );

    结构体:
          [StructLayout(LayoutKind.Explicit)]
            public struct SetInfo
            {
                [FieldOffset(0)]
                public UInt32 address;
                [FieldOffset(4)]
                public Byte data0;
                [FieldOffset(5)]
                public Byte data1;
                [FieldOffset(6)]
                public Byte data2;
                [FieldOffset(7)]
                public Byte data3;
            }

    编译没有报错,运行也没有报错!
    但结果显示:
       0 bytes data have writen to the IOBoard !  structSize: 8


    我也用表测了下输出,没变化,数据应该是没有写到输出板上。
    kaianli 兄,帮忙啊。
    困了有段时间了,郁闷中……


    yolon
    2009年3月30日 9:22
  •      struct SetInfo
          {
               ULONG address;
               BYTE data[4];
            }

    这是VC下定义的结构,就说明这个结构在32位系统上占用了 8个byte ,而对于从VC这边来说,所有的东西都是pointer所以只要在C#中定义了足够的空间,并正确地传给了VC的dll,应该是没有问题的,
    你使用了unsafe后,在传指针给 dll时,要使用 fixed
    使用unsafe的方法
     [DllImport("coredll.dll")]       
            private static extern bool WriteFile( 
            uint32 h_comm,                                        //  file  name  
            byte *text, 
            uint32 length, 
            uint32 *length2,
            uint32 overlap
            );

    unsafe void test()
    {
       byte[] dumy= new byte[32];
       uint32 length2=0;
       fixed(byte *pdumy = &dumy[0] )
       fixed(uint32* plen = &length2)
    {

      WriteFile(handle,pdumy,8,plen,0);
    }
    }
    我觉得这样试试能拿到什么东西回来,再想办法把ptrtostruct

    2009年3月30日 9:34
  • to:kaianli:
        我现在是写数据,不用提取他的信息。
        我明白您的意思,我现在要做的就是把这个结构体地址传过去,并保证Evc能把这个结构体里的数据取出来就是了。
        DLL源代码已经没有了,改都没法改了(如果改,只能是再写一个驱动了,但我对驱动开发又不熟!)
        现在是编译没有问题,但问题却更麻烦了。
        哎!
    yolon
    2009年3月30日 9:55
  • to:kaianli:
        unsafe void test()
    {
       byte[] dumy= new byte[32];               //申请32个字节? 结构体需要还是8个字节啊!
       uint32 length2=0;
       fixed(byte *pdumy = &dumy[0] )        //这样的话,我怎么给结构体中的data赋值?
       fixed(uint32* plen = &length2)
    {

      WriteFile(handle,pdumy,8,plen,0);
    }

    望兄台指教!


    yolon
    2009年3月30日 10:01
  • to:kaianli:
                unsafe void test()
            {
                byte[] dumy = new byte[8];               //申请32个字节? 结构体需要还是8个字节啊!
                UInt32 length2 = 0;
                dumy[4] = 0x3;
                dumy[5] = 0x4;
                dumy[6] = 0x5;
                dumy[7] = 0x6;
                fixed (byte *pdumy = &dumy[0])        //这样的话,我怎么给结构体中的 address 赋值?
                fixed (UInt32 *plen = &length2)
                {
                    WriteFile(handle, pdumy, 8, plen, 0);
                }
            }

    这是给数据data段赋值,
    原来的address段怎么赋值?
    (先用一个UInt32 temp,赋值完后把UInt32转化为数组,然后再赋给dumy[0]、dumy[1]、dumy[2]、dumy[3]?)
    是否是这这样呢?
    兄台有什么高见??
    yolon
    2009年3月30日 10:08
  • 还有一个问题:
        struct 在EVC(包括VC、C)中,其成员并不一定是顺序存储的,见http://zhidao.baidu.com/question/6576844.html
        所以这么去申明结构可行性呢?

      
    yolon
    2009年3月30日 10:13
  • 1. struct 在EVC(包括VC、C)中,其成员并不一定是顺序存储的
    我觉得,顺序存储应该是一定的,有么高字节在前,要么高字节在后.
    baidu中的例子举得不好,其实内存还是连续的,只是在边界做了地址的补充,align到地址边界去了,在ARM9中,操作32位的数据时要小心,如果地址不是align到4边界上,会报异常的.

    我也不大清楚你为什么老说运行不成功,要不这样吧,你不如用evc再写个dll wrap住算了,然后对外提供接口相对简单的api
    如 opendev,closedev,semdcmd(int address,byte1,byte2,byte3,byte4) 要这样还不行,就真是没天理了,哈哈
    2009年3月30日 10:58
  • to:kaianli
         按你的思路,可能会解决问题,但我觉得那不会是高效的解决问题的办法,其次,我对evc的操作不太熟,可能带来更大的麻烦!
         我对问题再详描述一下:
          原evc的结构体如下:
          struct SetInfo
          {
              ULONG address;
              BYTE data[4];
            }
        在evc里的调用
        writefile(handle,&setinfo,sizeof(setinfo),&nWriten,NULL)
        没有问题,

        现在我的问题是,我要写数据,我在C#里定义的结构体如下:
            [StructLayout(LayoutKind.Sequential)]
            unsafe public struct SetInfo
            {
                public ulong address;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
                public byte[] data;
            }
        在C#里申明的writefile如下:
            [DllImport("coredll.dll")]       
            unsafe public static extern bool WriteFile(
            System.IntPtr h_comm,                                        //  file handle 
            ref SetInfo text,
            UInt32 length,
            ref UInt32 length2,
            UInt32 overlap
            );

        测试代码如下:
          unsafe
                {
                    UInt32 HasWriten = 1;
                    common.IOFile.SetInfo Setinfo = new IOtest.common.IOFile.SetInfo();
                    Setinfo.address = 0x200;
                    Setinfo.data = new Byte[4];
                    Setinfo.data[0] = 0x3;
                    Setinfo.data[1] = 0x4;
                    Setinfo.data[2] = 0x5;
                    Setinfo.data[3] = 0x6;
                    if (common.IOFile.WriteFile(HandlePtr, ref Setinfo, (UInt32)Marshal.SizeOf(Setinfo), ref HasWriten, 0))
                    {
                        this.lbState.Text = HasWriten + " bytes data have writen to the IOBoard !  structSize: " + Marshal.SizeOf(Setinfo);
                    }
                    else
                    {
                        this.lbState.Text = "Some Error ocurred ,can not write to the IOBoard !  LastErrorCode:" + common.IOFile.GetLastError();
                    }
                }

        结果是编译,运行都没有问题,显示:0 bytes data have writen to the IOBoard !  structSize:16
        后来考虑到ULONG在evc与VS2005里的字节可能不一样,如是改成:
            [StructLayout(LayoutKind.Sequential)]
            unsafe public struct SetInfo
            {
                public UInt32 address;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
                public byte[] data;
            }
      结果是编译,运行都没有问题,显示:0 bytes data have writen to the IOBoard !  structSize:8
        总也发不了数据!
          我估计是结构体的问题,但开始也用了Marshal.StructureToPtr,都没有成功,也是不报错,但发不了数据!
         
     求助,紧急!!


    yolon
    2009年3月31日 3:06
  • [DllImport("coredll.dll")]       
            private static extern bool WriteFile( 
            uint32 h_comm,                                        //  file  name  
            uint32* text,     //定义为uint32 是为了字节边界对齐
            uint32 length, 
            uint32 *length2,
            uint32 overlap
            );

    unsafe void test()
    {
       uint32[] dumy= new uint32[2];   //定义为uint32 是为了字节边界对齐
       uint32 length2=0;
       int i=0;
       dumy[i++] = 0x200;
       dumy[i++] = 0x06050403;
       fixed(uint32* pdumy = &dumy[0] )
       fixed(uint32* plen = &length2)
    {

      WriteFile(handle,pdumy,8,plen,0);
    }
    }

    从我的感觉上来看,这样应该是可行的,如果还不行,我觉得是否是别的地方还有什么问题??方便的话你把代码都贴出来?

    2009年3月31日 4:02
  • TO:kaianli
        下午用你给你方法作了测试(修改了一点点地方,fixed(uint32* plen = &length2)报错,编译通不过),结果显示:
        0 bytes data have writen to the IOBoard ! 
        但为了保险起见,我对IO口的电压作了测试,发现数据已经送到口上了。
        然后我就对之前的代码有怀疑了,
        又用今天上午的代码作了测试,结果显示还是一样:0 bytes data have writen to the IOBoard !  structSize:8
        但测试IO口电压,发现数据也已经送到口上了。
        总算有进展了!

        现在奇怪的是,怎么数据发送反馈的发送字节是 0 呢??
        兄台可否解析一下?
    yolon
    2009年3月31日 8:41
  • [DllImport("coredll.dll")]       
            private static extern bool WriteFile( 
            uint32 h_comm,                                        //  file  name  
            uint32* text,     //定义为uint32 是为了字节边界对齐
            uint32 length, 
            uint32 *length2,
            uint32 overlap
            );

    unsafe void test()
    {
       uint32[] dumy= new uint32[2];   //定义为uint32 是为了字节边界对齐
       uint32 length2=1234;
       int i=0;
       dumy[i++] = 0x200;
       dumy[i++] = 0x06050403;
       fixed(uint32* pdumy = &dumy[0] )
       fixed(uint32* plen = &length2)
    {

      WriteFile(handle,pdumy,8,plen,0);
    //debug一下,看看 length2等于多少,是不是驱动根本就没有set这个值啊?
    //如果真是这样,那也没所谓,反正数据都发出去了,只是驱动在实现上的一些bug,你只能改驱动了
    }
    }

    2009年3月31日 9:57
  • TO:kaianli
        我之前用
          uint32 length2=1;
        测试过,但还是返回0
        这个值不是由驱动设置的吧?
        应该是由操作系统设置的,系统发送了多少字节数据,他会记数,然后设置这个值,
        不知道我说的有没有错!
        如果总是返回0的话,不太好判断是否发送成功呢!!

    yolon
    2009年4月1日 0:35
  • 这个值应该由驱动设置,正确地说应该是返回的吧

    xxx_API DWORD xxx_Write( DWORD hOpenContext, LPCVOID pBuffer, DWORD Count );
    这个是流驱动的接口, 你调用WriteFile后,会执行到xxx_Write, 它的返回值就是实际写入的长度了
    2009年4月1日 1:12
  • to:kaianli
        感谢您的技术支持!
        由于我没有原来的驱动代码,改是没法改了,先就这样用吧!
        再次感谢!
        结贴了。
    yolon
    2009年4月2日 1:01