diff options
Diffstat (limited to 'pofx/WDF/App')
| -rw-r--r-- | pofx/WDF/App/PowerFxApp.cpp | 592 | ||||
| -rw-r--r-- | pofx/WDF/App/PowerFxApp.vcxproj | 192 | ||||
| -rw-r--r-- | pofx/WDF/App/PowerFxApp.vcxproj.Filters | 25 | ||||
| -rw-r--r-- | pofx/WDF/App/UserInput.cpp | 201 | ||||
| -rw-r--r-- | pofx/WDF/App/include.h | 95 |
5 files changed, 1105 insertions, 0 deletions
diff --git a/pofx/WDF/App/PowerFxApp.cpp b/pofx/WDF/App/PowerFxApp.cpp new file mode 100644 index 00000000..c628d366 --- /dev/null +++ b/pofx/WDF/App/PowerFxApp.cpp @@ -0,0 +1,592 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + PowerFxApp.cpp + +Abstract: + + This application can be used to exercise KMDF sample drivers for the + new power framework. See application "usage" details for more information. + +Environment: + + user mode only + +--*/ + +#include "include.h" + +int __cdecl +wmain( + _In_ int argc, + _In_reads_(argc) PWSTR argv[] + ) +{ + DWORD err; + WCHAR devicePath[MAX_DEVPATH_LENGTH] = {UNICODE_NULL}; + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE hCompletionPort = NULL; + + + // + // Process user input. + // + err = ProcessUserInput(argc, argv); + if (ERROR_SUCCESS != err) + { + goto clean0; + } + + if ( !GetDevicePath( + (LPGUID) &GUID_DEVINTERFACE_POWERFX, + devicePath, + COUNT_OF(devicePath))) + { + printf("Unable to get device path. Has the device driver been installed? \n"); + err = ERROR_OPEN_FAILED; + goto clean0; + } + + hDevice = CreateFile(devicePath, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL ); + + if (hDevice == INVALID_HANDLE_VALUE) { + err = GetLastError(); + printf("Failed to open device. Error %d.\n",err); + goto clean0; + } + + hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0); + if (hCompletionPort == NULL) { + err = GetLastError(); + printf("Cannot open completion port %d.\n",err); + goto clean0; + } + + err = SendIO(hDevice, + hCompletionPort, + GetSetting(COMPONENT), + GetSetting(MAX_OUTSTANDING_IO), + GetSetting(DELAY), + (BOOLEAN)GetSetting(CANCEL)); + if (ERROR_SUCCESS != err) + { + goto clean0; + } + +clean0: + if (INVALID_HANDLE_VALUE != hDevice) + { + CloseHandle(hDevice); + } + if (NULL != hCompletionPort) + { + CloseHandle(hCompletionPort); + } + return err; +} + +DWORD Initialize( + _In_ ULONG Count, + _Out_ LPOVERLAPPED *pOverlappedPtr, + _Out_ PPOWERFX_READ_COMPONENT_INPUT *pInput, + _Out_ PPOWERFX_READ_COMPONENT_OUTPUT *pOutput + ) +{ + PPOWERFX_READ_COMPONENT_INPUT inputBuffer = NULL; + PPOWERFX_READ_COMPONENT_OUTPUT outputBuffer = NULL; + LPOVERLAPPED pOverlapped = NULL; + DWORD err = ERROR_SUCCESS; + + pOverlapped = new OVERLAPPED[Count]; + if (NULL == pOverlapped) + { + err = ERROR_OUTOFMEMORY; + goto clean0; + } + + inputBuffer = new POWERFX_READ_COMPONENT_INPUT[Count]; + if (NULL == inputBuffer) + { + err = ERROR_OUTOFMEMORY; + goto clean0; + } + + outputBuffer = new POWERFX_READ_COMPONENT_OUTPUT[Count]; + if (NULL == outputBuffer) + { + err = ERROR_OUTOFMEMORY; + goto clean0; + } + + ZeroMemory(pOverlapped, + sizeof(OVERLAPPED)*Count); + + for (UINT i = 0; i < Count; i++) + { + // + // When the component number is set to UNUSED it indicates + // that a request has not been issued (or has completed) + // using this input buffer. Hence the buffer along with the + // overlapped structure at the corresponding index is available + // for issuing a request. + // + inputBuffer[i].ComponentNumber = UNUSED; + } + + ZeroMemory(outputBuffer, + sizeof(POWERFX_READ_COMPONENT_OUTPUT)*Count); + +clean0: + if (err != ERROR_SUCCESS) + { + delete[] pOverlapped; + delete[] inputBuffer; + delete[] outputBuffer; + } + else + { + *pOverlappedPtr = pOverlapped; + *pInput = inputBuffer; + *pOutput = outputBuffer; + } + return err; +} + +/*++ + +Routine Description: + + This function sends requests to the driver based on the settings passed + in the arguments. The requests are sent indefinitely until an error occurs. + + Depending on the number of maximum outstanding I/O requests, + an array of overlapped structures and input/output buffers is allocated. + The method then loops through the overlapped structure array + to issue asynchronous requests. When a request completes, the + overlapped structure for that request is not immediately re-used to issue + a new request. Instead the method goes in-order through the array to + ensure that each issued request is completed in a reasonable amount + of time and it is able to detect if one or more requests do not complete + at all (or within the specified timeout). + +--*/ +DWORD SendIO( + _In_ HANDLE DeviceHandle, + _In_ HANDLE CompletionPortHandle, + _In_ ULONG Component, + _In_ ULONG MaxOutstandingIo, + _In_ ULONG Delay, + _In_ BOOLEAN Cancel + ) +{ + LPOVERLAPPED pOverlapped = NULL; + LPOVERLAPPED pOv = NULL; + PPOWERFX_READ_COMPONENT_INPUT inputBuffer = NULL; + PPOWERFX_READ_COMPONENT_OUTPUT outputBuffer = NULL; + DWORD err = ERROR_SUCCESS; + UINT outstandingIoCount = 0; + UINT index = 0; + + srand((DWORD)GetTickCount64()); + + err = Initialize(MaxOutstandingIo, + &pOverlapped, + &inputBuffer, + &outputBuffer); + if (ERROR_SUCCESS != err) + { + goto clean0; + } + + UINT k = 0; + + for (;;k++) + { + k = k % MaxOutstandingIo; + + if (UNUSED == inputBuffer[k].ComponentNumber) + { + // + // This indicates the input buffer and corresponding overlapped + // structure is available to issue a new request. + // + pOv = &pOverlapped[k]; + } + else + { + // + // Wait for request #k to complete. + // + DWORD completionStatus; + ULONGLONG startTime = GetTickCount64(); + + for(;;) + { + ULONG_PTR completedRequestIndex; + + err = WaitForIoCompletion(CompletionPortHandle, + &pOv, + &completionStatus); + if (ERROR_SUCCESS != err) { + goto clean0; + } + + completedRequestIndex = pOv-pOverlapped; + + printf(" Request %d completed with status 0x%X.\n", + (DWORD)completedRequestIndex, completionStatus); + + if (ERROR_SUCCESS != completionStatus) + { + if (!Cancel || + ERROR_OPERATION_ABORTED != completionStatus) + { + // + // If there is a setting to cancel requests it is ok for + // the requests to complete with aborted status. + // + err = completionStatus; + printf(" Unexpected completion status %d. \n", + completionStatus); + goto clean0; + } + } + else + { + // + // If request completed successfully verify the contents of the buffer. + // + if (! VerifyRequest(&inputBuffer[completedRequestIndex], + &outputBuffer[completedRequestIndex])) + { + printf(" Request completed with unexpected data in" + " output buffer. \n"); + err = ERROR_INVALID_DATA; + goto clean0; + } + } + + inputBuffer[completedRequestIndex].ComponentNumber = UNUSED; + outstandingIoCount--; + + if (k == completedRequestIndex) + { + // + // The request we are looking for has completed. + // + pOv = &pOverlapped[k]; + break; + } + else if (GetTickCount64() - startTime > REQUEST_TIMEOUT) + { + // + // The request we are looking for did not complete on time. + // + err = ERROR_TIMEOUT; + printf(" Request %d did not complete within the expected" + " time. \n", k); + assert(0); + goto clean0; + } + } + + } + + // + // We now have an overlapped structure to use. Set the input buffer + // to the target component and send the request. + // + ZeroMemory(pOv, sizeof(OVERLAPPED)); + inputBuffer[k].ComponentNumber = (Component == RANDOM_COMPONENT) ? + (rand() % COMPONENT_COUNT): + Component; + + if (0 != Delay) + { + // + // If there is a setting to introduce a delay, sleep and then send the + // request. + // + Sleep(rand() % Delay); + } + + err = SendRequest(DeviceHandle, + pOv, + &inputBuffer[k], + &outputBuffer[k]); + if (ERROR_SUCCESS != err) + { + goto clean0; + } + + outstandingIoCount++; + + printf(" Request number %d sent to component %d.\n", k, + inputBuffer[k].ComponentNumber); + + if (Cancel) + { + // + // If there is a setting to cancel the request then cancel it after + // issuing it. + // + CancelIoEx(DeviceHandle, + pOv); + } + } + +clean0: + if (outstandingIoCount > 0) + { + CancelIo(DeviceHandle); + for (index=0; index < outstandingIoCount; index++) + { + WaitForIoCompletion(CompletionPortHandle, + NULL, + NULL); + } + } + delete[] pOverlapped; + delete[] inputBuffer; + delete[] outputBuffer; + return err; +} + +BOOLEAN +VerifyRequest( + _In_ PPOWERFX_READ_COMPONENT_INPUT input, + _In_ PPOWERFX_READ_COMPONENT_OUTPUT output) +{ + return (output->ComponentData == ~input->ComponentNumber); +} + +DWORD +SendRequest( + _In_ HANDLE DeviceHandle, + _In_ LPOVERLAPPED OverlappedPtr, + _In_ PPOWERFX_READ_COMPONENT_INPUT inputBuffer, + _In_ PPOWERFX_READ_COMPONENT_OUTPUT outputBuffer) +{ + + BOOL bResult = FALSE; + DWORD err = ERROR_SUCCESS; + + bResult = DeviceIoControl(DeviceHandle, + (DWORD) IOCTL_POWERFX_READ_COMPONENT, + (PVOID)inputBuffer, + sizeof(POWERFX_READ_COMPONENT_INPUT), + (PVOID)outputBuffer, + sizeof(POWERFX_READ_COMPONENT_OUTPUT), + NULL, + OverlappedPtr); + if (FALSE == bResult) + { + err = GetLastError(); + if (ERROR_IO_PENDING == err) + { + // + // This is not really an error. + // + err = ERROR_SUCCESS; + } + else + { + printf("Unable to send request. DeviceIoControl failed with " + "error 0x%X. \n", err); + goto clean0; + } + } +clean0: + return err; +} + +DWORD +WaitForIoCompletion( + _In_ HANDLE CompletionPortHandle, + _In_opt_ LPOVERLAPPED* POvPtr, + _Out_opt_ PDWORD CompletionStatus) +{ + BOOL bResult; + DWORD err; + DWORD numBytes; + ULONG_PTR completionKey; + LPOVERLAPPED ovPtr; + DWORD completionStatus; + + // + // Assume successful completion of I/O request + // + completionStatus = ERROR_SUCCESS; + + // + // Dequeue a completion packet + // + bResult = GetQueuedCompletionStatus(CompletionPortHandle, + &numBytes, + &completionKey, + &ovPtr, + REQUEST_TIMEOUT); + if (FALSE == bResult) + { + err = GetLastError(); + if (NULL == ovPtr) + { + printf("Could not dequeue a completion packet. " + "GetQueuedCompletionStatus failed with error 0x%X.", + err); + assert(0); + goto clean0; + } + + // + // We dequeued a completion packet for an I/O operation that failed. + // Make a note of the failure status, but we need to return success from + // this function because we got a completion packet (even though it was + // for a failed I/O operation). + // + completionStatus = err; + err = ERROR_SUCCESS; + } + + if (NULL != POvPtr) { + *POvPtr = ovPtr; + } + + if (NULL != CompletionStatus) { + *CompletionStatus = completionStatus; + } + + err = ERROR_SUCCESS; + +clean0: + return err; +} + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PWSTR DevicePath, + _In_ size_t BufLen + ) +{ + HDEVINFO HardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData = NULL; + ULONG Length, RequiredLength = 0; + BOOL bResult; + HRESULT hr; + + HardwareDeviceInfo = SetupDiGetClassDevs( + InterfaceGuid, + NULL, + NULL, + (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + + if (HardwareDeviceInfo == INVALID_HANDLE_VALUE) { + printf("SetupDiGetClassDevs failed!\n"); + return FALSE; + } + + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + bResult = SetupDiEnumDeviceInterfaces(HardwareDeviceInfo, + 0, + InterfaceGuid, + 0, + &DeviceInterfaceData); + + if (bResult == FALSE) { + + LPVOID lpMsgBuf; + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR) &lpMsgBuf, + 0, + NULL + )) { + + printf("SetupDiEnumDeviceInterfaces failed: %ws", (LPTSTR)lpMsgBuf); + LocalFree(lpMsgBuf); + } + + printf("SetupDiEnumDeviceInterfaces failed.\n"); + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + return FALSE; + } + + SetupDiGetDeviceInterfaceDetail( + HardwareDeviceInfo, + &DeviceInterfaceData, + NULL, + 0, + &RequiredLength, + NULL + ); + + DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED, RequiredLength); + + if (DeviceInterfaceDetailData == NULL) { + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Failed to allocate memory.\n"); + return FALSE; + } + + DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + Length = RequiredLength; + + bResult = SetupDiGetDeviceInterfaceDetail( + HardwareDeviceInfo, + &DeviceInterfaceData, + DeviceInterfaceDetailData, + Length, + &RequiredLength, + NULL); + + if (bResult == FALSE) { + + LPVOID lpMsgBuf; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR) &lpMsgBuf, + 0, + NULL + ); + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Error in SetupDiGetDeviceInterfaceDetail: %ws\n", (LPWSTR)lpMsgBuf); + LocalFree(DeviceInterfaceDetailData); + LocalFree(lpMsgBuf); + return FALSE; + } + + hr = StringCchCopy(DevicePath, + BufLen, + DeviceInterfaceDetailData->DevicePath) ; + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); // It must be executed in both success and failure traces + LocalFree(DeviceInterfaceDetailData); + + return ( !FAILED(hr) ); // Result depends on StringCchCopy() +} + + diff --git a/pofx/WDF/App/PowerFxApp.vcxproj b/pofx/WDF/App/PowerFxApp.vcxproj new file mode 100644 index 00000000..32b104c3 --- /dev/null +++ b/pofx/WDF/App/PowerFxApp.vcxproj @@ -0,0 +1,192 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{3E233D0A-F988-4C9D-B15A-49B54025E11F}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{11455AB9-264E-4853-AE1E-615C1C5CA620}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>PowerFxApp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>PowerFxApp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>PowerFxApp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>PowerFxApp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="PowerFxApp.cpp" /> + <ClCompile Include="UserInput.cpp" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/pofx/WDF/App/PowerFxApp.vcxproj.Filters b/pofx/WDF/App/PowerFxApp.vcxproj.Filters new file mode 100644 index 00000000..8d16d12b --- /dev/null +++ b/pofx/WDF/App/PowerFxApp.vcxproj.Filters @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{C8B06C0E-8C3C-4875-8327-4C592F8FD738}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{8091FCE2-2451-4561-B199-CB021902EA1B}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{CC2C62EE-9135-480E-9DF9-5DB6BEB61DE8}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="PowerFxApp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="UserInput.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/pofx/WDF/App/UserInput.cpp b/pofx/WDF/App/UserInput.cpp new file mode 100644 index 00000000..dcd3ca75 --- /dev/null +++ b/pofx/WDF/App/UserInput.cpp @@ -0,0 +1,201 @@ +#include "include.h" + + +// +// The supported settings with their default values. +// +CONFIGURATION g_UserSettings[] = { + {COMPONENT ,0}, + {MAX_OUTSTANDING_IO ,1}, + {DELAY ,0}, + {CANCEL ,0} +}; + +DWORD +ProcessUserInput( + _In_ int argc, + _In_reads_(argc) PWSTR argv[] + ) +{ + DWORD err = ERROR_SUCCESS; + + for (int i=1; i < argc; i++) + { + PWSTR arg = argv[i]; + + // + // Setting must begin with / or - + // + if (arg[0] != L'-' && arg[0] != L'/') + { + printf("\n Invalid command-line argument %ws. \n", arg); + err = ERROR_INVALID_PARAMETER; + goto clean0; + } + + if (L'?' == arg[1]) + { + err = ERROR_INVALID_PARAMETER; + goto clean0; + } + + // + // Setting must contain ':' as the seperator. + // + PWSTR settingName = arg + 1; + PWSTR settingValue = NULL; + PWSTR seperator = wcschr(settingName, L':'); + if (seperator == NULL) + { + printf("\n Invalid command-line argument %ws. \n", arg); + err = ERROR_INVALID_PARAMETER; + goto clean0; + } + + settingValue = seperator + 1; + *seperator = L'\0'; + + // + // Store the value of the setting in the appropriate location. + // + err = ProcessSwitch(settingName, settingValue); + if (err != ERROR_SUCCESS) + { + goto clean0; + } + } + +clean0: + + if (ERROR_SUCCESS != err) + { + PrintUsage(argv); + } + return err; +} + + +PCONFIGURATION +LookupSwitch( + _In_ PWSTR Param) +{ + for (UINT i=0; i < COUNT_OF(g_UserSettings); i++) + { + if (_wcsicmp(Param, g_UserSettings[i].Option) == 0) + { + return &g_UserSettings[i]; + } + } + + return NULL; +} + +ULONG +GetSetting( + _In_ PWSTR Switch) +{ + return LookupSwitch(Switch)->Value; +} + +DWORD +ProcessSwitch( + _In_ PWSTR Param, + _In_ PWSTR Value) +{ + PCONFIGURATION config; + + config = LookupSwitch(Param); + if (NULL == config) + { + printf("\n '%ws' is not a valid switch", Param); + return ERROR_INVALID_PARAMETER; + } + + if (0 == _wcsicmp(Param, COMPONENT)) + { + if (0 == _wcsicmp(Value, L"*")) + { + config->Value = RANDOM_COMPONENT; + } + else + { + config->Value = _wtoi(Value); + if (config->Value >= COMPONENT_COUNT) + { + printf("Invalid component count '%ws' specified. " + "Component count must be less than %d. \n", Value, COMPONENT_COUNT); + return ERROR_INVALID_PARAMETER; + } + } + + } + else if (0 == _wcsicmp(Param, CANCEL)) + { + if (0 == _wcsicmp(Value, L"yes")) + { + config->Value = TRUE; + } + else if (0 == _wcsicmp(Value, L"no")) + { + config->Value = FALSE; + } + else + { + printf("'%ws' is not a valid option for '%ws'. Must be 'yes' or 'no'. \n", + Value, Param); + return ERROR_INVALID_PARAMETER; + } + } + else + { + // + // For MaxOutstandingIo or Delay this is sufficient. + // + config->Value = _wtoi(Value); + if (0 == config->Value) + { + printf("'%ws' is not a valid option for '%ws'", Value, Param); + return ERROR_INVALID_PARAMETER; + } + } + + return ERROR_SUCCESS; +} + + +void PrintUsage( + _In_ PWSTR argv[] + ) +{ + printf("\n This application can be used to send IO requests to a specified component"); + printf("\n of the WDF Power Fx sample driver. The requests will be sent indefinitely "); + printf("\n until a request fails or the user terminates the execution with ^C"); + printf("\n More details on the driver and application are in the associated help file."); + printf("\n "); + printf("\n Usage:"); + printf("\n %ws [/<SettingName>:<SettingValue> ...]", argv[0]); + printf("\n "); + printf("\n Available settings are:"); + printf("\n "); + printf("\n /Component:<Number>"); + printf("\n Where <Number> can be a specific component number, or if you are running with"); + printf("\n the multi-component sample driver you can specify '*'(without quotes) and "); + printf("\n each request will be sent to a random component between 0 and "); + printf("\n (COMPONENT_COUNT-1). Default value is component 0."); + printf("\n "); + printf("\n /Delay:<DelayInMilliSeconds>"); + printf("\n There is an approximate delay between 0 and <DelayInMilliSeconds> ms"); + printf("\n between each request. Default value is 0 (no delay)."); + printf("\n "); + printf("\n /MaxOutstandingIO:<NumberOfRequests>"); + printf("\n The maximum number of I/O requests that can be outstanding at any point."); + printf("\n Default value is 1 (equivalent to synchronously sending requests)."); + printf("\n "); + printf("\n /Cancel:<YesNo>"); + printf("\n Can be 'yes' or 'no' (without quotes)."); + printf("\n When set to 'yes' the application will attempt to cancel the requests once "); + printf("\n sent. Default value is 'no'."); + printf("\n "); + return; +} + diff --git a/pofx/WDF/App/include.h b/pofx/WDF/App/include.h new file mode 100644 index 00000000..29f0cb5e --- /dev/null +++ b/pofx/WDF/App/include.h @@ -0,0 +1,95 @@ +/*++ + + +--*/ +#include <DriverSpecs.h> + _Analysis_mode_(_Analysis_code_type_user_code_) + +#define INITGUID + +#include <windows.h> +#include <strsafe.h> +#include <setupapi.h> +#include <stdio.h> +#include <stdlib.h> +#include <devioctl.h> +#include <assert.h> +#include "AppInterface.h" + +#define COUNT_OF(x) sizeof(x)/sizeof(x[0]) + +#define MAX_DEVPATH_LENGTH 256 + +#define COMPONENT L"Component" +#define MAX_OUTSTANDING_IO L"MaxOutStandingIO" +#define DELAY L"Delay" +#define CANCEL L"Cancel" + +typedef struct _CONFIGURATION { + PWSTR Option; + ULONG Value; +} CONFIGURATION, *PCONFIGURATION; + +#define RANDOM_COMPONENT (DWORD)-1 +#define UNUSED COMPONENT_COUNT +#define REQUEST_TIMEOUT 10000 +#define MAX_DEVPATH_LENGTH 256 + +PCONFIGURATION +LookupSwitch( + _In_ PWSTR Param); + +DWORD +ProcessUserInput( + _In_ int argc, + _In_reads_(argc) PWSTR argv[] + ); + +ULONG +GetSetting( + _In_ PWSTR Switch); + +DWORD +ProcessSwitch( + _In_ PWSTR Param, + _In_ PWSTR Value); + +void PrintUsage( + _In_ PWSTR argv[] + ); + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PWCHAR DevicePath, + _In_ size_t BufLen + ); + + +DWORD SendIO( + _In_ HANDLE DeviceHandle, + _In_ HANDLE CompletionPortHandle, + _In_ ULONG Component, + _In_ ULONG MaxOutstandingIo, + _In_ ULONG Delay, + _In_ BOOLEAN Cancel + ); + +DWORD +WaitForIoCompletion( + _In_ HANDLE CompletionPortHandle, + _In_opt_ LPOVERLAPPED* POvPtr, + _Out_opt_ PDWORD CompletionStatus); + +BOOLEAN +VerifyRequest( + _In_ PPOWERFX_READ_COMPONENT_INPUT input, + _In_ PPOWERFX_READ_COMPONENT_OUTPUT output); + +DWORD +SendRequest( + _In_ HANDLE DeviceHandle, + _In_ LPOVERLAPPED OverlappedPtr, + _In_ PPOWERFX_READ_COMPONENT_INPUT inputBuffer, + _In_ PPOWERFX_READ_COMPONENT_OUTPUT outputBuffer); + |
