【问题标题】:Pinvoke call always returns a -1Pinvoke 调用始终返回 -1
【发布时间】:2011-09-25 03:22:32
【问题描述】:

Visual Studio 2005 .NET SDK 2.0

我们需要包装旧的 C++ 函数来打开内部和外部端口的句柄(C# 方法对我们的处理器来说开销太大)

这是原始的 C++ 函数:

extern "C" SERIALLIB_API HANDLE
OpenSerialConnection(TCHAR *port, int baudRate, int parity, int dataBits, int stopBits)
{
    // Open the serial device file driver
    HANDLE hSerial = CreateFile(port,
        GENERIC_READ | GENERIC_WRITE,
        0,    // must be opened with exclusive-access
        NULL, // default security attributes
        OPEN_EXISTING, // must use OPEN_EXISTING
        0,    // overlapped I/O not supported
        NULL  // hTemplate must be NULL for comm devices
        );

RETAILMSG(1, (TEXT("Handle %d\n"),hSerial));

// Ensure the handle opened correctly
if (hSerial == INVALID_HANDLE_VALUE)
{
    RETAILMSG(1, (TEXT("INVALID HANDLE #1\n")));
    return INVALID_HANDLE_VALUE;
}

// Set the handle to report only when there's
// a character to receive or when the transmit
// buffer is empty
if (!SetCommMask(hSerial, EV_RXCHAR|EV_TXEMPTY))
{
    CloseHandle(hSerial);
    RETAILMSG(1, (TEXT("INVALID HANDLE #2\n")));
    return INVALID_HANDLE_VALUE;
}

// The handle will now be configured to be the requested
// serial interface. The current settings are retrieved,
// and only the necessary settings are changed.
DCB dcb;
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);

BOOL fSuccess = GetCommState(hSerial, &dcb);
if (!fSuccess) 
{
    CloseHandle(hSerial);
    RETAILMSG(1, (TEXT("INVALID HANDLE #3\n")));
    return INVALID_HANDLE_VALUE;
}

// Fill in DCB with the desired settings
dcb.BaudRate = baudRate;   // set the baud rate
dcb.ByteSize = 8;             // data size, xmit, and rcv
dcb.Parity = parity;        // no parity bit
dcb.StopBits = stopBits;    // one stop bit

// Set the timeout values to make reading a synchronous activity.
// Reading from the serial line takes place in a separate thread,
// so this is what we want.
COMMTIMEOUTS timeout;
timeout.ReadIntervalTimeout = MAXDWORD;
timeout.ReadTotalTimeoutConstant = MAXDWORD - 1;
timeout.ReadTotalTimeoutMultiplier = MAXDWORD;
timeout.WriteTotalTimeoutConstant = 0;
timeout.WriteTotalTimeoutMultiplier = 0;

if (!SetCommTimeouts(hSerial, &timeout) ||
    !SetCommState(hSerial, &dcb))
{
    CloseHandle(hSerial);
    RETAILMSG(1, (TEXT("INVALID HANDLE #4\n")));
    return INVALID_HANDLE_VALUE;
}

return hSerial;
}

C# 包装器:

[DllImport("SerialLib.dll")]
    public static extern IntPtr OpenSerialConnection(string port, int baudRate, int parity, int dataBits, int stopBits);

句柄是 IntPtr 的调用:

handle = Unmanaged.SerialWrapper.OpenSerialConnection(portName,
                                                                  baudRate,
                                                                  parityToInt(parity),
                                                                  dataBits,
                                                                  stopBitsToInt(stopBits));

无论我在 OpenSerialConnection C++ 代码中有什么,handle 的值总是以 -1 的形式返回,我已经剥离了函数,只返回一个 int 值 4 作为测试。

我完全被难住了,我所有的阅读和搜索都没有证明对解决这个问题有帮助。

有什么建议吗?

编辑以删除复制错误

解决方案:

我遇到了两个错误。根据下面的建议,将返回值从 C++ 更改为 INT_PTR 和平台更改,我能够获得返回有效句柄的调用。

非常感谢您的所有帮助:)

【问题讨论】:

  • 只是确保:您将 C++ 函数剥离为简单的 return 4; 并且它仍然返回 -1?
  • 尝试明确定义双方的调用约定。 C#中根据实际字符串类型在C++函数中定义CharSet。

标签: c# .net sdk pinvoke


【解决方案1】:

您的代码正在将HANDLE 转换为int。在 64 位平台上,这将导致截断和数据丢失,因为 HANDLE 是 64 位宽,而 int 仅是 32 位宽。编译器应该用(至少)一个警告来标记它。

尝试从 OpenSerialConnection() 返回 INT_PTR(并相应地更改 C# 包装器的返回类型)。

【讨论】:

  • 这是我剥离函数只是为了返回 4 时的复制错误;
  • 原始 C++ 函数没有复制错误和 C# 包装器
  • extern "C" SERIALLIB_API HANDLE OpenSerialConnection(TCHAR *port, int baudRate, int parity, int dataBits, int stopBits)
  • @Ashley,即使该函数只返回 (HANDLE) 4,您在托管端看到的是 -1
  • @Frederic 是的,无论 C++ 函数包含什么,我都看到 -1,所以我在想两件事.. 数据在某处损坏,或者函数没有被调用
猜你喜欢
  • 1970-01-01
  • 2017-08-10
  • 2011-04-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-01
  • 2015-07-03
  • 2016-12-17
  • 2015-04-08
相关资源
最近更新 更多