PSTORAGE_DESCRIPTOR_HEADER pStorageQueryProperty( HANDLE hDevice, STORAGE_PROPERTY_ID PropertyId, STORAGE_QUERY_TYPE QueryType) { STORAGE_PROPERTY_QUERY spquery; ::ZeroMemory(&spquery, sizeof(spquery)); spquery.PropertyId = PropertyId; spquery.QueryType = QueryType; DWORD bufferLength = sizeof(STORAGE_DESCRIPTOR_HEADER); XTL::AutoProcessHeapPtr<STORAGE_DESCRIPTOR_HEADER> buffer = static_cast<STORAGE_DESCRIPTOR_HEADER*>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, bufferLength)); if (buffer.IsInvalid()) { return NULL; } DWORD returnedLength; BOOL fSuccess = ::DeviceIoControl( hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &spquery, sizeof(spquery), buffer, bufferLength, &returnedLength, NULL); if (!fSuccess) { XTLTRACE_ERR("IOCTL_STORAGE_QUERY_PROPERTY(HEADER) failed.\n"); return NULL; } // We only retrived the header, now we reallocate the buffer // required for the actual query bufferLength = buffer->Size; XTL::AutoProcessHeapPtr<STORAGE_DESCRIPTOR_HEADER> newBuffer = static_cast<STORAGE_DESCRIPTOR_HEADER*>( ::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, bufferLength)); if (newBuffer.IsInvalid()) { return NULL; } // set the buffer with the new buffer buffer.Detach(); buffer = newBuffer.Detach(); // now we can query the actual property with the proper size fSuccess = ::DeviceIoControl( hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &spquery, sizeof(spquery), buffer, bufferLength, &returnedLength, NULL); if (!fSuccess) { XTLTRACE_ERR("IOCTL_STORAGE_QUERY_PROPERTY(DATA) failed.\n"); return NULL; } return buffer.Detach(); }
DWORD CNdasCommandServer:: ThreadStart(LPVOID lpParam) { HANDLE hStopEvent = static_cast<HANDLE>(lpParam); CmdWorkItemVector workItems; workItems.reserve(MaxPipeInstances); size_t size = workItems.size(); XTLASSERT(0 == size); std::generate_n( std::back_inserter(workItems), MaxPipeInstances, pWorkItemPtrGenerator); size = workItems.size(); XTLASSERT(MaxPipeInstances == size); DWORD nWorkItems = 0; for (DWORD i = 0; i < MaxPipeInstances; ++i) { CmdWorkItemPtr p = workItems[i]; BOOL fSuccess = p->QueueUserWorkItemEx( this, &CNdasCommandServer::CommandProcessStart, hStopEvent, WT_EXECUTELONGFUNCTION); if (fSuccess) { ++nWorkItems; } else { XTLTRACE_ERR("Starting work item (%d/%d) failed.\n", i + 1, MaxPipeInstances); } } // Release semaphore to start workers (semaphore increment) LONG prev; XTLVERIFY( ::ReleaseSemaphore(m_hProcSemaphore, nWorkItems, &prev) ); XTLASSERT( 0 == prev ); // Wait for stop event XTLVERIFY(WAIT_OBJECT_0 == ::WaitForSingleObject(hStopEvent, INFINITE)); // Stopped and waits for user work items DWORD finished = 0; while (finished < nWorkItems) { ::Sleep(0); DWORD waitResult = ::WaitForSingleObject(m_hProcSemaphore, 0); if (waitResult == WAIT_OBJECT_0) { XTLTRACE("Command Process work item finished (%d/%d).\n", finished + 1, nWorkItems); ++finished; } XTLVERIFY(WAIT_OBJECT_0 == waitResult || WAIT_TIMEOUT == waitResult); } // Now Finally this thread can stop return 0; }
DWORD CNdasCommandServer::ServiceCommand(HANDLE hStopEvent) { // Named Pipe Connection Event XTL::AutoObjectHandle hConnectEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); if (hConnectEvent.IsInvalid()) { // Log Error Here XTLTRACE_ERR("Creating ndascmd connection event failed.\n"); return 1; } // Create a named pipe instance XTL::AutoFileHandle hPipe = ::CreateNamedPipe( PipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, MaxPipeInstances, 0, 0, PipeTimeout, NULL); if (hPipe.IsInvalid()) { // Log Error Here XTLTRACE_ERR("Creating pipe server failed.\n"); return 2; } HANDLE waitHandles[] = { hStopEvent, hConnectEvent }; const DWORD nWaitHandles = RTL_NUMBER_OF(waitHandles); while (TRUE) { // Initialize overlapped structure OVERLAPPED overlapped = {0}; overlapped.hEvent = hConnectEvent; XTLVERIFY( ::ResetEvent(hConnectEvent) ); CNamedPipeTransport namePipeTransport(hPipe); CNamedPipeTransport* pTransport = &namePipeTransport; BOOL fSuccess = pTransport->Accept(&overlapped); if (!fSuccess) { XTLTRACE_ERR("Transport Accept (Named Pipe) failed.\n"); break; } DWORD waitResult = ::WaitForMultipleObjects( nWaitHandles, waitHandles, FALSE, INFINITE); switch (waitResult) { case WAIT_OBJECT_0: // Terminate Thread Event return 0; case WAIT_OBJECT_0 + 1: // Connect Event // // Process the request // (Safely ignore error) // { CNdasCommandProcessor processor(m_service, pTransport); if (!processor.Process()) { XTLTRACE_ERR("CommandProcess failed.\n"); } // After processing the request, reset the pipe instance XTLVERIFY( ::FlushFileBuffers(hPipe) ); XTLVERIFY( ::DisconnectNamedPipe(hPipe) ); } break; default: XTLTRACE_ERR("Wait failed.\n"); XTLASSERT(FALSE); } } return 0; }