Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从C#调用Win32API SetCommTimeout?_C#_.net_Serial Port - Fatal编程技术网

如何从C#调用Win32API SetCommTimeout?

如何从C#调用Win32API SetCommTimeout?,c#,.net,serial-port,C#,.net,Serial Port,我在从C#通过Win32 API执行串行通信时遇到问题。无论调用SetCommTimeouts()时使用哪个值,对ReadFile的调用都不会返回,除非收到一个或多个字符 使用.Net System.IO.Port.SerialPort类不是一个选项。它有关于USB连接的COM端口的严重错误,这就是为什么我尝试直接使用Win32 API的原因 问题是否可能在于编组CommTimeouts结构,以便API接收不正确的值 下面提供完整的源代码: namespace SerialTest {

我在从C#通过Win32 API执行串行通信时遇到问题。无论调用SetCommTimeouts()时使用哪个值,对ReadFile的调用都不会返回,除非收到一个或多个字符

使用.Net System.IO.Port.SerialPort类不是一个选项。它有关于USB连接的COM端口的严重错误,这就是为什么我尝试直接使用Win32 API的原因

问题是否可能在于编组CommTimeouts结构,以便API接收不正确的值

下面提供完整的源代码:

namespace SerialTest
{
    using System;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using Microsoft.Win32.SafeHandles;

    [Flags]
    internal enum AccessRights : uint
    {
        GenericRead = (0x80000000),
        GenericWrite = (0x40000000),
        GenericExecute = (0x20000000),
        GenericAll = (0x10000000)
    }

    [Flags]
    internal enum ShareModes : uint
    {
        FileShareRead = 0x00000001,
        FileShareWrite = 0x00000002,
        FileShareDelete = 0x00000004
    }

    internal enum CreationDispositions
    {
        CreateNew = 1,
        CreateAlways = 2,
        OpenExisting = 3,
        OpenAlways = 4,
        TruncateExisting = 5
    }

    internal class CommTimeouts
    {
        public UInt32 ReadIntervalTimeout;
        public UInt32 ReadTotalTimeoutMultiplier;
        public UInt32 ReadTotalTimeoutConstant;
        public UInt32 WriteTotalTimeoutMultiplier;
        public UInt32 WriteTotalTimeoutConstant;
    }

    internal class Kernel32
    {
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern SafeFileHandle CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr lpSecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes,
            IntPtr hTemplateFile
        );

        [DllImport("kernel32.dll", EntryPoint = "SetCommTimeouts", SetLastError = true)]
        public static extern bool SetCommTimeouts(SafeHandle hFile, CommTimeouts timeouts);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool ReadFile(SafeHandle hFile, [Out] byte[] lpBuffer,
           uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
    }

    public class SerialTest
    {
        public void Test(string portName)
        {
            if (portName.Length > 5) portName = @"\\.\" + portName;
            var hPort = Kernel32.CreateFile(portName,
                                            (uint) (AccessRights.GenericRead | AccessRights.GenericWrite),
                                            0, // Not shared
                                            IntPtr.Zero, // Security attributes,
                                            (uint) CreationDispositions.OpenExisting,
                                            0,
                                            IntPtr.Zero // Template file
                );

            if (hPort.IsInvalid)
            {
                throw new Exception("Could not open port " + portName + ". Error: " + Marshal.GetLastWin32Error().ToString(CultureInfo.InvariantCulture));
            }

            try
            {
                // Set timeout so call returns immediately
                var timeouts = new CommTimeouts
                    {
                        ReadIntervalTimeout = 0xFFFFFFFF,
                        ReadTotalTimeoutMultiplier = 0,
                        ReadTotalTimeoutConstant = 0,
                        WriteTotalTimeoutMultiplier = 0,
                        WriteTotalTimeoutConstant = 0
                    };

                if (!Kernel32.SetCommTimeouts(hPort, timeouts))
                {
                    var error = Marshal.GetLastWin32Error();
                    throw new Exception("Could not set timeouts. Error: " + error.ToString(CultureInfo.InvariantCulture));                    
                }

                var buf = new byte[1];
                uint readBytes;
                if (!Kernel32.ReadFile(hPort,
                                       buf,
                                       1,
                                       out readBytes,
                                       IntPtr.Zero))
                {
                    var error = Marshal.GetLastWin32Error();
                    throw new Exception("Could not read. Error: " + error.ToString(CultureInfo.InvariantCulture));
                }
            }
            finally
            {
                hPort.Close();
            }
        }
    }
}

我在网上找到的SetCommTimeouts定义不正确。感谢Richard,我现在使用了正确的定义

static extern bool SetCommTimeouts(IntPtr hFile, [In] ref COMMTIMEOUTS
lpCommTimeouts);

你试过在拍摄结束后打电话确认你的理论吗?另外,虽然您的定义与P/Invoke的(和)稍有不同,但我认为这不会有什么区别。SetCommTimeouts的定义不正确。当设置为[In]ref CommTimeouts时,它按预期工作。我从我找到的一个示例中复制了这个定义,在使用之前没有仔细检查。谢谢。非常重要的一点是,您首先要识别错误,这样才能避免重新创建它。如果你做了功课,你会发现SerialPort本身就是一个使用pinvoke的薄包装器。因此,只需使用开始。复制存在的内容,减去错误:)