I am using VS 2013 Professional in an MFC project
I have been using my software to receive data from the com port for some time, but recently needed to add transmission capability
The Init code is:
BOOL PASCAL FAR SetupConnect(pCONNECTION pCon, pCOMCONFIG pCfg)
{
DCB dcb;
pSERBUF pSB = pCon->BufStruct;
// pSERBUF *ppSB = (pSERBUF*)pCon->BufStruct;
// pSB = *ppSB;
dcb.DCBlength = sizeof(DCB);
CheckComs(); // Gets available COM ports
pCon->Port = pNames[0].PortNames[3] - 0x30;
if (pCon->BufStruct == NULL) // This is a personal Communications structure
{ // Init
pCon->hSB = GlobalAlloc(GHND, sizeof(SERBUF));
if (pCon->hSB == NULL)
{
// return INVALID_HANDLE_VALUE;
return 0;
}
pSB = (pSERBUF)GlobalLock(pCon->hSB);
pSB->idComDev = INVALID_HANDLE_VALUE;
pCon->BufStruct = pSB;
}
else return (0);
if (pSB->idComDev == INVALID_HANDLE_VALUE)
{
pSB->idComDev = CreateFile(pNames[0].PortNames, GENERIC_READ | GENERIC_WRITE,
0, //exclusive access
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
}
// Current configuration
GetCommState(pSB->idComDev, &dcb);
// Setup baudrate, parity, etc.
dcb.BaudRate = pCfg->dwBaudRate;
dcb.ByteSize = pCfg->bDataBits;
dcb.Parity = pCfg->bParity;
dcb.StopBits = pCfg->bStopBits;
// Setup Flow Control
dcb.fOutxDsrFlow = pCfg->handshake_DTR;
dcb.fDtrControl = DTR_CONTROL_ENABLE; // DTR high while port open
dcb.fOutxCtsFlow = pCfg->handshake_RTS;
dcb.fRtsControl = RTS_CONTROL_DISABLE; // Toggle RTS with EscapeCommFunction
// XON/XOFF Not Used
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fBinary = TRUE;
dcb.fParity = TRUE;
//return TRUE if everything looks cool
return (SetCommState(pSB->idComDev, &dcb));
}
And:
CSerCom::CSerCom()
{
pCon = &Con;
pCfg = &Cfg;
m_SerHwnd = this;
pCfg->dwBaudRate = 115200;
pCfg->bDataBits = 8;
pCfg->bParity = NOPARITY;
pCfg->bStopBits = TWOSTOPBITS;
// here
SetupConnect(pCon, pCfg);
pSERBUF pSB = pCon->BufStruct; // pSB is set in SetUpConnect
if (pSB->idComDev == INVALID_HANDLE_VALUE)
{
// device open failure
// hardware not there or someone else controls it!
GlobalUnlock(pCon->hSB);
GlobalFree(pCon->hSB);
pCon->BufStruct = NULL;
// TODO stop this from going any further
HandleFailure();
}
else // Only continue if Port is available
{
// Clear Buffer
SetupComm(pSB->idComDev, 4096, 4096);
PurgeComm(pSB->idComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
// create the overlapped events
memset(&(pSB->osRead), 0, sizeof(OVERLAPPED));
memset(&(pSB->osWrite), 0, sizeof(OVERLAPPED));
pSB->osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
pSB->osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if ((pSB->osRead.hEvent == NULL) || (pSB->osWrite.hEvent == NULL))
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
// allocate & lock the mem
// (used to contain data points to & from the MODBUS
// as well as the receive buffer for incoming serial data)
pSB->hRcv = GlobalAlloc(GHND, MAX_RX_LEN);
if (pSB->hRcv == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
pSB->pRcv = (char *)GlobalLock(pSB->hRcv);
pSB->hTx = (char *)GlobalAlloc(GHND, MAX_TX_LEN);
if (pSB->hTx == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
pSB->pTx = (char *)GlobalLock(pSB->hTx);
// remember the setup params
pSB->TimeOut = 3; //CalculateTimeOut(pCfg->dwBaudRate);
// pSB->TimerId = TimerId;
// initialize the status counters
// pSB->ValidCt = 0;
// pSB->InvalidCt = 0;
pSB->RxInIdx = 0;
// pSB->RTS_Delay[0] = pCfg->RTS_Delay[0];
// pSB->RTS_Delay[1] = pCfg->RTS_Delay[1];
pSB->RTS_Delay[0] = 100;
pSB->RTS_Delay[1] = 100;
// setup the Comm Timeouts
CommTimeOuts.ReadIntervalTimeout = 0xffffffff;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 1000;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts(pSB->idComDev, &CommTimeOuts);
// if everything looks good to here
// create the Receive Thread & return the CONNECT handle
pSB->hIOThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)SerProc,
(LPVOID)pCon,
0,
&dwThreadID);
if (pSB->hIOThread == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
hIOT = pSB->hIOThread;
}
}
So with that set up, I enter a thread loop in which I have the following
// wait indefinitely for somthing to happen
WaitCommEvent(pSB->idComDev, &dwEvtMask, NULL);
// Catch Rx event
if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)
{
Edit1_txt.Format(_T("Rx'd"));
E1->SetWindowText(Edit1_txt);
CMFCView->UpdateWindow();
// only try to read number of bytes in queue
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
dwLength = ComStat.cbInQue;
// Read data bytes into connection Rcv Buffer at current RxInIdx
if (dwLength > 0)
{
fReadStat = ReadFile(pSB->idComDev,
&(pSB->pRcv[pSB->RxInIdx]),
dwLength,
&bytesread,
&(pSB->osRead));
if (!fReadStat)
{
if (GetLastError() == ERROR_IO_PENDING)
{
// We have to wait for read to complete.
while (!GetOverlappedResult(pSB->idComDev,
&(pSB->osRead), &bytesread, FALSE))
{
dwErrorFlags = GetLastError();
if (dwErrorFlags != ERROR_IO_INCOMPLETE)
// an error occurred, try to recover
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
}
else
{
// some other error occurred
dwLength = 0;
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
} // End of Read Error
} // End of Read Char
if (ComStat.cbInQue < 500)
{
// update the receive index
pSB->RxInIdx += dwLength;
wSleepime = GetTickCount(); // hkk 7/16/99 for console app
ParseAPI(pSB);
}
else
ComStat.cbInQue = 0;
}
// At some point in the program pSB->TxOutIdx is set to some positive value
if (pSB->TxOutIdx > 0)
{
dwLength = pSB->TxOutIdx;
fWriteStat = WriteFile(pSB->idComDev,
&(pSB->pTx[pSB->TxOutIdx]),
dwLength,
&byteswritten,
&(pSB->osWrite));
if (!fWriteStat)
{
if (GetLastError() == ERROR_IO_PENDING)
{
while (!GetOverlappedResult(pSB->idComDev,
&(pSB->osWrite), &byteswritten, FALSE))
{
dwErrorFlags = GetLastError();
if (dwErrorFlags != ERROR_IO_INCOMPLETE)
// an error occurred, try to recover
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
}
pSB->TxOutIdx -= byteswritten;
}
}
}
This detects the Tx buffer full, (pSB->TxOutIdx > 0)
and transmits the data
The transmit fails with an IO pending error, but after execution of GetOverlappedResult, bytes written show the length desired.
However, no data comes out the port. I have checked, and the port found and used is correct.
Wassup?
Related
In order to write to HD at max. performance I'm using overlapped I/O.
It works.
Upon acquiring 4MB of data (from sensor) I'm writing it to disk.
Then, upon getting the next 4MB I first ask if the previous writing completed.
How can I know what is the optimal block size (4MB ?) that is best for my disk ?
// AsyncFile.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "AsyncFile.h"
/****************************************************************************/
CAsyncFile::CAsyncFile()
{
}
/****************************************************************************/
CAsyncFile::~CAsyncFile()
{
}
/****************************************************************************/
int CAsyncFile::OpenFile(char *pcFileName,
bool bAsync, // Whether async read/write is required
bool bWrite) // True is file is used for writing to
{
DWORD dwAsyncMask = bAsync ? (FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING) : 0;
DWORD dwCreation = bWrite ? CREATE_ALWAYS : OPEN_EXISTING;
DWORD dwAccess = bWrite ? GENERIC_WRITE : GENERIC_READ;
DWORD dwShareMode = bWrite ? FILE_SHARE_READ : FILE_SHARE_WRITE;
if (strlen(pcFileName) < sizeof(m_cFileName))
strcpy_s(m_cFileName, 256, pcFileName);
else
m_cFileName[0] = 0; // NULL (error - file name is too long)
// Calling openFile() sets a valid value to the file handle
m_hFileHandle = INVALID_HANDLE_VALUE;
// Auto reset (manual reset=false), init state = false, no name
m_hIoCompleted = CreateEvent(NULL, FALSE, FALSE, NULL);
// Init OVERLAPPED structure, for async read
m_tOverlapped.Offset = 0;
m_tOverlapped.OffsetHigh = 0;
m_tOverlapped.hEvent = m_hIoCompleted;
m_Event = m_tOverlapped.hEvent;
if (m_hFileHandle != INVALID_HANDLE_VALUE)
{
// File is already openned; check open mode
if ((bAsync == m_bAsync) && (bWrite == m_bWrite))
return (ASYNCFILE_OK);
// File is already openned, but in other mode; Should close file
// before using it again
return ASYNCFILE_FILE_IS_NOT_IN_WRITE_MODE;
}
m_hFileHandle =
CreateFile((LPCTSTR)m_cFileName,
dwAccess, // Open for read or write
dwShareMode, //
NULL, // No SECURITY_ATTRBUTES
dwCreation, // Open exisiting file (if read) \ create new (if write)
dwAsyncMask, // For asynchronous operations, for maximum asynchronous performence
0);
if (m_hFileHandle == INVALID_HANDLE_VALUE)
{
DWORD dwError = GetLastError();
return ASYNCFILE_FAILED_TO_OPEN_FILE;
}
//In case file opened for reading, get its size
if (bWrite == false)
{
GetFileSizeEx(m_hFileHandle, &m_FileSize);
}
// Save open mode
m_bAsync = bAsync;
m_bWrite = bWrite;
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::CloseFile()
{
//BOOL Status;
if (!CloseHandle(m_hFileHandle))
return ASYNCFILE_FAILED_TO_CLOSE_FILE;
if (!CloseHandle(m_hIoCompleted))
return ASYNCFILE_FAILED_TO_CLOSE_FILE;
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::StartAsyncRead(void* pBuffer,
DWORD dwReadSize,
bool* pbEof)
{
*pbEof = false; // By default, EOF is false
int iError;
if (m_hFileHandle == INVALID_HANDLE_VALUE)
return (false);
if (!ReadFile(m_hFileHandle,
pBuffer,
dwReadSize,
NULL, // actual bytes read is not valid now
&m_tOverlapped))
{
if ((iError = GetLastError()) == ERROR_HANDLE_EOF)
{
*pbEof = true;
return ASYNCFILE_OK;
}
else if (!(m_bAsync && (iError == ERROR_IO_PENDING)))
{
return ASYNCFILE_START_READ_FAILED;
}
}
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::WaitAsyncOperationEnd(DWORD* pdwActualBytesTransferred)
{
if (m_hFileHandle == INVALID_HANDLE_VALUE)
return ASYNCFILE_WAIT_FOR_COMPLETION_FAILED;
// Wait for read operation to complete
if (!GetOverlappedResult(m_hFileHandle,
&m_tOverlapped,
pdwActualBytesTransferred,
true))
return ASYNCFILE_WAIT_FOR_COMPLETION_FAILED;
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::StartAsyncWrite(void* pSrcBuf,
DWORD dwSize) // In bytes
{
int iError;
if (!WriteFile(m_hFileHandle,
pSrcBuf,
dwSize,
NULL, // actual bytes written is not valid now
&m_tOverlapped))
{
iError = GetLastError();
if (iError != ERROR_IO_PENDING)
return ASYNCFILE_START_WRITE_FAILED;
}
return ASYNCFILE_OK;
}
/****************************************************************************/
void CAsyncFile::SetFilePosition(UINT64 Position)
{
m_tOverlapped.Offset = Position & 0xFFFFFFFF;
m_tOverlapped.OffsetHigh = Position >> 32;
}
/****************************************************************************/
UINT64 CAsyncFile::GetFilePosition()
{
UINT64 Position;
Position = (m_tOverlapped.Offset) | ((UINT64)m_tOverlapped.OffsetHigh << 32);
return (Position);
}
/****************************************************************************/
UINT64 CAsyncFile::GetFileSize()
{
return (m_FileSize.QuadPart);
}
Well it depends on the average size of your files as well. If your file sizes are constantly ranging near 7 to 8 MB, then there would be some benefit in increasing the buffer size to 8192KB. How old is the drive? How often have you used it, many other factors come into play. We are able to learn more about this topic from an excellent piece of software called FastCopy. Hope this helps.
I writed a file system demo most likely fast fat ,but when I use CreateFileA to call my dirver ,it gives an INVALID_HANDLE_VALUE result . I have checked the driver `s IRP dispatches and found no DbgPrint setting in the function entries triggered .
This is the user mode code:
public IntPtr LoadDriver(string lpFileName)
{
int error = 0;
string openName = string.Format("\\\\.\\{0}", EXE_DRIVER_NAME);
IntPtr hSCManager = WinAPI.OpenSCManager(null, null,
WinAPI.SC_MANAGER_CREATE_SERVICE);
if (IntPtr.Zero != hSCManager)
{
//创建服务
IntPtr hService = WinAPI.CreateService(hSCManager, EXE_DRIVER_NAME,
DISPLAY_NAME, WinAPI.SERVICE_START,
WinAPI.SERVICE_KERNEL_DRIVER, WinAPI.SERVICE_DEMAND_START,
WinAPI.SERVICE_ERROR_IGNORE, lpFileName, null, IntPtr.Zero, null, null, null);
if (WinAPI.ERROR_SERVICE_EXISTS == WinAPI.GetLastError())
{
hService = WinAPI.OpenService(hSCManager, EXE_DRIVER_NAME, WinAPI.SERVICE_START);
}
error = WinAPI.GetLastError();
if(error!=0)
{
dumpErrorCode("OpenService失败 ", error);
}
int startflag = WinAPI.StartService(hService, 0, 0);
if (startflag == 0)
{
error = WinAPI.GetLastError();
if (error != WinAPI.ERROR_SERVICE_ALREADY_RUNNING) //已经启动
{
dumpErrorCode("StartService失败", error);
}
else
{
MessageBox.Show("服务已经启动");
}
}
// WinAPI.CloseServiceHandle(hService);
// WinAPI.CloseServiceHandle(hSCManager);
MessageBox.Show(openName);
try
{
hDriver = WinAPI.CreateFileA(openName, WinAPI.GENERIC_READ , 0, IntPtr.Zero, WinAPI.OPEN_EXISTING, null, IntPtr.Zero);
if (hDriver == (IntPtr)(-1))
{
dumpErrorCode("获取文件句柄失败 ", error);
}
else
{
MessageBox.Show("成功创建驱动");
//his.OpenDriverEvent();
}
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
}
return hDriver;
}
This is the driver`s entry point code:
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
NTSTATUS Status;
UNICODE_STRING UnicodeString;
FS_FILTER_CALLBACKS FilterCallbacks;
UNREFERENCED_PARAMETER( RegistryPath );
DbgPrint("\nThis is HRFS Driver Entry\n");
RtlInitUnicodeString(&UnicodeString, L"\\fastFatDemo");
gSFilterDriverObject = DriverObject;
Status = IoCreateDevice( DriverObject,
0,
&UnicodeString,
FILE_DEVICE_DISK_FILE_SYSTEM,
0,
FALSE,
&HrfsDiskFileSystemDeviceObject );
if (!NT_SUCCESS( Status )) {
return Status;
}
DbgPrint("HRFS device HRFS created\n ");
DriverObject->DriverUnload = FatUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)FatFsdCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)HrfsFsdClose;
DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)FatFsdRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)FatFsdWrite;
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)FatFsdQueryInformation;
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)FatFsdSetInformation;
DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = (PDRIVER_DISPATCH)FatFsdQueryEa;
DriverObject->MajorFunction[IRP_MJ_SET_EA] = (PDRIVER_DISPATCH)FatFsdSetEa;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = (PDRIVER_DISPATCH)FatFsdFlushBuffers;
DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)FatFsdQueryVolumeInformation;
DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)FatFsdSetVolumeInformation;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)FatFsdCleanup;
DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = (PDRIVER_DISPATCH)FatFsdDirectoryControl;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)FatFsdFileSystemControl;
DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = (PDRIVER_DISPATCH)FatFsdLockControl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)FatFsdDeviceControl;
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = (PDRIVER_DISPATCH)FatFsdShutdown;
DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)FatFsdPnp;
DbgPrint("HRFS device HRFS MajorFunction created\n ");
DriverObject->FastIoDispatch = NULL;
DbgPrint("HRFS device HRFS FatFastIoDispatch created\n ");
RtlZeroMemory(&FatFastIoDispatch, sizeof(FatFastIoDispatch));
FatFastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
FatFastIoDispatch.FastIoCheckIfPossible = FALSE; // CheckForFastIo
FatFastIoDispatch.FastIoRead = FALSE; // Read
FatFastIoDispatch.FastIoWrite = FALSE; // Write
FatFastIoDispatch.FastIoQueryBasicInfo = FALSE; // QueryBasicInfo
FatFastIoDispatch.FastIoQueryStandardInfo = FALSE; // QueryStandardInfo
FatFastIoDispatch.FastIoLock = FALSE; // Lock
FatFastIoDispatch.FastIoUnlockSingle = FALSE; // UnlockSingle
FatFastIoDispatch.FastIoUnlockAll = FALSE; // UnlockAll
FatFastIoDispatch.FastIoUnlockAllByKey = FALSE; // UnlockAllByKey
FatFastIoDispatch.FastIoQueryNetworkOpenInfo = FALSE;
FatFastIoDispatch.AcquireForCcFlush = FALSE;
FatFastIoDispatch.ReleaseForCcFlush = FALSE;
FatFastIoDispatch.MdlRead = FALSE;
FatFastIoDispatch.MdlReadComplete = FALSE;
FatFastIoDispatch.PrepareMdlWrite = FALSE;
FatFastIoDispatch.MdlWriteComplete = FALSE;
//FatFastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
//FatFastIoDispatch.FastIoCheckIfPossible = FatFastIoCheckIfPossible; // CheckForFastIo
//FatFastIoDispatch.FastIoRead = FsRtlCopyRead; // Read
//FatFastIoDispatch.FastIoWrite = FsRtlCopyWrite; // Write
//FatFastIoDispatch.FastIoQueryBasicInfo = FatFastQueryBasicInfo; // QueryBasicInfo
//FatFastIoDispatch.FastIoQueryStandardInfo = FatFastQueryStdInfo; // QueryStandardInfo
//FatFastIoDispatch.FastIoLock = FatFastLock; // Lock
//FatFastIoDispatch.FastIoUnlockSingle = FatFastUnlockSingle; // UnlockSingle
//FatFastIoDispatch.FastIoUnlockAll = FatFastUnlockAll; // UnlockAll
//FatFastIoDispatch.FastIoUnlockAllByKey = FatFastUnlockAllByKey; // UnlockAllByKey
//FatFastIoDispatch.FastIoQueryNetworkOpenInfo = FatFastQueryNetworkOpenInfo;
//FatFastIoDispatch.AcquireForCcFlush = HrfsAcquireForCcFlush;
//FatFastIoDispatch.ReleaseForCcFlush = HrfsReleaseForCcFlush;
//FatFastIoDispatch.MdlRead = FsRtlMdlReadDev;
//FatFastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev;
//FatFastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev;
//FatFastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev;
/* FsFilter通知回调例程在下层文件系统执行某些操作之前或之后调用。
如果需要获取更多有关于FsFilter回调例程相关信息,可参见FsRtlRegisterFileSystemFilterCallbacks例程
为了注册FsFilter的通知回调例程必须分配并初始化FS_FILTER_CALLBACKS结构体,然后向该结构体中促出FsFilter回调例程,
并将存储有Callbacks parameter到FsRtlRegisterFileSystemFilterCallbacks中。*/
RtlZeroMemory( &FilterCallbacks,
sizeof(FS_FILTER_CALLBACKS) );
FilterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS);
FilterCallbacks.PreAcquireForSectionSynchronization = HrfsFilterCallbackAcquireForCreateSection;
Status = FsRtlRegisterFileSystemFilterCallbacks( DriverObject,
&FilterCallbacks );
if (!NT_SUCCESS( Status )) {
IoDeleteDevice( HrfsDiskFileSystemDeviceObject );
return Status;
}
DbgPrint("HRFS device HRFS FilterCallbacks registed\n ");
RtlZeroMemory( &HrfsData, sizeof(FAT_DATA));
HrfsData.NodeTypeCode = HRFS_NTC_DATA_HEADER;
HrfsData.NodeByteSize = sizeof(FAT_DATA);
InitializeListHead(&HrfsData.VcbQueue);
pDriverObject = DriverObject;
HrfsData.DiskFileSystemDeviceObject = HrfsDiskFileSystemDeviceObject;
//
// This list head keeps track of closes yet to be done.
//
InitializeListHead( &HrfsData.AsyncCloseList );
InitializeListHead( &HrfsData.DelayedCloseList );
HrfsData.FatCloseItem = IoAllocateWorkItem( HrfsDiskFileSystemDeviceObject);
if (HrfsData.FatCloseItem == NULL) {
IoDeleteDevice (HrfsDiskFileSystemDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
DbgPrint("HRFS device HRFS workitem created\n ");
//
// Allocate the zero page
//
HrfsData.ZeroPage = ExAllocatePoolWithTag( NonPagedPoolNx, PAGE_SIZE, 'ZtaF' );
if (HrfsData.ZeroPage == NULL) {
IoDeleteDevice (HrfsDiskFileSystemDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory( HrfsData.ZeroPage, PAGE_SIZE );
//
// Now initialize our general purpose spinlock (gag) and figure out how
// deep and wide we want our delayed lists (along with fooling ourselves
// about the lookaside depths).
//
KeInitializeSpinLock( &HrfsData.GeneralSpinLock );
HrfsData.CacheManagerCallbacks.AcquireForLazyWrite = &HrfsAcquireFcbForLazyWrite;
HrfsData.CacheManagerCallbacks.ReleaseFromLazyWrite = &HrfsReleaseFcbFromLazyWrite;
HrfsData.CacheManagerCallbacks.AcquireForReadAhead = &HrfsAcquireFcbForReadAhead;
HrfsData.CacheManagerCallbacks.ReleaseFromReadAhead = &HrfsReleaseFcbFromReadAhead;
HrfsData.CacheManagerNoOpCallbacks.AcquireForLazyWrite = &HrfsNoOpAcquire;
HrfsData.CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = &HrfsNoOpRelease;
HrfsData.CacheManagerNoOpCallbacks.AcquireForReadAhead = &HrfsNoOpAcquire;
HrfsData.CacheManagerNoOpCallbacks.ReleaseFromReadAhead = &HrfsNoOpRelease;
//
// Set up global pointer to our process.
//
HrfsData.OurProcess = PsGetCurrentProcess();
DbgPrint("HRFS device HRFS our process getted\n ");
//
// Setup the number of processors we support for statistics as the current number
// running.
//
#if (NTDDI_VERSION >= NTDDI_VISTA)
HrfsData.NumberProcessors = KeQueryActiveProcessorCount( NULL );
#else
HrfsData.NumberProcessors = KeNumberProcessors;
#endif
DbgPrint("HrfsData.NumberProcessors :%d", HrfsData.NumberProcessors);
ExInitializeResourceLite( &HrfsData.Resource );
IoRegisterFileSystem(HrfsDiskFileSystemDeviceObject);
ObReferenceObject (HrfsDiskFileSystemDeviceObject);
DbgPrint("Device HRFS HrfsDiskFileSystemDeviceObject registed\n ");
return( STATUS_SUCCESS );
}
I've written a credential provider and a key storage provider to logon to windows via certificate. As the documentation in this points is quite vague I used different samples from Microsoft to get things working.
I think I'm nearly there, but the logon behaves unpredictably. Sometimes I get through to the kerberos server (which complains about the certificate), sometimes the process fails with 0x80090029 without any information and sometimes windows crashes. As these crashes all have to do with access violations or null pointers and happen to occur in various places (kerberos.dll, Windows.UI.Logon.dll, ...) I think it has something to do with my key structure that i point the given NCRYT_KEY_HANDLE to in my OpenKey-implementation.
The KeyStorageProviderSample in the CNG-Kit has an example, but relies on a RSA-key stored in %AppData%. I don't have the private key available as it is stored in secure hardware, I just have the public part (i.e. the public certificate), that I read from another device and import via the following code:
SECURITY_STATUS WINAPI KeyHandler::ReadPemCert(__inout KSP_KEY *keyHandle)
{
LOG_FUNCTION;
CERT_CONTEXT certContext = {};
DWORD readLength = 0;
LOG("Fetch certificate");
const int maxSizeInBytes = 4096;
char pemCertificateAsBytes[maxSizeInBytes];
BluetoothClient bluetoothClient = BluetoothClient();
bluetoothClient.getCertificate((PBYTE)pemCertificateAsBytes, readLength);
DWORD certAsDerLen = readLength;
BYTE* certAsDer = new BYTE[certAsDerLen];
LOG("convert PEM to DER");
if (!CryptStringToBinaryA(pemCertificateAsBytes, 0, CRYPT_STRING_BASE64, certAsDer, &certAsDerLen, NULL, NULL))
{
LOG_LAST_ERROR("CryptStringToBinary failed. Err:");
}
LOG_BYTES_AS_HEX("DER-Zertifikat", certAsDer, certAsDerLen);
PCCERT_CONTEXT pcCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, certAsDer, certAsDerLen);
certContext->pCertInfo = pcCertContext->pCertInfo;
certContext->cbCertEncoded = pcCertContext->cbCertEncoded;
certContext->pbCertEncoded = pcCertContext->pbCertEncoded;
certContext->dwCertEncodingType = pcCertContext->dwCertEncodingType;
CERT_INFO *certInfo;
certInfo = certContext.pCertInfo;
CERT_PUBLIC_KEY_INFO pubKeyInfo = certInfo->SubjectPublicKeyInfo;
LOG("Aquire cryptocontext");
HCRYPTPROV hProv = 0;
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
{
LOG_LAST_ERROR("CryptAcquireContext failed. Err:");
return -1;
}
}
LOG("Importing public key");
NCRYPT_KEY_HANDLE publicKeyHandle = NULL;
if (!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING, &pubKeyInfo, &publicKeyHandle))
{
LOG_LAST_ERROR("CryptImportPublicKeyInfo failed. Err:");
return -1;
}
keyHandle->fFinished = TRUE;
keyHandle->hPublicKey = (BCRYPT_KEY_HANDLE)publicKeyHandle;
keyHandle->pszKeyBlobType = BCRYPT_RSAPUBLIC_BLOB;
LocalFree(certInfo);
return ERROR_SUCCESS;
}
The key structure is initialized this way:
SECURITY_STATUS
WINAPI
KeyHandler::CreateNewKeyObject(
__in_opt LPCWSTR pszKeyName,
__deref_out KSP_KEY **ppKey)
{
LOG_FUNCTION;
KSP_KEY *pKey = NULL;
DWORD cbKeyName = 0;
SECURITY_STATUS Status = NTE_INTERNAL_ERROR;
NTSTATUS ntStatus = STATUS_INTERNAL_ERROR;
pKey = (KSP_KEY *)HeapAlloc(GetProcessHeap(), 0, sizeof(KSP_KEY));
if (pKey == NULL)
{
return NTE_NO_MEMORY;
}
pKey->cbLength = sizeof(KSP_KEY);
pKey->dwMagic = KSP_KEY_MAGIC;
pKey->dwAlgID = KSP_RSA_ALGID;
pKey->pszKeyFilePath = NULL;
pKey->pszKeyBlobType = NULL;
pKey->dwKeyBitLength = 0;
pKey->fFinished = FALSE;
//Copy the keyname into the key struct.
if (pszKeyName != NULL)
{
cbKeyName = (DWORD)(wcslen(pszKeyName) + 1) * sizeof(WCHAR);
pKey->pszKeyName = (LPWSTR)HeapAlloc(
GetProcessHeap(),
0,
cbKeyName + sizeof(WCHAR));
if (pKey->pszKeyName == NULL)
{
return NTE_NO_MEMORY;
}
CopyMemory(pKey->pszKeyName, pszKeyName, cbKeyName);
pKey->pszKeyName[cbKeyName / sizeof(WCHAR)] = L'\0';
}
else
{
pKey->pszKeyName = NULL;
}
if (globalRSAProviderHandle == NULL)
{
ntStatus = BCryptOpenAlgorithmProvider(
&globalRSAProviderHandle,
BCRYPT_RSA_ALGORITHM,
NULL,
0);
if (!NT_SUCCESS(ntStatus))
{
return NormalizeNteStatus(ntStatus);
}
}
pKey->hProvider = globalRSAProviderHandle;
pKey->pbKeyFile = NULL;
pKey->cbKeyFile = 0;
pKey->pbPrivateKey = NULL;
pKey->cbPrivateKey = 0;
pKey->hPublicKey = NULL;
pKey->hPrivateKey = NULL;
pKey->dwExportPolicy = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
pKey->dwKeyUsagePolicy = NCRYPT_ALLOW_DECRYPT_FLAG | NCRYPT_ALLOW_SIGNING_FLAG;
pKey->pbSecurityDescr = NULL;
pKey->cbSecurityDescr = 0;
InitializeListHead(&pKey->PropertyList);
*ppKey = pKey;
pKey = NULL;
return ERROR_SUCCESS;
}
Somewhere in there must be the mistake leading to the various memory errors. But as I'm quite new to windows programming and c/c++ I just can't spot the point and can't find any documentation about the datastructure that windows expects for the NCRYTP_KEY_HANDLE.
Does anybody know more about this structure?
NCRYPT_KEY_HANDLE is just a pointer to a structure that you defined.
Windows itself doesn't care about this structure and expect that your provider knows how to work with it.
In KeyHandler::ReadPemCert you mixed legacy CryptoAPI and CNG API. Since you are implementing KSP you should use only CNG API (CryptImportPublicKeyInfoEx2).
DWORD error = NTE_FAIL;
BCRYPT_KEY_HANDLE hKey = NULL;
...
PCCERT_CONTEXT pcCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, certAsDer, certAsDerLen);
if(!pcCertContext)
{
goto Exit;
}
if (!CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, &pcCertContext->pCertInfo->SubjectPublicKeyInfo, 0, nullptr, &hKey))
{
goto Exit;
}
/* Also you can export key and print out the result to make sure everything works
DWORD temp = 0;
status = BCryptExportKey(hKey, 0, BCRYPT_RSAPUBLIC_BLOB, nullptr, 0, &temp, 0);
if (status != ERROR_SUCCESS)
{
goto Exit;
}
std::vector<BYTE> key(temp);
status = BCryptExportKey(hKey, 0, BCRYPT_RSAPUBLIC_BLOB, key.data(), key.size(), &temp, 0);
if (status != ERROR_SUCCESS)
{
goto Exit;
}
for (auto const& i : key)
{
std::cout << std::hex << (int)i;
}
}
*/
keyHandle->fFinished = TRUE;
keyHandle->hPublicKey = hKey;
keyHandle->pszKeyBlobType = BCRYPT_RSAPUBLIC_BLOB;
erro = ERROR_SUCCESS;
Exit:
if(pcCertContext)
{
CertFreeCertificateContext(pcCertContext);
}
return error;
I'm trying to read the current volume level.
I moved from the waveOut* functions to the mixer* functions.
If I run the application under Windows XP the value are aligned with the system volume level.
If I run under Win8.1 and Win10 I always receive 0xFFFF.
My code is:
TCHAR msg[100];
g_uNumDevs = mixerGetNumDevs();
wsprintf( msg, L"N. mixer: %d", g_uNumDevs);
pInfo->Log(msg);
if (g_uNumDevs)
{
UINT i = 0;
while(i < g_uNumDevs)
{
MMRESULT mmRes = mixerOpen(&hMixer, i, 0, 0, MIXER_OBJECTF_MIXER);
if (mmRes != MMSYSERR_NOERROR)
{
wsprintf( msg, L"Errore openMixer i:%d err:%d", i, mmRes);
pInfo->Log(msg);
}
// Master line
MIXERLINE ml = {0};
ml.cbStruct = sizeof(MIXERLINE);
ml.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; // Volume master
mmRes = mixerGetLineInfo((HMIXEROBJ) hMixer, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE);
pInfo->Log( ml.szName);
if (mmRes != MMSYSERR_NOERROR)
{
wsprintf( msg, L"Errore mixerGetLineInfo err:%d", mmRes);
pInfo->Log(msg);
mixerClose(hMixer);
return FALSE;
}
// get the volume control of the speaker line.
MIXERLINECONTROLS mlc = {0};
MIXERCONTROL mc = {0};
mlc.cbStruct = sizeof(MIXERLINECONTROLS);
mlc.dwLineID = ml.dwLineID;
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mlc.cControls = 1;
mlc.pamxctrl = &mc;
mlc.cbmxctrl = sizeof(MIXERCONTROL);
mmRes = mixerGetLineControls((HMIXEROBJ) hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmRes != MMSYSERR_NOERROR)
{
wsprintf( msg, L"Errore mixerGetLineControls err:%d", mmRes);
pInfo->Log(msg);
EnableWindow( g_hwndSlider, FALSE);
EnableWindow( g_hwndVerifBtn, FALSE);
}
else {
// GetVolume level
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = mc.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails = &mxcdVolume;
mmRes = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(hMixer),
&mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE);
if (mmRes != MMSYSERR_NOERROR)
{
EnableWindow( g_hwndSlider, FALSE);
EnableWindow( g_hwndVerifBtn, FALSE);
//return FALSE;
}
else {
DWORD dwVol = mxcdVolume.dwValue;
dwVol &= 0xFFFF;
DWORD perc = dwVol * 100 / 0xFFFF;
SendMessage( g_hwndSlider, TBM_SETPOS, 1, perc);
wsprintf( msg, L"Volume = %d %% [%d]", perc, dwVol);
pInfo->Log(msg);
}
}
mixerClose(hMixer);
++i;
} // while
}
else {
pInfo->Log(L"No audio device !!");
return FALSE;
}
As a part of encoding decoded audio packets, I'm using avcodec_fill_audio_frame(). I'm passing allocated AVFrame pointer to along with buffer containing the decoded samples and other parameters number of channels, sample format, buffer size. Though the encoding is working fine I'm not able to completely eliminate the memory leaks. I've taken care of most of things but still I'm not able detect the leakage.
Below is the function which I'm using for encoding. Please suggest something.
AudioSample contains decoded data and it is completely managed in different class(free in class destructor). I'm freeing the AVFrame in FFmpegEncoder destructor and AVPacket is freed every time using av_free_packet() with av_packet_destruct enabled. What more do I need to free?
void FfmpegEncoder::WriteAudioSample(AudioSample *audS)
{
int num_audio_frame = 0;
AVCodecContext *c = NULL;
// AVFrame *frame;
AVPacket pkt;
av_init_packet(&pkt);
pkt.destruct = av_destruct_packet;
pkt.data = NULL;
pkt.size = 0;
int ret = 0, got_packet = 0;
c = m_out_aud_strm->codec;
static int64_t aud_pts_in = -1;
if((audS != NULL) && (audS->GetSampleLength() > 0) )
{
int byte_per_sample = av_get_bytes_per_sample(c->sample_fmt);
PRINT_VAL("Byte Per Sample ", byte_per_sample)
m_frame->nb_samples = (audS->GetSampleLength())/(c->channels*av_get_bytes_per_sample(c->sample_fmt));
if(m_frame->nb_samples == c->frame_size)
{
#if 1
if(m_need_resample && (c->channels >= 2))
{
uint8_t * t_buff1 = new uint8_t[audS->GetSampleLength()];
if(t_buff1 != NULL)
{
for(int64_t i = 0; i< m_frame->nb_samples; i++)
{
memcpy(t_buff1 + i*byte_per_sample, (uint8_t*)((uint8_t*)audS->GetAudioSampleData() + i*byte_per_sample*c->channels), byte_per_sample);
memcpy(t_buff1 + (audS->GetSampleLength())/2 + i*byte_per_sample, (uint8_t*)((uint8_t*)audS->GetAudioSampleData() + i*byte_per_sample*c->channels+ byte_per_sample), byte_per_sample);
}
audS->FillAudioSample(t_buff1, audS->GetSampleLength());
delete[] t_buff1;
}
}
#endif
ret = avcodec_fill_audio_frame(m_frame, c->channels, c->sample_fmt, (uint8_t*)audS->GetAudioSampleData(),m_frame->nb_samples*byte_per_sample*c->channels, 0);
//ret = avcodec_fill_audio_frame(&frame, c->channels, c->sample_fmt, t_buff,frame.nb_samples*byte_per_sample*c->channels, 0);
if(ret != 0)
{
PRINT_MSG("Avcodec Fill Audio Failed ")
}
else
{
got_packet = 0;
ret = avcodec_encode_audio2(c, &pkt, m_frame, &got_packet);
if(ret < 0 || got_packet == 0)
{
PRINT_MSG("failed to encode audio ")
}
else
{
PRINT_MSG("Audio Packet Encoded ");
aud_pts_in++;
pkt.pts = aud_pts_in;
pkt.dts = pkt.pts;
pkt.stream_index = m_out_aud_strm->index;
ret = av_interleaved_write_frame(oc, &pkt);
if(ret != 0)
{
PRINT_MSG("Error Write Audio PKT ")
}
else
{
PRINT_MSG("Audio PKT Writen ")
}
}
}
}
avcodec_flush_buffers(c);
// avcodec_free_frame(&frame);
}
av_free_packet(&pkt);
}
Thanks,
Pradeep
//================== SEND AUDIO OUTPUT =======================
void AVOutputStream::sendAudioOutput (AVFrame* inputFrame)
{
AVCodecContext *codecCtx = pOutputAudioStream->codec;
// set source data variables
sourceNumberOfChannels = inputFrame->channels;
sourceChannelLayout = inputFrame->channel_layout;
sourceSampleRate = inputFrame->sample_rate;
_sourceSampleFormat = (AVSampleFormat)inputFrame->format;
sourceNumberOfSamples = inputFrame->nb_samples;
// set destination data variables
destinationNumberOfChannels = codecCtx->channels;
destinationChannelLayout = codecCtx->channel_layout;
destinationSampleRate = codecCtx->sample_rate;
destinationSampleFormat = codecCtx->sample_fmt;//AV_SAMPLE_FMT_FLTP;//EncodecCtx->sample_fmt;
destinationLineSize = 0;
destinationData = NULL;
int returnVal = 0;
if (startDecode == false)
{
startDecode = true;
resamplerCtx = swr_alloc_set_opts(NULL,
destinationChannelLayout,
destinationSampleFormat,
destinationSampleRate,
sourceChannelLayout,
_sourceSampleFormat,
sourceSampleRate,
0,
NULL);
if (resamplerCtx == NULL)
{
std::cout << "Unable to create the resampler context for the audio frame";
isConnected = false;
}
// initialize the resampling context
returnVal = swr_init(resamplerCtx);
if (returnVal < 0)
{
std::cout << "Unable to init the resampler context, error:";
isConnected = false;
}
} //if (startDecode == false)
if (sourceSampleRate != 0)
destinationNumberOfSamples = destinationSampleRate/sourceSampleRate * sourceNumberOfSamples;
// allocate the destination samples buffer
returnVal = av_samples_alloc_array_and_samples(&destinationData,
&destinationLineSize,
destinationNumberOfChannels,
destinationNumberOfSamples,
destinationSampleFormat,
0);
if (returnVal < 0)
{
std::cout << "Unable to allocate destination samples, error";
isConnected = false;
}
// convert to destination format
returnVal = swr_convert(resamplerCtx,
destinationData,
destinationNumberOfSamples,
(const uint8_t **)inputFrame->data, //sourceData,
sourceNumberOfSamples);
if (returnVal < 0)
{
std::cout << "Resampling failed, error \n";
isConnected = false;
}
int bufferSize = av_samples_get_buffer_size(&destinationLineSize,
destinationNumberOfChannels,
destinationNumberOfSamples,
destinationSampleFormat,
0);
//whithout fifo
pOutputAudioFrame = av_frame_alloc();
pOutputAudioFrame->nb_samples = codecCtx->frame_size;//frameNumberOfSamples;
pOutputAudioFrame->format = codecCtx->sample_fmt;
pOutputAudioFrame->channel_layout = codecCtx->channel_layout;
pOutputAudioFrame->channels = codecCtx->channels;
pOutputAudioFrame->sample_rate = codecCtx->sample_rate;
returnVal = avcodec_fill_audio_frame(pOutputAudioFrame,
pOutputAudioFrame->channels,
(AVSampleFormat)pOutputAudioFrame->format,
(const uint8_t *)destinationData[0],
bufferSize,0);
pOutputAudioFrame->pts = inputFrame->pts;
if (returnVal < 0)
{
std::cout << "Unable to fill the audio frame wsampleIndexith captured audio data,error";
isConnected = false;
}
// encode the audio frame, fill a packet for streaming
av_init_packet(&outAudioPacket);
outAudioPacket.data = NULL;
outAudioPacket.size = 0;
outAudioPacket.dts = outAudioPacket.pts = 0;
int gotPacket;
// encoding
returnVal = avcodec_encode_audio2(codecCtx, &outAudioPacket, pOutputAudioFrame, &gotPacket);
// free buffers
av_freep(&destinationData[0]);
av_freep(&destinationData);
av_frame_free(&pOutputAudioFrame);
if (gotPacket)
{
outAudioPacket.stream_index = pOutputAudioStream->index;
outAudioPacket.flags |= AV_PKT_FLAG_KEY;
returnVal = av_interleaved_write_frame(pOutputFormatCtx, &outAudioPacket);
//returnVal = av_write_frame(pOutputFormatCtx, &outAudioPacket);
if (returnVal != 0)
{
std::cout << "Cannot write audio packet \n";
isConnected = false;
}
av_free_packet(&outAudioPacket);
} // if (gotPacket)
}
You can see after resample i free used buffers.
// free buffers
av_freep(&destinationData[0]);
av_freep(&destinationData);