📄 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
Copyright (c) 1999 - 2000 by PJ Naughter.
All rights reserved.
*/
///////////////////////////////// Includes //////////////////////////////////
#include "stdafx.h"
#include "ParallelPort.h"
#include <winerror.h>
#include <conio.h>
#include <afxpriv.h>
///////////////////////////////// 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("Running on Windows NT / Windows 2000 and the DriverLINX PORTIO driver is not installed, aborting !!\n"));
AfxThrowParallelException();
}
}
//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("No parallel ports are available to Win32, aborting !!\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("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)
{
TRACE(_T("Failed to open parallel port, LPT%d\n"), nPort);
Close();
AfxThrowParallelException();
}
}
else
{
TRACE(_T("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("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))
{
settings.m_nBaseAddress = nBaseAddress;
settings.m_Type = CParallelPortSettings::ParallelTypeECP;
settings.m_ECPMode = ReadECPMode(nBaseAddress);
bSuccess = TRUE;
}
else
{
//If its not an ECP, look for an EPP.
//If the baseaddress is 3BCh, skip the EPP test.
//EPPs aren't allowed at 3BCh due to possible conflicts
//with video memory
BOOL bFoundEPP = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -