//========================================================================
//TITLE:
// WinCE虚拟串口驱动(二)
//AUTHOR:
// norains
//DATE:
// Saturday 28-March-2009
//Environment:
// WINDOWS CE 5.0
//========================================================================
虚拟串口驱动的完整代码如下:
view plaincopy to clipboardprint?
// VirtualSerial.cpp : Defines the entry point for the DLL application.
//
#include "windows.h"
#include "reg.h"
#include <vector>
#include <Pegdser.h>
#include "algorithm"
//--------------------------------------------------------------------------
//Macro
#define REG_ROOT_KEY HKEY_LOCAL_MACHINE
#define REG_DEVICE_SUB_KEY TEXT("Drivers//Builtin//VirtualSerial")
#define REG_MAP_PORT_NAME TEXT("Map_Port")
//The buffer length for storing the read data.
#define READ_BUFFER_LENGTH MAX_PATH
//--------------------------------------------------------------------------
//Gloabal variable
HANDLE g_hCom = INVALID_HANDLE_VALUE;
unsigned int g_uiOpenCount = 0;
CRITICAL_SECTION g_csOpen;
CRITICAL_SECTION g_csRead;
CRITICAL_SECTION g_csWrite;
std::vector<BYTE> g_vtBufRead(READ_BUFFER_LENGTH,0);
DWORD g_dwLenReadBuf = 0;
DWORD g_dwEvtMask = 0;
DWORD g_dwWaitMask = 0;
HANDLE g_hEventComm = NULL;
BOOL g_bMonitorProcRunning = FALSE;
BOOL g_bExitMonitorProc = FALSE;
BOOL g_bReaded = FALSE;
//--------------------------------------------------------------------------
BOOL WINAPI DllEntry(HANDLE hInstDll, DWORD dwReason, LPVOID lpvReserved)
{
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
break;
}
return TRUE;
}
DWORD MonitorCommEventProc(LPVOID pParam)
{
InterlockedExchange(reinterpret_cast<LONG *>(&g_bMonitorProcRunning),TRUE);
RETAILMSG(TRUE,(TEXT("[VSP]:MonitorCommEventProc Running!/r/n")));
std::vector<BYTE> vtBufRead(g_vtBufRead.size(),0);
while(TRUE)
{
DWORD dwEvtMask = 0;
BOOL bWaitRes = WaitCommEvent(g_hCom,&dwEvtMask,NULL);
if(g_bExitMonitorProc != FALSE)
{
break;
}
if(bWaitRes == FALSE)
{
continue;
}
DWORD dwRead = 0;
if(dwEvtMask & EV_RXCHAR)
{
EnterCriticalSection(&g_csRead);
ReadFile(g_hCom,&g_vtBufRead[0],vtBufRead.size(),&dwRead,NULL);
if(dwRead == vtBufRead.size() || g_bReaded != FALSE)
{
g_dwLenReadBuf = dwRead;
g_vtBufRead.swap(vtBufRead);
}
else if(dwRead != 0)
{
if(g_dwLenReadBuf + dwRead <= g_vtBufRead.size())
{
g_dwLenReadBuf += dwRead;
g_vtBufRead.insert(g_vtBufRead.end(),vtBufRead.begin(),vtBufRead.begin() + dwRead);
}
else
{
DWORD dwCover = g_dwLenReadBuf + dwRead - g_vtBufRead.size();
std::copy(g_vtBufRead.begin() + dwCover,g_vtBufRead.begin() + g_dwLenReadBuf,g_vtBufRead.begin());
std::copy(vtBufRead.begin(),vtBufRead.begin() + dwRead,g_vtBufRead.begin() + (g_dwLenReadBuf - dwCover));
g_dwLenReadBuf = g_vtBufRead.size();
}
}
g_bReaded = FALSE;
DEBUGMSG(TRUE,(TEXT("[VSP]:Read data : %d/r/n"),dwRead));
LeaveCriticalSection(&g_csRead);
}
if(dwEvtMask == EV_RXCHAR && ((g_dwWaitMask & EV_RXCHAR) == 0 || dwRead == 0))
{
//The return event mask is only EV_RXCHAR and there is not EV_RXCHAR in the wait mask.
continue;
}
InterlockedExchange(reinterpret_cast<LONG *>(&g_dwEvtMask),dwEvtMask);
PulseEvent(g_hEventComm);
//Sleep for other thread to respond to the event
Sleep(100);
DEBUGMSG(TRUE,(TEXT("[VSP]:PulseEvent! The event-mask is 0x%x/r/n"),dwEvtMask));
}
RETAILMSG(TRUE,(TEXT("[VSP]:Exit the MonitorCommEventProc/r/n")));
InterlockedExchange(reinterpret_cast<LONG *>(&g_bMonitorProcRunning),FALSE);
return 0;
}
BOOL VSP_Close(DWORD dwHandle)
{
EnterCriticalSection(&g_csOpen);
g_uiOpenCount --;
if(g_uiOpenCount == 0)
{
//Notify the monitor thread to exit.
InterlockedExchange(reinterpret_cast<LONG *>(&g_bExitMonitorProc),TRUE);
DWORD dwMask = 0;
GetCommMask(g_hCom,&dwMask);
SetCommMask(g_hCom,dwMask);
while(InterlockedExchange(reinterpret_cast<LONG *>(&g_bMonitorProcRunning),TRUE) == TRUE)
{
Sleep(20);
}
InterlockedExchange(reinterpret_cast<LONG *>(&g_bMonitorProcRunning),FALSE);
CloseHandle(g_hCom);
g_hCom = NULL;
}
LeaveCriticalSection(&g_csOpen);
return TRUE;
}
DWORD VSP_Init(DWORD dwContext)
{
RETAILMSG(TRUE,(TEXT("[+VSP_Init]/r/n")));
InitializeCriticalSection(&g_csOpen);
InitializeCriticalSection(&g_csRead);
InitializeCriticalSection(&g_csWrite);
g_hEventComm = CreateEvent(NULL,TRUE,FALSE,NULL);
RETAILMSG(TRUE,(TEXT("[-VSP_Init]/r/n")));
return TRUE;
}
BOOL VSP_Deinit(
DWORD dwContext // future: pointer to the per disk structure
)
{
RETAILMSG(TRUE,(TEXT("[+VSP_Deinit]/r/n")));
CloseHandle(g_hEventComm);
g_hEventComm = NULL;
DeleteCriticalSection(&g_csOpen);
DeleteCriticalSection(&g_csRead);
DeleteCriticalSection(&g_csWrite);
RETAILMSG(TRUE,(TEXT("[-VSP_Deinit]/r/n")));
return TRUE;
}
DWORD VSP_Open(
DWORD dwData,
DWORD dwAccess,
DWORD dwShareMode
)
{
BOOL bResult = FALSE;
EnterCriticalSection(&g_csOpen);
//The variable
CReg reg;
std::vector<TCHAR> vtBuf(MAX_PATH,0);
COMMPROP commProp = {0};
if(g_uiOpenCount != 0)
{
goto SET_SUCCEED_FLAG;
}
if(reg.Open(REG_ROOT_KEY,REG_DEVICE_SUB_KEY) == FALSE)
{
RETAILMSG(TRUE,(TEXT("[VSP]:Failed to open the registry/r/n")));
goto LEAVE_CRITICAL_SECTION;
}
//Get the MAP_PORT name
reg.GetValueSZ(REG_MAP_PORT_NAME,&vtBuf[0],vtBuf.size());
g_hCom = CreateFile(&vtBuf[0],GENERIC_READ | GENERIC_WRITE ,0,NULL,OPEN_EXISTING,0,NULL);
if(g_hCom == INVALID_HANDLE_VALUE )
{
RETAILMSG(TRUE,(TEXT("[VSP]Failed to map to %s/r/n"),&vtBuf[0]));
goto LEAVE_CRITICAL_SECTION;
}
else
{
RETAILMSG(TRUE,(TEXT("[VSP]Succeed to map to %s/r/n"),&vtBuf[0]));
}
InterlockedExchange(reinterpret_cast<LONG *>(&g_bExitMonitorProc),FALSE);
CloseHandle(CreateThread(NULL,NULL,MonitorCommEventProc,NULL,NULL,NULL));
SET_SUCCEED_FLAG:
g_uiOpenCount ++;
bResult = TRUE;
LEAVE_CRITICAL_SECTION:
LeaveCriticalSection(&g_csOpen);
return bResult;
}
BOOL VSP_IOControl(
DWORD dwHandle,
DWORD dwIoControlCode,
PBYTE pBufIn,
DWORD dwBufInSize,
PBYTE pBufOut,
DWORD dwBufOutSize,
PDWORD pBytesReturned
)
{
switch(dwIoControlCode)
{
case IOCTL_SERIAL_SET_DCB:
{
return SetCommState(g_hCom,reinterpret_cast<DCB *>(pBufIn));
}
case IOCTL_SERIAL_GET_DCB:
{
return GetCommState(g_hCom,reinterpret_cast<DCB *>(pBufOut));
}
case IOCTL_SERIAL_WAIT_ON_MASK:
{
if(dwBufOutSize < sizeof(DWORD) || WaitForSingleObject(g_hEventComm,INFINITE) == WAIT_TIMEOUT)
{
*pBytesReturned = 0;
return FALSE;
}
else
{
InterlockedExchange(reinterpret_cast<LONG *>(pBufOut),g_dwEvtMask);
*pBytesReturned = sizeof(DWORD);
return TRUE;
}
}
case IOCTL_SERIAL_SET_WAIT_MASK:
{
g_dwWaitMask = *reinterpret_cast<DWORD *>(pBufIn);
return SetCommMask(g_hCom,g_dwWaitMask | EV_RXCHAR); //The driver need the EV_RXCHAR notify event.
}
case IOCTL_SERIAL_GET_WAIT_MASK:
{
if(dwBufOutSize < sizeof(DWORD) || GetCommMask(g_hCom,reinterpret_cast<DWORD *>(pBufOut)) == FALSE)
{
*pBytesReturned = 0;
return FALSE;
}
else
{
*pBytesReturned = sizeof(DWORD);
return TRUE;
}
}
}
return FALSE;
}
DWORD VSP_Read(DWORD dwHandle, LPVOID pBuffer, DWORD dwNumBytes)
{
EnterCriticalSection(&g_csRead);
//The g_dwLenReadBuf must be less than or equal to g_vtBufRead.size(), so needn't compare with each other.
DWORD dwCopy = g_dwLenReadBuf > dwNumBytes ? dwNumBytes : g_dwLenReadBuf;
if(dwCopy != 0)
{
memcpy(pBuffer,&g_vtBufRead[0],dwCopy);
}
DEBUGMSG(TRUE,(TEXT("[VSP]:Copy cout:%d/r/n"),dwCopy));
g_bReaded = TRUE;
LeaveCriticalSection(&g_csRead);
//Sleep for other thread to entry the function.
Sleep(10);
return dwCopy;
}
DWORD VSP_Write(DWORD dwHandle, LPCVOID pBuffer, DWORD dwNumBytes)
{
EnterCriticalSection(&g_csWrite);
DWORD dwWrite = 0;
WriteFile(g_hCom,pBuffer,dwNumBytes,&dwWrite,NULL);
LeaveCriticalSection(&g_csWrite);
return dwWrite;
}
DWORD VSP_Seek(DWORD dwHandle, long lDistance, DWORD dwMoveMethod)
{
return FALSE;
}
void VSP_PowerUp(void)
{
return;
}
void VSP_PowerDown(void)
{
return;
}
// VirtualSerial.cpp : Defines the entry point for the DLL application.
//
#include "windows.h"
#include "reg.h"
#include <vector>
#include <Pegdser.h>
#include "algorithm"
//--------------------------------------------------------------------------
//Macro
#define REG_ROOT_KEY HKEY_LOCAL_MACHINE
#define REG_DEVICE_SUB_KEY TEXT("Drivers//Builtin//VirtualSerial")
#define REG_MAP_PORT_NAME TEXT("Map_Port")
//The buffer length for storing the read data.
#define READ_BUFFER_LENGTH MAX_PATH
//--------------------------------------------------------------------------
//Gloabal variable
HANDLE g_hCom = INVALID_HANDLE_VALUE;
unsigned int g_uiOpenCount = 0;
CRITICAL_SECTION g_csOpen;
CRITICAL_SECTION g_csRead;
CRITICAL_SECTION g_csWrite;
std::vector<BYTE> g_vtBufRead(READ_BUFFER_LENGTH,0);
DWORD g_dwLenReadBuf = 0;
DWORD g_dwEvtMask = 0;
DWORD g_dwWaitMask = 0;
HANDLE g_hEventComm = NULL;
BOOL g_bMonitorProcRunning = FALSE;
BOOL g_bExitMonitorProc = FALSE;
BOOL g_bReaded = FALSE;
//--------------------------------------------------------------------------
BOOL WINAPI DllEntry(HANDLE hInstDll, DWORD dwReason, LPVOID lpvReserved)
{
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
break;
}
return TRUE;
}
DWORD MonitorCommEventProc(LPVOID pParam)
{
InterlockedExchange(reinterpret_cast<LONG *>(&g_bMonitorProcRunning),TRUE);
RETAILMSG(TRUE,(TEXT("[VSP]:MonitorCommEventProc Running!/r/n")));
std::vector<BYTE> vtBufRead(g_vtBufRead.size(),0);
while(TRUE)
{
DWORD dwEvtMask = 0;
BOOL bWaitRes = WaitCommEvent(g_hCom,&dwEvtMask,NULL);
if(g_bExitMonitorProc != FALSE)
{
break;
}
if(bWaitRes == FALSE)
{
continue;
}
DWORD dwRead = 0;
if(dwEvtMask & EV_RXCHAR)
{
EnterCriticalSection(&g_csRead);
ReadFile(g_hCom,&g_vtBufRead[0],vtBufRead.size(),&dwRead,NULL);
if(dwRead == vtBufRead.size() || g_bReaded != FALSE)
{
g_dwLenReadBuf = dwRead;
g_vtBufRead.swap(vtBufRead);
}
else if(dwRead != 0)
{
if(g_dwLenReadBuf + dwRead <= g_vtBufRead.size())
{
g_dwLenReadBuf += dwRead;
g_vtBufRead.insert(g_vtBufRead.end(),vtBufRead.begin(),vtBufRead.begin() + dwRead);
}
else
{
DWORD dwCover = g_dwLenReadBuf + dwRead - g_vtBufRead.size();
std::copy(g_vtBufRead.begin() + dwCover,g_vtBufRead.begin() + g_dwLenReadBuf,g_vtBufRead.begin());
std::copy(vtBufRead.begin(),vtBufRead.begin() + dwRead,g_vtBufRead.begin() + (g_dwLenReadBuf - dwCover));
g_dwLenReadBuf = g_vtBufRead.size();
}
}
g_bReaded = FALSE;
DEBUGMSG(TRUE,(TEXT("[VSP]:Read data : %d/r/n"),dwRead));
LeaveCriticalSection(&g_csRead);
}
if(dwEvtMask == EV_RXCHAR && ((g_dwWaitMask & EV_RXCHAR) == 0 || dwRead == 0))
{
//The return event mask is only EV_RXCHAR and there is not EV_RXCHAR in the wait mask.
continue;
}
InterlockedExchange(reinterpret_cast<LONG *>(&g_dwEvtMask),dwEvtMask);
PulseEvent(g_hEventComm);
//Sleep for other thread to respond to the event
Sleep(100);
DEBUGMSG(TRUE,(TEXT("[VSP]:PulseEvent! The event-mask is 0x%x/r/n"),dwEvtMask));
}
RETAILMSG(TRUE,(TEXT("[VSP]:Exit the MonitorCommEventProc/r/n")));
InterlockedExchange(reinterpret_cast<LONG *>(&g_bMonitorProcRunning),FALSE);
return 0;
}
BOOL VSP_Close(DWORD dwHandle)
{
EnterCriticalSection(&g_csOpen);
g_uiOpenCount --;
if(g_uiOpenCount == 0)
{
//Notify the monitor thread to exit.
InterlockedExchange(reinterpret_cast<LONG *>(&g_bExitMonitorProc),TRUE);
DWORD dwMask = 0;
GetCommMask(g_hCom,&dwMask);
SetCommMask(g_hCom,dwMask);
while(InterlockedExchange(reinterpret_cast<LONG *>(&g_bMonitorProcRunning),TRUE) == TRUE)
{
Sleep(20);
}
InterlockedExchange(reinterpret_cast<LONG *>(&g_bMonitorProcRunning),FALSE);
CloseHandle(g_hCom);
g_hCom = NULL;
}
LeaveCriticalSection(&g_csOpen);
return TRUE;
}
DWORD VSP_Init(DWORD dwContext)
{
RETAILMSG(TRUE,(TEXT("[+VSP_Init]/r/n")));
InitializeCriticalSection(&g_csOpen);
InitializeCriticalSection(&g_csRead);
InitializeCriticalSection(&g_csWrite);
g_hEventComm = CreateEvent(NULL,TRUE,FALSE,NULL);
RETAILMSG(TRUE,(TEXT("[-VSP_Init]/r/n")));
return TRUE;
}
BOOL VSP_Deinit(
DWORD dwContext // future: pointer to the per disk structure
)
{
RETAILMSG(TRUE,(TEXT("[+VSP_Deinit]/r/n")));
CloseHandle(g_hEventComm);
g_hEventComm = NULL;
DeleteCriticalSection(&g_csOpen);
DeleteCriticalSection(&g_csRead);
DeleteCriticalSection(&g_csWrite);
RETAILMSG(TRUE,(TEXT("[-VSP_Deinit]/r/n")));
return TRUE;
}
DWORD VSP_Open(
DWORD dwData,
DWORD dwAccess,
DWORD dwShareMode
)
{
BOOL bResult = FALSE;
EnterCriticalSection(&g_csOpen);
//The variable
CReg reg;
std::vector<TCHAR> vtBuf(MAX_PATH,0);
COMMPROP commProp = {0};
if(g_uiOpenCount != 0)
{
goto SET_SUCCEED_FLAG;
}
if(reg.Open(REG_ROOT_KEY,REG_DEVICE_SUB_KEY) == FALSE)
{
RETAILMSG(TRUE,(TEXT("[VSP]:Failed to open the registry/r/n")));
goto LEAVE_CRITICAL_SECTION;
}
//Get the MAP_PORT name
reg.GetValueSZ(REG_MAP_PORT_NAME,&vtBuf[0],vtBuf.size());
g_hCom = CreateFile(&vtBuf[0],GENERIC_READ | GENERIC_WRITE ,0,NULL,OPEN_EXISTING,0,NULL);
if(g_hCom == INVALID_HANDLE_VALUE )
{
RETAILMSG(TRUE,(TEXT("[VSP]Failed to map to %s/r/n"),&vtBuf[0]));
goto LEAVE_CRITICAL_SECTION;
}
else
{
RETAILMSG(TRUE,(TEXT("[VSP]Succeed to map to %s/r/n"),&vtBuf[0]));
}
InterlockedExchange(reinterpret_cast<LONG *>(&g_bExitMonitorProc),FALSE);
CloseHandle(CreateThread(NULL,NULL,MonitorCommEventProc,NULL,NULL,NULL));
SET_SUCCEED_FLAG:
g_uiOpenCount ++;
bResult = TRUE;
LEAVE_CRITICAL_SECTION:
LeaveCriticalSection(&g_csOpen);
return bResult;
}
BOOL VSP_IOControl(
DWORD dwHandle,
DWORD dwIoControlCode,
PBYTE pBufIn,
DWORD dwBufInSize,
PBYTE pBufOut,
DWORD dwBufOutSize,
PDWORD pBytesReturned
)
{
switch(dwIoControlCode)
{
case IOCTL_SERIAL_SET_DCB:
{
return SetCommState(g_hCom,reinterpret_cast<DCB *>(pBufIn));
}
case IOCTL_SERIAL_GET_DCB:
{
return GetCommState(g_hCom,reinterpret_cast<DCB *>(pBufOut));
}
case IOCTL_SERIAL_WAIT_ON_MASK:
{
if(dwBufOutSize < sizeof(DWORD) || WaitForSingleObject(g_hEventComm,INFINITE) == WAIT_TIMEOUT)
{
*pBytesReturned = 0;
return FALSE;
}
else
{
InterlockedExchange(reinterpret_cast<LONG *>(pBufOut),g_dwEvtMask);
*pBytesReturned = sizeof(DWORD);
return TRUE;
}
}
case IOCTL_SERIAL_SET_WAIT_MASK:
{
g_dwWaitMask = *reinterpret_cast<DWORD *>(pBufIn);
return SetCommMask(g_hCom,g_dwWaitMask | EV_RXCHAR); //The driver need the EV_RXCHAR notify event.
}
case IOCTL_SERIAL_GET_WAIT_MASK:
{
if(dwBufOutSize < sizeof(DWORD) || GetCommMask(g_hCom,reinterpret_cast<DWORD *>(pBufOut)) == FALSE)
{
*pBytesReturned = 0;
return FALSE;
}
else
{
*pBytesReturned = sizeof(DWORD);
return TRUE;
}
}
}
return FALSE;
}
DWORD VSP_Read(DWORD dwHandle, LPVOID pBuffer, DWORD dwNumBytes)
{
EnterCriticalSection(&g_csRead);
//The g_dwLenReadBuf must be less than or equal to g_vtBufRead.size(), so needn't compare with each other.
DWORD dwCopy = g_dwLenReadBuf > dwNumBytes ? dwNumBytes : g_dwLenReadBuf;
if(dwCopy != 0)
{
memcpy(pBuffer,&g_vtBufRead[0],dwCopy);
}
DEBUGMSG(TRUE,(TEXT("[VSP]:Copy cout:%d/r/n"),dwCopy));
g_bReaded = TRUE;
LeaveCriticalSection(&g_csRead);
//Sleep for other thread to entry the function.
Sleep(10);
return dwCopy;
}
DWORD VSP_Write(DWORD dwHandle, LPCVOID pBuffer, DWORD dwNumBytes)
{
EnterCriticalSection(&g_csWrite);
DWORD dwWrite = 0;
WriteFile(g_hCom,pBuffer,dwNumBytes,&dwWrite,NULL);
LeaveCriticalSection(&g_csWrite);
return dwWrite;
}
DWORD VSP_Seek(DWORD dwHandle, long lDistance, DWORD dwMoveMethod)
{
return FALSE;
}
void VSP_PowerUp(void)
{
return;
}
void VSP_PowerDown(void)
{
return;
}
不过该驱动代码是作者量身定做的,像IOControl就简单地实现了几个,其余的因为在实际使用中本人没用到,所以都没实现,只是简单地返回了FALSE。如果有朋友对此有兴趣,并且实际中也使用到,可以自行调用原生函数实现。
最后,是能让驱动正常挂载的注册表设置:
[HKEY_LOCAL_MACHINE/Drivers/Builtin/VirtualSerial]
"Prefix"="VSP"
"Dll"="VirtualSerial.dll"
"Order"=dword:0
"Index"=dword:1
"Map_Port"="COM1:"
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/norains/archive/2009/03/28/4032332.aspx