首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在C#中模拟C函数sprintf_s的效果?

如何在C#中模拟C函数sprintf_s的效果?
EN

Stack Overflow用户
提问于 2019-06-13 00:02:55
回答 1查看 113关注 0票数 1

我正在尝试将我的前辈用C编写的一些旧代码移植到C#上。我尝试过使用P/invoke的方式,但是遇到了sprint_s的问题,有什么建议可以修复这个问题或者使用C#的SerialPort类来编写它吗?

代码语言:javascript
复制
    [StructLayout(LayoutKind.Sequential)]
    internal struct Dcb
    {
        internal uint DCBLength;
        internal uint BaudRate;
        private BitVector32 Flags;

        private ushort wReserved;        // not currently used 
        internal ushort XonLim;           // transmit XON threshold 
        internal ushort XoffLim;          // transmit XOFF threshold             

        internal byte ByteSize;
        internal Parity Parity;
        internal StopBits StopBits;

        internal sbyte XonChar;          // Tx and Rx XON character 
        internal sbyte XoffChar;         // Tx and Rx XOFF character 
        internal sbyte ErrorChar;        // error replacement character 
        internal sbyte EofChar;          // end of input character 
        internal sbyte EvtChar;          // received event character 
        private ushort wReserved1;       // reserved; do not use     

        private static readonly int fBinary;
        private static readonly int fParity;
        private static readonly int fOutxCtsFlow;
        private static readonly int fOutxDsrFlow;
        private static readonly BitVector32.Section fDtrControl;
        private static readonly int fDsrSensitivity;
        private static readonly int fTXContinueOnXoff;
        private static readonly int fOutX;
        private static readonly int fInX;
        private static readonly int fErrorChar;
        private static readonly int fNull;
        private static readonly BitVector32.Section fRtsControl;
        private static readonly int fAbortOnError;

        static Dcb()
        {
            // Create Boolean Mask
            int previousMask;
            fBinary = BitVector32.CreateMask();
            fParity = BitVector32.CreateMask(fBinary);
            fOutxCtsFlow = BitVector32.CreateMask(fParity);
            fOutxDsrFlow = BitVector32.CreateMask(fOutxCtsFlow);
            previousMask = BitVector32.CreateMask(fOutxDsrFlow);
            previousMask = BitVector32.CreateMask(previousMask);
            fDsrSensitivity = BitVector32.CreateMask(previousMask);
            fTXContinueOnXoff = BitVector32.CreateMask(fDsrSensitivity);
            fOutX = BitVector32.CreateMask(fTXContinueOnXoff);
            fInX = BitVector32.CreateMask(fOutX);
            fErrorChar = BitVector32.CreateMask(fInX);
            fNull = BitVector32.CreateMask(fErrorChar);
            previousMask = BitVector32.CreateMask(fNull);
            previousMask = BitVector32.CreateMask(previousMask);
            fAbortOnError = BitVector32.CreateMask(previousMask);

            // Create section Mask
            BitVector32.Section previousSection;
            previousSection = BitVector32.CreateSection(1);
            previousSection = BitVector32.CreateSection(1, previousSection);
            previousSection = BitVector32.CreateSection(1, previousSection);
            previousSection = BitVector32.CreateSection(1, previousSection);
            fDtrControl = BitVector32.CreateSection(2, previousSection);
            previousSection = BitVector32.CreateSection(1, fDtrControl);
            previousSection = BitVector32.CreateSection(1, previousSection);
            previousSection = BitVector32.CreateSection(1, previousSection);
            previousSection = BitVector32.CreateSection(1, previousSection);
            previousSection = BitVector32.CreateSection(1, previousSection);
            previousSection = BitVector32.CreateSection(1, previousSection);
            fRtsControl = BitVector32.CreateSection(3, previousSection);
            previousSection = BitVector32.CreateSection(1, fRtsControl);
        }

        public bool Binary
        {
            get { return Flags[fBinary]; }
            set { Flags[fBinary] = value; }
        }

        public bool CheckParity
        {
            get { return Flags[fParity]; }
            set { Flags[fParity] = value; }
        }

        public bool OutxCtsFlow
        {
            get { return Flags[fOutxCtsFlow]; }
            set { Flags[fOutxCtsFlow] = value; }
        }

        public bool OutxDsrFlow
        {
            get { return Flags[fOutxDsrFlow]; }
            set { Flags[fOutxDsrFlow] = value; }
        }

        public DtrControl DtrControl
        {
            get { return (DtrControl)Flags[fDtrControl]; }
            set { Flags[fDtrControl] = (int)value; }
        }

        public bool DsrSensitivity
        {
            get { return Flags[fDsrSensitivity]; }
            set { Flags[fDsrSensitivity] = value; }
        }

        public bool TxContinueOnXoff
        {
            get { return Flags[fTXContinueOnXoff]; }
            set { Flags[fTXContinueOnXoff] = value; }
        }

        public bool OutX
        {
            get { return Flags[fOutX]; }
            set { Flags[fOutX] = value; }
        }

        public bool InX
        {
            get { return Flags[fInX]; }
            set { Flags[fInX] = value; }
        }

        public bool ReplaceErrorChar
        {
            get { return Flags[fErrorChar]; }
            set { Flags[fErrorChar] = value; }
        }

        public bool Null
        {
            get { return Flags[fNull]; }
            set { Flags[fNull] = value; }
        }

        public RtsControl RtsControl
        {
            get { return (RtsControl)Flags[fRtsControl]; }
            set { Flags[fRtsControl] = (int)value; }
        }

        public bool AbortOnError
        {
            get { return Flags[fAbortOnError]; }
            set { Flags[fAbortOnError] = value; }
        }
    }

    public enum DtrControl : int
    {
        /// <summary>
        /// Disables the DTR line when the device is opened and leaves it disabled.
        /// </summary>
        Disable = 0,

        /// <summary>
        /// Enables the DTR line when the device is opened and leaves it on.
        /// </summary>
        Enable = 1,

        /// <summary>
        /// Enables DTR handshaking. If handshaking is enabled, it is an error for the application to adjust the line by 
        /// using the EscapeCommFunction function.
        /// </summary>
        Handshake = 2
    }
    public enum RtsControl : int
    {
        /// <summary>
        /// Disables the RTS line when the device is opened and leaves it disabled.
        /// </summary>
        Disable = 0,

        /// <summary>
        /// Enables the RTS line when the device is opened and leaves it on.
        /// </summary>
        Enable = 1,

        /// <summary>
        /// Enables RTS handshaking. The driver raises the RTS line when the "type-ahead" (input) buffer 
        /// is less than one-half full and lowers the RTS line when the buffer is more than 
        /// three-quarters full. If handshaking is enabled, it is an error for the application to 
        /// adjust the line by using the EscapeCommFunction function.
        /// </summary>
        Handshake = 2,

        /// <summary>
        /// Specifies that the RTS line will be high if bytes are available for transmission. After 
        /// all buffered bytes have been sent, the RTS line will be low.
        /// </summary>
        Toggle = 3
    }
    public enum Parity : byte
    {
        None = 0,
        Odd = 1,
        Even = 2,
        Mark = 3,
        Space = 4,
    }
    public enum StopBits : byte
    {
        One = 0,
        OnePointFive = 1,
        Two = 2
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReadFile(IntPtr handle,
                                        byte[] buffer, uint toRead, ref uint read, IntPtr lpOverLapped);

    [DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
    public static extern IntPtr MemSet(IntPtr dest, int c, int byteCount);


    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool SetCommTimeouts(IntPtr hFile, [In] ref COMMTIMEOUTS
                                           lpCommTimeouts);
    struct COMMTIMEOUTS
    {
        public UInt32 ReadIntervalTimeout;
        public UInt32 ReadTotalTimeoutMultiplier;
        public UInt32 ReadTotalTimeoutConstant;
        public UInt32 WriteTotalTimeoutMultiplier;
        public UInt32 WriteTotalTimeoutConstant;
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CreateFile(
        [MarshalAs(UnmanagedType.LPTStr)] string filename,
        [MarshalAs(UnmanagedType.U4)] FileAccess access,
        [MarshalAs(UnmanagedType.U4)] FileShare share,
        IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
        [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
        [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
        IntPtr templateFile);

    struct FILE
    {
        IntPtr _ptr;
        int _cnt;
        IntPtr _base;
        int _flag;
        int _file;
        int _charbuf;
        int _bufsiz;
        IntPtr _tmpfname;
    };


    [DllImport("kernel32.dll")]
    static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer,
                                 uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
                                 IntPtr lpOverLapped);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool FlushFileBuffers(IntPtr handle);

    public bool InitSerialComms()
    {
        FILE file = new FILE();
        COMMTIMEOUTS timeouts;
        Dcb dcb = new Dcb();
        long len;
        char[] name = new char[10];
        char[] settings = new char[40];
        string str;

        // Form the initialization file name

        sprintf_s(str, 800, "%s\\SerialComms.ini", path);

        // Open the initialization file
        fopen_s(&file, str, "r");

        // Check for errors
        if (file)
        {
            Console.WriteLine("Error: cannot open file %s\n");
            return false;
        }

        // Scan the serial port name
        fgets(name, 10, file);
        len = strlen(name);
        name[len - 1] = 0;

        // Scan the serial port settings
        fgets(settings, 40, file);
        len = settings.Length;
        settings[len - 1] = 0;

        // Scan the timeout settings
        fgets(str, 40, file); len = strlen(str); string[len - 1] = 0;
        sscanf_s(str, "%d,%d,%d,%d,%d",
            &timeouts.ReadIntervalTimeout,
            &timeouts.ReadTotalTimeoutConstant,
            &timeouts.ReadTotalTimeoutMultiplier,
            &timeouts.WriteTotalTimeoutConstant,
            &timeouts.WriteTotalTimeoutMultiplier);

        // Close the initialization file
        fclose(file);

        // Open the serial port
        port = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
            0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);

        // Check for errors
        if (port == INVALID_HANDLE_VALUE)
        {
            // Report the error and return
            fprintf(stderr, "Error: cannot open serial port %s\n", name);
            fflush(stderr);
            return false;
        }

        // Build the serial port device control block
        MemSet(dcb., 0, sizeof(DCB));
        dcb.DCBlength = sizeof(DCB);
        if (!BuildCommDCB(settings, &dcb))
        {
            // Report the error and return
            fprintf(stderr, "Error: cannot create device control block for %s\n", name);
            CloseHandle(port);
            fflush(stderr);
            return false;
        }

        // Configure the serial port
        if (!SetCommState(port, &dcb))
        {
            // Report the error and return
            fprintf(stderr, "Error: cannot configure serial port %s\n", name);
            CloseHandle(port);
            fflush(stderr);
            return false;
        }

        // Set the timeouts for the serial port
        if (!SetCommTimeouts(port, &timeouts))
        {
            // Report the error and return
            fprintf(stderr, "Error: cannot set timeouts for %s\n", name);
            CloseHandle(port);
            fflush(stderr);
            return false;
        }

        // Success
        return true;
    }

    bool ReceiveReply(IntPtr port, ref byte[] reply, ref byte num)
    {

        uint num_read = 0;
        uint num_to_read = 255;
        ushort crc = 0XFFFF;
        byte i, j;

        // Clear the reply buffer
        //reply = new byte[255]; 

        num = 0;

        // Read the data
        if (!ReadFile(port, reply, num_to_read, ref num_read, IntPtr.Zero)) return false;

        // Check number of bytes that were read
        if (num_read < 2) return false;

        // Check number of bytes that were read
        if (num_read > 255) return false;

        // Form the CRC
        for (i = 0; i < num_read - 2; i++)
        {
            crc ^= reply[i];
            for (j = 0; j < 8; j++)
            {
                ushort flag = (ushort) (crc & 0X0001);
                crc >>= 1;
                //TODO: risky flag check
                if (flag == 0) crc ^= 0XA001;
            }
        }

        // Check the CRC
        if (reply[i++] != (crc & 0X00FF)) return false;
        if (reply[i++] != (crc & 0XFF00) >> 8) return false;
        num = (byte)(num_read - 2);

        // Success
        return true;
    }


    public static bool SendRequest(IntPtr port, ref byte[] request, ref byte num)
    {
        ushort crc = 0XFFFF;
        byte i, j;

        // Check number of bytes
        if (num > 253) return false;

        // Set number of bytes to write
        uint num_to_write = num;

        // Form the CRC
        for (i = 0; i < num_to_write; i++)
        {
            crc ^= request[i];
            for (j = 0; j < 8; j++)
            {
                ushort flag =  (ushort) (crc & 0X0001);
                crc >>= 1; if (flag == 0) crc =  (ushort) (crc ^ 0XA001);
            }
        }

        // Set the CRC bytes in the request
        request[num_to_write++] = (byte) (crc & 0X00FF);
        request[num_to_write++] = (byte) ((crc & 0XFF00) >> 8);

        // Send the request
        if (!WriteFile(port, request, num_to_write, out uint _, IntPtr.Zero)) return false;

        string text = request.ToString().Substring(0, (int) num_to_write).Replace("\r\n", " ");

        // Flush the serial line
        if (!FlushFileBuffers(port)) return false;

        // Success
        return true;
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-13 00:25:22

在像C#这样的高级语言中,您不需要sprintf-family函数,因为它们通常允许使用简单的=+=运算符进行字符串连接和赋值。

只需为它编写惯用的C#代码:

代码语言:javascript
复制
str = path + "\\SerialComms.ini";

Commenter @itsme86指出,对于构建路径的任务,您应该改用Path.Combine

代码语言:javascript
复制
Path.Combine(path, "SerialComms.ini");
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56566300

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档