pinvoke SetCommState Windows CE 5.0

G

Guest

I have an existing serial comms library written in C# (CF 1.0). This library
has been working flawlessly on CE.NET 4.1/4.2. However we have recently
started to use Windows CE 5.0 and are now finding problems when p/invoking
the SetCommState API call.

I am using GetCommState to populate the DCB structure and then I am updating
the baud rate, data bits, stop bits and parity. Upon calling SetCommState it
returns an error 87 (parameter incorrect).

I tried the MS sample located at

http://msdn.microsoft.com/mobility/default.aspx?pull=/library/en-us/dnnetcomp/html/PISAPICF.asp

Funny thing is, MS are not checking the return value from SetCommState. If
you add code to check the return value you find that thier code also fails.

Does anyone have any suggestions ?

PS. We can't move to CF 2.0 due to the existing population of CE 4.1/4.2

Thanks

Steve
 
G

Ginny Caughey [MVP]

Steve,

This code seems to work for me on both CE 4.1 and WM 5 using either CF 1 or
CF 2. (I don't have a CE 5 device to test it with.)

public bool SetPort(uint baud, char parity, byte dataBits, byte stopBits)
{
bool retVal = false;
if(!IsOpen)
return false;
DCB dcb = new DCB();
dcb.DCBlength = Marshal.SizeOf(dcb);
if(!GetCommState(hPort, ref dcb))
throw new Exception("Unable to get DCB: "+GetLastError());
else
{
byte valParity = NOPARITY;
if(parity == 'O' || parity == 'o')
valParity = ODDPARITY;
else if(parity == 'E' || parity == 'e')
valParity = EVENPARITY;
else if(parity == 'M' || parity == 'm')
valParity = MARKPARITY;
else if(parity == 'S' || parity == 's')
valParity = SPACEPARITY;
dcb.BaudRate = baud;
dcb.ByteSize = dataBits;
if(stopBits == 1)
dcb.StopBits = ONESTOPBIT;
else if(stopBits == 2)
dcb.StopBits = TWOSTOPBITS;
dcb.Parity = valParity;
if(!SetCommState(hPort, ref dcb))
throw new Exception("Unable to set DCB: "+GetLastError());
else
retVal = true;
}
return retVal;
}

#region Constants
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;
public const uint PURGE_TXABORT = 0x0001; // Kill the pending/current writes
to the comm port.
public const uint PURGE_RXABORT = 0x0002; // Kill the pending/current reads
to the comm port.
public const uint PURGE_TXCLEAR = 0x0004; // Kill the transmit queue if
there.
public const uint PURGE_RXCLEAR = 0x0008; // Kill the typeahead buffer if
there.
public const byte NOPARITY = 0;
public const byte ODDPARITY = 1;
public const byte EVENPARITY = 2;
public const byte MARKPARITY = 3;
public const byte SPACEPARITY = 4;
public const byte ONESTOPBIT = 0;
public const byte ONE5STOPBITS = 1;
public const byte TWOSTOPBITS = 2;
public const byte EV_RXCHAR = 1;
public const uint ERROR_INVALID_HANDLE = 6;
#endregion

#region DLLImports
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool WriteFile(int hFile,
Byte[] lpBuffer,
int nNumberOfBytesToWrite,
ref int lpNumberOfBytesWritten,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern Boolean ReadFile(int hFile,
byte[] lpBuffer,
int nNumberOfBytesToRead,
out int nNumberOfBytesRead,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int CreateFile(string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool CloseHandle(int hObject);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int GetLastError();
[DllImport("coredll.dll", EntryPoint="GetCommState")]
public static extern bool GetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool PurgeComm(int hFile, uint dwFlags);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommTimeouts(int hFile, ref CommTimeouts
lpTimeouts);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommMask(int hFile, uint eventMask);
[DllImport("coredll.dll", SetLastError=true)]
// Note that overlapped I/O is not used here
public static extern bool WaitCommEvent(int hFile, ref uint eventMask, int
struOverlapped);
#endregion
 
G

Guest

Ginny,

Thanks for the information, I'll give it a try.

Steve

Ginny Caughey said:
Steve,

This code seems to work for me on both CE 4.1 and WM 5 using either CF 1 or
CF 2. (I don't have a CE 5 device to test it with.)

public bool SetPort(uint baud, char parity, byte dataBits, byte stopBits)
{
bool retVal = false;
if(!IsOpen)
return false;
DCB dcb = new DCB();
dcb.DCBlength = Marshal.SizeOf(dcb);
if(!GetCommState(hPort, ref dcb))
throw new Exception("Unable to get DCB: "+GetLastError());
else
{
byte valParity = NOPARITY;
if(parity == 'O' || parity == 'o')
valParity = ODDPARITY;
else if(parity == 'E' || parity == 'e')
valParity = EVENPARITY;
else if(parity == 'M' || parity == 'm')
valParity = MARKPARITY;
else if(parity == 'S' || parity == 's')
valParity = SPACEPARITY;
dcb.BaudRate = baud;
dcb.ByteSize = dataBits;
if(stopBits == 1)
dcb.StopBits = ONESTOPBIT;
else if(stopBits == 2)
dcb.StopBits = TWOSTOPBITS;
dcb.Parity = valParity;
if(!SetCommState(hPort, ref dcb))
throw new Exception("Unable to set DCB: "+GetLastError());
else
retVal = true;
}
return retVal;
}

#region Constants
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;
public const uint PURGE_TXABORT = 0x0001; // Kill the pending/current writes
to the comm port.
public const uint PURGE_RXABORT = 0x0002; // Kill the pending/current reads
to the comm port.
public const uint PURGE_TXCLEAR = 0x0004; // Kill the transmit queue if
there.
public const uint PURGE_RXCLEAR = 0x0008; // Kill the typeahead buffer if
there.
public const byte NOPARITY = 0;
public const byte ODDPARITY = 1;
public const byte EVENPARITY = 2;
public const byte MARKPARITY = 3;
public const byte SPACEPARITY = 4;
public const byte ONESTOPBIT = 0;
public const byte ONE5STOPBITS = 1;
public const byte TWOSTOPBITS = 2;
public const byte EV_RXCHAR = 1;
public const uint ERROR_INVALID_HANDLE = 6;
#endregion

#region DLLImports
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool WriteFile(int hFile,
Byte[] lpBuffer,
int nNumberOfBytesToWrite,
ref int lpNumberOfBytesWritten,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern Boolean ReadFile(int hFile,
byte[] lpBuffer,
int nNumberOfBytesToRead,
out int nNumberOfBytesRead,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int CreateFile(string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool CloseHandle(int hObject);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int GetLastError();
[DllImport("coredll.dll", EntryPoint="GetCommState")]
public static extern bool GetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool PurgeComm(int hFile, uint dwFlags);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommTimeouts(int hFile, ref CommTimeouts
lpTimeouts);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommMask(int hFile, uint eventMask);
[DllImport("coredll.dll", SetLastError=true)]
// Note that overlapped I/O is not used here
public static extern bool WaitCommEvent(int hFile, ref uint eventMask, int
struOverlapped);
#endregion

--
Ginny Caughey
..NET Compact Framework MVP


Steve Wilkinson said:
I have an existing serial comms library written in C# (CF 1.0). This
library
has been working flawlessly on CE.NET 4.1/4.2. However we have recently
started to use Windows CE 5.0 and are now finding problems when p/invoking
the SetCommState API call.

I am using GetCommState to populate the DCB structure and then I am
updating
the baud rate, data bits, stop bits and parity. Upon calling SetCommState
it
returns an error 87 (parameter incorrect).

I tried the MS sample located at

http://msdn.microsoft.com/mobility/default.aspx?pull=/library/en-us/dnnetcomp/html/PISAPICF.asp

Funny thing is, MS are not checking the return value from SetCommState.
If
you add code to check the return value you find that thier code also
fails.

Does anyone have any suggestions ?

PS. We can't move to CF 2.0 due to the existing population of CE 4.1/4.2

Thanks

Steve
 
G

Guest

Ginny,

I checked your code against mine, I'm performing exactly the same tasks but
the CE 5.0 device still reports a failure on the SetCommState call. Whereas
the 4.1 & 4.2 devices do not.

Thanks

Steve


Ginny Caughey said:
Steve,

This code seems to work for me on both CE 4.1 and WM 5 using either CF 1 or
CF 2. (I don't have a CE 5 device to test it with.)

public bool SetPort(uint baud, char parity, byte dataBits, byte stopBits)
{
bool retVal = false;
if(!IsOpen)
return false;
DCB dcb = new DCB();
dcb.DCBlength = Marshal.SizeOf(dcb);
if(!GetCommState(hPort, ref dcb))
throw new Exception("Unable to get DCB: "+GetLastError());
else
{
byte valParity = NOPARITY;
if(parity == 'O' || parity == 'o')
valParity = ODDPARITY;
else if(parity == 'E' || parity == 'e')
valParity = EVENPARITY;
else if(parity == 'M' || parity == 'm')
valParity = MARKPARITY;
else if(parity == 'S' || parity == 's')
valParity = SPACEPARITY;
dcb.BaudRate = baud;
dcb.ByteSize = dataBits;
if(stopBits == 1)
dcb.StopBits = ONESTOPBIT;
else if(stopBits == 2)
dcb.StopBits = TWOSTOPBITS;
dcb.Parity = valParity;
if(!SetCommState(hPort, ref dcb))
throw new Exception("Unable to set DCB: "+GetLastError());
else
retVal = true;
}
return retVal;
}

#region Constants
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;
public const uint PURGE_TXABORT = 0x0001; // Kill the pending/current writes
to the comm port.
public const uint PURGE_RXABORT = 0x0002; // Kill the pending/current reads
to the comm port.
public const uint PURGE_TXCLEAR = 0x0004; // Kill the transmit queue if
there.
public const uint PURGE_RXCLEAR = 0x0008; // Kill the typeahead buffer if
there.
public const byte NOPARITY = 0;
public const byte ODDPARITY = 1;
public const byte EVENPARITY = 2;
public const byte MARKPARITY = 3;
public const byte SPACEPARITY = 4;
public const byte ONESTOPBIT = 0;
public const byte ONE5STOPBITS = 1;
public const byte TWOSTOPBITS = 2;
public const byte EV_RXCHAR = 1;
public const uint ERROR_INVALID_HANDLE = 6;
#endregion

#region DLLImports
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool WriteFile(int hFile,
Byte[] lpBuffer,
int nNumberOfBytesToWrite,
ref int lpNumberOfBytesWritten,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern Boolean ReadFile(int hFile,
byte[] lpBuffer,
int nNumberOfBytesToRead,
out int nNumberOfBytesRead,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int CreateFile(string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool CloseHandle(int hObject);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int GetLastError();
[DllImport("coredll.dll", EntryPoint="GetCommState")]
public static extern bool GetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool PurgeComm(int hFile, uint dwFlags);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommTimeouts(int hFile, ref CommTimeouts
lpTimeouts);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommMask(int hFile, uint eventMask);
[DllImport("coredll.dll", SetLastError=true)]
// Note that overlapped I/O is not used here
public static extern bool WaitCommEvent(int hFile, ref uint eventMask, int
struOverlapped);
#endregion

--
Ginny Caughey
..NET Compact Framework MVP


Steve Wilkinson said:
I have an existing serial comms library written in C# (CF 1.0). This
library
has been working flawlessly on CE.NET 4.1/4.2. However we have recently
started to use Windows CE 5.0 and are now finding problems when p/invoking
the SetCommState API call.

I am using GetCommState to populate the DCB structure and then I am
updating
the baud rate, data bits, stop bits and parity. Upon calling SetCommState
it
returns an error 87 (parameter incorrect).

I tried the MS sample located at

http://msdn.microsoft.com/mobility/default.aspx?pull=/library/en-us/dnnetcomp/html/PISAPICF.asp

Funny thing is, MS are not checking the return value from SetCommState.
If
you add code to check the return value you find that thier code also
fails.

Does anyone have any suggestions ?

PS. We can't move to CF 2.0 due to the existing population of CE 4.1/4.2

Thanks

Steve
 
G

Ginny Caughey [MVP]

Steve,

It sounds like you're trying to set a baud, etc., that the particular
hardware or driver doesn't support then. But it does show why it's always a
good idea to check the return values of these API functions. What do you
find if you call GetCommState right after the failed SetCommState? Did the
protocol you asked for "take"?

--
Ginny Caughey
..NET Compact Framework MVP


Steve Wilkinson said:
Ginny,

I checked your code against mine, I'm performing exactly the same tasks
but
the CE 5.0 device still reports a failure on the SetCommState call.
Whereas
the 4.1 & 4.2 devices do not.

Thanks

Steve


Ginny Caughey said:
Steve,

This code seems to work for me on both CE 4.1 and WM 5 using either CF 1
or
CF 2. (I don't have a CE 5 device to test it with.)

public bool SetPort(uint baud, char parity, byte dataBits, byte stopBits)
{
bool retVal = false;
if(!IsOpen)
return false;
DCB dcb = new DCB();
dcb.DCBlength = Marshal.SizeOf(dcb);
if(!GetCommState(hPort, ref dcb))
throw new Exception("Unable to get DCB: "+GetLastError());
else
{
byte valParity = NOPARITY;
if(parity == 'O' || parity == 'o')
valParity = ODDPARITY;
else if(parity == 'E' || parity == 'e')
valParity = EVENPARITY;
else if(parity == 'M' || parity == 'm')
valParity = MARKPARITY;
else if(parity == 'S' || parity == 's')
valParity = SPACEPARITY;
dcb.BaudRate = baud;
dcb.ByteSize = dataBits;
if(stopBits == 1)
dcb.StopBits = ONESTOPBIT;
else if(stopBits == 2)
dcb.StopBits = TWOSTOPBITS;
dcb.Parity = valParity;
if(!SetCommState(hPort, ref dcb))
throw new Exception("Unable to set DCB: "+GetLastError());
else
retVal = true;
}
return retVal;
}

#region Constants
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;
public const uint PURGE_TXABORT = 0x0001; // Kill the pending/current
writes
to the comm port.
public const uint PURGE_RXABORT = 0x0002; // Kill the pending/current
reads
to the comm port.
public const uint PURGE_TXCLEAR = 0x0004; // Kill the transmit queue if
there.
public const uint PURGE_RXCLEAR = 0x0008; // Kill the typeahead buffer if
there.
public const byte NOPARITY = 0;
public const byte ODDPARITY = 1;
public const byte EVENPARITY = 2;
public const byte MARKPARITY = 3;
public const byte SPACEPARITY = 4;
public const byte ONESTOPBIT = 0;
public const byte ONE5STOPBITS = 1;
public const byte TWOSTOPBITS = 2;
public const byte EV_RXCHAR = 1;
public const uint ERROR_INVALID_HANDLE = 6;
#endregion

#region DLLImports
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool WriteFile(int hFile,
Byte[] lpBuffer,
int nNumberOfBytesToWrite,
ref int lpNumberOfBytesWritten,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern Boolean ReadFile(int hFile,
byte[] lpBuffer,
int nNumberOfBytesToRead,
out int nNumberOfBytesRead,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int CreateFile(string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool CloseHandle(int hObject);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int GetLastError();
[DllImport("coredll.dll", EntryPoint="GetCommState")]
public static extern bool GetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool PurgeComm(int hFile, uint dwFlags);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommTimeouts(int hFile, ref CommTimeouts
lpTimeouts);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommMask(int hFile, uint eventMask);
[DllImport("coredll.dll", SetLastError=true)]
// Note that overlapped I/O is not used here
public static extern bool WaitCommEvent(int hFile, ref uint eventMask,
int
struOverlapped);
#endregion

--
Ginny Caughey
..NET Compact Framework MVP


Steve Wilkinson said:
I have an existing serial comms library written in C# (CF 1.0). This
library
has been working flawlessly on CE.NET 4.1/4.2. However we have
recently
started to use Windows CE 5.0 and are now finding problems when
p/invoking
the SetCommState API call.

I am using GetCommState to populate the DCB structure and then I am
updating
the baud rate, data bits, stop bits and parity. Upon calling
SetCommState
it
returns an error 87 (parameter incorrect).

I tried the MS sample located at

http://msdn.microsoft.com/mobility/default.aspx?pull=/library/en-us/dnnetcomp/html/PISAPICF.asp

Funny thing is, MS are not checking the return value from SetCommState.
If
you add code to check the return value you find that thier code also
fails.

Does anyone have any suggestions ?

PS. We can't move to CF 2.0 due to the existing population of CE
4.1/4.2

Thanks

Steve
 
G

Guest

Ginny,

I've solved the problem.

Calling GetCommState after a call to SetCommState does indicate that the new
baud rate etc. has been accepted even though SetCommState returns an error.

However I noticed the initial call to GetCommState specifies the DCBLength
as 28 bytes. Marshal.SizeOf(dcb) returns a length of 36 bytes.

Providing you don't update the DCBLength with the value returned from
Marshal.SizeOf() the SetCommState call will complete without error.

Interestingly Windows CE.NET 4.1/4.2 also returns a length of 36 bytes from
Marshal.SizeOf() however the SetCommState doesn't return an error.

Perhaps this is a one for the OpenNetCF knowledge base.

Thanks for your help.

Steve

Ginny Caughey said:
Steve,

It sounds like you're trying to set a baud, etc., that the particular
hardware or driver doesn't support then. But it does show why it's always a
good idea to check the return values of these API functions. What do you
find if you call GetCommState right after the failed SetCommState? Did the
protocol you asked for "take"?

--
Ginny Caughey
..NET Compact Framework MVP


Steve Wilkinson said:
Ginny,

I checked your code against mine, I'm performing exactly the same tasks
but
the CE 5.0 device still reports a failure on the SetCommState call.
Whereas
the 4.1 & 4.2 devices do not.

Thanks

Steve


Ginny Caughey said:
Steve,

This code seems to work for me on both CE 4.1 and WM 5 using either CF 1
or
CF 2. (I don't have a CE 5 device to test it with.)

public bool SetPort(uint baud, char parity, byte dataBits, byte stopBits)
{
bool retVal = false;
if(!IsOpen)
return false;
DCB dcb = new DCB();
dcb.DCBlength = Marshal.SizeOf(dcb);
if(!GetCommState(hPort, ref dcb))
throw new Exception("Unable to get DCB: "+GetLastError());
else
{
byte valParity = NOPARITY;
if(parity == 'O' || parity == 'o')
valParity = ODDPARITY;
else if(parity == 'E' || parity == 'e')
valParity = EVENPARITY;
else if(parity == 'M' || parity == 'm')
valParity = MARKPARITY;
else if(parity == 'S' || parity == 's')
valParity = SPACEPARITY;
dcb.BaudRate = baud;
dcb.ByteSize = dataBits;
if(stopBits == 1)
dcb.StopBits = ONESTOPBIT;
else if(stopBits == 2)
dcb.StopBits = TWOSTOPBITS;
dcb.Parity = valParity;
if(!SetCommState(hPort, ref dcb))
throw new Exception("Unable to set DCB: "+GetLastError());
else
retVal = true;
}
return retVal;
}

#region Constants
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;
public const uint PURGE_TXABORT = 0x0001; // Kill the pending/current
writes
to the comm port.
public const uint PURGE_RXABORT = 0x0002; // Kill the pending/current
reads
to the comm port.
public const uint PURGE_TXCLEAR = 0x0004; // Kill the transmit queue if
there.
public const uint PURGE_RXCLEAR = 0x0008; // Kill the typeahead buffer if
there.
public const byte NOPARITY = 0;
public const byte ODDPARITY = 1;
public const byte EVENPARITY = 2;
public const byte MARKPARITY = 3;
public const byte SPACEPARITY = 4;
public const byte ONESTOPBIT = 0;
public const byte ONE5STOPBITS = 1;
public const byte TWOSTOPBITS = 2;
public const byte EV_RXCHAR = 1;
public const uint ERROR_INVALID_HANDLE = 6;
#endregion

#region DLLImports
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool WriteFile(int hFile,
Byte[] lpBuffer,
int nNumberOfBytesToWrite,
ref int lpNumberOfBytesWritten,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern Boolean ReadFile(int hFile,
byte[] lpBuffer,
int nNumberOfBytesToRead,
out int nNumberOfBytesRead,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int CreateFile(string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool CloseHandle(int hObject);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int GetLastError();
[DllImport("coredll.dll", EntryPoint="GetCommState")]
public static extern bool GetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool PurgeComm(int hFile, uint dwFlags);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommTimeouts(int hFile, ref CommTimeouts
lpTimeouts);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommMask(int hFile, uint eventMask);
[DllImport("coredll.dll", SetLastError=true)]
// Note that overlapped I/O is not used here
public static extern bool WaitCommEvent(int hFile, ref uint eventMask,
int
struOverlapped);
#endregion

--
Ginny Caughey
..NET Compact Framework MVP


message I have an existing serial comms library written in C# (CF 1.0). This
library
has been working flawlessly on CE.NET 4.1/4.2. However we have
recently
started to use Windows CE 5.0 and are now finding problems when
p/invoking
the SetCommState API call.

I am using GetCommState to populate the DCB structure and then I am
updating
the baud rate, data bits, stop bits and parity. Upon calling
SetCommState
it
returns an error 87 (parameter incorrect).

I tried the MS sample located at

http://msdn.microsoft.com/mobility/default.aspx?pull=/library/en-us/dnnetcomp/html/PISAPICF.asp

Funny thing is, MS are not checking the return value from SetCommState.
If
you add code to check the return value you find that thier code also
fails.

Does anyone have any suggestions ?

PS. We can't move to CF 2.0 due to the existing population of CE
4.1/4.2

Thanks

Steve
 
G

Ginny Caughey [MVP]

Thanks for reporting back, Steve. I'm glad you got it working. That is
indeed interesting that the same error isn't thrown on CE 4.1/4.2.

--
Ginny Caughey
..NET Compact Framework MVP


Steve Wilkinson said:
Ginny,

I've solved the problem.

Calling GetCommState after a call to SetCommState does indicate that the
new
baud rate etc. has been accepted even though SetCommState returns an
error.

However I noticed the initial call to GetCommState specifies the DCBLength
as 28 bytes. Marshal.SizeOf(dcb) returns a length of 36 bytes.

Providing you don't update the DCBLength with the value returned from
Marshal.SizeOf() the SetCommState call will complete without error.

Interestingly Windows CE.NET 4.1/4.2 also returns a length of 36 bytes
from
Marshal.SizeOf() however the SetCommState doesn't return an error.

Perhaps this is a one for the OpenNetCF knowledge base.

Thanks for your help.

Steve

Ginny Caughey said:
Steve,

It sounds like you're trying to set a baud, etc., that the particular
hardware or driver doesn't support then. But it does show why it's always
a
good idea to check the return values of these API functions. What do you
find if you call GetCommState right after the failed SetCommState? Did
the
protocol you asked for "take"?

--
Ginny Caughey
..NET Compact Framework MVP


Steve Wilkinson said:
Ginny,

I checked your code against mine, I'm performing exactly the same tasks
but
the CE 5.0 device still reports a failure on the SetCommState call.
Whereas
the 4.1 & 4.2 devices do not.

Thanks

Steve


:

Steve,

This code seems to work for me on both CE 4.1 and WM 5 using either CF
1
or
CF 2. (I don't have a CE 5 device to test it with.)

public bool SetPort(uint baud, char parity, byte dataBits, byte
stopBits)
{
bool retVal = false;
if(!IsOpen)
return false;
DCB dcb = new DCB();
dcb.DCBlength = Marshal.SizeOf(dcb);
if(!GetCommState(hPort, ref dcb))
throw new Exception("Unable to get DCB: "+GetLastError());
else
{
byte valParity = NOPARITY;
if(parity == 'O' || parity == 'o')
valParity = ODDPARITY;
else if(parity == 'E' || parity == 'e')
valParity = EVENPARITY;
else if(parity == 'M' || parity == 'm')
valParity = MARKPARITY;
else if(parity == 'S' || parity == 's')
valParity = SPACEPARITY;
dcb.BaudRate = baud;
dcb.ByteSize = dataBits;
if(stopBits == 1)
dcb.StopBits = ONESTOPBIT;
else if(stopBits == 2)
dcb.StopBits = TWOSTOPBITS;
dcb.Parity = valParity;
if(!SetCommState(hPort, ref dcb))
throw new Exception("Unable to set DCB: "+GetLastError());
else
retVal = true;
}
return retVal;
}

#region Constants
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;
public const uint PURGE_TXABORT = 0x0001; // Kill the pending/current
writes
to the comm port.
public const uint PURGE_RXABORT = 0x0002; // Kill the pending/current
reads
to the comm port.
public const uint PURGE_TXCLEAR = 0x0004; // Kill the transmit queue
if
there.
public const uint PURGE_RXCLEAR = 0x0008; // Kill the typeahead buffer
if
there.
public const byte NOPARITY = 0;
public const byte ODDPARITY = 1;
public const byte EVENPARITY = 2;
public const byte MARKPARITY = 3;
public const byte SPACEPARITY = 4;
public const byte ONESTOPBIT = 0;
public const byte ONE5STOPBITS = 1;
public const byte TWOSTOPBITS = 2;
public const byte EV_RXCHAR = 1;
public const uint ERROR_INVALID_HANDLE = 6;
#endregion

#region DLLImports
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool WriteFile(int hFile,
Byte[] lpBuffer,
int nNumberOfBytesToWrite,
ref int lpNumberOfBytesWritten,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern Boolean ReadFile(int hFile,
byte[] lpBuffer,
int nNumberOfBytesToRead,
out int nNumberOfBytesRead,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int CreateFile(string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool CloseHandle(int hObject);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int GetLastError();
[DllImport("coredll.dll", EntryPoint="GetCommState")]
public static extern bool GetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool PurgeComm(int hFile, uint dwFlags);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommTimeouts(int hFile, ref CommTimeouts
lpTimeouts);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommMask(int hFile, uint eventMask);
[DllImport("coredll.dll", SetLastError=true)]
// Note that overlapped I/O is not used here
public static extern bool WaitCommEvent(int hFile, ref uint eventMask,
int
struOverlapped);
#endregion

--
Ginny Caughey
..NET Compact Framework MVP


message I have an existing serial comms library written in C# (CF 1.0). This
library
has been working flawlessly on CE.NET 4.1/4.2. However we have
recently
started to use Windows CE 5.0 and are now finding problems when
p/invoking
the SetCommState API call.

I am using GetCommState to populate the DCB structure and then I am
updating
the baud rate, data bits, stop bits and parity. Upon calling
SetCommState
it
returns an error 87 (parameter incorrect).

I tried the MS sample located at

http://msdn.microsoft.com/mobility/default.aspx?pull=/library/en-us/dnnetcomp/html/PISAPICF.asp

Funny thing is, MS are not checking the return value from
SetCommState.
If
you add code to check the return value you find that thier code
also
fails.

Does anyone have any suggestions ?

PS. We can't move to CF 2.0 due to the existing population of CE
4.1/4.2

Thanks

Steve
 
C

Chris Tacke [MVP]

There's either a bug in the DCB returning a bad length or being of the wrong
actual length. Those two should match. Your 4.2 driver simply isn't
checking that they do and 5.0 is.

-Chris


Steve Wilkinson said:
Ginny,

I've solved the problem.

Calling GetCommState after a call to SetCommState does indicate that the
new
baud rate etc. has been accepted even though SetCommState returns an
error.

However I noticed the initial call to GetCommState specifies the DCBLength
as 28 bytes. Marshal.SizeOf(dcb) returns a length of 36 bytes.

Providing you don't update the DCBLength with the value returned from
Marshal.SizeOf() the SetCommState call will complete without error.

Interestingly Windows CE.NET 4.1/4.2 also returns a length of 36 bytes
from
Marshal.SizeOf() however the SetCommState doesn't return an error.

Perhaps this is a one for the OpenNetCF knowledge base.

Thanks for your help.

Steve

Ginny Caughey said:
Steve,

It sounds like you're trying to set a baud, etc., that the particular
hardware or driver doesn't support then. But it does show why it's always
a
good idea to check the return values of these API functions. What do you
find if you call GetCommState right after the failed SetCommState? Did
the
protocol you asked for "take"?

--
Ginny Caughey
..NET Compact Framework MVP


Steve Wilkinson said:
Ginny,

I checked your code against mine, I'm performing exactly the same tasks
but
the CE 5.0 device still reports a failure on the SetCommState call.
Whereas
the 4.1 & 4.2 devices do not.

Thanks

Steve


:

Steve,

This code seems to work for me on both CE 4.1 and WM 5 using either CF
1
or
CF 2. (I don't have a CE 5 device to test it with.)

public bool SetPort(uint baud, char parity, byte dataBits, byte
stopBits)
{
bool retVal = false;
if(!IsOpen)
return false;
DCB dcb = new DCB();
dcb.DCBlength = Marshal.SizeOf(dcb);
if(!GetCommState(hPort, ref dcb))
throw new Exception("Unable to get DCB: "+GetLastError());
else
{
byte valParity = NOPARITY;
if(parity == 'O' || parity == 'o')
valParity = ODDPARITY;
else if(parity == 'E' || parity == 'e')
valParity = EVENPARITY;
else if(parity == 'M' || parity == 'm')
valParity = MARKPARITY;
else if(parity == 'S' || parity == 's')
valParity = SPACEPARITY;
dcb.BaudRate = baud;
dcb.ByteSize = dataBits;
if(stopBits == 1)
dcb.StopBits = ONESTOPBIT;
else if(stopBits == 2)
dcb.StopBits = TWOSTOPBITS;
dcb.Parity = valParity;
if(!SetCommState(hPort, ref dcb))
throw new Exception("Unable to set DCB: "+GetLastError());
else
retVal = true;
}
return retVal;
}

#region Constants
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;
public const uint PURGE_TXABORT = 0x0001; // Kill the pending/current
writes
to the comm port.
public const uint PURGE_RXABORT = 0x0002; // Kill the pending/current
reads
to the comm port.
public const uint PURGE_TXCLEAR = 0x0004; // Kill the transmit queue
if
there.
public const uint PURGE_RXCLEAR = 0x0008; // Kill the typeahead buffer
if
there.
public const byte NOPARITY = 0;
public const byte ODDPARITY = 1;
public const byte EVENPARITY = 2;
public const byte MARKPARITY = 3;
public const byte SPACEPARITY = 4;
public const byte ONESTOPBIT = 0;
public const byte ONE5STOPBITS = 1;
public const byte TWOSTOPBITS = 2;
public const byte EV_RXCHAR = 1;
public const uint ERROR_INVALID_HANDLE = 6;
#endregion

#region DLLImports
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool WriteFile(int hFile,
Byte[] lpBuffer,
int nNumberOfBytesToWrite,
ref int lpNumberOfBytesWritten,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern Boolean ReadFile(int hFile,
byte[] lpBuffer,
int nNumberOfBytesToRead,
out int nNumberOfBytesRead,
int lpOverlapped);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int CreateFile(string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool CloseHandle(int hObject);
[DllImport("coredll.dll", SetLastError=true)]
public static extern int GetLastError();
[DllImport("coredll.dll", EntryPoint="GetCommState")]
public static extern bool GetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommState(int hFile, ref DCB dcb);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool PurgeComm(int hFile, uint dwFlags);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommTimeouts(int hFile, ref CommTimeouts
lpTimeouts);
[DllImport("coredll.dll", SetLastError=true)]
public static extern bool SetCommMask(int hFile, uint eventMask);
[DllImport("coredll.dll", SetLastError=true)]
// Note that overlapped I/O is not used here
public static extern bool WaitCommEvent(int hFile, ref uint eventMask,
int
struOverlapped);
#endregion

--
Ginny Caughey
..NET Compact Framework MVP


message I have an existing serial comms library written in C# (CF 1.0). This
library
has been working flawlessly on CE.NET 4.1/4.2. However we have
recently
started to use Windows CE 5.0 and are now finding problems when
p/invoking
the SetCommState API call.

I am using GetCommState to populate the DCB structure and then I am
updating
the baud rate, data bits, stop bits and parity. Upon calling
SetCommState
it
returns an error 87 (parameter incorrect).

I tried the MS sample located at

http://msdn.microsoft.com/mobility/default.aspx?pull=/library/en-us/dnnetcomp/html/PISAPICF.asp

Funny thing is, MS are not checking the return value from
SetCommState.
If
you add code to check the return value you find that thier code
also
fails.

Does anyone have any suggestions ?

PS. We can't move to CF 2.0 due to the existing population of CE
4.1/4.2

Thanks

Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top