📄 parallelport.cpp
字号:
/*
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 + -