⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parallelport.cpp

📁 vc并口编程实例
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*
Module : PARALLEL.CPP
Purpose: Implementation for an MFC class to encapsulate parallel ports
Created: PJN / 28-12-1999
History: PJN / 06-03-2000 Code now throws an exception if no Win32 parallel ports are available
         PJN / 04-04-2000 Code handles the case where it is run on NT / Windows 2000 by throwing
                          an exception                 
         PJN / 19-07-2000 1. Now works on NT / Windows 2000 thanks to DriverLINX Port I/O Driver
                          2. Made all typedefs and enums local to the appropiate class rather
                          than polluting the global namespace
         PJN / 12-04-2003 1. Updated copyright details. 
                          2. Updated documentation to refer to new DriverLinx web site.
                          3. Code now issues compile time message if conio or afxpriv are not in 
                          your PCH.
         PJN / 11-06-2003 1. Reviewed all places where exceptions are throw and the details which
                          are logged in TRACE statements.


Copyright (c) 1999 - 2003 by PJ Naughter.  (Web: www.naughter.com, Email: pjna@naughter.com)

All rights reserved.

Copyright / Usage Details:

You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise) 
when your product is released in binary form. You are allowed to modify the source code in any way you want 
except you cannot modify the copyright details at the top of each module. If you want to distribute source 
code with your application, then you are only allowed to distribute versions released by the author. This is 
to maintain a single distribution point for the source code. 

*/

/////////////////////////////////  Includes  //////////////////////////////////
#include "stdafx.h"
#include "ParallelPort.h"
#ifndef _INC_CONIO
#pragma message("To avoid this message, please put conio.h in your PCH (normally stdafx.h)")
#include <conio.h>
#endif
#ifndef __AFXPRIV_H__
#pragma message("To avoid this message, please put afxpriv.h in your PCH (normally stdafx.h)")
#include <afxpriv.h>
#endif




///////////////////////////////// Defines / Statics ///////////////////////////

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

int CParallelPort::sm_nRefCount = 0;
BOOL CParallelPort::sm_bRunningOnNT = FALSE;
HINSTANCE CParallelPort::sm_hDLINX = NULL;
CParallelPort::LPDLPORTREADPORTUCHAR CParallelPort::sm_lpfnDlPortReadUchar = NULL;
CParallelPort::LPDLPORTWRITEPORTUCHAR CParallelPort::sm_lpfnDlPortWriteUchar = NULL;
CArray<CParallelPortSettings, CParallelPortSettings&> CParallelPort::sm_Ports;




//////////////////////////////// Implementation ///////////////////////////////


////////// Exception handling code

void AfxThrowParallelException(DWORD dwError /* = 0 */)
{
	if (dwError == 0)
		dwError = ::GetLastError();

	CParallelException* pException = new CParallelException(dwError);

	TRACE(_T("Warning: throwing CParallelException for error %d\n"), dwError);
	THROW(pException);
}

BOOL CParallelException::GetErrorMessage(LPTSTR pstrError, UINT nMaxError, PUINT pnHelpContext)
{
	ASSERT(pstrError != NULL && AfxIsValidString(pstrError, nMaxError));

	if (pnHelpContext != NULL)
		*pnHelpContext = 0;

	LPTSTR lpBuffer;
	BOOL bRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
			                      NULL,  m_dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
			                      (LPTSTR) &lpBuffer, 0, NULL);

	if (bRet == FALSE)
		*pstrError = '\0';
	else
	{
		lstrcpyn(pstrError, lpBuffer, nMaxError);
		bRet = TRUE;

		LocalFree(lpBuffer);
	}

	return bRet;
}

CString CParallelException::GetErrorMessage()
{
  CString rVal;
  LPTSTR pstrError = rVal.GetBuffer(4096);
  GetErrorMessage(pstrError, 4096, NULL);
  rVal.ReleaseBuffer();
  return rVal;
}

CParallelException::CParallelException(DWORD dwError)
{
	m_dwError = dwError;
}

CParallelException::~CParallelException()
{
}

IMPLEMENT_DYNAMIC(CParallelException, CException)

#ifdef _DEBUG
void CParallelException::Dump(CDumpContext& dc) const
{
	CObject::Dump(dc);

	dc << "m_dwError = " << m_dwError;
}
#endif



////////// Settings class

CParallelPortSettings::CParallelPortSettings()
{
  m_nBaseAddress = 0;
  m_Type         = ParallelTypeUndefined;
  m_ECPMode      = ECPModeUndefined;
}

