WinCE虚拟串口驱动(二)

简介: //========================================================================  //TITLE:  //    WinCE虚拟串口驱动(二)  //AUTHOR:  //    ...

//========================================================================
  //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

目录
相关文章
WinCE下串口虚拟软件
前段时间,介绍了一个WinCE下的串口调试软件Serial Splitter Mobile 3.2。它的主要功能是将一个物理串口克隆成N个,供不同的应用程序使用,以监视物理串口收发的数据。今天介绍一个WinCE下的串口虚拟软件VSPD Mobile 4.2。
921 0
Jlink使用技巧之虚拟串口功能
前言 串口调试是单片机开发过程必不可少的一个功能,一般是使用一个UART-TTL的串口模块来实现串口的功能,其实下载调试使用的Jlink仿真器也可以实现串口调试的功能,本篇文章将介绍如何使用Jlink实现虚拟串口功能。
2392 0