在上位机开发过程中,控制软件往往会拥有一个通信串口与下位机进行数据通信,如果上位机需要添加一个小的功能模块,而此模块是以另一个进程出现,并且也通过相同的串口与下位机进行通信,这里就会出现串口共享的问题。下面我就利用内核对象复制的原理实现进程间串口的共享问题。
技术点分析:
- 串口对象:串口对象属于Windows I/O对象中的一种,通过CreateFile函数进行创建,创建成功后会获取一个HANDEL句柄,数据的发送与接受采用WriteFile和ReadFile函数;
- 跨进程边界的内核对象共享:内核对象的共享方式可以采用子进程继承、命名内核对象和内核对象复制。本工程中采用内核对象复制的方式实现,关键函数是DuplicateHandle;
- 内核对象传递:在共享内核对象后,共享的内核对象已经在子进程的内核对象句柄表中进行了创建,但此时的内核对象还存在与主进程中,子进程并不知道此内核对象复制成功,所以需要采用进程间通信的方式将此内核对象传给子进程;本工程利用Windows消息机制进行传递,也可以采用相关的LPC方式,如:管道、邮槽等进程通信的方式传递;
- 子进程创建:进程创建很简单,本工程中会有一个主进程MainProcess,通过一个按钮创建一个子进程SubProcess,采用的创建函数是CreateProcess。
API函数解析:
- 用CreateFile创建一个串口对象,例如创建一个端口号1、波特率115200、数据位8、停止位1、校验位无的串口
DCB dcb;
// Open Comm
HANDLE m_hComm = CreateFile(L"COM1",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (m_hComm != INVALID_HANDLE_VALUE)
{
GetCommState(m_hComm,&dcb);
dcb.BaudRate = CBR_115200;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
SetCommState(m_hComm,&dcb);
}
- 用WriteFile发送一串协议码
if (m_hComm != INVALID_HANDLE_VALUE)
{
byte sendBuffer[8];
sendBuffer[0] = 0x80;
sendBuffer[1] = 0x94;
sendBuffer[2] = 0x06;
sendBuffer[3] = 0xff;
sendBuffer[4] = 0xff;
sendBuffer[5] = 0xff;
sendBuffer[6] = 0xff;
sendBuffer[7] = 0xff;
WriteFile(m_hComm,sendBuffer,8,NULL,NULL);
}
- 子进程创建,此处子进程执行文件名为SubProcess
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
TCHAR subPath[] = L"SubProcess";
CreateProcess(NULL,subPath,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi);
m_hSubProcess = pi.hProcess;
m_hMainProcess = GetCurrentProcess();
- 内核对象跨进程共享
上述过程中,获取了子进程的进程句柄m_hSubProcess,和主进程的进程句柄m_hMainProcess,又得到了串口对象的句柄m_hComm,通过查阅MSDN关于DuplicateHandle的使用方法,如下:
BOOL DuplicateHandle(
HANDLE hSourceProcessHandle, // handle to source process
HANDLE hSourceHandle, // handle to duplicate
HANDLE hTargetProcessHandle, // handle to target process
LPHANDLE lpTargetHandle, // duplicate handle
DWORD dwDesiredAccess, // requested access
BOOL bInheritHandle, // handle inheritance option
DWORD dwOptions // optional actions
);
现在就只需要一个接受的句柄m_hSubComm,就可以进行内核对象的复制了,代码如下:
// Share Comm
BOOL bSuccess = DuplicateHandle(m_hMainProcess,m_hComm,m_hSubProcess,&m_hSubComm,
0,TRUE,DUPLICATE_SAME_ACCESS);
// Send Share Handle to SubProcess
if (bSuccess)
{
AfxMessageBox(_T("Success"));
HWND hWindow = ::FindWindow(NULL,_T("SubProcess"));
::PostMessage(hWindow,UWM_COPYHANDLE,(WPARAM)m_hSubComm,0);
}
- 进程间内核对象传递
如上述代码所示,通过查找子进程的窗口句柄,然后发送自定义消息到子进程,就可以将句柄传递过去,这样子进程接收到消息后就可以利用传递过来的句柄进行串口操作了。
转载请注明出处,谢谢~~~