DWORD
ScannerWorker(
__in PSCANNER_THREAD_CONTEXT Context
)
/*++
Routine Description
This is a worker thread that
Arguments
Context - This thread context has a pointer to the port
handle we use to send/receive messages,
and a completion port
handle that was already associated with the comm. port by the caller
Return Value
HRESULT indicating the status of thread exit.
--*/
{
PSCANNER_NOTIFICATION notification;
SCANNER_REPLY_MESSAGE replyMessage;
PSCANNER_MESSAGE message;
LPOVERLAPPED pOvlp;
BOOL result;
DWORD outSize;
HRESULT hr;
ULONG_PTR key;
while (TRUE) {
//
// Poll for messages from the filter component to scan.
//
result = GetQueuedCompletionStatus( Context->Completion, &outSize, &key, &pOvlp, INFINITE );
//
// Obtain the message: note that the message we sent down via FltGetMessage() may NOT be
// the one dequeued off the completion queue: this is solely because there are multiple
// threads per single port
handle. Any of the FilterGetMessage() issued messages can be
// completed in random order - and we will just dequeue a random one.
//
message = CONTAINING_RECORD( pOvlp, SCANNER_MESSAGE, Ovlp );
if (!result) {
//
// An error occured.
//
hr = HRESULT_FROM_WIN32( GetLastError() );
break;
}
printf( "Received message, size %d\n", pOvlp->InternalHigh );
notification = &message->Notification;
assert(notification->BytesToScan <= SCANNER_READ_BUFFER_SIZE);
__analysis_assume(notification->BytesToScan <= SCANNER_READ_BUFFER_SIZE);
result = ScanBuffer( notification->Contents, notification->BytesToScan );
replyMessage.ReplyHeader.Status = 0;
replyMessage.ReplyHeader.MessageId = message->MessageHeader.MessageId;
//
// Need to invert the boolean -- result is true if found
// foul language, in which case SafeToOpen should be set to false.
//
replyMessage.Reply.SafeToOpen = !result;
printf( "Replying message, SafeToOpen: %d\n", replyMessage.Reply.SafeToOpen );
hr = FilterReplyMessage( Context->Port,
(PFILTER_REPLY_HEADER) &replyMessage,
sizeof( replyMessage ) );
if (SUCCEEDED( hr )) {
printf( "Replied message\n" );
} else {
printf( "Scanner: Error replying message. Error = 0x%X\n", hr );
break;
}
memset( &message->Ovlp, 0, sizeof( OVERLAPPED ) );
hr = FilterGetMessage( Context->Port,
&message->MessageHeader,
FIELD_OFFSET( SCANNER_MESSAGE, Ovlp ),
&message->Ovlp );
if (hr != HRESULT_FROM_WIN32( ERROR_IO_PENDING )) {
break;
}
}
if (!SUCCEEDED( hr )) {
if (hr == HRESULT_FROM_WIN32( ERROR_INVALID_HANDLE )) {
//
// Scanner port disconncted.
//
printf( "Scanner: Port is disconnected, probably due to scanner filter unloading.\n" );
} else {
printf( "Scanner: Unknown error occured. Error = 0x%X\n", hr );
}
}
free( message );
return hr;
}
int _cdecl
main (
__in int argc,
__in_ecount(argc) char *argv[]
)
{
DWORD requestCount = SCANNER_DEFAULT_REQUEST_COUNT;
DWORD threadCount = SCANNER_DEFAULT_THREAD_COUNT;
HANDLE threads[SCANNER_MAX_THREAD_COUNT];
SCANNER_THREAD_CONTEXT context;
HANDLE port, completion;
PSCANNER_MESSAGE msg;
DWORD threadId;
DWORD retVal = 0;
HRESULT hr;
DWORD i, j;
//
// Check how many threads and per thread requests are desired.
//
if (argc > 1) {
requestCount = atoi( argv[1] );
if (argc > 2) {
threadCount = atoi( argv[2] );
}
if (requestCount <= 0 || threadCount <= 0 || threadCount > 64) {
Usage();
return 1;
}
}
//
// Open a commuication channel to the filter
//
printf( "Scanner: Connecting to the filter ...\n" );
hr = FilterConnectCommunicationPort( ScannerPortName,
0,
NULL,
0,
NULL,
&port );
if (IS_ERROR( hr )) {
printf( "ERROR: Connecting to filter port: 0x%08x\n", hr );
return 2;
}
//
// Create a completion port to associate with this
handle.
//
completion = CreateIoCompletionPort( port,
NULL,
0,
threadCount );
if (completion == NULL) {
printf( "ERROR: Creating completion port: %d\n", GetLastError() );
CloseHandle( port );
return 3;
}
printf( "Scanner: Port = 0x%p Completion = 0x%p\n", port, completion );
context.Port = port;
context.Completion = completion;
//
// Create specified number of threads.
//
for (i = 0; i < threadCount; i++) {
threads[i] = CreateThread( NULL,
0,
ScannerWorker,
&context,
0,
&threadId );
if (threads[i] == NULL) {
//
// Couldn't create thread.
//
hr = GetLastError();
printf( "ERROR: Couldn't create thread: %d\n", hr );
goto main_cleanup;
}
for (j = 0; j < requestCount; j++) {
//
// Allocate the message.
//
msg = malloc( sizeof( SCANNER_MESSAGE ) );
if (msg == NULL) {
hr = ERROR_NOT_ENOUGH_MEMORY;
goto main_cleanup;
}
memset( &msg->Ovlp, 0, sizeof( OVERLAPPED ) );
//
// Request messages from the filter driver.
//
hr = FilterGetMessage( port,
&msg->MessageHeader,
FIELD_OFFSET( SCANNER_MESSAGE, Ovlp ),
&msg->Ovlp );
if (hr != HRESULT_FROM_WIN32( ERROR_IO_PENDING )) {
free( msg );
goto main_cleanup;
}
}
}
hr = S_OK;
WaitForMultipleObjects( i, threads, TRUE, INFINITE );
main_cleanup:
printf( "Scanner: All done. Result = 0x%08x\n", hr );
CloseHandle( port );
CloseHandle( completion );
return hr;