CParallelPortSettings::CParallelPortSettings(const CParallelPortSettings& state)
{
  *this = state;
}

CParallelPortSettings& CParallelPortSettings::operator=(const CParallelPortSettings& state)
{
  m_nBaseAddress = state.m_nBaseAddress;
  m_Type         = state.m_Type;   
  m_ECPMode      = state.m_ECPMode;

  return *this;
}



////////// The actual parallel port class

CParallelPort::CParallelPort()
{
  m_hPort = INVALID_HANDLE_VALUE;
  m_nPortIndex = -1;
  m_nBaseAddress = 0;
  m_dwTimeout = 1000;  //Default timeout is 1 second

  //Test for presence of parallel ports at the standard addresses of 0x3BC, 0x378 and 0x278
  if (sm_nRefCount == 0)
  {
    ++sm_nRefCount;

    //Initialize the DriverLINX driver if on NT / Windows 2000
    sm_bRunningOnNT = RunningOnNT();
    if (sm_bRunningOnNT)
    {
      if (!InitializeDriverLINX())
      {
        TRACE(_T("CParallelPort::CParallelPort, Running on Windows NT, Windows 2000, Windows XP or Windows 2003 and the DriverLINX PORTIO driver is not installed\n"));
        AfxThrowParallelException(ERROR_CALL_NOT_IMPLEMENTED);
      }
    }

    //Open LPT1 - LPT3 as a precaution against other processes trying to write 
    //to the port while we are detecting them
    HANDLE hPort1 = CreateFile(_T("\\\\.\\LPT1"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    HANDLE hPort2 = CreateFile(_T("\\\\.\\LPT2"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    HANDLE hPort3 = CreateFile(_T("\\\\.\\LPT3"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

    //Must have at least one port available in Win32 to continue to attempt
    //detection of the ports
    int nWin32Ports = 0;
    if (hPort1 != INVALID_HANDLE_VALUE)
      ++nWin32Ports;
    if (hPort2 != INVALID_HANDLE_VALUE)
      ++nWin32Ports;
    if (hPort3 != INVALID_HANDLE_VALUE)
      ++nWin32Ports;
    if (nWin32Ports == 0)
    {
      TRACE(_T("CParallelPort::CParallelPort, No parallel ports are available to Win32 SDK\n"));
      AfxThrowParallelException(ERROR_DEV_NOT_EXIST);
    }

    //Try to detect the details of the 3 standard ports
    CParallelPortSettings settings;
    if (GetPort(0x3BC, settings))
      sm_Ports.Add(settings);

    if (sm_Ports.GetSize() < nWin32Ports) 
      if (GetPort(0x378, settings))
        sm_Ports.Add(settings);

    if (sm_Ports.GetSize() < nWin32Ports) 
      if (GetPort(0x278, settings))
        sm_Ports.Add(settings);

    if (sm_Ports.GetSize() == 0)
      TRACE(_T("CParallelPort::CParallelPort, Could not detect any parallel ports on this machine\n"));

    //Don't forget to close the 3 SDK handles we had open
    CloseHandle(hPort3);
    CloseHandle(hPort2);
    CloseHandle(hPort1);
  }
}

CParallelPort::~CParallelPort()
{
  //decrement the reference count and 
  //free the DriverLINX pointers if necessary
  --sm_nRefCount;
  if (sm_nRefCount == 0)
    DeInitializeDriverLINX();

  Close();
}

IMPLEMENT_DYNAMIC(CParallelPort, CObject)

#ifdef _DEBUG
void CParallelPort::Dump(CDumpContext& dc) const
{
	CObject::Dump(dc);

	dc << _T("m_hPort = ") << m_hPort << _T("\n");
}
#endif

void CParallelPort::Open(int nPort)
{
  //Call Close just in case we already have the port open
  Close();

  m_nPortIndex = nPort - 1;
  if (m_nPortIndex < sm_Ports.GetSize())
  {
    //Cache the base address of the port for performance reasons
    m_nBaseAddress = sm_Ports.ElementAt(m_nPortIndex).m_nBaseAddress;

    //Call CreateFile to open up the parallel port. This prevents other apps 
    //causing problems when we do the Port IO directly.
    CString sPort;
    sPort.Format(_T("\\\\.\\LPT%d"), nPort);
    m_hPort = CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (m_hPort == INVALID_HANDLE_VALUE)
    {
      DWORD dwLastError = GetLastError();
      TRACE(_T("CParallelPort::Open, Failed to open parallel port, LPT%d, Error:%d\n"), nPort, dwLastError);
      Close();
      AfxThrowParallelException(dwLastError);
    }
  }
  else
  {
    TRACE(_T("CParallelPort::Open, Could not find the parallel port, LPT%d\n"), nPort);
    Close();
    AfxThrowParallelException(ERROR_FILE_NOT_FOUND);
  }
}

BOOL CParallelPort::IsOpen() const
{
  return (m_hPort != INVALID_HANDLE_VALUE);
}

void CParallelPort::Close()
{
  if (IsOpen())
  {
    BOOL bSuccess = CloseHandle(m_hPort);
    m_hPort = INVALID_HANDLE_VALUE;
    m_nPortIndex = -1;
    m_nBaseAddress = 0;
    if (!bSuccess)
      TRACE(_T("CParallelPort::Close, Failed to close the parallel port, GetLastError:%d\n"), GetLastError());
  }
}

void CParallelPort::SetECPMode(CParallelPortSettings::ECPPortMode mode)
{
  ASSERT(IsOpen()); //Port must be open 
  CParallelPortSettings& settings = sm_Ports.ElementAt(m_nPortIndex);
  ASSERT(settings.m_Type == CParallelPortSettings::ParallelTypeECP); //Must be an ECP port
  ASSERT(mode != CParallelPortSettings::ECPModeUndefined);

  unsigned short nEcrAddress = (unsigned short)(m_nBaseAddress + 0x402);

  //Read the ECR & clear bits 5, 6 & 7
  int nEcrData = _inp(nEcrAddress) & 0x1F;
  
  //Write the selected value to bits 5, 6 & 7
  switch (mode)
  {
    case CParallelPortSettings::ECPModeSPP:            nEcrData |= (0 << 5); break;
    case CParallelPortSettings::ECPModePS2:            nEcrData |= (1 << 5); break;
    case CParallelPortSettings::ECPModeFastCentronics: nEcrData |= (2 << 5); break;
    case CParallelPortSettings::ECPModeECP:            nEcrData |= (3 << 5); break;
    case CParallelPortSettings::ECPModeEPP:            nEcrData |= (4 << 5); break;
    case CParallelPortSettings::ECPModeTest:           nEcrData |= (6 << 5); break;
    case CParallelPortSettings::ECPModeConfiguration:  nEcrData |= (7 << 5); break;
    default: ASSERT(FALSE);                           break;
  }
  _outp(nEcrAddress, nEcrData);

  //Update the value in our cached array
  settings.m_ECPMode = mode;
}

CParallelPortSettings::ECPPortMode CParallelPort::GetECPMode()
{
  ASSERT(IsOpen()); //Port must be open 
  CParallelPortSettings& settings = sm_Ports.ElementAt(m_nPortIndex);
  ASSERT(settings.m_Type == CParallelPortSettings::ParallelTypeECP); //Must be an ECP port

  CParallelPortSettings::ECPPortMode t = ReadECPMode(settings.m_nBaseAddress);
  ASSERT(t == settings.m_ECPMode);

  return settings.m_ECPMode;
}

CParallelPortSettings::ECPPortMode CParallelPort::ReadECPMode(unsigned short nBaseAddress)
{
  CParallelPortSettings::ECPPortMode mode = CParallelPortSettings::ECPModeUndefined;
  int nEcrData = _inp((unsigned short)(nBaseAddress+0x402));
  nEcrData = (nEcrData & 0xE0) >> 5;
  switch (nEcrData)
  { 
    case 0: mode = CParallelPortSettings::ECPModeSPP;            break;
    case 1: mode = CParallelPortSettings::ECPModePS2;            break;
    case 2: mode = CParallelPortSettings::ECPModeFastCentronics; break;
    case 3: mode = CParallelPortSettings::ECPModeECP;            break;
    case 4: mode = CParallelPortSettings::ECPModeEPP;            break;
    case 6: mode = CParallelPortSettings::ECPModeTest;           break;
    case 7: mode = CParallelPortSettings::ECPModeConfiguration;  break;
    default: break;
  }
  return mode;
}

BOOL CParallelPort::GetPort(unsigned short nBaseAddress, CParallelPortSettings& settings)
{
  BOOL bSuccess = FALSE;

  //First try to detect an ECP port
  if (GetECPPort(nBaseAddress))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -