Winows API串口编程

      使用Windows API操作串口有两种方式:同步方式异步方式(又称为重叠方式)。同步方式是指API函数会阻塞直到操作完成才返回;在多线程下,虽然不会阻塞主线程,但是仍然会阻塞监听线程。而异步方式下,API函数会立即返回,操作在后台进行,避免线程的阻塞。

   操作串口一般有以下几步骤:

   1)获取串口

  2)打开串口

  3)配置串口

  4)读写串口

  5)关闭串口


一、获取串口

1)下面是项目中使用到的方法,使用QueryDosDevice函数查找COM口

BOOL CActiveReaderDlg::GetLocalSerialPort(CUIntArray &ports)
{
	//Make sure we clear out any elements which may already be in the array
	ports.RemoveAll();
	//Determine what OS we are running on
	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	BOOL bGetVer = GetVersionEx(&osvi);
	
	//On NT use the QueryDosDevice API
	if (bGetVer && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT))
	{
		//Use QueryDosDevice to look for all devices of the form COMx. This is a better
		//solution as it means that no ports have to be opened at all.
		TCHAR szDevices[65535];
		DWORD dwChars = QueryDosDevice(NULL, szDevices, 65535);
		if (dwChars)
		{
			int i=0;
			
			for (;;)
			{
				//Get the current device name
				TCHAR* pszCurrentDevice = &szDevices[i];
				
				//If it looks like "COMX" then
				//add it to the array which will be returned
				int nLen = _tcslen(pszCurrentDevice);
				if (nLen > 3 && _tcsncmp(pszCurrentDevice, _T("COM"), 3) == 0)
				{
					//Work out the port number
					int nPort = _ttoi(&pszCurrentDevice[3]);
					ports.Add(nPort);
				}
				
				// Go to next NULL character
				while(szDevices[i] != _T('\0'))
					i++;
				
				// Bump pointer to the next string
				i++;
				
				// The list is double-NULL terminated, so if the character is
				// now NULL, we're at the end
				if (szDevices[i] == _T('\0'))
					break;
			}
		}
		else
			TRACE(_T("Failed in call to QueryDosDevice, GetLastError:%d\n"), GetLastError());
	}
	else
	{
		//On 95/98 open up each port to determine their existence
		
		//Up to 255 COM ports are supported so we iterate through all of them seeing
		//if we can open them or if we fail to open them, get an access denied or general error error.
		//Both of these cases indicate that there is a COM port at that number. 
		for (UINT i=1; i<256; i++)
		{
			//Form the Raw device name
			CString sPort;
			sPort.Format(_T("\\\\.\\COM%d"), i);
			
			//Try to open the port
			BOOL bSuccess = FALSE;
			HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
			if (hPort == INVALID_HANDLE_VALUE)
			{
				DWORD dwError = GetLastError();
				
				//Check to see if the error was because some other app had the port open or a general failure
				if (dwError == ERROR_ACCESS_DENIED || dwError == ERROR_GEN_FAILURE)
					bSuccess = TRUE;
			}
			else
			{
				//The port was opened successfully
				bSuccess = TRUE;
				
				//Don't forget to close the port, since we are going to do nothing with it anyway
				CloseHandle(hPort);
			}
			
			//Add the port number to the array which will be returned
			if (bSuccess)
				ports.Add(i);
		}
	}
	return true;
} 

BOOL CActiveReaderDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
        GetLocalSerialPort(ports);
	for (int i=0; i<ports.GetSize(); i++)
	{
		CString str="";
		CString port="COM";
		str.Format("%d",ports.ElementAt(i));
		port = port+str;
		((CComboBox *)GetDlgItem(IDC_SP_NUM_COMBO))->AddString(port);
	}
} 


以下方法是网上摘录的:

2)打开注册表枚举串口的方法

void CPageSetCom::ShowComm()
{
long  lReg; 
HKEY  hKey; 
DWORD  MaxValueLength; 
DWORD  dwValueNumber; 

lReg=RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey); 
if(lReg!=ERROR_SUCCESS) 
{ 
  AfxMessageBox(L"Open Registry Error!\n"); 
  return; 
} 

lReg=RegQueryInfoKeyA(hKey, 
  NULL, 
  NULL, 
  NULL, 
  NULL, 
  NULL, 
  NULL, 
  &dwValueNumber, //返回和hKey关联的值 
  &MaxValueLength, 
  NULL, 
  NULL, 
  NULL); 
if(lReg!=ERROR_SUCCESS) //没有成功 
{ 
  AfxMessageBox(L"Getting  Info  Error!\n"); 
  return; 
} 

LPSTR  pValueName,pCOMNumber; 
DWORD  cchValueName,dwValueSize=6; 

for(DWORD  i=0;i < dwValueNumber;i++) 
{ 
  cchValueName=MaxValueLength+1; 
  dwValueSize=6; 
  pValueName=(LPSTR)VirtualAlloc(NULL,cchValueName,MEM_COMMIT,PAGE_READWRITE); 
  lReg=RegEnumValueA(hKey, 
   i, 
   pValueName, 
   &cchValueName, 
   NULL, 
   NULL, 
   NULL, 
   NULL); 
  
  if((lReg!=ERROR_SUCCESS)&&(lReg!=ERROR_NO_MORE_ITEMS)) 
  { 
   AfxMessageBox(L"Enum  Registry  Error or No More Items!\n"); 
   continue; 
  } 
  
  pCOMNumber=(LPSTR)VirtualAlloc(NULL,6,MEM_COMMIT,PAGE_READWRITE); 
  lReg=RegQueryValueExA(hKey, 
   pValueName, 
   NULL, 
   NULL, 
   (LPBYTE)pCOMNumber, 
   &dwValueSize); 
  
  if(lReg!=ERROR_SUCCESS) 
  { 
   AfxMessageBox(L"Can not get the name of the port"); 
   continue; 
  } 
  CString strCommList;
  //AfxMessageBox(pCOMNumber);
  CharToUnicode(pCOMNumber,&strCommList);
  //m_ctlPort.AddString(strCommList);
  BOOL m_bInsert=0;
  
  if(((CComboBox*)GetDlgItem(IDC_CMBREADERCOM))->GetCount()==0)
   ((CComboBox*)GetDlgItem(IDC_CMBREADERCOM))->AddString(strCommList);
  else
  {
   CString strTemp=strCommList;
   strCommList.TrimLeft(L"COM");
   for(int icurrent=0;icurrent<((CComboBox*)GetDlgItem(IDC_CMBREADERCOM))->GetCount();icurrent++)
   {
    CString strCurrent;
    ((CComboBox*)GetDlgItem(IDC_CMBREADERCOM))->GetLBText(icurrent,strCurrent);
    strCurrent.TrimLeft(L"COM");
    if(_ttol(strCurrent)>_ttol(strCommList))
    {
     ((CComboBox*)GetDlgItem(IDC_CMBREADERCOM))->InsertString(icurrent,strTemp);
     m_bInsert = 1;
     break;
    }
   }
   if(!m_bInsert)
    ((CComboBox*)GetDlgItem(IDC_CMBREADERCOM))->InsertString(icurrent,strTemp);
  }
  
  VirtualFree(pValueName,0,MEM_RELEASE); 
  VirtualFree(pCOMNumber,0,MEM_RELEASE); 
} 
}
int CPageSetCom::CharToUnicode(char *pchIn, CString *pstrOut)
{
int nLen;
    WCHAR *ptch;
    if(pchIn == NULL)
    {
        return 0;
    }
    nLen = MultiByteToWideChar(CP_ACP, 0, pchIn, -1, NULL, 0);
    ptch = new WCHAR[nLen];
    MultiByteToWideChar(CP_ACP, 0, pchIn, -1, ptch, nLen);
    pstrOut->Format(_T("%s"), ptch);
    
    delete [] ptch;
    return nLen;
}

3)使用EnumPort方法

   该方法调用EnumPort()函数,该函数本身就是枚举电脑端口用的,它枚举的并非只有串口,所以必须对其所得串口进行筛选。

</pre><pre name="code" class="cpp">int m_nSerialPortNum
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值